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_container_node_pool 33description: 34- NodePool contains the name and configuration for a cluster's node pool. 35- Node pools are a set of nodes (i.e. VM's), with a common configuration and specification, 36 under the control of the cluster master. They may have a set of Kubernetes labels 37 applied to them, which may be used to reference them during pod scheduling. They 38 may also be resized up or down, to accommodate the workload. 39short_description: Creates a GCP NodePool 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 name: 56 description: 57 - The name of the node pool. 58 required: false 59 type: str 60 config: 61 description: 62 - The node configuration of the pool. 63 required: false 64 type: dict 65 suboptions: 66 machine_type: 67 description: 68 - The name of a Google Compute Engine machine type (e.g. 69 - n1-standard-1). If unspecified, the default machine type is n1-standard-1. 70 required: false 71 type: str 72 disk_size_gb: 73 description: 74 - Size of the disk attached to each node, specified in GB. The smallest allowed 75 disk size is 10GB. If unspecified, the default disk size is 100GB. 76 required: false 77 type: int 78 oauth_scopes: 79 description: 80 - The set of Google API scopes to be made available on all of the node VMs 81 under the "default" service account. 82 - 'The following scopes are recommended, but not required, and by default 83 are not included: U(https://www.googleapis.com/auth/compute) is required 84 for mounting persistent storage on your nodes.' 85 - U(https://www.googleapis.com/auth/devstorage.read_only) is required for 86 communicating with gcr.io (the Google Container Registry). 87 - If unspecified, no scopes are added, unless Cloud Logging or Cloud Monitoring 88 are enabled, in which case their required scopes will be added. 89 required: false 90 type: list 91 service_account: 92 description: 93 - The Google Cloud Platform Service Account to be used by the node VMs. If 94 no Service Account is specified, the "default" service account is used. 95 required: false 96 type: str 97 metadata: 98 description: 99 - The metadata key/value pairs assigned to instances in the cluster. 100 - 'Keys must conform to the regexp [a-zA-Z0-9-_]+ and be less than 128 bytes 101 in length. These are reflected as part of a URL in the metadata server. 102 Additionally, to avoid ambiguity, keys must not conflict with any other 103 metadata keys for the project or be one of the four reserved keys: "instance-template", 104 "kube-env", "startup-script", and "user-data" Values are free-form strings, 105 and only have meaning as interpreted by the image running in the instance. 106 The only restriction placed on them is that each value''s size must be less 107 than or equal to 32 KB.' 108 - The total size of all keys and values must be less than 512 KB. 109 - 'An object containing a list of "key": value pairs.' 110 - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' 111 required: false 112 type: dict 113 image_type: 114 description: 115 - The image type to use for this node. Note that for a given image type, the 116 latest version of it will be used. 117 required: false 118 type: str 119 labels: 120 description: 121 - 'The map of Kubernetes labels (key/value pairs) to be applied to each node. 122 These will added in addition to any default label(s) that Kubernetes may 123 apply to the node. In case of conflict in label keys, the applied set may 124 differ depending on the Kubernetes version -- it''s best to assume the behavior 125 is undefined and conflicts should be avoided. For more information, including 126 usage and the valid values, see: U(http://kubernetes.io/v1.1/docs/user-guide/labels.html) 127 An object containing a list of "key": value pairs.' 128 - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' 129 required: false 130 type: dict 131 local_ssd_count: 132 description: 133 - The number of local SSD disks to be attached to the node. 134 - 'The limit for this value is dependant upon the maximum number of disks 135 available on a machine per zone. See: U(https://cloud.google.com/compute/docs/disks/local-ssd#local_ssd_limits) 136 for more information.' 137 required: false 138 type: int 139 tags: 140 description: 141 - The list of instance tags applied to all nodes. Tags are used to identify 142 valid sources or targets for network firewalls and are specified by the 143 client during cluster or node pool creation. Each tag within the list must 144 comply with RFC1035. 145 required: false 146 type: list 147 preemptible: 148 description: 149 - 'Whether the nodes are created as preemptible VM instances. See: U(https://cloud.google.com/compute/docs/instances/preemptible) 150 for more information about preemptible VM instances.' 151 required: false 152 type: bool 153 accelerators: 154 description: 155 - A list of hardware accelerators to be attached to each node. 156 required: false 157 type: list 158 version_added: 2.9 159 suboptions: 160 accelerator_count: 161 description: 162 - The number of the accelerator cards exposed to an instance. 163 required: false 164 type: int 165 accelerator_type: 166 description: 167 - The accelerator type resource name. 168 required: false 169 type: str 170 disk_type: 171 description: 172 - Type of the disk attached to each node (e.g. 'pd-standard' or 'pd-ssd') 173 If unspecified, the default disk type is 'pd-standard' . 174 required: false 175 type: str 176 version_added: 2.9 177 min_cpu_platform: 178 description: 179 - Minimum CPU platform to be used by this instance. The instance may be scheduled 180 on the specified or newer CPU platform . 181 required: false 182 type: str 183 version_added: 2.9 184 taints: 185 description: 186 - List of kubernetes taints to be applied to each node. 187 required: false 188 type: list 189 version_added: 2.9 190 suboptions: 191 key: 192 description: 193 - Key for taint. 194 required: false 195 type: str 196 value: 197 description: 198 - Value for taint. 199 required: false 200 type: str 201 effect: 202 description: 203 - Effect for taint. 204 required: false 205 type: str 206 initial_node_count: 207 description: 208 - The initial node count for the pool. You must ensure that your Compute Engine 209 resource quota is sufficient for this number of instances. You must also have 210 available firewall and routes quota. 211 required: true 212 type: int 213 version: 214 description: 215 - The version of the Kubernetes of this node. 216 required: false 217 type: str 218 version_added: 2.8 219 autoscaling: 220 description: 221 - Autoscaler configuration for this NodePool. Autoscaler is enabled only if a 222 valid configuration is present. 223 required: false 224 type: dict 225 suboptions: 226 enabled: 227 description: 228 - Is autoscaling enabled for this node pool. 229 required: false 230 type: bool 231 min_node_count: 232 description: 233 - Minimum number of nodes in the NodePool. Must be >= 1 and <= maxNodeCount. 234 required: false 235 type: int 236 max_node_count: 237 description: 238 - Maximum number of nodes in the NodePool. Must be >= minNodeCount. 239 - There has to enough quota to scale up the cluster. 240 required: false 241 type: int 242 management: 243 description: 244 - Management configuration for this NodePool. 245 required: false 246 type: dict 247 suboptions: 248 auto_upgrade: 249 description: 250 - A flag that specifies whether node auto-upgrade is enabled for the node 251 pool. If enabled, node auto-upgrade helps keep the nodes in your node pool 252 up to date with the latest release version of Kubernetes. 253 required: false 254 type: bool 255 auto_repair: 256 description: 257 - A flag that specifies whether the node auto-repair is enabled for the node 258 pool. If enabled, the nodes in this node pool will be monitored and, if 259 they fail health checks too many times, an automatic repair action will 260 be triggered. 261 required: false 262 type: bool 263 upgrade_options: 264 description: 265 - Specifies the Auto Upgrade knobs for the node pool. 266 required: false 267 type: dict 268 suboptions: {} 269 max_pods_constraint: 270 description: 271 - The constraint on the maximum number of pods that can be run simultaneously 272 on a node in the node pool. 273 required: false 274 type: dict 275 version_added: 2.9 276 suboptions: 277 max_pods_per_node: 278 description: 279 - Constraint enforced on the max num of pods per node. 280 required: false 281 type: int 282 conditions: 283 description: 284 - Which conditions caused the current node pool state. 285 required: false 286 type: list 287 version_added: 2.9 288 suboptions: 289 code: 290 description: 291 - Machine-friendly representation of the condition. 292 - 'Some valid choices include: "UNKNOWN", "GCE_STOCKOUT", "GKE_SERVICE_ACCOUNT_DELETED", 293 "GCE_QUOTA_EXCEEDED", "SET_BY_OPERATOR"' 294 required: false 295 type: str 296 cluster: 297 description: 298 - The cluster this node pool belongs to. 299 - 'This field represents a link to a Cluster resource in GCP. It can be specified 300 in two ways. First, you can place a dictionary with key ''name'' and value of 301 your resource''s name Alternatively, you can add `register: name-of-resource` 302 to a gcp_container_cluster task and then set this cluster field to "{{ name-of-resource 303 }}"' 304 required: true 305 type: dict 306 location: 307 description: 308 - The location where the node pool is deployed. 309 required: true 310 type: str 311 aliases: 312 - region 313 - zone 314 version_added: 2.8 315extends_documentation_fragment: gcp 316''' 317 318EXAMPLES = ''' 319- name: create a cluster 320 gcp_container_cluster: 321 name: cluster-nodepool 322 initial_node_count: 4 323 location: us-central1-a 324 project: "{{ gcp_project }}" 325 auth_kind: "{{ gcp_cred_kind }}" 326 service_account_file: "{{ gcp_cred_file }}" 327 state: present 328 register: cluster 329 330- name: create a node pool 331 gcp_container_node_pool: 332 name: my-pool 333 initial_node_count: 4 334 cluster: "{{ cluster }}" 335 location: us-central1-a 336 project: test_project 337 auth_kind: serviceaccount 338 service_account_file: "/tmp/auth.pem" 339 state: present 340''' 341 342RETURN = ''' 343name: 344 description: 345 - The name of the node pool. 346 returned: success 347 type: str 348config: 349 description: 350 - The node configuration of the pool. 351 returned: success 352 type: complex 353 contains: 354 machineType: 355 description: 356 - The name of a Google Compute Engine machine type (e.g. 357 - n1-standard-1). If unspecified, the default machine type is n1-standard-1. 358 returned: success 359 type: str 360 diskSizeGb: 361 description: 362 - Size of the disk attached to each node, specified in GB. The smallest allowed 363 disk size is 10GB. If unspecified, the default disk size is 100GB. 364 returned: success 365 type: int 366 oauthScopes: 367 description: 368 - The set of Google API scopes to be made available on all of the node VMs under 369 the "default" service account. 370 - 'The following scopes are recommended, but not required, and by default are 371 not included: U(https://www.googleapis.com/auth/compute) is required for mounting 372 persistent storage on your nodes.' 373 - U(https://www.googleapis.com/auth/devstorage.read_only) is required for communicating 374 with gcr.io (the Google Container Registry). 375 - If unspecified, no scopes are added, unless Cloud Logging or Cloud Monitoring 376 are enabled, in which case their required scopes will be added. 377 returned: success 378 type: list 379 serviceAccount: 380 description: 381 - The Google Cloud Platform Service Account to be used by the node VMs. If no 382 Service Account is specified, the "default" service account is used. 383 returned: success 384 type: str 385 metadata: 386 description: 387 - The metadata key/value pairs assigned to instances in the cluster. 388 - 'Keys must conform to the regexp [a-zA-Z0-9-_]+ and be less than 128 bytes 389 in length. These are reflected as part of a URL in the metadata server. Additionally, 390 to avoid ambiguity, keys must not conflict with any other metadata keys for 391 the project or be one of the four reserved keys: "instance-template", "kube-env", 392 "startup-script", and "user-data" Values are free-form strings, and only have 393 meaning as interpreted by the image running in the instance. The only restriction 394 placed on them is that each value''s size must be less than or equal to 32 395 KB.' 396 - The total size of all keys and values must be less than 512 KB. 397 - 'An object containing a list of "key": value pairs.' 398 - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' 399 returned: success 400 type: dict 401 imageType: 402 description: 403 - The image type to use for this node. Note that for a given image type, the 404 latest version of it will be used. 405 returned: success 406 type: str 407 labels: 408 description: 409 - 'The map of Kubernetes labels (key/value pairs) to be applied to each node. 410 These will added in addition to any default label(s) that Kubernetes may apply 411 to the node. In case of conflict in label keys, the applied set may differ 412 depending on the Kubernetes version -- it''s best to assume the behavior is 413 undefined and conflicts should be avoided. For more information, including 414 usage and the valid values, see: U(http://kubernetes.io/v1.1/docs/user-guide/labels.html) 415 An object containing a list of "key": value pairs.' 416 - 'Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.' 417 returned: success 418 type: dict 419 localSsdCount: 420 description: 421 - The number of local SSD disks to be attached to the node. 422 - 'The limit for this value is dependant upon the maximum number of disks available 423 on a machine per zone. See: U(https://cloud.google.com/compute/docs/disks/local-ssd#local_ssd_limits) 424 for more information.' 425 returned: success 426 type: int 427 tags: 428 description: 429 - The list of instance tags applied to all nodes. Tags are used to identify 430 valid sources or targets for network firewalls and are specified by the client 431 during cluster or node pool creation. Each tag within the list must comply 432 with RFC1035. 433 returned: success 434 type: list 435 preemptible: 436 description: 437 - 'Whether the nodes are created as preemptible VM instances. See: U(https://cloud.google.com/compute/docs/instances/preemptible) 438 for more information about preemptible VM instances.' 439 returned: success 440 type: bool 441 accelerators: 442 description: 443 - A list of hardware accelerators to be attached to each node. 444 returned: success 445 type: complex 446 contains: 447 acceleratorCount: 448 description: 449 - The number of the accelerator cards exposed to an instance. 450 returned: success 451 type: int 452 acceleratorType: 453 description: 454 - The accelerator type resource name. 455 returned: success 456 type: str 457 diskType: 458 description: 459 - Type of the disk attached to each node (e.g. 'pd-standard' or 'pd-ssd') If 460 unspecified, the default disk type is 'pd-standard' . 461 returned: success 462 type: str 463 minCpuPlatform: 464 description: 465 - Minimum CPU platform to be used by this instance. The instance may be scheduled 466 on the specified or newer CPU platform . 467 returned: success 468 type: str 469 taints: 470 description: 471 - List of kubernetes taints to be applied to each node. 472 returned: success 473 type: complex 474 contains: 475 key: 476 description: 477 - Key for taint. 478 returned: success 479 type: str 480 value: 481 description: 482 - Value for taint. 483 returned: success 484 type: str 485 effect: 486 description: 487 - Effect for taint. 488 returned: success 489 type: str 490initialNodeCount: 491 description: 492 - The initial node count for the pool. You must ensure that your Compute Engine 493 resource quota is sufficient for this number of instances. You must also have 494 available firewall and routes quota. 495 returned: success 496 type: int 497status: 498 description: 499 - Status of nodes in this pool instance. 500 returned: success 501 type: str 502statusMessage: 503 description: 504 - Additional information about the current status of this node pool instance. 505 returned: success 506 type: str 507version: 508 description: 509 - The version of the Kubernetes of this node. 510 returned: success 511 type: str 512autoscaling: 513 description: 514 - Autoscaler configuration for this NodePool. Autoscaler is enabled only if a valid 515 configuration is present. 516 returned: success 517 type: complex 518 contains: 519 enabled: 520 description: 521 - Is autoscaling enabled for this node pool. 522 returned: success 523 type: bool 524 minNodeCount: 525 description: 526 - Minimum number of nodes in the NodePool. Must be >= 1 and <= maxNodeCount. 527 returned: success 528 type: int 529 maxNodeCount: 530 description: 531 - Maximum number of nodes in the NodePool. Must be >= minNodeCount. 532 - There has to enough quota to scale up the cluster. 533 returned: success 534 type: int 535management: 536 description: 537 - Management configuration for this NodePool. 538 returned: success 539 type: complex 540 contains: 541 autoUpgrade: 542 description: 543 - A flag that specifies whether node auto-upgrade is enabled for the node pool. 544 If enabled, node auto-upgrade helps keep the nodes in your node pool up to 545 date with the latest release version of Kubernetes. 546 returned: success 547 type: bool 548 autoRepair: 549 description: 550 - A flag that specifies whether the node auto-repair is enabled for the node 551 pool. If enabled, the nodes in this node pool will be monitored and, if they 552 fail health checks too many times, an automatic repair action will be triggered. 553 returned: success 554 type: bool 555 upgradeOptions: 556 description: 557 - Specifies the Auto Upgrade knobs for the node pool. 558 returned: success 559 type: complex 560 contains: 561 autoUpgradeStartTime: 562 description: 563 - This field is set when upgrades are about to commence with the approximate 564 start time for the upgrades, in RFC3339 text format. 565 returned: success 566 type: str 567 description: 568 description: 569 - This field is set when upgrades are about to commence with the description 570 of the upgrade. 571 returned: success 572 type: str 573maxPodsConstraint: 574 description: 575 - The constraint on the maximum number of pods that can be run simultaneously on 576 a node in the node pool. 577 returned: success 578 type: complex 579 contains: 580 maxPodsPerNode: 581 description: 582 - Constraint enforced on the max num of pods per node. 583 returned: success 584 type: int 585conditions: 586 description: 587 - Which conditions caused the current node pool state. 588 returned: success 589 type: complex 590 contains: 591 code: 592 description: 593 - Machine-friendly representation of the condition. 594 returned: success 595 type: str 596podIpv4CidrSize: 597 description: 598 - The pod CIDR block size per node in this node pool. 599 returned: success 600 type: int 601cluster: 602 description: 603 - The cluster this node pool belongs to. 604 returned: success 605 type: dict 606location: 607 description: 608 - The location where the node pool is deployed. 609 returned: success 610 type: str 611''' 612 613################################################################################ 614# Imports 615################################################################################ 616 617from ansible.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest, remove_nones_from_dict, replace_resource_dict 618import json 619import time 620 621################################################################################ 622# Main 623################################################################################ 624 625 626def main(): 627 """Main function""" 628 629 module = GcpModule( 630 argument_spec=dict( 631 state=dict(default='present', choices=['present', 'absent'], type='str'), 632 name=dict(type='str'), 633 config=dict( 634 type='dict', 635 options=dict( 636 machine_type=dict(type='str'), 637 disk_size_gb=dict(type='int'), 638 oauth_scopes=dict(type='list', elements='str'), 639 service_account=dict(type='str'), 640 metadata=dict(type='dict'), 641 image_type=dict(type='str'), 642 labels=dict(type='dict'), 643 local_ssd_count=dict(type='int'), 644 tags=dict(type='list', elements='str'), 645 preemptible=dict(type='bool'), 646 accelerators=dict(type='list', elements='dict', options=dict(accelerator_count=dict(type='int'), accelerator_type=dict(type='str'))), 647 disk_type=dict(type='str'), 648 min_cpu_platform=dict(type='str'), 649 taints=dict(type='list', elements='dict', options=dict(key=dict(type='str'), value=dict(type='str'), effect=dict(type='str'))), 650 ), 651 ), 652 initial_node_count=dict(required=True, type='int'), 653 version=dict(type='str'), 654 autoscaling=dict(type='dict', options=dict(enabled=dict(type='bool'), min_node_count=dict(type='int'), max_node_count=dict(type='int'))), 655 management=dict( 656 type='dict', options=dict(auto_upgrade=dict(type='bool'), auto_repair=dict(type='bool'), upgrade_options=dict(type='dict', options=dict())) 657 ), 658 max_pods_constraint=dict(type='dict', options=dict(max_pods_per_node=dict(type='int'))), 659 conditions=dict(type='list', elements='dict', options=dict(code=dict(type='str'))), 660 cluster=dict(required=True, type='dict'), 661 location=dict(required=True, type='str', aliases=['region', 'zone']), 662 ) 663 ) 664 665 if not module.params['scopes']: 666 module.params['scopes'] = ['https://www.googleapis.com/auth/cloud-platform'] 667 668 state = module.params['state'] 669 670 fetch = fetch_resource(module, self_link(module)) 671 changed = False 672 673 if fetch: 674 if state == 'present': 675 if is_different(module, fetch): 676 update(module, self_link(module)) 677 fetch = fetch_resource(module, self_link(module)) 678 changed = True 679 else: 680 delete(module, self_link(module)) 681 fetch = {} 682 changed = True 683 else: 684 if state == 'present': 685 fetch = create(module, collection(module)) 686 changed = True 687 else: 688 fetch = {} 689 690 fetch.update({'changed': changed}) 691 692 module.exit_json(**fetch) 693 694 695def create(module, link): 696 auth = GcpSession(module, 'container') 697 return wait_for_operation(module, auth.post(link, resource_to_request(module))) 698 699 700def update(module, link): 701 auth = GcpSession(module, 'container') 702 return wait_for_operation(module, auth.put(link, resource_to_request(module))) 703 704 705def delete(module, link): 706 auth = GcpSession(module, 'container') 707 return wait_for_operation(module, auth.delete(link)) 708 709 710def resource_to_request(module): 711 request = { 712 u'name': module.params.get('name'), 713 u'config': NodePoolConfig(module.params.get('config', {}), module).to_request(), 714 u'initialNodeCount': module.params.get('initial_node_count'), 715 u'version': module.params.get('version'), 716 u'autoscaling': NodePoolAutoscaling(module.params.get('autoscaling', {}), module).to_request(), 717 u'management': NodePoolManagement(module.params.get('management', {}), module).to_request(), 718 u'maxPodsConstraint': NodePoolMaxpodsconstraint(module.params.get('max_pods_constraint', {}), module).to_request(), 719 u'conditions': NodePoolConditionsArray(module.params.get('conditions', []), module).to_request(), 720 } 721 request = encode_request(request, module) 722 return_vals = {} 723 for k, v in request.items(): 724 if v or v is False: 725 return_vals[k] = v 726 727 return return_vals 728 729 730def fetch_resource(module, link, allow_not_found=True): 731 auth = GcpSession(module, 'container') 732 return return_if_object(module, auth.get(link), allow_not_found) 733 734 735def self_link(module): 736 res = { 737 'project': module.params['project'], 738 'location': module.params['location'], 739 'cluster': replace_resource_dict(module.params['cluster'], 'name'), 740 'name': module.params['name'], 741 } 742 return "https://container.googleapis.com/v1/projects/{project}/locations/{location}/clusters/{cluster}/nodePools/{name}".format(**res) 743 744 745def collection(module): 746 res = {'project': module.params['project'], 'location': module.params['location'], 'cluster': replace_resource_dict(module.params['cluster'], 'name')} 747 return "https://container.googleapis.com/v1/projects/{project}/locations/{location}/clusters/{cluster}/nodePools".format(**res) 748 749 750def return_if_object(module, response, allow_not_found=False): 751 # If not found, return nothing. 752 if allow_not_found and response.status_code == 404: 753 return None 754 755 # If no content, return nothing. 756 if response.status_code == 204: 757 return None 758 759 try: 760 module.raise_for_status(response) 761 result = response.json() 762 except getattr(json.decoder, 'JSONDecodeError', ValueError): 763 module.fail_json(msg="Invalid JSON response with error: %s" % response.text) 764 765 if navigate_hash(result, ['error', 'errors']): 766 module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) 767 768 return result 769 770 771def is_different(module, response): 772 request = resource_to_request(module) 773 response = response_to_hash(module, response) 774 775 # Remove all output-only from response. 776 response_vals = {} 777 for k, v in response.items(): 778 if k in request: 779 response_vals[k] = v 780 781 request_vals = {} 782 for k, v in request.items(): 783 if k in response: 784 request_vals[k] = v 785 786 return GcpRequest(request_vals) != GcpRequest(response_vals) 787 788 789# Remove unnecessary properties from the response. 790# This is for doing comparisons with Ansible's current parameters. 791def response_to_hash(module, response): 792 return { 793 u'name': response.get(u'name'), 794 u'config': NodePoolConfig(response.get(u'config', {}), module).from_response(), 795 u'initialNodeCount': module.params.get('initial_node_count'), 796 u'status': response.get(u'status'), 797 u'statusMessage': response.get(u'statusMessage'), 798 u'version': module.params.get('version'), 799 u'autoscaling': NodePoolAutoscaling(response.get(u'autoscaling', {}), module).from_response(), 800 u'management': NodePoolManagement(response.get(u'management', {}), module).from_response(), 801 u'maxPodsConstraint': NodePoolMaxpodsconstraint(response.get(u'maxPodsConstraint', {}), module).from_response(), 802 u'conditions': NodePoolConditionsArray(response.get(u'conditions', []), module).from_response(), 803 u'podIpv4CidrSize': response.get(u'podIpv4CidrSize'), 804 } 805 806 807def async_op_url(module, extra_data=None): 808 if extra_data is None: 809 extra_data = {} 810 url = "https://container.googleapis.com/v1/projects/{project}/locations/{location}/operations/{op_id}" 811 combined = extra_data.copy() 812 combined.update(module.params) 813 return url.format(**combined) 814 815 816def wait_for_operation(module, response): 817 op_result = return_if_object(module, response) 818 if op_result is None: 819 return {} 820 status = navigate_hash(op_result, ['status']) 821 wait_done = wait_for_completion(status, op_result, module) 822 return fetch_resource(module, navigate_hash(wait_done, ['targetLink'])) 823 824 825def wait_for_completion(status, op_result, module): 826 op_id = navigate_hash(op_result, ['name']) 827 op_uri = async_op_url(module, {'op_id': op_id}) 828 while status != 'DONE': 829 raise_if_errors(op_result, ['error', 'errors'], module) 830 time.sleep(1.0) 831 op_result = fetch_resource(module, op_uri, False) 832 status = navigate_hash(op_result, ['status']) 833 return op_result 834 835 836def raise_if_errors(response, err_path, module): 837 errors = navigate_hash(response, err_path) 838 if errors is not None: 839 module.fail_json(msg=errors) 840 841 842# Google Container Engine API has its own layout for the create method, 843# defined like this: 844# 845# { 846# 'nodePool': { 847# ... node pool data 848# } 849# } 850# 851# Format the request to match the expected input by the API 852def encode_request(resource_request, module): 853 return {'nodePool': resource_request} 854 855 856class NodePoolConfig(object): 857 def __init__(self, request, module): 858 self.module = module 859 if request: 860 self.request = request 861 else: 862 self.request = {} 863 864 def to_request(self): 865 return remove_nones_from_dict( 866 { 867 u'machineType': self.request.get('machine_type'), 868 u'diskSizeGb': self.request.get('disk_size_gb'), 869 u'oauthScopes': self.request.get('oauth_scopes'), 870 u'serviceAccount': self.request.get('service_account'), 871 u'metadata': self.request.get('metadata'), 872 u'imageType': self.request.get('image_type'), 873 u'labels': self.request.get('labels'), 874 u'localSsdCount': self.request.get('local_ssd_count'), 875 u'tags': self.request.get('tags'), 876 u'preemptible': self.request.get('preemptible'), 877 u'accelerators': NodePoolAcceleratorsArray(self.request.get('accelerators', []), self.module).to_request(), 878 u'diskType': self.request.get('disk_type'), 879 u'minCpuPlatform': self.request.get('min_cpu_platform'), 880 u'taints': NodePoolTaintsArray(self.request.get('taints', []), self.module).to_request(), 881 } 882 ) 883 884 def from_response(self): 885 return remove_nones_from_dict( 886 { 887 u'machineType': self.request.get(u'machineType'), 888 u'diskSizeGb': self.request.get(u'diskSizeGb'), 889 u'oauthScopes': self.request.get(u'oauthScopes'), 890 u'serviceAccount': self.request.get(u'serviceAccount'), 891 u'metadata': self.request.get(u'metadata'), 892 u'imageType': self.request.get(u'imageType'), 893 u'labels': self.request.get(u'labels'), 894 u'localSsdCount': self.request.get(u'localSsdCount'), 895 u'tags': self.request.get(u'tags'), 896 u'preemptible': self.request.get(u'preemptible'), 897 u'accelerators': NodePoolAcceleratorsArray(self.request.get(u'accelerators', []), self.module).from_response(), 898 u'diskType': self.request.get(u'diskType'), 899 u'minCpuPlatform': self.request.get(u'minCpuPlatform'), 900 u'taints': NodePoolTaintsArray(self.request.get(u'taints', []), self.module).from_response(), 901 } 902 ) 903 904 905class NodePoolAcceleratorsArray(object): 906 def __init__(self, request, module): 907 self.module = module 908 if request: 909 self.request = request 910 else: 911 self.request = [] 912 913 def to_request(self): 914 items = [] 915 for item in self.request: 916 items.append(self._request_for_item(item)) 917 return items 918 919 def from_response(self): 920 items = [] 921 for item in self.request: 922 items.append(self._response_from_item(item)) 923 return items 924 925 def _request_for_item(self, item): 926 return remove_nones_from_dict({u'acceleratorCount': item.get('accelerator_count'), u'acceleratorType': item.get('accelerator_type')}) 927 928 def _response_from_item(self, item): 929 return remove_nones_from_dict({u'acceleratorCount': item.get(u'acceleratorCount'), u'acceleratorType': item.get(u'acceleratorType')}) 930 931 932class NodePoolTaintsArray(object): 933 def __init__(self, request, module): 934 self.module = module 935 if request: 936 self.request = request 937 else: 938 self.request = [] 939 940 def to_request(self): 941 items = [] 942 for item in self.request: 943 items.append(self._request_for_item(item)) 944 return items 945 946 def from_response(self): 947 items = [] 948 for item in self.request: 949 items.append(self._response_from_item(item)) 950 return items 951 952 def _request_for_item(self, item): 953 return remove_nones_from_dict({u'key': item.get('key'), u'value': item.get('value'), u'effect': item.get('effect')}) 954 955 def _response_from_item(self, item): 956 return remove_nones_from_dict({u'key': item.get(u'key'), u'value': item.get(u'value'), u'effect': item.get(u'effect')}) 957 958 959class NodePoolAutoscaling(object): 960 def __init__(self, request, module): 961 self.module = module 962 if request: 963 self.request = request 964 else: 965 self.request = {} 966 967 def to_request(self): 968 return remove_nones_from_dict( 969 {u'enabled': self.request.get('enabled'), u'minNodeCount': self.request.get('min_node_count'), u'maxNodeCount': self.request.get('max_node_count')} 970 ) 971 972 def from_response(self): 973 return remove_nones_from_dict( 974 {u'enabled': self.request.get(u'enabled'), u'minNodeCount': self.request.get(u'minNodeCount'), u'maxNodeCount': self.request.get(u'maxNodeCount')} 975 ) 976 977 978class NodePoolManagement(object): 979 def __init__(self, request, module): 980 self.module = module 981 if request: 982 self.request = request 983 else: 984 self.request = {} 985 986 def to_request(self): 987 return remove_nones_from_dict( 988 { 989 u'autoUpgrade': self.request.get('auto_upgrade'), 990 u'autoRepair': self.request.get('auto_repair'), 991 u'upgradeOptions': NodePoolUpgradeoptions(self.request.get('upgrade_options', {}), self.module).to_request(), 992 } 993 ) 994 995 def from_response(self): 996 return remove_nones_from_dict( 997 { 998 u'autoUpgrade': self.request.get(u'autoUpgrade'), 999 u'autoRepair': self.request.get(u'autoRepair'), 1000 u'upgradeOptions': NodePoolUpgradeoptions(self.request.get(u'upgradeOptions', {}), self.module).from_response(), 1001 } 1002 ) 1003 1004 1005class NodePoolUpgradeoptions(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 def from_response(self): 1017 return remove_nones_from_dict({}) 1018 1019 1020class NodePoolMaxpodsconstraint(object): 1021 def __init__(self, request, module): 1022 self.module = module 1023 if request: 1024 self.request = request 1025 else: 1026 self.request = {} 1027 1028 def to_request(self): 1029 return remove_nones_from_dict({u'maxPodsPerNode': self.request.get('max_pods_per_node')}) 1030 1031 def from_response(self): 1032 return remove_nones_from_dict({u'maxPodsPerNode': self.request.get(u'maxPodsPerNode')}) 1033 1034 1035class NodePoolConditionsArray(object): 1036 def __init__(self, request, module): 1037 self.module = module 1038 if request: 1039 self.request = request 1040 else: 1041 self.request = [] 1042 1043 def to_request(self): 1044 items = [] 1045 for item in self.request: 1046 items.append(self._request_for_item(item)) 1047 return items 1048 1049 def from_response(self): 1050 items = [] 1051 for item in self.request: 1052 items.append(self._response_from_item(item)) 1053 return items 1054 1055 def _request_for_item(self, item): 1056 return remove_nones_from_dict({u'code': item.get('code')}) 1057 1058 def _response_from_item(self, item): 1059 return remove_nones_from_dict({u'code': item.get(u'code')}) 1060 1061 1062if __name__ == '__main__': 1063 main() 1064