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_health_check
33description:
34- Health Checks determine whether instances are responsive and able to do work.
35- They are an important part of a comprehensive load balancing configuration, as they
36  enable monitoring instances behind load balancers.
37- Health Checks poll instances at a specified interval. Instances that do not respond
38  successfully to some number of probes in a row are marked as unhealthy. No new connections
39  are sent to unhealthy instances, though existing connections will continue. The
40  health check will continue to poll unhealthy instances. If an instance later responds
41  successfully to some number of consecutive probes, it is marked healthy again and
42  can receive new connections.
43short_description: Creates a GCP HealthCheck
44version_added: 2.6
45author: Google Inc. (@googlecloudplatform)
46requirements:
47- python >= 2.6
48- requests >= 2.18.4
49- google-auth >= 1.3.0
50options:
51  state:
52    description:
53    - Whether the given object should exist in GCP
54    choices:
55    - present
56    - absent
57    default: present
58    type: str
59  check_interval_sec:
60    description:
61    - How often (in seconds) to send a health check. The default value is 5 seconds.
62    required: false
63    default: '5'
64    type: int
65  description:
66    description:
67    - An optional description of this resource. Provide this property when you create
68      the resource.
69    required: false
70    type: str
71  healthy_threshold:
72    description:
73    - A so-far unhealthy instance will be marked healthy after this many consecutive
74      successes. The default value is 2.
75    required: false
76    default: '2'
77    type: int
78  name:
79    description:
80    - Name of the resource. Provided by the client when the resource is created. The
81      name must be 1-63 characters long, and comply with RFC1035. Specifically, the
82      name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?`
83      which means the first character must be a lowercase letter, and all following
84      characters must be a dash, lowercase letter, or digit, except the last character,
85      which cannot be a dash.
86    required: true
87    type: str
88  timeout_sec:
89    description:
90    - How long (in seconds) to wait before claiming failure.
91    - The default value is 5 seconds. It is invalid for timeoutSec to have greater
92      value than checkIntervalSec.
93    required: false
94    default: '5'
95    type: int
96    aliases:
97    - timeout_seconds
98  unhealthy_threshold:
99    description:
100    - A so-far healthy instance will be marked unhealthy after this many consecutive
101      failures. The default value is 2.
102    required: false
103    default: '2'
104    type: int
105  type:
106    description:
107    - Specifies the type of the healthCheck, either TCP, SSL, HTTP or HTTPS. If not
108      specified, the default is TCP. Exactly one of the protocol-specific health check
109      field must be specified, which must match type field.
110    - 'Some valid choices include: "TCP", "SSL", "HTTP", "HTTPS"'
111    required: false
112    type: str
113  http_health_check:
114    description:
115    - A nested object resource.
116    required: false
117    type: dict
118    suboptions:
119      host:
120        description:
121        - The value of the host header in the HTTP health check request.
122        - If left empty (default value), the public IP on behalf of which this health
123          check is performed will be used.
124        required: false
125        type: str
126      request_path:
127        description:
128        - The request path of the HTTP health check request.
129        - The default value is /.
130        required: false
131        default: "/"
132        type: str
133      response:
134        description:
135        - The bytes to match against the beginning of the response data. If left empty
136          (the default value), any response will indicate health. The response data
137          can only be ASCII.
138        required: false
139        type: str
140      port:
141        description:
142        - The TCP port number for the HTTP health check request.
143        - The default value is 80.
144        required: false
145        type: int
146      port_name:
147        description:
148        - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
149          are defined, port takes precedence.
150        required: false
151        type: str
152      proxy_header:
153        description:
154        - Specifies the type of proxy header to append before sending data to the
155          backend, either NONE or PROXY_V1. The default is NONE.
156        - 'Some valid choices include: "NONE", "PROXY_V1"'
157        required: false
158        default: NONE
159        type: str
160      port_specification:
161        description:
162        - 'Specifies how port is selected for health checking, can be one of the following
163          values: * `USE_FIXED_PORT`: The port number in `port` is used for health
164          checking.'
165        - "* `USE_NAMED_PORT`: The `portName` is used for health checking."
166        - "* `USE_SERVING_PORT`: For NetworkEndpointGroup, the port specified for
167          each network endpoint is used for health checking. For other backends, the
168          port or named port specified in the Backend Service is used for health checking."
169        - If not specified, HTTP health check follows behavior specified in `port`
170          and `portName` fields.
171        - 'Some valid choices include: "USE_FIXED_PORT", "USE_NAMED_PORT", "USE_SERVING_PORT"'
172        required: false
173        type: str
174        version_added: 2.9
175  https_health_check:
176    description:
177    - A nested object resource.
178    required: false
179    type: dict
180    suboptions:
181      host:
182        description:
183        - The value of the host header in the HTTPS health check request.
184        - If left empty (default value), the public IP on behalf of which this health
185          check is performed will be used.
186        required: false
187        type: str
188      request_path:
189        description:
190        - The request path of the HTTPS health check request.
191        - The default value is /.
192        required: false
193        default: "/"
194        type: str
195      response:
196        description:
197        - The bytes to match against the beginning of the response data. If left empty
198          (the default value), any response will indicate health. The response data
199          can only be ASCII.
200        required: false
201        type: str
202      port:
203        description:
204        - The TCP port number for the HTTPS health check request.
205        - The default value is 443.
206        required: false
207        type: int
208      port_name:
209        description:
210        - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
211          are defined, port takes precedence.
212        required: false
213        type: str
214      proxy_header:
215        description:
216        - Specifies the type of proxy header to append before sending data to the
217          backend, either NONE or PROXY_V1. The default is NONE.
218        - 'Some valid choices include: "NONE", "PROXY_V1"'
219        required: false
220        default: NONE
221        type: str
222      port_specification:
223        description:
224        - 'Specifies how port is selected for health checking, can be one of the following
225          values: * `USE_FIXED_PORT`: The port number in `port` is used for health
226          checking.'
227        - "* `USE_NAMED_PORT`: The `portName` is used for health checking."
228        - "* `USE_SERVING_PORT`: For NetworkEndpointGroup, the port specified for
229          each network endpoint is used for health checking. For other backends, the
230          port or named port specified in the Backend Service is used for health checking."
231        - If not specified, HTTPS health check follows behavior specified in `port`
232          and `portName` fields.
233        - 'Some valid choices include: "USE_FIXED_PORT", "USE_NAMED_PORT", "USE_SERVING_PORT"'
234        required: false
235        type: str
236        version_added: 2.9
237  tcp_health_check:
238    description:
239    - A nested object resource.
240    required: false
241    type: dict
242    suboptions:
243      request:
244        description:
245        - The application data to send once the TCP connection has been established
246          (default value is empty). If both request and response are empty, the connection
247          establishment alone will indicate health. The request data can only be ASCII.
248        required: false
249        type: str
250      response:
251        description:
252        - The bytes to match against the beginning of the response data. If left empty
253          (the default value), any response will indicate health. The response data
254          can only be ASCII.
255        required: false
256        type: str
257      port:
258        description:
259        - The TCP port number for the TCP health check request.
260        - The default value is 443.
261        required: false
262        type: int
263      port_name:
264        description:
265        - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
266          are defined, port takes precedence.
267        required: false
268        type: str
269      proxy_header:
270        description:
271        - Specifies the type of proxy header to append before sending data to the
272          backend, either NONE or PROXY_V1. The default is NONE.
273        - 'Some valid choices include: "NONE", "PROXY_V1"'
274        required: false
275        default: NONE
276        type: str
277      port_specification:
278        description:
279        - 'Specifies how port is selected for health checking, can be one of the following
280          values: * `USE_FIXED_PORT`: The port number in `port` is used for health
281          checking.'
282        - "* `USE_NAMED_PORT`: The `portName` is used for health checking."
283        - "* `USE_SERVING_PORT`: For NetworkEndpointGroup, the port specified for
284          each network endpoint is used for health checking. For other backends, the
285          port or named port specified in the Backend Service is used for health checking."
286        - If not specified, TCP health check follows behavior specified in `port`
287          and `portName` fields.
288        - 'Some valid choices include: "USE_FIXED_PORT", "USE_NAMED_PORT", "USE_SERVING_PORT"'
289        required: false
290        type: str
291        version_added: 2.9
292  ssl_health_check:
293    description:
294    - A nested object resource.
295    required: false
296    type: dict
297    suboptions:
298      request:
299        description:
300        - The application data to send once the SSL connection has been established
301          (default value is empty). If both request and response are empty, the connection
302          establishment alone will indicate health. The request data can only be ASCII.
303        required: false
304        type: str
305      response:
306        description:
307        - The bytes to match against the beginning of the response data. If left empty
308          (the default value), any response will indicate health. The response data
309          can only be ASCII.
310        required: false
311        type: str
312      port:
313        description:
314        - The TCP port number for the SSL health check request.
315        - The default value is 443.
316        required: false
317        type: int
318      port_name:
319        description:
320        - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
321          are defined, port takes precedence.
322        required: false
323        type: str
324      proxy_header:
325        description:
326        - Specifies the type of proxy header to append before sending data to the
327          backend, either NONE or PROXY_V1. The default is NONE.
328        - 'Some valid choices include: "NONE", "PROXY_V1"'
329        required: false
330        default: NONE
331        type: str
332      port_specification:
333        description:
334        - 'Specifies how port is selected for health checking, can be one of the following
335          values: * `USE_FIXED_PORT`: The port number in `port` is used for health
336          checking.'
337        - "* `USE_NAMED_PORT`: The `portName` is used for health checking."
338        - "* `USE_SERVING_PORT`: For NetworkEndpointGroup, the port specified for
339          each network endpoint is used for health checking. For other backends, the
340          port or named port specified in the Backend Service is used for health checking."
341        - If not specified, SSL health check follows behavior specified in `port`
342          and `portName` fields.
343        - 'Some valid choices include: "USE_FIXED_PORT", "USE_NAMED_PORT", "USE_SERVING_PORT"'
344        required: false
345        type: str
346        version_added: 2.9
347extends_documentation_fragment: gcp
348notes:
349- 'API Reference: U(https://cloud.google.com/compute/docs/reference/rest/v1/healthChecks)'
350- 'Official Documentation: U(https://cloud.google.com/load-balancing/docs/health-checks)'
351'''
352
353EXAMPLES = '''
354- name: create a health check
355  gcp_compute_health_check:
356    name: test_object
357    type: TCP
358    tcp_health_check:
359      port_name: service-health
360      request: ping
361      response: pong
362    healthy_threshold: 10
363    timeout_sec: 2
364    unhealthy_threshold: 5
365    project: test_project
366    auth_kind: serviceaccount
367    service_account_file: "/tmp/auth.pem"
368    state: present
369'''
370
371RETURN = '''
372checkIntervalSec:
373  description:
374  - How often (in seconds) to send a health check. The default value is 5 seconds.
375  returned: success
376  type: int
377creationTimestamp:
378  description:
379  - Creation timestamp in RFC3339 text format.
380  returned: success
381  type: str
382description:
383  description:
384  - An optional description of this resource. Provide this property when you create
385    the resource.
386  returned: success
387  type: str
388healthyThreshold:
389  description:
390  - A so-far unhealthy instance will be marked healthy after this many consecutive
391    successes. The default value is 2.
392  returned: success
393  type: int
394id:
395  description:
396  - The unique identifier for the resource. This identifier is defined by the server.
397  returned: success
398  type: int
399name:
400  description:
401  - Name of the resource. Provided by the client when the resource is created. The
402    name must be 1-63 characters long, and comply with RFC1035. Specifically, the
403    name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?`
404    which means the first character must be a lowercase letter, and all following
405    characters must be a dash, lowercase letter, or digit, except the last character,
406    which cannot be a dash.
407  returned: success
408  type: str
409timeoutSec:
410  description:
411  - How long (in seconds) to wait before claiming failure.
412  - The default value is 5 seconds. It is invalid for timeoutSec to have greater value
413    than checkIntervalSec.
414  returned: success
415  type: int
416unhealthyThreshold:
417  description:
418  - A so-far healthy instance will be marked unhealthy after this many consecutive
419    failures. The default value is 2.
420  returned: success
421  type: int
422type:
423  description:
424  - Specifies the type of the healthCheck, either TCP, SSL, HTTP or HTTPS. If not
425    specified, the default is TCP. Exactly one of the protocol-specific health check
426    field must be specified, which must match type field.
427  returned: success
428  type: str
429httpHealthCheck:
430  description:
431  - A nested object resource.
432  returned: success
433  type: complex
434  contains:
435    host:
436      description:
437      - The value of the host header in the HTTP health check request.
438      - If left empty (default value), the public IP on behalf of which this health
439        check is performed will be used.
440      returned: success
441      type: str
442    requestPath:
443      description:
444      - The request path of the HTTP health check request.
445      - The default value is /.
446      returned: success
447      type: str
448    response:
449      description:
450      - The bytes to match against the beginning of the response data. If left empty
451        (the default value), any response will indicate health. The response data
452        can only be ASCII.
453      returned: success
454      type: str
455    port:
456      description:
457      - The TCP port number for the HTTP health check request.
458      - The default value is 80.
459      returned: success
460      type: int
461    portName:
462      description:
463      - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
464        are defined, port takes precedence.
465      returned: success
466      type: str
467    proxyHeader:
468      description:
469      - Specifies the type of proxy header to append before sending data to the backend,
470        either NONE or PROXY_V1. The default is NONE.
471      returned: success
472      type: str
473    portSpecification:
474      description:
475      - 'Specifies how port is selected for health checking, can be one of the following
476        values: * `USE_FIXED_PORT`: The port number in `port` is used for health checking.'
477      - "* `USE_NAMED_PORT`: The `portName` is used for health checking."
478      - "* `USE_SERVING_PORT`: For NetworkEndpointGroup, the port specified for each
479        network endpoint is used for health checking. For other backends, the port
480        or named port specified in the Backend Service is used for health checking."
481      - If not specified, HTTP health check follows behavior specified in `port` and
482        `portName` fields.
483      returned: success
484      type: str
485httpsHealthCheck:
486  description:
487  - A nested object resource.
488  returned: success
489  type: complex
490  contains:
491    host:
492      description:
493      - The value of the host header in the HTTPS health check request.
494      - If left empty (default value), the public IP on behalf of which this health
495        check is performed will be used.
496      returned: success
497      type: str
498    requestPath:
499      description:
500      - The request path of the HTTPS health check request.
501      - The default value is /.
502      returned: success
503      type: str
504    response:
505      description:
506      - The bytes to match against the beginning of the response data. If left empty
507        (the default value), any response will indicate health. The response data
508        can only be ASCII.
509      returned: success
510      type: str
511    port:
512      description:
513      - The TCP port number for the HTTPS health check request.
514      - The default value is 443.
515      returned: success
516      type: int
517    portName:
518      description:
519      - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
520        are defined, port takes precedence.
521      returned: success
522      type: str
523    proxyHeader:
524      description:
525      - Specifies the type of proxy header to append before sending data to the backend,
526        either NONE or PROXY_V1. The default is NONE.
527      returned: success
528      type: str
529    portSpecification:
530      description:
531      - 'Specifies how port is selected for health checking, can be one of the following
532        values: * `USE_FIXED_PORT`: The port number in `port` is used for health checking.'
533      - "* `USE_NAMED_PORT`: The `portName` is used for health checking."
534      - "* `USE_SERVING_PORT`: For NetworkEndpointGroup, the port specified for each
535        network endpoint is used for health checking. For other backends, the port
536        or named port specified in the Backend Service is used for health checking."
537      - If not specified, HTTPS health check follows behavior specified in `port`
538        and `portName` fields.
539      returned: success
540      type: str
541tcpHealthCheck:
542  description:
543  - A nested object resource.
544  returned: success
545  type: complex
546  contains:
547    request:
548      description:
549      - The application data to send once the TCP connection has been established
550        (default value is empty). If both request and response are empty, the connection
551        establishment alone will indicate health. The request data can only be ASCII.
552      returned: success
553      type: str
554    response:
555      description:
556      - The bytes to match against the beginning of the response data. If left empty
557        (the default value), any response will indicate health. The response data
558        can only be ASCII.
559      returned: success
560      type: str
561    port:
562      description:
563      - The TCP port number for the TCP health check request.
564      - The default value is 443.
565      returned: success
566      type: int
567    portName:
568      description:
569      - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
570        are defined, port takes precedence.
571      returned: success
572      type: str
573    proxyHeader:
574      description:
575      - Specifies the type of proxy header to append before sending data to the backend,
576        either NONE or PROXY_V1. The default is NONE.
577      returned: success
578      type: str
579    portSpecification:
580      description:
581      - 'Specifies how port is selected for health checking, can be one of the following
582        values: * `USE_FIXED_PORT`: The port number in `port` is used for health checking.'
583      - "* `USE_NAMED_PORT`: The `portName` is used for health checking."
584      - "* `USE_SERVING_PORT`: For NetworkEndpointGroup, the port specified for each
585        network endpoint is used for health checking. For other backends, the port
586        or named port specified in the Backend Service is used for health checking."
587      - If not specified, TCP health check follows behavior specified in `port` and
588        `portName` fields.
589      returned: success
590      type: str
591sslHealthCheck:
592  description:
593  - A nested object resource.
594  returned: success
595  type: complex
596  contains:
597    request:
598      description:
599      - The application data to send once the SSL connection has been established
600        (default value is empty). If both request and response are empty, the connection
601        establishment alone will indicate health. The request data can only be ASCII.
602      returned: success
603      type: str
604    response:
605      description:
606      - The bytes to match against the beginning of the response data. If left empty
607        (the default value), any response will indicate health. The response data
608        can only be ASCII.
609      returned: success
610      type: str
611    port:
612      description:
613      - The TCP port number for the SSL health check request.
614      - The default value is 443.
615      returned: success
616      type: int
617    portName:
618      description:
619      - Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name
620        are defined, port takes precedence.
621      returned: success
622      type: str
623    proxyHeader:
624      description:
625      - Specifies the type of proxy header to append before sending data to the backend,
626        either NONE or PROXY_V1. The default is NONE.
627      returned: success
628      type: str
629    portSpecification:
630      description:
631      - 'Specifies how port is selected for health checking, can be one of the following
632        values: * `USE_FIXED_PORT`: The port number in `port` is used for health checking.'
633      - "* `USE_NAMED_PORT`: The `portName` is used for health checking."
634      - "* `USE_SERVING_PORT`: For NetworkEndpointGroup, the port specified for each
635        network endpoint is used for health checking. For other backends, the port
636        or named port specified in the Backend Service is used for health checking."
637      - If not specified, SSL health check follows behavior specified in `port` and
638        `portName` fields.
639      returned: success
640      type: str
641'''
642
643################################################################################
644# Imports
645################################################################################
646
647from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, remove_nones_from_dict, replace_resource_dict
648import json
649import time
650
651################################################################################
652# Main
653################################################################################
654
655
656def main():
657    """Main function"""
658
659    module = GcpModule(
660        argument_spec=dict(
661            state=dict(default='present', choices=['present', 'absent'], type='str'),
662            check_interval_sec=dict(default=5, type='int'),
663            description=dict(type='str'),
664            healthy_threshold=dict(default=2, type='int'),
665            name=dict(required=True, type='str'),
666            timeout_sec=dict(default=5, type='int', aliases=['timeout_seconds']),
667            unhealthy_threshold=dict(default=2, type='int'),
668            type=dict(type='str'),
669            http_health_check=dict(
670                type='dict',
671                options=dict(
672                    host=dict(type='str'),
673                    request_path=dict(default='/', type='str'),
674                    response=dict(type='str'),
675                    port=dict(type='int'),
676                    port_name=dict(type='str'),
677                    proxy_header=dict(default='NONE', type='str'),
678                    port_specification=dict(type='str'),
679                ),
680            ),
681            https_health_check=dict(
682                type='dict',
683                options=dict(
684                    host=dict(type='str'),
685                    request_path=dict(default='/', type='str'),
686                    response=dict(type='str'),
687                    port=dict(type='int'),
688                    port_name=dict(type='str'),
689                    proxy_header=dict(default='NONE', type='str'),
690                    port_specification=dict(type='str'),
691                ),
692            ),
693            tcp_health_check=dict(
694                type='dict',
695                options=dict(
696                    request=dict(type='str'),
697                    response=dict(type='str'),
698                    port=dict(type='int'),
699                    port_name=dict(type='str'),
700                    proxy_header=dict(default='NONE', type='str'),
701                    port_specification=dict(type='str'),
702                ),
703            ),
704            ssl_health_check=dict(
705                type='dict',
706                options=dict(
707                    request=dict(type='str'),
708                    response=dict(type='str'),
709                    port=dict(type='int'),
710                    port_name=dict(type='str'),
711                    proxy_header=dict(default='NONE', type='str'),
712                    port_specification=dict(type='str'),
713                ),
714            ),
715        ),
716        mutually_exclusive=[['http_health_check', 'https_health_check', 'ssl_health_check', 'tcp_health_check']],
717    )
718
719    if not module.params['scopes']:
720        module.params['scopes'] = ['https://www.googleapis.com/auth/compute']
721
722    state = module.params['state']
723    kind = 'compute#healthCheck'
724
725    fetch = fetch_resource(module, self_link(module), kind)
726    changed = False
727
728    if fetch:
729        if state == 'present':
730            if is_different(module, fetch):
731                update(module, self_link(module), kind)
732                fetch = fetch_resource(module, self_link(module), kind)
733                changed = True
734        else:
735            delete(module, self_link(module), kind)
736            fetch = {}
737            changed = True
738    else:
739        if state == 'present':
740            fetch = create(module, collection(module), kind)
741            changed = True
742        else:
743            fetch = {}
744
745    fetch.update({'changed': changed})
746
747    module.exit_json(**fetch)
748
749
750def create(module, link, kind):
751    auth = GcpSession(module, 'compute')
752    return wait_for_operation(module, auth.post(link, resource_to_request(module)))
753
754
755def update(module, link, kind):
756    auth = GcpSession(module, 'compute')
757    return wait_for_operation(module, auth.put(link, resource_to_request(module)))
758
759
760def delete(module, link, kind):
761    auth = GcpSession(module, 'compute')
762    return wait_for_operation(module, auth.delete(link))
763
764
765def resource_to_request(module):
766    request = {
767        u'kind': 'compute#healthCheck',
768        u'checkIntervalSec': module.params.get('check_interval_sec'),
769        u'description': module.params.get('description'),
770        u'healthyThreshold': module.params.get('healthy_threshold'),
771        u'name': module.params.get('name'),
772        u'timeoutSec': module.params.get('timeout_sec'),
773        u'unhealthyThreshold': module.params.get('unhealthy_threshold'),
774        u'type': module.params.get('type'),
775        u'httpHealthCheck': HealthCheckHttphealthcheck(module.params.get('http_health_check', {}), module).to_request(),
776        u'httpsHealthCheck': HealthCheckHttpshealthcheck(module.params.get('https_health_check', {}), module).to_request(),
777        u'tcpHealthCheck': HealthCheckTcphealthcheck(module.params.get('tcp_health_check', {}), module).to_request(),
778        u'sslHealthCheck': HealthCheckSslhealthcheck(module.params.get('ssl_health_check', {}), module).to_request(),
779    }
780    return_vals = {}
781    for k, v in request.items():
782        if v or v is False:
783            return_vals[k] = v
784
785    return return_vals
786
787
788def fetch_resource(module, link, kind, allow_not_found=True):
789    auth = GcpSession(module, 'compute')
790    return return_if_object(module, auth.get(link), kind, allow_not_found)
791
792
793def self_link(module):
794    return "https://www.googleapis.com/compute/v1/projects/{project}/global/healthChecks/{name}".format(**module.params)
795
796
797def collection(module):
798    return "https://www.googleapis.com/compute/v1/projects/{project}/global/healthChecks".format(**module.params)
799
800
801def return_if_object(module, response, kind, allow_not_found=False):
802    # If not found, return nothing.
803    if allow_not_found and response.status_code == 404:
804        return None
805
806    # If no content, return nothing.
807    if response.status_code == 204:
808        return None
809
810    try:
811        module.raise_for_status(response)
812        result = response.json()
813    except getattr(json.decoder, 'JSONDecodeError', ValueError):
814        module.fail_json(msg="Invalid JSON response with error: %s" % response.text)
815
816    if navigate_hash(result, ['error', 'errors']):
817        module.fail_json(msg=navigate_hash(result, ['error', 'errors']))
818
819    return result
820
821
822def is_different(module, response):
823    request = resource_to_request(module)
824    response = response_to_hash(module, response)
825
826    # Remove all output-only from response.
827    response_vals = {}
828    for k, v in response.items():
829        if k in request:
830            response_vals[k] = v
831
832    request_vals = {}
833    for k, v in request.items():
834        if k in response:
835            request_vals[k] = v
836
837    return GcpRequest(request_vals) != GcpRequest(response_vals)
838
839
840# Remove unnecessary properties from the response.
841# This is for doing comparisons with Ansible's current parameters.
842def response_to_hash(module, response):
843    return {
844        u'checkIntervalSec': response.get(u'checkIntervalSec'),
845        u'creationTimestamp': response.get(u'creationTimestamp'),
846        u'description': response.get(u'description'),
847        u'healthyThreshold': response.get(u'healthyThreshold'),
848        u'id': response.get(u'id'),
849        u'name': module.params.get('name'),
850        u'timeoutSec': response.get(u'timeoutSec'),
851        u'unhealthyThreshold': response.get(u'unhealthyThreshold'),
852        u'type': response.get(u'type'),
853        u'httpHealthCheck': HealthCheckHttphealthcheck(response.get(u'httpHealthCheck', {}), module).from_response(),
854        u'httpsHealthCheck': HealthCheckHttpshealthcheck(response.get(u'httpsHealthCheck', {}), module).from_response(),
855        u'tcpHealthCheck': HealthCheckTcphealthcheck(response.get(u'tcpHealthCheck', {}), module).from_response(),
856        u'sslHealthCheck': HealthCheckSslhealthcheck(response.get(u'sslHealthCheck', {}), module).from_response(),
857    }
858
859
860def async_op_url(module, extra_data=None):
861    if extra_data is None:
862        extra_data = {}
863    url = "https://www.googleapis.com/compute/v1/projects/{project}/global/operations/{op_id}"
864    combined = extra_data.copy()
865    combined.update(module.params)
866    return url.format(**combined)
867
868
869def wait_for_operation(module, response):
870    op_result = return_if_object(module, response, 'compute#operation')
871    if op_result is None:
872        return {}
873    status = navigate_hash(op_result, ['status'])
874    wait_done = wait_for_completion(status, op_result, module)
875    return fetch_resource(module, navigate_hash(wait_done, ['targetLink']), 'compute#healthCheck')
876
877
878def wait_for_completion(status, op_result, module):
879    op_id = navigate_hash(op_result, ['name'])
880    op_uri = async_op_url(module, {'op_id': op_id})
881    while status != 'DONE':
882        raise_if_errors(op_result, ['error', 'errors'], module)
883        time.sleep(1.0)
884        op_result = fetch_resource(module, op_uri, 'compute#operation', False)
885        status = navigate_hash(op_result, ['status'])
886    return op_result
887
888
889def raise_if_errors(response, err_path, module):
890    errors = navigate_hash(response, err_path)
891    if errors is not None:
892        module.fail_json(msg=errors)
893
894
895class HealthCheckHttphealthcheck(object):
896    def __init__(self, request, module):
897        self.module = module
898        if request:
899            self.request = request
900        else:
901            self.request = {}
902
903    def to_request(self):
904        return remove_nones_from_dict(
905            {
906                u'host': self.request.get('host'),
907                u'requestPath': self.request.get('request_path'),
908                u'response': self.request.get('response'),
909                u'port': self.request.get('port'),
910                u'portName': self.request.get('port_name'),
911                u'proxyHeader': self.request.get('proxy_header'),
912                u'portSpecification': self.request.get('port_specification'),
913            }
914        )
915
916    def from_response(self):
917        return remove_nones_from_dict(
918            {
919                u'host': self.request.get(u'host'),
920                u'requestPath': self.request.get(u'requestPath'),
921                u'response': self.request.get(u'response'),
922                u'port': self.request.get(u'port'),
923                u'portName': self.request.get(u'portName'),
924                u'proxyHeader': self.request.get(u'proxyHeader'),
925                u'portSpecification': self.request.get(u'portSpecification'),
926            }
927        )
928
929
930class HealthCheckHttpshealthcheck(object):
931    def __init__(self, request, module):
932        self.module = module
933        if request:
934            self.request = request
935        else:
936            self.request = {}
937
938    def to_request(self):
939        return remove_nones_from_dict(
940            {
941                u'host': self.request.get('host'),
942                u'requestPath': self.request.get('request_path'),
943                u'response': self.request.get('response'),
944                u'port': self.request.get('port'),
945                u'portName': self.request.get('port_name'),
946                u'proxyHeader': self.request.get('proxy_header'),
947                u'portSpecification': self.request.get('port_specification'),
948            }
949        )
950
951    def from_response(self):
952        return remove_nones_from_dict(
953            {
954                u'host': self.request.get(u'host'),
955                u'requestPath': self.request.get(u'requestPath'),
956                u'response': self.request.get(u'response'),
957                u'port': self.request.get(u'port'),
958                u'portName': self.request.get(u'portName'),
959                u'proxyHeader': self.request.get(u'proxyHeader'),
960                u'portSpecification': self.request.get(u'portSpecification'),
961            }
962        )
963
964
965class HealthCheckTcphealthcheck(object):
966    def __init__(self, request, module):
967        self.module = module
968        if request:
969            self.request = request
970        else:
971            self.request = {}
972
973    def to_request(self):
974        return remove_nones_from_dict(
975            {
976                u'request': self.request.get('request'),
977                u'response': self.request.get('response'),
978                u'port': self.request.get('port'),
979                u'portName': self.request.get('port_name'),
980                u'proxyHeader': self.request.get('proxy_header'),
981                u'portSpecification': self.request.get('port_specification'),
982            }
983        )
984
985    def from_response(self):
986        return remove_nones_from_dict(
987            {
988                u'request': self.request.get(u'request'),
989                u'response': self.request.get(u'response'),
990                u'port': self.request.get(u'port'),
991                u'portName': self.request.get(u'portName'),
992                u'proxyHeader': self.request.get(u'proxyHeader'),
993                u'portSpecification': self.request.get(u'portSpecification'),
994            }
995        )
996
997
998class HealthCheckSslhealthcheck(object):
999    def __init__(self, request, module):
1000        self.module = module
1001        if request:
1002            self.request = request
1003        else:
1004            self.request = {}
1005
1006    def to_request(self):
1007        return remove_nones_from_dict(
1008            {
1009                u'request': self.request.get('request'),
1010                u'response': self.request.get('response'),
1011                u'port': self.request.get('port'),
1012                u'portName': self.request.get('port_name'),
1013                u'proxyHeader': self.request.get('proxy_header'),
1014                u'portSpecification': self.request.get('port_specification'),
1015            }
1016        )
1017
1018    def from_response(self):
1019        return remove_nones_from_dict(
1020            {
1021                u'request': self.request.get(u'request'),
1022                u'response': self.request.get(u'response'),
1023                u'port': self.request.get(u'port'),
1024                u'portName': self.request.get(u'portName'),
1025                u'proxyHeader': self.request.get(u'proxyHeader'),
1026                u'portSpecification': self.request.get(u'portSpecification'),
1027            }
1028        )
1029
1030
1031if __name__ == '__main__':
1032    main()
1033