1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3#
4# Copyright (C) 2017 Google
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6# ----------------------------------------------------------------------------
7#
8#     ***     AUTO GENERATED CODE    ***    AUTO GENERATED CODE     ***
9#
10# ----------------------------------------------------------------------------
11#
12#     This file is automatically generated by Magic Modules and manual
13#     changes will be clobbered when the file is regenerated.
14#
15#     Please read more about how to change this file at
16#     https://www.github.com/GoogleCloudPlatform/magic-modules
17#
18# ----------------------------------------------------------------------------
19
20from __future__ import absolute_import, division, print_function
21
22__metaclass__ = type
23
24################################################################################
25# Documentation
26################################################################################
27
28ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ["preview"], 'supported_by': 'community'}
29
30DOCUMENTATION = '''
31---
32module: gcp_compute_backend_service
33description:
34- A Backend Service defines a group of virtual machines that will serve traffic for
35  load balancing. This resource is a global backend service, appropriate for external
36  load balancing or self-managed internal load balancing.
37- For managed internal load balancing, use a regional backend service instead.
38- Currently self-managed internal load balancing is only available in beta.
39short_description: Creates a GCP BackendService
40version_added: 2.6
41author: Google Inc. (@googlecloudplatform)
42requirements:
43- python >= 2.6
44- requests >= 2.18.4
45- google-auth >= 1.3.0
46options:
47  state:
48    description:
49    - Whether the given object should exist in GCP
50    choices:
51    - present
52    - absent
53    default: present
54    type: str
55  affinity_cookie_ttl_sec:
56    description:
57    - Lifetime of cookies in seconds if session_affinity is GENERATED_COOKIE. If set
58      to 0, the cookie is non-persistent and lasts only until the end of the browser
59      session (or equivalent). The maximum allowed value for TTL is one day.
60    - When the load balancing scheme is INTERNAL, this field is not used.
61    required: false
62    type: int
63  backends:
64    description:
65    - The set of backends that serve this BackendService.
66    required: false
67    type: list
68    suboptions:
69      balancing_mode:
70        description:
71        - Specifies the balancing mode for this backend.
72        - For global HTTP(S) or TCP/SSL load balancing, the default is UTILIZATION.
73          Valid values are UTILIZATION, RATE (for HTTP(S)) and CONNECTION (for TCP/SSL).
74        - 'Some valid choices include: "UTILIZATION", "RATE", "CONNECTION"'
75        required: false
76        default: UTILIZATION
77        type: str
78      capacity_scaler:
79        description:
80        - A multiplier applied to the group's maximum servicing capacity (based on
81          UTILIZATION, RATE or CONNECTION).
82        - Default value is 1, which means the group will serve up to 100% of its configured
83          capacity (depending on balancingMode). A setting of 0 means the group is
84          completely drained, offering 0% of its available Capacity. Valid range is
85          [0.0,1.0].
86        required: false
87        default: '1.0'
88        type: str
89      description:
90        description:
91        - An optional description of this resource.
92        - Provide this property when you create the resource.
93        required: false
94        type: str
95      group:
96        description:
97        - The fully-qualified URL of an Instance Group or Network Endpoint Group resource.
98          In case of instance group this defines the list of instances that serve
99          traffic. Member virtual machine instances from each instance group must
100          live in the same zone as the instance group itself. No two backends in a
101          backend service are allowed to use same Instance Group resource.
102        - For Network Endpoint Groups this defines list of endpoints. All endpoints
103          of Network Endpoint Group must be hosted on instances located in the same
104          zone as the Network Endpoint Group.
105        - Backend service can not contain mix of Instance Group and Network Endpoint
106          Group backends.
107        - Note that you must specify an Instance Group or Network Endpoint Group resource
108          using the fully-qualified URL, rather than a partial URL.
109        required: false
110        type: str
111      max_connections:
112        description:
113        - The max number of simultaneous connections for the group. Can be used with
114          either CONNECTION or UTILIZATION balancing modes.
115        - For CONNECTION mode, either maxConnections or one of maxConnectionsPerInstance
116          or maxConnectionsPerEndpoint, as appropriate for group type, must be set.
117        required: false
118        type: int
119      max_connections_per_instance:
120        description:
121        - The max number of simultaneous connections that a single backend instance
122          can handle. This is used to calculate the capacity of the group. Can be
123          used in either CONNECTION or UTILIZATION balancing modes.
124        - For CONNECTION mode, either maxConnections or maxConnectionsPerInstance
125          must be set.
126        required: false
127        type: int
128      max_connections_per_endpoint:
129        description:
130        - The max number of simultaneous connections that a single backend network
131          endpoint can handle. This is used to calculate the capacity of the group.
132          Can be used in either CONNECTION or UTILIZATION balancing modes.
133        - For CONNECTION mode, either maxConnections or maxConnectionsPerEndpoint
134          must be set.
135        required: false
136        type: int
137        version_added: 2.9
138      max_rate:
139        description:
140        - The max requests per second (RPS) of the group.
141        - Can be used with either RATE or UTILIZATION balancing modes, but required
142          if RATE mode. For RATE mode, either maxRate or one of maxRatePerInstance
143          or maxRatePerEndpoint, as appropriate for group type, must be set.
144        required: false
145        type: int
146      max_rate_per_instance:
147        description:
148        - The max requests per second (RPS) that a single backend instance can handle.
149          This is used to calculate the capacity of the group. Can be used in either
150          balancing mode. For RATE mode, either maxRate or maxRatePerInstance must
151          be set.
152        required: false
153        type: str
154      max_rate_per_endpoint:
155        description:
156        - The max requests per second (RPS) that a single backend network endpoint
157          can handle. This is used to calculate the capacity of the group. Can be
158          used in either balancing mode. For RATE mode, either maxRate or maxRatePerEndpoint
159          must be set.
160        required: false
161        type: str
162        version_added: 2.9
163      max_utilization:
164        description:
165        - Used when balancingMode is UTILIZATION. This ratio defines the CPU utilization
166          target for the group. The default is 0.8. Valid range is [0.0, 1.0].
167        required: false
168        default: '0.8'
169        type: str
170  cdn_policy:
171    description:
172    - Cloud CDN configuration for this BackendService.
173    required: false
174    type: dict
175    suboptions:
176      cache_key_policy:
177        description:
178        - The CacheKeyPolicy for this CdnPolicy.
179        required: false
180        type: dict
181        suboptions:
182          include_host:
183            description:
184            - If true requests to different hosts will be cached separately.
185            required: false
186            type: bool
187          include_protocol:
188            description:
189            - If true, http and https requests will be cached separately.
190            required: false
191            type: bool
192          include_query_string:
193            description:
194            - If true, include query string parameters in the cache key according
195              to query_string_whitelist and query_string_blacklist. If neither is
196              set, the entire query string will be included.
197            - If false, the query string will be excluded from the cache key entirely.
198            required: false
199            type: bool
200          query_string_blacklist:
201            description:
202            - Names of query string parameters to exclude in cache keys.
203            - All other parameters will be included. Either specify query_string_whitelist
204              or query_string_blacklist, not both.
205            - "'&' and '=' will be percent encoded and not treated as delimiters."
206            required: false
207            type: list
208          query_string_whitelist:
209            description:
210            - Names of query string parameters to include in cache keys.
211            - All other parameters will be excluded. Either specify query_string_whitelist
212              or query_string_blacklist, not both.
213            - "'&' and '=' will be percent encoded and not treated as delimiters."
214            required: false
215            type: list
216      signed_url_cache_max_age_sec:
217        description:
218        - Maximum number of seconds the response to a signed URL request will be considered
219          fresh, defaults to 1hr (3600s). After this time period, the response will
220          be revalidated before being served.
221        - 'When serving responses to signed URL requests, Cloud CDN will internally
222          behave as though all responses from this backend had a "Cache-Control: public,
223          max-age=[TTL]" header, regardless of any existing Cache-Control header.
224          The actual headers served in responses will not be altered.'
225        required: false
226        default: '3600'
227        type: int
228        version_added: 2.8
229  connection_draining:
230    description:
231    - Settings for connection draining .
232    required: false
233    type: dict
234    suboptions:
235      draining_timeout_sec:
236        description:
237        - Time for which instance will be drained (not accept new connections, but
238          still work to finish started).
239        required: false
240        default: '300'
241        type: int
242  description:
243    description:
244    - An optional description of this resource.
245    required: false
246    type: str
247  enable_cdn:
248    description:
249    - If true, enable Cloud CDN for this BackendService.
250    required: false
251    type: bool
252  health_checks:
253    description:
254    - The set of URLs to the HttpHealthCheck or HttpsHealthCheck resource for health
255      checking this BackendService. Currently at most one health check can be specified,
256      and a health check is required.
257    - For internal load balancing, a URL to a HealthCheck resource must be specified
258      instead.
259    required: true
260    type: list
261  iap:
262    description:
263    - Settings for enabling Cloud Identity Aware Proxy.
264    required: false
265    type: dict
266    version_added: 2.7
267    suboptions:
268      enabled:
269        description:
270        - Enables IAP.
271        required: false
272        type: bool
273      oauth2_client_id:
274        description:
275        - OAuth2 Client ID for IAP .
276        required: true
277        type: str
278      oauth2_client_secret:
279        description:
280        - OAuth2 Client Secret for IAP .
281        required: true
282        type: str
283  load_balancing_scheme:
284    description:
285    - Indicates whether the backend service will be used with internal or external
286      load balancing. A backend service created for one type of load balancing cannot
287      be used with the other. Must be `EXTERNAL` or `INTERNAL_SELF_MANAGED` for a
288      global backend service. Defaults to `EXTERNAL`.
289    - 'Some valid choices include: "EXTERNAL", "INTERNAL_SELF_MANAGED"'
290    required: false
291    default: EXTERNAL
292    type: str
293    version_added: 2.7
294  name:
295    description:
296    - Name of the resource. Provided by the client when the resource is created. The
297      name must be 1-63 characters long, and comply with RFC1035. Specifically, the
298      name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?`
299      which means the first character must be a lowercase letter, and all following
300      characters must be a dash, lowercase letter, or digit, except the last character,
301      which cannot be a dash.
302    required: true
303    type: str
304  port_name:
305    description:
306    - Name of backend port. The same name should appear in the instance groups referenced
307      by this service. Required when the load balancing scheme is EXTERNAL.
308    required: false
309    type: str
310  protocol:
311    description:
312    - The protocol this BackendService uses to communicate with backends.
313    - 'Possible values are HTTP, HTTPS, HTTP2, TCP, and SSL. The default is HTTP.
314      **NOTE**: HTTP2 is only valid for beta HTTP/2 load balancer types and may result
315      in errors if used with the GA API.'
316    - 'Some valid choices include: "HTTP", "HTTPS", "HTTP2", "TCP", "SSL"'
317    required: false
318    type: str
319  security_policy:
320    description:
321    - The security policy associated with this backend service.
322    required: false
323    type: str
324    version_added: 2.8
325  session_affinity:
326    description:
327    - Type of session affinity to use. The default is NONE.
328    - When the load balancing scheme is EXTERNAL, can be NONE, CLIENT_IP, or GENERATED_COOKIE.
329    - When the protocol is UDP, this field is not used.
330    - 'Some valid choices include: "NONE", "CLIENT_IP", "GENERATED_COOKIE"'
331    required: false
332    type: str
333  timeout_sec:
334    description:
335    - How many seconds to wait for the backend before considering it a failed request.
336      Default is 30 seconds. Valid range is [1, 86400].
337    required: false
338    type: int
339    aliases:
340    - timeout_seconds
341extends_documentation_fragment: gcp
342notes:
343- 'API Reference: U(https://cloud.google.com/compute/docs/reference/v1/backendServices)'
344- 'Official Documentation: U(https://cloud.google.com/compute/docs/load-balancing/http/backend-service)'
345'''
346
347EXAMPLES = '''
348- name: create a instance group
349  gcp_compute_instance_group:
350    name: instancegroup-backendservice
351    zone: us-central1-a
352    project: "{{ gcp_project }}"
353    auth_kind: "{{ gcp_cred_kind }}"
354    service_account_file: "{{ gcp_cred_file }}"
355    state: present
356  register: instancegroup
357
358- name: create a HTTP health check
359  gcp_compute_http_health_check:
360    name: httphealthcheck-backendservice
361    healthy_threshold: 10
362    port: 8080
363    timeout_sec: 2
364    unhealthy_threshold: 5
365    project: "{{ gcp_project }}"
366    auth_kind: "{{ gcp_cred_kind }}"
367    service_account_file: "{{ gcp_cred_file }}"
368    state: present
369  register: healthcheck
370
371- name: create a backend service
372  gcp_compute_backend_service:
373    name: test_object
374    backends:
375    - group: "{{ instancegroup.selfLink }}"
376    health_checks:
377    - "{{ healthcheck.selfLink }}"
378    enable_cdn: 'true'
379    project: test_project
380    auth_kind: serviceaccount
381    service_account_file: "/tmp/auth.pem"
382    state: present
383'''
384
385RETURN = '''
386affinityCookieTtlSec:
387  description:
388  - Lifetime of cookies in seconds if session_affinity is GENERATED_COOKIE. If set
389    to 0, the cookie is non-persistent and lasts only until the end of the browser
390    session (or equivalent). The maximum allowed value for TTL is one day.
391  - When the load balancing scheme is INTERNAL, this field is not used.
392  returned: success
393  type: int
394backends:
395  description:
396  - The set of backends that serve this BackendService.
397  returned: success
398  type: complex
399  contains:
400    balancingMode:
401      description:
402      - Specifies the balancing mode for this backend.
403      - For global HTTP(S) or TCP/SSL load balancing, the default is UTILIZATION.
404        Valid values are UTILIZATION, RATE (for HTTP(S)) and CONNECTION (for TCP/SSL).
405      returned: success
406      type: str
407    capacityScaler:
408      description:
409      - A multiplier applied to the group's maximum servicing capacity (based on UTILIZATION,
410        RATE or CONNECTION).
411      - Default value is 1, which means the group will serve up to 100% of its configured
412        capacity (depending on balancingMode). A setting of 0 means the group is completely
413        drained, offering 0% of its available Capacity. Valid range is [0.0,1.0].
414      returned: success
415      type: str
416    description:
417      description:
418      - An optional description of this resource.
419      - Provide this property when you create the resource.
420      returned: success
421      type: str
422    group:
423      description:
424      - The fully-qualified URL of an Instance Group or Network Endpoint Group resource.
425        In case of instance group this defines the list of instances that serve traffic.
426        Member virtual machine instances from each instance group must live in the
427        same zone as the instance group itself. No two backends in a backend service
428        are allowed to use same Instance Group resource.
429      - For Network Endpoint Groups this defines list of endpoints. All endpoints
430        of Network Endpoint Group must be hosted on instances located in the same
431        zone as the Network Endpoint Group.
432      - Backend service can not contain mix of Instance Group and Network Endpoint
433        Group backends.
434      - Note that you must specify an Instance Group or Network Endpoint Group resource
435        using the fully-qualified URL, rather than a partial URL.
436      returned: success
437      type: str
438    maxConnections:
439      description:
440      - The max number of simultaneous connections for the group. Can be used with
441        either CONNECTION or UTILIZATION balancing modes.
442      - For CONNECTION mode, either maxConnections or one of maxConnectionsPerInstance
443        or maxConnectionsPerEndpoint, as appropriate for group type, must be set.
444      returned: success
445      type: int
446    maxConnectionsPerInstance:
447      description:
448      - The max number of simultaneous connections that a single backend instance
449        can handle. This is used to calculate the capacity of the group. Can be used
450        in either CONNECTION or UTILIZATION balancing modes.
451      - For CONNECTION mode, either maxConnections or maxConnectionsPerInstance must
452        be set.
453      returned: success
454      type: int
455    maxConnectionsPerEndpoint:
456      description:
457      - The max number of simultaneous connections that a single backend network endpoint
458        can handle. This is used to calculate the capacity of the group. Can be used
459        in either CONNECTION or UTILIZATION balancing modes.
460      - For CONNECTION mode, either maxConnections or maxConnectionsPerEndpoint must
461        be set.
462      returned: success
463      type: int
464    maxRate:
465      description:
466      - The max requests per second (RPS) of the group.
467      - Can be used with either RATE or UTILIZATION balancing modes, but required
468        if RATE mode. For RATE mode, either maxRate or one of maxRatePerInstance or
469        maxRatePerEndpoint, as appropriate for group type, must be set.
470      returned: success
471      type: int
472    maxRatePerInstance:
473      description:
474      - The max requests per second (RPS) that a single backend instance can handle.
475        This is used to calculate the capacity of the group. Can be used in either
476        balancing mode. For RATE mode, either maxRate or maxRatePerInstance must be
477        set.
478      returned: success
479      type: str
480    maxRatePerEndpoint:
481      description:
482      - The max requests per second (RPS) that a single backend network endpoint can
483        handle. This is used to calculate the capacity of the group. Can be used in
484        either balancing mode. For RATE mode, either maxRate or maxRatePerEndpoint
485        must be set.
486      returned: success
487      type: str
488    maxUtilization:
489      description:
490      - Used when balancingMode is UTILIZATION. This ratio defines the CPU utilization
491        target for the group. The default is 0.8. Valid range is [0.0, 1.0].
492      returned: success
493      type: str
494cdnPolicy:
495  description:
496  - Cloud CDN configuration for this BackendService.
497  returned: success
498  type: complex
499  contains:
500    cacheKeyPolicy:
501      description:
502      - The CacheKeyPolicy for this CdnPolicy.
503      returned: success
504      type: complex
505      contains:
506        includeHost:
507          description:
508          - If true requests to different hosts will be cached separately.
509          returned: success
510          type: bool
511        includeProtocol:
512          description:
513          - If true, http and https requests will be cached separately.
514          returned: success
515          type: bool
516        includeQueryString:
517          description:
518          - If true, include query string parameters in the cache key according to
519            query_string_whitelist and query_string_blacklist. If neither is set,
520            the entire query string will be included.
521          - If false, the query string will be excluded from the cache key entirely.
522          returned: success
523          type: bool
524        queryStringBlacklist:
525          description:
526          - Names of query string parameters to exclude in cache keys.
527          - All other parameters will be included. Either specify query_string_whitelist
528            or query_string_blacklist, not both.
529          - "'&' and '=' will be percent encoded and not treated as delimiters."
530          returned: success
531          type: list
532        queryStringWhitelist:
533          description:
534          - Names of query string parameters to include in cache keys.
535          - All other parameters will be excluded. Either specify query_string_whitelist
536            or query_string_blacklist, not both.
537          - "'&' and '=' will be percent encoded and not treated as delimiters."
538          returned: success
539          type: list
540    signedUrlCacheMaxAgeSec:
541      description:
542      - Maximum number of seconds the response to a signed URL request will be considered
543        fresh, defaults to 1hr (3600s). After this time period, the response will
544        be revalidated before being served.
545      - 'When serving responses to signed URL requests, Cloud CDN will internally
546        behave as though all responses from this backend had a "Cache-Control: public,
547        max-age=[TTL]" header, regardless of any existing Cache-Control header. The
548        actual headers served in responses will not be altered.'
549      returned: success
550      type: int
551connectionDraining:
552  description:
553  - Settings for connection draining .
554  returned: success
555  type: complex
556  contains:
557    drainingTimeoutSec:
558      description:
559      - Time for which instance will be drained (not accept new connections, but still
560        work to finish started).
561      returned: success
562      type: int
563creationTimestamp:
564  description:
565  - Creation timestamp in RFC3339 text format.
566  returned: success
567  type: str
568fingerprint:
569  description:
570  - Fingerprint of this resource. A hash of the contents stored in this object. This
571    field is used in optimistic locking.
572  returned: success
573  type: str
574description:
575  description:
576  - An optional description of this resource.
577  returned: success
578  type: str
579enableCDN:
580  description:
581  - If true, enable Cloud CDN for this BackendService.
582  returned: success
583  type: bool
584healthChecks:
585  description:
586  - The set of URLs to the HttpHealthCheck or HttpsHealthCheck resource for health
587    checking this BackendService. Currently at most one health check can be specified,
588    and a health check is required.
589  - For internal load balancing, a URL to a HealthCheck resource must be specified
590    instead.
591  returned: success
592  type: list
593id:
594  description:
595  - The unique identifier for the resource.
596  returned: success
597  type: int
598iap:
599  description:
600  - Settings for enabling Cloud Identity Aware Proxy.
601  returned: success
602  type: complex
603  contains:
604    enabled:
605      description:
606      - Enables IAP.
607      returned: success
608      type: bool
609    oauth2ClientId:
610      description:
611      - OAuth2 Client ID for IAP .
612      returned: success
613      type: str
614    oauth2ClientSecret:
615      description:
616      - OAuth2 Client Secret for IAP .
617      returned: success
618      type: str
619    oauth2ClientSecretSha256:
620      description:
621      - OAuth2 Client Secret SHA-256 for IAP .
622      returned: success
623      type: str
624loadBalancingScheme:
625  description:
626  - Indicates whether the backend service will be used with internal or external load
627    balancing. A backend service created for one type of load balancing cannot be
628    used with the other. Must be `EXTERNAL` or `INTERNAL_SELF_MANAGED` for a global
629    backend service. Defaults to `EXTERNAL`.
630  returned: success
631  type: str
632name:
633  description:
634  - Name of the resource. Provided by the client when the resource is created. The
635    name must be 1-63 characters long, and comply with RFC1035. Specifically, the
636    name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?`
637    which means the first character must be a lowercase letter, and all following
638    characters must be a dash, lowercase letter, or digit, except the last character,
639    which cannot be a dash.
640  returned: success
641  type: str
642portName:
643  description:
644  - Name of backend port. The same name should appear in the instance groups referenced
645    by this service. Required when the load balancing scheme is EXTERNAL.
646  returned: success
647  type: str
648protocol:
649  description:
650  - The protocol this BackendService uses to communicate with backends.
651  - 'Possible values are HTTP, HTTPS, HTTP2, TCP, and SSL. The default is HTTP. **NOTE**:
652    HTTP2 is only valid for beta HTTP/2 load balancer types and may result in errors
653    if used with the GA API.'
654  returned: success
655  type: str
656securityPolicy:
657  description:
658  - The security policy associated with this backend service.
659  returned: success
660  type: str
661sessionAffinity:
662  description:
663  - Type of session affinity to use. The default is NONE.
664  - When the load balancing scheme is EXTERNAL, can be NONE, CLIENT_IP, or GENERATED_COOKIE.
665  - When the protocol is UDP, this field is not used.
666  returned: success
667  type: str
668timeoutSec:
669  description:
670  - How many seconds to wait for the backend before considering it a failed request.
671    Default is 30 seconds. Valid range is [1, 86400].
672  returned: success
673  type: int
674'''
675
676################################################################################
677# Imports
678################################################################################
679
680from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, remove_nones_from_dict, replace_resource_dict
681import json
682import time
683
684################################################################################
685# Main
686################################################################################
687
688
689def main():
690    """Main function"""
691
692    module = GcpModule(
693        argument_spec=dict(
694            state=dict(default='present', choices=['present', 'absent'], type='str'),
695            affinity_cookie_ttl_sec=dict(type='int'),
696            backends=dict(
697                type='list',
698                elements='dict',
699                options=dict(
700                    balancing_mode=dict(default='UTILIZATION', type='str'),
701                    capacity_scaler=dict(default=1.0, type='str'),
702                    description=dict(type='str'),
703                    group=dict(type='str'),
704                    max_connections=dict(type='int'),
705                    max_connections_per_instance=dict(type='int'),
706                    max_connections_per_endpoint=dict(type='int'),
707                    max_rate=dict(type='int'),
708                    max_rate_per_instance=dict(type='str'),
709                    max_rate_per_endpoint=dict(type='str'),
710                    max_utilization=dict(default=0.8, type='str'),
711                ),
712            ),
713            cdn_policy=dict(
714                type='dict',
715                options=dict(
716                    cache_key_policy=dict(
717                        type='dict',
718                        options=dict(
719                            include_host=dict(type='bool'),
720                            include_protocol=dict(type='bool'),
721                            include_query_string=dict(type='bool'),
722                            query_string_blacklist=dict(type='list', elements='str'),
723                            query_string_whitelist=dict(type='list', elements='str'),
724                        ),
725                    ),
726                    signed_url_cache_max_age_sec=dict(default=3600, type='int'),
727                ),
728            ),
729            connection_draining=dict(type='dict', options=dict(draining_timeout_sec=dict(default=300, type='int'))),
730            description=dict(type='str'),
731            enable_cdn=dict(type='bool'),
732            health_checks=dict(required=True, type='list', elements='str'),
733            iap=dict(
734                type='dict',
735                options=dict(
736                    enabled=dict(type='bool'),
737                    oauth2_client_id=dict(required=True, type='str'),
738                    oauth2_client_secret=dict(required=True, type='str', no_log=True),
739                ),
740            ),
741            load_balancing_scheme=dict(default='EXTERNAL', type='str'),
742            name=dict(required=True, type='str'),
743            port_name=dict(type='str'),
744            protocol=dict(type='str'),
745            security_policy=dict(type='str'),
746            session_affinity=dict(type='str'),
747            timeout_sec=dict(type='int', aliases=['timeout_seconds']),
748        )
749    )
750
751    if not module.params['scopes']:
752        module.params['scopes'] = ['https://www.googleapis.com/auth/compute']
753
754    state = module.params['state']
755    kind = 'compute#backendService'
756
757    fetch = fetch_resource(module, self_link(module), kind)
758    changed = False
759
760    if fetch:
761        if state == 'present':
762            if is_different(module, fetch):
763                update(module, self_link(module), kind, fetch)
764                fetch = fetch_resource(module, self_link(module), kind)
765                changed = True
766        else:
767            delete(module, self_link(module), kind)
768            fetch = {}
769            changed = True
770    else:
771        if state == 'present':
772            fetch = create(module, collection(module), kind)
773            changed = True
774        else:
775            fetch = {}
776
777    fetch.update({'changed': changed})
778
779    module.exit_json(**fetch)
780
781
782def create(module, link, kind):
783    auth = GcpSession(module, 'compute')
784    return wait_for_operation(module, auth.post(link, resource_to_request(module)))
785
786
787def update(module, link, kind, fetch):
788    update_fields(module, resource_to_request(module), response_to_hash(module, fetch))
789    auth = GcpSession(module, 'compute')
790    return wait_for_operation(module, auth.put(link, resource_to_request(module)))
791
792
793def update_fields(module, request, response):
794    if response.get('securityPolicy') != request.get('securityPolicy'):
795        security_policy_update(module, request, response)
796
797
798def security_policy_update(module, request, response):
799    auth = GcpSession(module, 'compute')
800    auth.post(
801        ''.join(["https://www.googleapis.com/compute/v1/", "projects/{project}/global/backendServices/{name}/setSecurityPolicy"]).format(**module.params),
802        {u'securityPolicy': module.params.get('security_policy')},
803    )
804
805
806def delete(module, link, kind):
807    auth = GcpSession(module, 'compute')
808    return wait_for_operation(module, auth.delete(link))
809
810
811def resource_to_request(module):
812    request = {
813        u'kind': 'compute#backendService',
814        u'affinityCookieTtlSec': module.params.get('affinity_cookie_ttl_sec'),
815        u'backends': BackendServiceBackendsArray(module.params.get('backends', []), module).to_request(),
816        u'cdnPolicy': BackendServiceCdnpolicy(module.params.get('cdn_policy', {}), module).to_request(),
817        u'connectionDraining': BackendServiceConnectiondraining(module.params.get('connection_draining', {}), module).to_request(),
818        u'description': module.params.get('description'),
819        u'enableCDN': module.params.get('enable_cdn'),
820        u'healthChecks': module.params.get('health_checks'),
821        u'iap': BackendServiceIap(module.params.get('iap', {}), module).to_request(),
822        u'loadBalancingScheme': module.params.get('load_balancing_scheme'),
823        u'name': module.params.get('name'),
824        u'portName': module.params.get('port_name'),
825        u'protocol': module.params.get('protocol'),
826        u'securityPolicy': module.params.get('security_policy'),
827        u'sessionAffinity': module.params.get('session_affinity'),
828        u'timeoutSec': module.params.get('timeout_sec'),
829    }
830    return_vals = {}
831    for k, v in request.items():
832        if v or v is False:
833            return_vals[k] = v
834
835    return return_vals
836
837
838def fetch_resource(module, link, kind, allow_not_found=True):
839    auth = GcpSession(module, 'compute')
840    return return_if_object(module, auth.get(link), kind, allow_not_found)
841
842
843def self_link(module):
844    return "https://www.googleapis.com/compute/v1/projects/{project}/global/backendServices/{name}".format(**module.params)
845
846
847def collection(module):
848    return "https://www.googleapis.com/compute/v1/projects/{project}/global/backendServices".format(**module.params)
849
850
851def return_if_object(module, response, kind, allow_not_found=False):
852    # If not found, return nothing.
853    if allow_not_found and response.status_code == 404:
854        return None
855
856    # If no content, return nothing.
857    if response.status_code == 204:
858        return None
859
860    try:
861        module.raise_for_status(response)
862        result = response.json()
863    except getattr(json.decoder, 'JSONDecodeError', ValueError):
864        module.fail_json(msg="Invalid JSON response with error: %s" % response.text)
865
866    if navigate_hash(result, ['error', 'errors']):
867        module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
868
869    return result
870
871
872def is_different(module, response):
873    request = resource_to_request(module)
874    response = response_to_hash(module, response)
875
876    # Remove all output-only from response.
877    response_vals = {}
878    for k, v in response.items():
879        if k in request:
880            response_vals[k] = v
881
882    request_vals = {}
883    for k, v in request.items():
884        if k in response:
885            request_vals[k] = v
886
887    return GcpRequest(request_vals) != GcpRequest(response_vals)
888
889
890# Remove unnecessary properties from the response.
891# This is for doing comparisons with Ansible's current parameters.
892def response_to_hash(module, response):
893    return {
894        u'affinityCookieTtlSec': response.get(u'affinityCookieTtlSec'),
895        u'backends': BackendServiceBackendsArray(response.get(u'backends', []), module).from_response(),
896        u'cdnPolicy': BackendServiceCdnpolicy(response.get(u'cdnPolicy', {}), module).from_response(),
897        u'connectionDraining': BackendServiceConnectiondraining(response.get(u'connectionDraining', {}), module).from_response(),
898        u'creationTimestamp': response.get(u'creationTimestamp'),
899        u'fingerprint': response.get(u'fingerprint'),
900        u'description': response.get(u'description'),
901        u'enableCDN': response.get(u'enableCDN'),
902        u'healthChecks': response.get(u'healthChecks'),
903        u'id': response.get(u'id'),
904        u'iap': BackendServiceIap(response.get(u'iap', {}), module).from_response(),
905        u'loadBalancingScheme': module.params.get('load_balancing_scheme'),
906        u'name': module.params.get('name'),
907        u'portName': response.get(u'portName'),
908        u'protocol': response.get(u'protocol'),
909        u'securityPolicy': response.get(u'securityPolicy'),
910        u'sessionAffinity': response.get(u'sessionAffinity'),
911        u'timeoutSec': response.get(u'timeoutSec'),
912    }
913
914
915def async_op_url(module, extra_data=None):
916    if extra_data is None:
917        extra_data = {}
918    url = "https://www.googleapis.com/compute/v1/projects/{project}/global/operations/{op_id}"
919    combined = extra_data.copy()
920    combined.update(module.params)
921    return url.format(**combined)
922
923
924def wait_for_operation(module, response):
925    op_result = return_if_object(module, response, 'compute#operation')
926    if op_result is None:
927        return {}
928    status = navigate_hash(op_result, ['status'])
929    wait_done = wait_for_completion(status, op_result, module)
930    return fetch_resource(module, navigate_hash(wait_done, ['targetLink']), 'compute#backendService')
931
932
933def wait_for_completion(status, op_result, module):
934    op_id = navigate_hash(op_result, ['name'])
935    op_uri = async_op_url(module, {'op_id': op_id})
936    while status != 'DONE':
937        raise_if_errors(op_result, ['error', 'errors'], module)
938        time.sleep(1.0)
939        op_result = fetch_resource(module, op_uri, 'compute#operation', False)
940        status = navigate_hash(op_result, ['status'])
941    return op_result
942
943
944def raise_if_errors(response, err_path, module):
945    errors = navigate_hash(response, err_path)
946    if errors is not None:
947        module.fail_json(msg=errors)
948
949
950class BackendServiceBackendsArray(object):
951    def __init__(self, request, module):
952        self.module = module
953        if request:
954            self.request = request
955        else:
956            self.request = []
957
958    def to_request(self):
959        items = []
960        for item in self.request:
961            items.append(self._request_for_item(item))
962        return items
963
964    def from_response(self):
965        items = []
966        for item in self.request:
967            items.append(self._response_from_item(item))
968        return items
969
970    def _request_for_item(self, item):
971        return remove_nones_from_dict(
972            {
973                u'balancingMode': item.get('balancing_mode'),
974                u'capacityScaler': item.get('capacity_scaler'),
975                u'description': item.get('description'),
976                u'group': item.get('group'),
977                u'maxConnections': item.get('max_connections'),
978                u'maxConnectionsPerInstance': item.get('max_connections_per_instance'),
979                u'maxConnectionsPerEndpoint': item.get('max_connections_per_endpoint'),
980                u'maxRate': item.get('max_rate'),
981                u'maxRatePerInstance': item.get('max_rate_per_instance'),
982                u'maxRatePerEndpoint': item.get('max_rate_per_endpoint'),
983                u'maxUtilization': item.get('max_utilization'),
984            }
985        )
986
987    def _response_from_item(self, item):
988        return remove_nones_from_dict(
989            {
990                u'balancingMode': item.get(u'balancingMode'),
991                u'capacityScaler': item.get(u'capacityScaler'),
992                u'description': item.get(u'description'),
993                u'group': item.get(u'group'),
994                u'maxConnections': item.get(u'maxConnections'),
995                u'maxConnectionsPerInstance': item.get(u'maxConnectionsPerInstance'),
996                u'maxConnectionsPerEndpoint': item.get(u'maxConnectionsPerEndpoint'),
997                u'maxRate': item.get(u'maxRate'),
998                u'maxRatePerInstance': item.get(u'maxRatePerInstance'),
999                u'maxRatePerEndpoint': item.get(u'maxRatePerEndpoint'),
1000                u'maxUtilization': item.get(u'maxUtilization'),
1001            }
1002        )
1003
1004
1005class BackendServiceCdnpolicy(object):
1006    def __init__(self, request, module):
1007        self.module = module
1008        if request:
1009            self.request = request
1010        else:
1011            self.request = {}
1012
1013    def to_request(self):
1014        return remove_nones_from_dict(
1015            {
1016                u'cacheKeyPolicy': BackendServiceCachekeypolicy(self.request.get('cache_key_policy', {}), self.module).to_request(),
1017                u'signedUrlCacheMaxAgeSec': self.request.get('signed_url_cache_max_age_sec'),
1018            }
1019        )
1020
1021    def from_response(self):
1022        return remove_nones_from_dict(
1023            {
1024                u'cacheKeyPolicy': BackendServiceCachekeypolicy(self.request.get(u'cacheKeyPolicy', {}), self.module).from_response(),
1025                u'signedUrlCacheMaxAgeSec': self.request.get(u'signedUrlCacheMaxAgeSec'),
1026            }
1027        )
1028
1029
1030class BackendServiceCachekeypolicy(object):
1031    def __init__(self, request, module):
1032        self.module = module
1033        if request:
1034            self.request = request
1035        else:
1036            self.request = {}
1037
1038    def to_request(self):
1039        return remove_nones_from_dict(
1040            {
1041                u'includeHost': self.request.get('include_host'),
1042                u'includeProtocol': self.request.get('include_protocol'),
1043                u'includeQueryString': self.request.get('include_query_string'),
1044                u'queryStringBlacklist': self.request.get('query_string_blacklist'),
1045                u'queryStringWhitelist': self.request.get('query_string_whitelist'),
1046            }
1047        )
1048
1049    def from_response(self):
1050        return remove_nones_from_dict(
1051            {
1052                u'includeHost': self.request.get(u'includeHost'),
1053                u'includeProtocol': self.request.get(u'includeProtocol'),
1054                u'includeQueryString': self.request.get(u'includeQueryString'),
1055                u'queryStringBlacklist': self.request.get(u'queryStringBlacklist'),
1056                u'queryStringWhitelist': self.request.get(u'queryStringWhitelist'),
1057            }
1058        )
1059
1060
1061class BackendServiceConnectiondraining(object):
1062    def __init__(self, request, module):
1063        self.module = module
1064        if request:
1065            self.request = request
1066        else:
1067            self.request = {}
1068
1069    def to_request(self):
1070        return remove_nones_from_dict({u'drainingTimeoutSec': self.request.get('draining_timeout_sec')})
1071
1072    def from_response(self):
1073        return remove_nones_from_dict({u'drainingTimeoutSec': self.request.get(u'drainingTimeoutSec')})
1074
1075
1076class BackendServiceIap(object):
1077    def __init__(self, request, module):
1078        self.module = module
1079        if request:
1080            self.request = request
1081        else:
1082            self.request = {}
1083
1084    def to_request(self):
1085        return remove_nones_from_dict(
1086            {
1087                u'enabled': self.request.get('enabled'),
1088                u'oauth2ClientId': self.request.get('oauth2_client_id'),
1089                u'oauth2ClientSecret': self.request.get('oauth2_client_secret'),
1090            }
1091        )
1092
1093    def from_response(self):
1094        return remove_nones_from_dict(
1095            {
1096                u'enabled': self.request.get(u'enabled'),
1097                u'oauth2ClientId': self.request.get(u'oauth2ClientId'),
1098                u'oauth2ClientSecret': self.request.get(u'oauth2ClientSecret'),
1099            }
1100        )
1101
1102
1103if __name__ == '__main__':
1104    main()
1105