1#!/usr/local/bin/python3.8 2# 3# Copyright (c) 2017 Zim Kalinowski, <zikalino@microsoft.com> 4# 5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 7from __future__ import absolute_import, division, print_function 8__metaclass__ = type 9 10 11DOCUMENTATION = ''' 12--- 13module: azure_rm_appgateway 14version_added: "0.1.2" 15short_description: Manage Application Gateway instance 16description: 17 - Create, update and delete instance of Application Gateway. 18 19options: 20 resource_group: 21 description: 22 - The name of the resource group. 23 required: True 24 name: 25 description: 26 - The name of the application gateway. 27 required: True 28 location: 29 description: 30 - Resource location. If not set, location from the resource group will be used as default. 31 sku: 32 description: 33 - SKU of the application gateway resource. 34 suboptions: 35 name: 36 description: 37 - Name of an application gateway SKU. 38 choices: 39 - 'standard_small' 40 - 'standard_medium' 41 - 'standard_large' 42 - 'standard_v2' 43 - 'waf_medium' 44 - 'waf_large' 45 - 'waf_v2' 46 tier: 47 description: 48 - Tier of an application gateway. 49 choices: 50 - 'standard' 51 - 'standard_v2' 52 - 'waf' 53 - 'waf_v2' 54 capacity: 55 description: 56 - Capacity (instance count) of an application gateway. 57 ssl_policy: 58 description: 59 - SSL policy of the application gateway resource. 60 suboptions: 61 disabled_ssl_protocols: 62 description: 63 - List of SSL protocols to be disabled on application gateway. 64 choices: 65 - 'tls_v1_0' 66 - 'tls_v1_1' 67 - 'tls_v1_2' 68 policy_type: 69 description: 70 - Type of SSL Policy. 71 choices: 72 - 'predefined' 73 - 'custom' 74 policy_name: 75 description: 76 - Name of Ssl C(predefined) policy. 77 choices: 78 - 'ssl_policy20150501' 79 - 'ssl_policy20170401' 80 - 'ssl_policy20170401_s' 81 cipher_suites: 82 description: 83 - List of SSL cipher suites to be enabled in the specified order to application gateway. 84 choices: 85 - tls_ecdhe_rsa_with_aes_256_gcm_sha384 86 - tls_ecdhe_rsa_with_aes_128_gcm_sha256 87 - tls_ecdhe_rsa_with_aes_256_cbc_sha384 88 - tls_ecdhe_rsa_with_aes_128_cbc_sha256 89 - tls_ecdhe_rsa_with_aes_256_cbc_sha 90 - tls_ecdhe_rsa_with_aes_128_cbc_sha 91 - tls_dhe_rsa_with_aes_256_gcm_sha384 92 - tls_dhe_rsa_with_aes_128_gcm_sha256 93 - tls_dhe_rsa_with_aes_256_cbc_sha 94 - tls_dhe_rsa_with_aes_128_cbc_sha 95 - tls_rsa_with_aes_256_gcm_sha384 96 - tls_rsa_with_aes_128_gcm_sha256 97 - tls_rsa_with_aes_256_cbc_sha256 98 - tls_rsa_with_aes_128_cbc_sha256 99 - tls_rsa_with_aes_256_cbc_sha 100 - tls_rsa_with_aes_128_cbc_sha 101 - tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 102 - tls_ecdhe_ecdsa_with_aes_128_gcm_sha256 103 - tls_ecdhe_ecdsa_with_aes_256_cbc_sha384 104 - tls_ecdhe_ecdsa_with_aes_128_cbc_sha256 105 - tls_ecdhe_ecdsa_with_aes_256_cbc_sha 106 - tls_ecdhe_ecdsa_with_aes_128_cbc_sha 107 - tls_dhe_dss_with_aes_256_cbc_sha256 108 - tls_dhe_dss_with_aes_128_cbc_sha256 109 - tls_dhe_dss_with_aes_256_cbc_sha 110 - tls_dhe_dss_with_aes_128_cbc_sha 111 - tls_rsa_with_3des_ede_cbc_sha 112 - tls_dhe_dss_with_3des_ede_cbc_sha 113 min_protocol_version: 114 description: 115 - Minimum version of Ssl protocol to be supported on application gateway. 116 choices: 117 - 'tls_v1_0' 118 - 'tls_v1_1' 119 - 'tls_v1_2' 120 gateway_ip_configurations: 121 description: 122 - List of subnets used by the application gateway. 123 suboptions: 124 subnet: 125 description: 126 - Reference of the subnet resource. A subnet from where application gateway gets its private address. 127 suboptions: 128 id: 129 description: 130 - Full ID of the subnet resource. Required if name and virtual_network_name are not provided. 131 name: 132 description: 133 - Name of the subnet. Only used if virtual_network_name is also provided. 134 virtual_network_name: 135 description: 136 - Name of the virtual network. Only used if name is also provided. 137 name: 138 description: 139 - Name of the resource that is unique within a resource group. This name can be used to access the resource. 140 authentication_certificates: 141 description: 142 - Authentication certificates of the application gateway resource. 143 suboptions: 144 data: 145 description: 146 - Certificate public data - base64 encoded pfx. 147 name: 148 description: 149 - Name of the resource that is unique within a resource group. This name can be used to access the resource. 150 redirect_configurations: 151 description: 152 - Redirect configurations of the application gateway resource. 153 suboptions: 154 redirect_type: 155 description: 156 - Redirection type. 157 choices: 158 - 'permanent' 159 - 'found' 160 - 'see_other' 161 - 'temporary' 162 target_listener: 163 description: 164 - Reference to a listener to redirect the request to. 165 include_path: 166 description: 167 - Include path in the redirected url. 168 include_query_string: 169 description: 170 - Include query string in the redirected url. 171 name: 172 description: 173 - Name of the resource that is unique within a resource group. 174 ssl_certificates: 175 description: 176 - SSL certificates of the application gateway resource. 177 suboptions: 178 data: 179 description: 180 - Base-64 encoded pfx certificate. 181 - Only applicable in PUT Request. 182 password: 183 description: 184 - Password for the pfx file specified in I(data). 185 - Only applicable in PUT request. 186 name: 187 description: 188 - Name of the resource that is unique within a resource group. This name can be used to access the resource. 189 frontend_ip_configurations: 190 description: 191 - Frontend IP addresses of the application gateway resource. 192 suboptions: 193 private_ip_address: 194 description: 195 - PrivateIPAddress of the network interface IP Configuration. 196 private_ip_allocation_method: 197 description: 198 - PrivateIP allocation method. 199 choices: 200 - 'static' 201 - 'dynamic' 202 subnet: 203 description: 204 - Reference of the subnet resource. 205 suboptions: 206 id: 207 description: 208 - Full ID of the subnet resource. Required if name and virtual_network_name are not provided. 209 name: 210 description: 211 - Name of the subnet. Only used if virtual_network_name is also provided. 212 virtual_network_name: 213 description: 214 - Name of the virtual network. Only used if name is also provided. 215 public_ip_address: 216 description: 217 - Reference of the PublicIP resource. 218 name: 219 description: 220 - Name of the resource that is unique within a resource group. This name can be used to access the resource. 221 frontend_ports: 222 description: 223 - List of frontend ports of the application gateway resource. 224 suboptions: 225 port: 226 description: 227 - Frontend port. 228 name: 229 description: 230 - Name of the resource that is unique within a resource group. This name can be used to access the resource. 231 backend_address_pools: 232 description: 233 - List of backend address pool of the application gateway resource. 234 suboptions: 235 backend_addresses: 236 description: 237 - List of backend addresses. 238 suboptions: 239 fqdn: 240 description: 241 - Fully qualified domain name (FQDN). 242 ip_address: 243 description: 244 - IP address. 245 name: 246 description: 247 - Resource that is unique within a resource group. This name can be used to access the resource. 248 probes: 249 description: 250 - Probes available to the application gateway resource. 251 suboptions: 252 name: 253 description: 254 - Name of the I(probe) that is unique within an Application Gateway. 255 protocol: 256 description: 257 - The protocol used for the I(probe). 258 choices: 259 - 'http' 260 - 'https' 261 host: 262 description: 263 - Host name to send the I(probe) to. 264 path: 265 description: 266 - Relative path of I(probe). 267 - Valid path starts from '/'. 268 - Probe is sent to <Protocol>://<host>:<port><path>. 269 timeout: 270 description: 271 - The probe timeout in seconds. 272 - Probe marked as failed if valid response is not received with this timeout period. 273 - Acceptable values are from 1 second to 86400 seconds. 274 interval: 275 description: 276 - The probing interval in seconds. 277 - This is the time interval between two consecutive probes. 278 - Acceptable values are from 1 second to 86400 seconds. 279 unhealthy_threshold: 280 description: 281 - The I(probe) retry count. 282 - Backend server is marked down after consecutive probe failure count reaches UnhealthyThreshold. 283 - Acceptable values are from 1 second to 20. 284 pick_host_name_from_backend_http_settings: 285 description: 286 - Whether host header should be picked from the host name of the backend HTTP settings. Default value is false. 287 type: bool 288 default: False 289 backend_http_settings_collection: 290 description: 291 - Backend http settings of the application gateway resource. 292 suboptions: 293 probe: 294 description: 295 - Probe resource of an application gateway. 296 port: 297 description: 298 - The destination port on the backend. 299 protocol: 300 description: 301 - The protocol used to communicate with the backend. 302 choices: 303 - 'http' 304 - 'https' 305 cookie_based_affinity: 306 description: 307 - Cookie based affinity. 308 choices: 309 - 'enabled' 310 - 'disabled' 311 request_timeout: 312 description: 313 - Request timeout in seconds. 314 - Application Gateway will fail the request if response is not received within RequestTimeout. 315 - Acceptable values are from 1 second to 86400 seconds. 316 authentication_certificates: 317 description: 318 - List of references to application gateway authentication certificates. 319 - Applicable only when C(cookie_based_affinity) is enabled, otherwise quietly ignored. 320 suboptions: 321 id: 322 description: 323 - Resource ID. 324 host_name: 325 description: 326 - Host header to be sent to the backend servers. 327 pick_host_name_from_backend_address: 328 description: 329 - Whether host header should be picked from the host name of the backend server. Default value is false. 330 affinity_cookie_name: 331 description: 332 - Cookie name to use for the affinity cookie. 333 path: 334 description: 335 - Path which should be used as a prefix for all C(http) requests. 336 - Null means no path will be prefixed. Default value is null. 337 name: 338 description: 339 - Name of the resource that is unique within a resource group. This name can be used to access the resource. 340 http_listeners: 341 description: 342 - List of HTTP listeners of the application gateway resource. 343 suboptions: 344 frontend_ip_configuration: 345 description: 346 - Frontend IP configuration resource of an application gateway. 347 frontend_port: 348 description: 349 - Frontend port resource of an application gateway. 350 protocol: 351 description: 352 - Protocol of the C(http) listener. 353 choices: 354 - 'http' 355 - 'https' 356 host_name: 357 description: 358 - Host name of C(http) listener. 359 ssl_certificate: 360 description: 361 - SSL certificate resource of an application gateway. 362 require_server_name_indication: 363 description: 364 - Applicable only if I(protocol) is C(https). Enables SNI for multi-hosting. 365 name: 366 description: 367 - Name of the resource that is unique within a resource group. This name can be used to access the resource. 368 url_path_maps: 369 description: 370 - List of URL path maps of the application gateway resource. 371 suboptions: 372 name: 373 description: 374 - Name of the resource that is unique within the application gateway. This name can be used to access the resource. 375 default_backend_address_pool: 376 description: 377 - Backend address pool resource of the application gateway which will be used if no path matches occur. 378 default_backend_http_settings: 379 description: 380 - Backend http settings resource of the application gateway; used for the I(default_backend_address_pool). 381 path_rules: 382 description: 383 - List of URL path rules. 384 suboptions: 385 name: 386 description: 387 - Name of the resource that is unique within the path map. 388 backend_address_pool: 389 description: 390 - Backend address pool resource of the application gateway which will be used if the path is matched. 391 backend_http_settings: 392 description: 393 - Backend http settings resource of the application gateway; used for the path's I(backend_address_pool). 394 paths: 395 description: 396 - List of paths. 397 request_routing_rules: 398 description: 399 - List of request routing rules of the application gateway resource. 400 suboptions: 401 rule_type: 402 description: 403 - Rule type. 404 choices: 405 - 'basic' 406 - 'path_based_routing' 407 backend_address_pool: 408 description: 409 - Backend address pool resource of the application gateway. Not used if I(rule_type) is C(path_based_routing). 410 backend_http_settings: 411 description: 412 - Backend C(http) settings resource of the application gateway. 413 http_listener: 414 description: 415 - Http listener resource of the application gateway. 416 name: 417 description: 418 - Name of the resource that is unique within a resource group. This name can be used to access the resource. 419 redirect_configuration: 420 description: 421 - Redirect configuration resource of the application gateway. 422 url_path_map: 423 description: 424 - URL path map resource of the application gateway. Required if I(rule_type) is C(path_based_routing). 425 state: 426 description: 427 - Assert the state of the Public IP. Use C(present) to create or update a and 428 C(absent) to delete. 429 default: present 430 choices: 431 - absent 432 - present 433 434extends_documentation_fragment: 435 - azure.azcollection.azure 436 - azure.azcollection.azure_tags 437 438author: 439 - Zim Kalinowski (@zikalino) 440 441''' 442 443EXAMPLES = ''' 444- name: Create instance of Application Gateway 445 azure_rm_appgateway: 446 resource_group: myResourceGroup 447 name: myAppGateway 448 sku: 449 name: standard_small 450 tier: standard 451 capacity: 2 452 gateway_ip_configurations: 453 - subnet: 454 id: "{{ subnet_id }}" 455 name: app_gateway_ip_config 456 frontend_ip_configurations: 457 - subnet: 458 id: "{{ subnet_id }}" 459 name: sample_gateway_frontend_ip_config 460 frontend_ports: 461 - port: 90 462 name: ag_frontend_port 463 backend_address_pools: 464 - backend_addresses: 465 - ip_address: 10.0.0.4 466 name: test_backend_address_pool 467 backend_http_settings_collection: 468 - port: 80 469 protocol: http 470 cookie_based_affinity: enabled 471 name: sample_appgateway_http_settings 472 http_listeners: 473 - frontend_ip_configuration: sample_gateway_frontend_ip_config 474 frontend_port: ag_frontend_port 475 name: sample_http_listener 476 request_routing_rules: 477 - rule_type: Basic 478 backend_address_pool: test_backend_address_pool 479 backend_http_settings: sample_appgateway_http_settings 480 http_listener: sample_http_listener 481 name: rule1 482 483- name: Create instance of Application Gateway by looking up virtual network and subnet 484 azure_rm_appgateway: 485 resource_group: myResourceGroup 486 name: myAppGateway 487 sku: 488 name: standard_small 489 tier: standard 490 capacity: 2 491 gateway_ip_configurations: 492 - subnet: 493 name: default 494 virtual_network_name: my-vnet 495 name: app_gateway_ip_config 496 frontend_ip_configurations: 497 - subnet: 498 name: default 499 virtual_network_name: my-vnet 500 name: sample_gateway_frontend_ip_config 501 frontend_ports: 502 - port: 90 503 name: ag_frontend_port 504 backend_address_pools: 505 - backend_addresses: 506 - ip_address: 10.0.0.4 507 name: test_backend_address_pool 508 backend_http_settings_collection: 509 - port: 80 510 protocol: http 511 cookie_based_affinity: enabled 512 name: sample_appgateway_http_settings 513 http_listeners: 514 - frontend_ip_configuration: sample_gateway_frontend_ip_config 515 frontend_port: ag_frontend_port 516 name: sample_http_listener 517 request_routing_rules: 518 - rule_type: Basic 519 backend_address_pool: test_backend_address_pool 520 backend_http_settings: sample_appgateway_http_settings 521 http_listener: sample_http_listener 522 name: rule1 523 524- name: Create instance of Application Gateway with path based rules 525 azure_rm_appgateway: 526 resource_group: myResourceGroup 527 name: myAppGateway 528 sku: 529 name: standard_small 530 tier: standard 531 capacity: 2 532 gateway_ip_configurations: 533 - subnet: 534 id: "{{ subnet_id }}" 535 name: app_gateway_ip_config 536 frontend_ip_configurations: 537 - subnet: 538 id: "{{ subnet_id }}" 539 name: sample_gateway_frontend_ip_config 540 frontend_ports: 541 - port: 90 542 name: ag_frontend_port 543 backend_address_pools: 544 - backend_addresses: 545 - ip_address: 10.0.0.4 546 name: test_backend_address_pool 547 backend_http_settings_collection: 548 - port: 80 549 protocol: http 550 cookie_based_affinity: enabled 551 name: sample_appgateway_http_settings 552 http_listeners: 553 - frontend_ip_configuration: sample_gateway_frontend_ip_config 554 frontend_port: ag_frontend_port 555 name: sample_http_listener 556 request_routing_rules: 557 - rule_type: path_based_routing 558 http_listener: sample_http_listener 559 name: rule1 560 url_path_map: path_mappings 561 url_path_maps: 562 - name: path_mappings 563 default_backend_address_pool: test_backend_address_pool 564 default_backend_http_settings: sample_appgateway_http_settings 565 path_rules: 566 - name: path_rules 567 backend_address_pool: test_backend_address_pool 568 backend_http_settings: sample_appgateway_http_settings 569 paths: 570 - "/abc" 571 - "/123/*" 572''' 573 574RETURN = ''' 575id: 576 description: 577 - Resource ID. 578 returned: always 579 type: str 580 sample: id 581''' 582 583import time 584from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMModuleBase 585from copy import deepcopy 586from ansible.module_utils.common.dict_transformations import ( 587 camel_dict_to_snake_dict, snake_dict_to_camel_dict, 588 _camel_to_snake, _snake_to_camel, dict_merge, 589) 590 591try: 592 from msrestazure.azure_exceptions import CloudError 593 from msrest.polling import LROPoller 594 from azure.mgmt.network import NetworkManagementClient 595 from msrest.serialization import Model 596except ImportError: 597 # This is handled in azure_rm_common 598 pass 599 600 601class Actions: 602 NoAction, Create, Update, Delete = range(4) 603 604 605ssl_policy_spec = dict( 606 disabled_ssl_protocols=dict(type='list'), 607 policy_type=dict(type='str', choices=['predefined', 'custom']), 608 policy_name=dict(type='str', choices=['ssl_policy20150501', 'ssl_policy20170401', 'ssl_policy20170401_s']), 609 cipher_suites=dict(type='list'), 610 min_protocol_version=dict(type='str', choices=['tls_v1_0', 'tls_v1_1', 'tls_v1_2']) 611) 612 613 614probe_spec = dict( 615 host=dict(type='str'), 616 interval=dict(type='int'), 617 name=dict(type='str'), 618 path=dict(type='str'), 619 protocol=dict(type='str', choices=['http', 'https']), 620 timeout=dict(type='int'), 621 unhealthy_threshold=dict(type='int'), 622 pick_host_name_from_backend_http_settings=dict(type='bool', default=False) 623) 624 625 626redirect_configuration_spec = dict( 627 include_path=dict(type='bool'), 628 include_query_string=dict(type='bool'), 629 name=dict(type='str'), 630 redirect_type=dict(type='str', choices=['permanent', 'found', 'see_other', 'temporary']), 631 target_listener=dict(type='str') 632) 633 634 635class AzureRMApplicationGateways(AzureRMModuleBase): 636 """Configuration class for an Azure RM Application Gateway resource""" 637 638 def __init__(self): 639 self.module_arg_spec = dict( 640 resource_group=dict( 641 type='str', 642 required=True 643 ), 644 name=dict( 645 type='str', 646 required=True 647 ), 648 location=dict( 649 type='str' 650 ), 651 sku=dict( 652 type='dict' 653 ), 654 ssl_policy=dict( 655 type='dict', 656 options=ssl_policy_spec 657 ), 658 gateway_ip_configurations=dict( 659 type='list' 660 ), 661 authentication_certificates=dict( 662 type='list' 663 ), 664 ssl_certificates=dict( 665 type='list' 666 ), 667 redirect_configurations=dict( 668 type='list', 669 elements='dict', 670 options=redirect_configuration_spec 671 ), 672 frontend_ip_configurations=dict( 673 type='list' 674 ), 675 frontend_ports=dict( 676 type='list' 677 ), 678 backend_address_pools=dict( 679 type='list' 680 ), 681 backend_http_settings_collection=dict( 682 type='list' 683 ), 684 probes=dict( 685 type='list', 686 elements='dict', 687 options=probe_spec 688 ), 689 http_listeners=dict( 690 type='list' 691 ), 692 url_path_maps=dict( 693 type='list' 694 ), 695 request_routing_rules=dict( 696 type='list' 697 ), 698 state=dict( 699 type='str', 700 default='present', 701 choices=['present', 'absent'] 702 ) 703 ) 704 705 self.resource_group = None 706 self.name = None 707 self.parameters = dict() 708 709 self.results = dict(changed=False) 710 self.mgmt_client = None 711 self.state = None 712 self.to_do = Actions.NoAction 713 714 super(AzureRMApplicationGateways, self).__init__(derived_arg_spec=self.module_arg_spec, 715 supports_check_mode=True, 716 supports_tags=True) 717 718 def exec_module(self, **kwargs): 719 """Main module execution method""" 720 721 for key in list(self.module_arg_spec.keys()) + ['tags']: 722 if hasattr(self, key): 723 setattr(self, key, kwargs[key]) 724 elif kwargs[key] is not None: 725 if key == "id": 726 self.parameters["id"] = kwargs[key] 727 elif key == "location": 728 self.parameters["location"] = kwargs[key] 729 elif key == "sku": 730 ev = kwargs[key] 731 if 'name' in ev: 732 if ev['name'] == 'standard_small': 733 ev['name'] = 'Standard_Small' 734 elif ev['name'] == 'standard_medium': 735 ev['name'] = 'Standard_Medium' 736 elif ev['name'] == 'standard_large': 737 ev['name'] = 'Standard_Large' 738 elif ev['name'] == 'standard_v2': 739 ev['name'] = 'Standard_v2' 740 elif ev['name'] == 'waf_medium': 741 ev['name'] = 'WAF_Medium' 742 elif ev['name'] == 'waf_large': 743 ev['name'] = 'WAF_Large' 744 elif ev['name'] == 'waf_v2': 745 ev['name'] = 'WAF_v2' 746 if 'tier' in ev: 747 if ev['tier'] == 'standard': 748 ev['tier'] = 'Standard' 749 if ev['tier'] == 'standard_v2': 750 ev['tier'] = 'Standard_v2' 751 elif ev['tier'] == 'waf': 752 ev['tier'] = 'WAF' 753 elif ev['tier'] == 'waf_v2': 754 ev['tier'] = 'WAF_v2' 755 self.parameters["sku"] = ev 756 elif key == "ssl_policy": 757 ev = kwargs[key] 758 if 'policy_type' in ev: 759 ev['policy_type'] = _snake_to_camel(ev['policy_type'], True) 760 if 'policy_name' in ev: 761 if ev['policy_name'] == 'ssl_policy20150501': 762 ev['policy_name'] = 'AppGwSslPolicy20150501' 763 elif ev['policy_name'] == 'ssl_policy20170401': 764 ev['policy_name'] = 'AppGwSslPolicy20170401' 765 elif ev['policy_name'] == 'ssl_policy20170401_s': 766 ev['policy_name'] = 'AppGwSslPolicy20170401S' 767 if 'min_protocol_version' in ev: 768 if ev['min_protocol_version'] == 'tls_v1_0': 769 ev['min_protocol_version'] = 'TLSv1_0' 770 elif ev['min_protocol_version'] == 'tls_v1_1': 771 ev['min_protocol_version'] = 'TLSv1_1' 772 elif ev['min_protocol_version'] == 'tls_v1_2': 773 ev['min_protocol_version'] = 'TLSv1_2' 774 if 'disabled_ssl_protocols' in ev: 775 protocols = ev['disabled_ssl_protocols'] 776 if protocols is not None: 777 for i in range(len(protocols)): 778 if protocols[i] == 'tls_v1_0': 779 protocols[i] = 'TLSv1_0' 780 elif protocols[i] == 'tls_v1_1': 781 protocols[i] = 'TLSv1_1' 782 elif protocols[i] == 'tls_v1_2': 783 protocols[i] = 'TLSv1_2' 784 if 'cipher_suites' in ev: 785 suites = ev['cipher_suites'] 786 if suites is not None: 787 for i in range(len(suites)): 788 suites[i] = suites[i].upper() 789 elif key == "gateway_ip_configurations": 790 ev = kwargs[key] 791 for i in range(len(ev)): 792 item = ev[i] 793 if 'subnet' in item and 'name' in item['subnet'] and 'virtual_network_name' in item['subnet']: 794 id = subnet_id(self.subscription_id, 795 kwargs['resource_group'], 796 item['subnet']['virtual_network_name'], 797 item['subnet']['name']) 798 item['subnet'] = {'id': id} 799 self.parameters["gateway_ip_configurations"] = kwargs[key] 800 elif key == "authentication_certificates": 801 self.parameters["authentication_certificates"] = kwargs[key] 802 elif key == "ssl_certificates": 803 self.parameters["ssl_certificates"] = kwargs[key] 804 elif key == "redirect_configurations": 805 ev = kwargs[key] 806 for i in range(len(ev)): 807 item = ev[i] 808 if 'redirect_type' in item: 809 item['redirect_type'] = _snake_to_camel(item['redirect_type'], True) 810 if 'target_listener' in item: 811 id = http_listener_id(self.subscription_id, 812 kwargs['resource_group'], 813 kwargs['name'], 814 item['target_listener']) 815 item['target_listener'] = {'id': id} 816 self.parameters["redirect_configurations"] = ev 817 elif key == "frontend_ip_configurations": 818 ev = kwargs[key] 819 for i in range(len(ev)): 820 item = ev[i] 821 if 'private_ip_allocation_method' in item: 822 item['private_ip_allocation_method'] = _snake_to_camel(item['private_ip_allocation_method'], True) 823 if 'public_ip_address' in item: 824 id = public_ip_id(self.subscription_id, 825 kwargs['resource_group'], 826 item['public_ip_address']) 827 item['public_ip_address'] = {'id': id} 828 if 'subnet' in item and 'name' in item['subnet'] and 'virtual_network_name' in item['subnet']: 829 id = subnet_id(self.subscription_id, 830 kwargs['resource_group'], 831 item['subnet']['virtual_network_name'], 832 item['subnet']['name']) 833 item['subnet'] = {'id': id} 834 self.parameters["frontend_ip_configurations"] = ev 835 elif key == "frontend_ports": 836 self.parameters["frontend_ports"] = kwargs[key] 837 elif key == "backend_address_pools": 838 self.parameters["backend_address_pools"] = kwargs[key] 839 elif key == "probes": 840 ev = kwargs[key] 841 for i in range(len(ev)): 842 item = ev[i] 843 if 'protocol' in item: 844 item['protocol'] = _snake_to_camel(item['protocol'], True) 845 if 'pick_host_name_from_backend_http_settings' in item and item['pick_host_name_from_backend_http_settings'] and 'host' in item: 846 del item['host'] 847 self.parameters["probes"] = ev 848 elif key == "backend_http_settings_collection": 849 ev = kwargs[key] 850 for i in range(len(ev)): 851 item = ev[i] 852 if 'protocol' in item: 853 item['protocol'] = _snake_to_camel(item['protocol'], True) 854 if 'cookie_based_affinity' in item: 855 item['cookie_based_affinity'] = _snake_to_camel(item['cookie_based_affinity'], True) 856 if 'probe' in item: 857 id = probe_id(self.subscription_id, 858 kwargs['resource_group'], 859 kwargs['name'], 860 item['probe']) 861 item['probe'] = {'id': id} 862 self.parameters["backend_http_settings_collection"] = ev 863 elif key == "http_listeners": 864 ev = kwargs[key] 865 for i in range(len(ev)): 866 item = ev[i] 867 if 'frontend_ip_configuration' in item: 868 id = frontend_ip_configuration_id(self.subscription_id, 869 kwargs['resource_group'], 870 kwargs['name'], 871 item['frontend_ip_configuration']) 872 item['frontend_ip_configuration'] = {'id': id} 873 874 if 'frontend_port' in item: 875 id = frontend_port_id(self.subscription_id, 876 kwargs['resource_group'], 877 kwargs['name'], 878 item['frontend_port']) 879 item['frontend_port'] = {'id': id} 880 if 'ssl_certificate' in item: 881 id = ssl_certificate_id(self.subscription_id, 882 kwargs['resource_group'], 883 kwargs['name'], 884 item['ssl_certificate']) 885 item['ssl_certificate'] = {'id': id} 886 if 'protocol' in item: 887 item['protocol'] = _snake_to_camel(item['protocol'], True) 888 ev[i] = item 889 self.parameters["http_listeners"] = ev 890 elif key == "url_path_maps": 891 ev = kwargs[key] 892 for i in range(len(ev)): 893 item = ev[i] 894 if 'default_backend_address_pool' in item: 895 id = backend_address_pool_id(self.subscription_id, 896 kwargs['resource_group'], 897 kwargs['name'], 898 item['default_backend_address_pool']) 899 item['default_backend_address_pool'] = {'id': id} 900 if 'default_backend_http_settings' in item: 901 id = backend_http_settings_id(self.subscription_id, 902 kwargs['resource_group'], 903 kwargs['name'], 904 item['default_backend_http_settings']) 905 item['default_backend_http_settings'] = {'id': id} 906 if 'path_rules' in item: 907 ev2 = item['path_rules'] 908 for j in range(len(ev2)): 909 item2 = ev2[j] 910 if 'backend_address_pool' in item2: 911 id = backend_address_pool_id(self.subscription_id, 912 kwargs['resource_group'], 913 kwargs['name'], 914 item2['backend_address_pool']) 915 item2['backend_address_pool'] = {'id': id} 916 if 'backend_http_settings' in item2: 917 id = backend_http_settings_id(self.subscription_id, 918 kwargs['resource_group'], 919 kwargs['name'], 920 item2['backend_http_settings']) 921 item2['backend_http_settings'] = {'id': id} 922 ev2[j] = item2 923 ev[i] = item 924 self.parameters["url_path_maps"] = ev 925 elif key == "request_routing_rules": 926 ev = kwargs[key] 927 for i in range(len(ev)): 928 item = ev[i] 929 if 'rule_type' in item and item['rule_type'] == 'path_based_routing' and 'backend_address_pool' in item: 930 del item['backend_address_pool'] 931 if 'backend_address_pool' in item: 932 id = backend_address_pool_id(self.subscription_id, 933 kwargs['resource_group'], 934 kwargs['name'], 935 item['backend_address_pool']) 936 item['backend_address_pool'] = {'id': id} 937 if 'backend_http_settings' in item: 938 id = backend_http_settings_id(self.subscription_id, 939 kwargs['resource_group'], 940 kwargs['name'], 941 item['backend_http_settings']) 942 item['backend_http_settings'] = {'id': id} 943 if 'http_listener' in item: 944 id = http_listener_id(self.subscription_id, 945 kwargs['resource_group'], 946 kwargs['name'], 947 item['http_listener']) 948 item['http_listener'] = {'id': id} 949 if 'protocol' in item: 950 item['protocol'] = _snake_to_camel(item['protocol'], True) 951 if 'rule_type' in item: 952 item['rule_type'] = _snake_to_camel(item['rule_type'], True) 953 if 'redirect_configuration' in item: 954 id = redirect_configuration_id(self.subscription_id, 955 kwargs['resource_group'], 956 kwargs['name'], 957 item['redirect_configuration']) 958 item['redirect_configuration'] = {'id': id} 959 if 'url_path_map' in item: 960 id = url_path_map_id(self.subscription_id, 961 kwargs['resource_group'], 962 kwargs['name'], 963 item['url_path_map']) 964 item['url_path_map'] = {'id': id} 965 ev[i] = item 966 self.parameters["request_routing_rules"] = ev 967 elif key == "etag": 968 self.parameters["etag"] = kwargs[key] 969 970 old_response = None 971 response = None 972 973 self.mgmt_client = self.get_mgmt_svc_client(NetworkManagementClient, 974 base_url=self._cloud_environment.endpoints.resource_manager) 975 976 resource_group = self.get_resource_group(self.resource_group) 977 978 if "location" not in self.parameters: 979 self.parameters["location"] = resource_group.location 980 981 old_response = self.get_applicationgateway() 982 983 if not old_response: 984 self.log("Application Gateway instance doesn't exist") 985 if self.state == 'absent': 986 self.log("Old instance didn't exist") 987 else: 988 self.to_do = Actions.Create 989 else: 990 self.log("Application Gateway instance already exists") 991 if self.state == 'absent': 992 self.to_do = Actions.Delete 993 elif self.state == 'present': 994 self.log("Need to check if Application Gateway instance has to be deleted or may be updated") 995 self.to_do = Actions.Update 996 997 if (self.to_do == Actions.Update): 998 if (self.parameters['location'] != old_response['location'] or 999 self.parameters['sku']['name'] != old_response['sku']['name'] or 1000 self.parameters['sku']['tier'] != old_response['sku']['tier'] or 1001 self.parameters['sku']['capacity'] != old_response['sku']['capacity'] or 1002 not compare_arrays(old_response, self.parameters, 'authentication_certificates') or 1003 not compare_arrays(old_response, self.parameters, 'gateway_ip_configurations') or 1004 not compare_arrays(old_response, self.parameters, 'redirect_configurations') or 1005 not compare_arrays(old_response, self.parameters, 'frontend_ip_configurations') or 1006 not compare_arrays(old_response, self.parameters, 'frontend_ports') or 1007 not compare_arrays(old_response, self.parameters, 'backend_address_pools') or 1008 not compare_arrays(old_response, self.parameters, 'probes') or 1009 not compare_arrays(old_response, self.parameters, 'backend_http_settings_collection') or 1010 not compare_arrays(old_response, self.parameters, 'request_routing_rules') or 1011 not compare_arrays(old_response, self.parameters, 'http_listeners') or 1012 not compare_arrays(old_response, self.parameters, 'url_path_maps')): 1013 1014 self.to_do = Actions.Update 1015 else: 1016 self.to_do = Actions.NoAction 1017 1018 if (self.to_do == Actions.Create) or (self.to_do == Actions.Update): 1019 self.log("Need to Create / Update the Application Gateway instance") 1020 1021 if self.check_mode: 1022 self.results['changed'] = True 1023 self.results["parameters"] = self.parameters 1024 return self.results 1025 1026 response = self.create_update_applicationgateway() 1027 1028 if not old_response: 1029 self.results['changed'] = True 1030 else: 1031 self.results['changed'] = old_response.__ne__(response) 1032 self.log("Creation / Update done") 1033 elif self.to_do == Actions.Delete: 1034 self.log("Application Gateway instance deleted") 1035 self.results['changed'] = True 1036 1037 if self.check_mode: 1038 return self.results 1039 1040 self.delete_applicationgateway() 1041 # make sure instance is actually deleted, for some Azure resources, instance is hanging around 1042 # for some time after deletion -- this should be really fixed in Azure 1043 while self.get_applicationgateway(): 1044 time.sleep(20) 1045 else: 1046 self.log("Application Gateway instance unchanged") 1047 self.results['changed'] = False 1048 response = old_response 1049 1050 if response: 1051 self.results["id"] = response["id"] 1052 1053 return self.results 1054 1055 def create_update_applicationgateway(self): 1056 ''' 1057 Creates or updates Application Gateway with the specified configuration. 1058 1059 :return: deserialized Application Gateway instance state dictionary 1060 ''' 1061 self.log("Creating / Updating the Application Gateway instance {0}".format(self.name)) 1062 1063 try: 1064 response = self.mgmt_client.application_gateways.create_or_update(resource_group_name=self.resource_group, 1065 application_gateway_name=self.name, 1066 parameters=self.parameters) 1067 if isinstance(response, LROPoller): 1068 response = self.get_poller_result(response) 1069 1070 except CloudError as exc: 1071 self.log('Error attempting to create the Application Gateway instance.') 1072 self.fail("Error creating the Application Gateway instance: {0}".format(str(exc))) 1073 return response.as_dict() 1074 1075 def delete_applicationgateway(self): 1076 ''' 1077 Deletes specified Application Gateway instance in the specified subscription and resource group. 1078 1079 :return: True 1080 ''' 1081 self.log("Deleting the Application Gateway instance {0}".format(self.name)) 1082 try: 1083 response = self.mgmt_client.application_gateways.delete(resource_group_name=self.resource_group, 1084 application_gateway_name=self.name) 1085 except CloudError as e: 1086 self.log('Error attempting to delete the Application Gateway instance.') 1087 self.fail("Error deleting the Application Gateway instance: {0}".format(str(e))) 1088 1089 return True 1090 1091 def get_applicationgateway(self): 1092 ''' 1093 Gets the properties of the specified Application Gateway. 1094 1095 :return: deserialized Application Gateway instance state dictionary 1096 ''' 1097 self.log("Checking if the Application Gateway instance {0} is present".format(self.name)) 1098 found = False 1099 try: 1100 response = self.mgmt_client.application_gateways.get(resource_group_name=self.resource_group, 1101 application_gateway_name=self.name) 1102 found = True 1103 self.log("Response : {0}".format(response)) 1104 self.log("Application Gateway instance : {0} found".format(response.name)) 1105 except CloudError as e: 1106 self.log('Did not find the Application Gateway instance.') 1107 if found is True: 1108 return response.as_dict() 1109 1110 return False 1111 1112 1113def public_ip_id(subscription_id, resource_group_name, name): 1114 """Generate the id for a frontend ip configuration""" 1115 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/publicIPAddresses/{2}'.format( 1116 subscription_id, 1117 resource_group_name, 1118 name 1119 ) 1120 1121 1122def frontend_ip_configuration_id(subscription_id, resource_group_name, appgateway_name, name): 1123 """Generate the id for a frontend ip configuration""" 1124 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/frontendIPConfigurations/{3}'.format( 1125 subscription_id, 1126 resource_group_name, 1127 appgateway_name, 1128 name 1129 ) 1130 1131 1132def frontend_port_id(subscription_id, resource_group_name, appgateway_name, name): 1133 """Generate the id for a frontend port""" 1134 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/frontendPorts/{3}'.format( 1135 subscription_id, 1136 resource_group_name, 1137 appgateway_name, 1138 name 1139 ) 1140 1141 1142def redirect_configuration_id(subscription_id, resource_group_name, appgateway_name, name): 1143 """Generate the id for a redirect configuration""" 1144 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/redirectConfigurations/{3}'.format( 1145 subscription_id, 1146 resource_group_name, 1147 appgateway_name, 1148 name 1149 ) 1150 1151 1152def ssl_certificate_id(subscription_id, resource_group_name, ssl_certificate_name, name): 1153 """Generate the id for a frontend port""" 1154 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/sslCertificates/{3}'.format( 1155 subscription_id, 1156 resource_group_name, 1157 ssl_certificate_name, 1158 name 1159 ) 1160 1161 1162def backend_address_pool_id(subscription_id, resource_group_name, appgateway_name, name): 1163 """Generate the id for an address pool""" 1164 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/backendAddressPools/{3}'.format( 1165 subscription_id, 1166 resource_group_name, 1167 appgateway_name, 1168 name 1169 ) 1170 1171 1172def probe_id(subscription_id, resource_group_name, appgateway_name, name): 1173 """Generate the id for a probe""" 1174 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/probes/{3}'.format( 1175 subscription_id, 1176 resource_group_name, 1177 appgateway_name, 1178 name 1179 ) 1180 1181 1182def backend_http_settings_id(subscription_id, resource_group_name, appgateway_name, name): 1183 """Generate the id for a http settings""" 1184 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/backendHttpSettingsCollection/{3}'.format( 1185 subscription_id, 1186 resource_group_name, 1187 appgateway_name, 1188 name 1189 ) 1190 1191 1192def http_listener_id(subscription_id, resource_group_name, appgateway_name, name): 1193 """Generate the id for a http listener""" 1194 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/httpListeners/{3}'.format( 1195 subscription_id, 1196 resource_group_name, 1197 appgateway_name, 1198 name 1199 ) 1200 1201 1202def url_path_map_id(subscription_id, resource_group_name, appgateway_name, name): 1203 """Generate the id for a url path map""" 1204 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/applicationGateways/{2}/urlPathMaps/{3}'.format( 1205 subscription_id, 1206 resource_group_name, 1207 appgateway_name, 1208 name 1209 ) 1210 1211 1212def subnet_id(subscription_id, resource_group_name, virtual_network_name, name): 1213 """Generate the id for a subnet in a virtual network""" 1214 return '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/virtualNetworks/{2}/subnets/{3}'.format( 1215 subscription_id, 1216 resource_group_name, 1217 virtual_network_name, 1218 name 1219 ) 1220 1221 1222def compare_arrays(old_params, new_params, param_name): 1223 old = old_params.get(param_name) or [] 1224 new = new_params.get(param_name) or [] 1225 1226 oldd = array_to_dict(old) 1227 newd = array_to_dict(new) 1228 1229 newd = dict_merge(oldd, newd) 1230 return newd == oldd 1231 1232 1233def array_to_dict(array): 1234 '''Converts list object to dictionary object, including any nested properties on elements.''' 1235 new = {} 1236 for index, item in enumerate(array): 1237 new[index] = deepcopy(item) 1238 if isinstance(item, dict): 1239 for nested in item: 1240 if isinstance(item[nested], list): 1241 new[index][nested] = array_to_dict(item[nested]) 1242 return new 1243 1244 1245def main(): 1246 """Main execution""" 1247 AzureRMApplicationGateways() 1248 1249 1250if __name__ == '__main__': 1251 main() 1252