summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Elrod <rick@elrod.me>2020-08-08 00:56:53 -0500
committerGitHub <noreply@github.com>2020-08-08 00:56:53 -0500
commit4f54fb8d439ea8a41dfe1084fbc6d8e0e3f42264 (patch)
tree099097bd7270a05f2bc05a59ce2d6d8a39dc45a4
parent501f30df45b03a9ce6d272d50e217deed2d40fb3 (diff)
downloadansible-4f54fb8d439ea8a41dfe1084fbc6d8e0e3f42264.tar.gz
Remove incidental azure tests (#71164)
Change: - All incidental coverage from these tests has moved to intentional coverage. Test Plan: - CI Signed-off-by: Rick Elrod <rick@elrod.me>
-rw-r--r--shippable.yml2
-rw-r--r--test/integration/targets/incidental_azure_rm_resource/aliases3
-rw-r--r--test/integration/targets/incidental_azure_rm_resource/tasks/main.yml158
-rw-r--r--test/sanity/ignore.txt4
-rw-r--r--test/support/integration/plugins/module_utils/azure_rm_common.py1473
-rw-r--r--test/support/integration/plugins/module_utils/azure_rm_common_rest.py97
l---------test/support/integration/plugins/modules/_azure_rm_mariadbconfiguration_facts.py1
l---------test/support/integration/plugins/modules/_azure_rm_mariadbdatabase_facts.py1
l---------test/support/integration/plugins/modules/_azure_rm_mariadbfirewallrule_facts.py1
l---------test/support/integration/plugins/modules/_azure_rm_mariadbserver_facts.py1
l---------test/support/integration/plugins/modules/_azure_rm_resource_facts.py1
l---------test/support/integration/plugins/modules/_azure_rm_webapp_facts.py1
-rw-r--r--test/support/integration/plugins/modules/azure_rm_appserviceplan.py379
-rw-r--r--test/support/integration/plugins/modules/azure_rm_functionapp.py421
-rw-r--r--test/support/integration/plugins/modules/azure_rm_functionapp_info.py207
-rw-r--r--test/support/integration/plugins/modules/azure_rm_mariadbconfiguration.py241
-rw-r--r--test/support/integration/plugins/modules/azure_rm_mariadbconfiguration_info.py217
-rw-r--r--test/support/integration/plugins/modules/azure_rm_mariadbdatabase.py304
-rw-r--r--test/support/integration/plugins/modules/azure_rm_mariadbdatabase_info.py212
-rw-r--r--test/support/integration/plugins/modules/azure_rm_mariadbfirewallrule.py277
-rw-r--r--test/support/integration/plugins/modules/azure_rm_mariadbfirewallrule_info.py208
-rw-r--r--test/support/integration/plugins/modules/azure_rm_mariadbserver_info.py265
-rw-r--r--test/support/integration/plugins/modules/azure_rm_resource.py427
-rw-r--r--test/support/integration/plugins/modules/azure_rm_resource_info.py432
-rw-r--r--test/support/integration/plugins/modules/azure_rm_storageaccount.py684
-rw-r--r--test/support/integration/plugins/modules/azure_rm_webapp.py1070
-rw-r--r--test/support/integration/plugins/modules/azure_rm_webapp_info.py489
-rw-r--r--test/support/integration/plugins/modules/azure_rm_webappslot.py1058
l---------test/utils/shippable/incidental/azure.sh1
29 files changed, 0 insertions, 8635 deletions
diff --git a/shippable.yml b/shippable.yml
index 86ee46764b..3dfb2ca657 100644
--- a/shippable.yml
+++ b/shippable.yml
@@ -139,8 +139,6 @@ matrix:
- env: T=i/aws/2.7/1
- env: T=i/aws/3.6/1
- - env: T=i/azure/2.7/1
- - env: T=i/azure/3.6/1
- env: T=i/vcenter//1
- env: T=i/cs//1
- env: T=i/tower//1
diff --git a/test/integration/targets/incidental_azure_rm_resource/aliases b/test/integration/targets/incidental_azure_rm_resource/aliases
deleted file mode 100644
index 9901373af2..0000000000
--- a/test/integration/targets/incidental_azure_rm_resource/aliases
+++ /dev/null
@@ -1,3 +0,0 @@
-cloud/azure
-destructive
-shippable/azure/incidental
diff --git a/test/integration/targets/incidental_azure_rm_resource/tasks/main.yml b/test/integration/targets/incidental_azure_rm_resource/tasks/main.yml
deleted file mode 100644
index 7c3024a5ef..0000000000
--- a/test/integration/targets/incidental_azure_rm_resource/tasks/main.yml
+++ /dev/null
@@ -1,158 +0,0 @@
-- name: Prepare random number
- set_fact:
- nsgname: "{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}"
- storageaccountname: "stacc{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}"
- dbname: "mdb{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}"
- run_once: yes
-
-- name: Call REST API
- azure_rm_resource:
- api_version: '2018-02-01'
- resource_group: "{{ resource_group }}"
- provider: network
- resource_type: networksecuritygroups
- resource_name: "{{ nsgname }}"
- body:
- location: eastus
- idempotency: yes
- register: output
-
-- name: Assert that something has changed
- assert:
- that: output.changed
-
-- name: Call REST API
- azure_rm_resource:
- api_version: '2018-02-01'
- resource_group: "{{ resource_group }}"
- provider: network
- resource_type: networksecuritygroups
- resource_name: "{{ nsgname }}"
- body:
- location: eastus
- idempotency: yes
- register: output
-
-- name: Assert that nothing has changed
- assert:
- that: not output.changed
-
-- name: Call REST API
- azure_rm_resource:
- api_version: '2018-02-01'
- resource_group: "{{ resource_group }}"
- provider: network
- resource_type: networksecuritygroups
- resource_name: "{{ nsgname }}"
- body:
- location: eastus
- tags:
- a: "abc"
- b: "cde"
- idempotency: yes
- register: output
-
-- name: Assert that something has changed
- assert:
- that: output.changed
-
-- name: Try to get information about account
- azure_rm_resource_facts:
- api_version: '2018-02-01'
- resource_group: "{{ resource_group }}"
- provider: network
- resource_type: networksecuritygroups
- resource_name: "{{ nsgname }}"
- register: output
-
-- name: Assert value was returned
- assert:
- that:
- - not output.changed
- - output.response[0]['name'] != None
- - output.response | length == 1
-
-- name: Try to query a list
- azure_rm_resource_facts:
- api_version: '2018-02-01'
- resource_group: "{{ resource_group }}"
- provider: network
- resource_type: networksecuritygroups
- register: output
-- name: Assert value was returned
- assert:
- that:
- - not output.changed
- - output.response[0]['name'] != None
- - output.response | length >= 1
-
-- name: Try to query a list - same without API version
- azure_rm_resource_facts:
- resource_group: "{{ resource_group }}"
- provider: network
- resource_type: networksecuritygroups
- register: output
-- name: Assert value was returned
- assert:
- that:
- - not output.changed
- - output.response[0]['name'] != None
- - output.response | length >= 1
-
-- name: Query all the resources in the resource group
- azure_rm_resource_facts:
- resource_group: "{{ resource_group }}"
- resource_type: resources
- register: output
-- name: Assert value was returned
- assert:
- that:
- - not output.changed
- - output.response | length >= 1
-
-- name: Create storage account that requires LRO polling
- azure_rm_resource:
- polling_timeout: 600
- polling_interval: 60
- api_version: '2018-07-01'
- resource_group: "{{ resource_group }}"
- provider: Storage
- resource_type: storageAccounts
- resource_name: "{{ storageaccountname }}"
- body:
- sku:
- name: Standard_GRS
- kind: Storage
- location: eastus
- register: output
-
-- name: Assert that storage was successfully created
- assert:
- that: "output['response']['name'] == '{{ storageaccountname }}'"
-
-
-- name: Try to storage keys -- special case when subresource part has no name
- azure_rm_resource:
- resource_group: "{{ resource_group }}"
- provider: storage
- resource_type: storageAccounts
- resource_name: "{{ storageaccountname }}"
- subresource:
- - type: listkeys
- api_version: '2018-03-01-preview'
- method: POST
- register: keys
-
-- name: Assert that key was returned
- assert:
- that: keys['response']['keys'][0]['value'] | length > 0
-
-- name: Delete storage - without API version
- azure_rm_resource:
- polling_timeout: 600
- polling_interval: 60
- method: DELETE
- resource_group: "{{ resource_group }}"
- provider: Storage
- resource_type: storageAccounts
- resource_name: "{{ storageaccountname }}"
diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt
index 74abc7047c..e253307578 100644
--- a/test/sanity/ignore.txt
+++ b/test/sanity/ignore.txt
@@ -236,10 +236,6 @@ test/lib/ansible_test/_data/setup/ConfigureRemotingForAnsible.ps1 pslint:PSCusto
test/lib/ansible_test/_data/setup/windows-httptester.ps1 pslint:PSCustomUseLiteralPath
test/support/integration/plugins/module_utils/ansible_tower.py future-import-boilerplate
test/support/integration/plugins/module_utils/ansible_tower.py metaclass-boilerplate
-test/support/integration/plugins/module_utils/azure_rm_common.py future-import-boilerplate
-test/support/integration/plugins/module_utils/azure_rm_common.py metaclass-boilerplate
-test/support/integration/plugins/module_utils/azure_rm_common_rest.py future-import-boilerplate
-test/support/integration/plugins/module_utils/azure_rm_common_rest.py metaclass-boilerplate
test/support/integration/plugins/module_utils/cloud.py future-import-boilerplate
test/support/integration/plugins/module_utils/cloud.py metaclass-boilerplate
test/support/integration/plugins/module_utils/compat/ipaddress.py future-import-boilerplate
diff --git a/test/support/integration/plugins/module_utils/azure_rm_common.py b/test/support/integration/plugins/module_utils/azure_rm_common.py
deleted file mode 100644
index a7b55e972e..0000000000
--- a/test/support/integration/plugins/module_utils/azure_rm_common.py
+++ /dev/null
@@ -1,1473 +0,0 @@
-# Copyright (c) 2016 Matt Davis, <mdavis@ansible.com>
-# Chris Houseknecht, <house@redhat.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-import os
-import re
-import types
-import copy
-import inspect
-import traceback
-import json
-
-from os.path import expanduser
-
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-try:
- from ansible.module_utils.ansible_release import __version__ as ANSIBLE_VERSION
-except Exception:
- ANSIBLE_VERSION = 'unknown'
-from ansible.module_utils.six.moves import configparser
-import ansible.module_utils.six.moves.urllib.parse as urlparse
-
-AZURE_COMMON_ARGS = dict(
- auth_source=dict(
- type='str',
- choices=['auto', 'cli', 'env', 'credential_file', 'msi']
- ),
- profile=dict(type='str'),
- subscription_id=dict(type='str'),
- client_id=dict(type='str', no_log=True),
- secret=dict(type='str', no_log=True),
- tenant=dict(type='str', no_log=True),
- ad_user=dict(type='str', no_log=True),
- password=dict(type='str', no_log=True),
- cloud_environment=dict(type='str', default='AzureCloud'),
- cert_validation_mode=dict(type='str', choices=['validate', 'ignore']),
- api_profile=dict(type='str', default='latest'),
- adfs_authority_url=dict(type='str', default=None)
-)
-
-AZURE_CREDENTIAL_ENV_MAPPING = dict(
- profile='AZURE_PROFILE',
- subscription_id='AZURE_SUBSCRIPTION_ID',
- client_id='AZURE_CLIENT_ID',
- secret='AZURE_SECRET',
- tenant='AZURE_TENANT',
- ad_user='AZURE_AD_USER',
- password='AZURE_PASSWORD',
- cloud_environment='AZURE_CLOUD_ENVIRONMENT',
- cert_validation_mode='AZURE_CERT_VALIDATION_MODE',
- adfs_authority_url='AZURE_ADFS_AUTHORITY_URL'
-)
-
-
-class SDKProfile(object): # pylint: disable=too-few-public-methods
-
- def __init__(self, default_api_version, profile=None):
- """Constructor.
-
- :param str default_api_version: Default API version if not overridden by a profile. Nullable.
- :param profile: A dict operation group name to API version.
- :type profile: dict[str, str]
- """
- self.profile = profile if profile is not None else {}
- self.profile[None] = default_api_version
-
- @property
- def default_api_version(self):
- return self.profile[None]
-
-
-# FUTURE: this should come from the SDK or an external location.
-# For now, we have to copy from azure-cli
-AZURE_API_PROFILES = {
- 'latest': {
- 'ContainerInstanceManagementClient': '2018-02-01-preview',
- 'ComputeManagementClient': dict(
- default_api_version='2018-10-01',
- resource_skus='2018-10-01',
- disks='2018-06-01',
- snapshots='2018-10-01',
- virtual_machine_run_commands='2018-10-01'
- ),
- 'NetworkManagementClient': '2018-08-01',
- 'ResourceManagementClient': '2017-05-10',
- 'StorageManagementClient': '2017-10-01',
- 'WebSiteManagementClient': '2018-02-01',
- 'PostgreSQLManagementClient': '2017-12-01',
- 'MySQLManagementClient': '2017-12-01',
- 'MariaDBManagementClient': '2019-03-01',
- 'ManagementLockClient': '2016-09-01'
- },
- '2019-03-01-hybrid': {
- 'StorageManagementClient': '2017-10-01',
- 'NetworkManagementClient': '2017-10-01',
- 'ComputeManagementClient': SDKProfile('2017-12-01', {
- 'resource_skus': '2017-09-01',
- 'disks': '2017-03-30',
- 'snapshots': '2017-03-30'
- }),
- 'ManagementLinkClient': '2016-09-01',
- 'ManagementLockClient': '2016-09-01',
- 'PolicyClient': '2016-12-01',
- 'ResourceManagementClient': '2018-05-01',
- 'SubscriptionClient': '2016-06-01',
- 'DnsManagementClient': '2016-04-01',
- 'KeyVaultManagementClient': '2016-10-01',
- 'AuthorizationManagementClient': SDKProfile('2015-07-01', {
- 'classic_administrators': '2015-06-01',
- 'policy_assignments': '2016-12-01',
- 'policy_definitions': '2016-12-01'
- }),
- 'KeyVaultClient': '2016-10-01',
- 'azure.multiapi.storage': '2017-11-09',
- 'azure.multiapi.cosmosdb': '2017-04-17'
- },
- '2018-03-01-hybrid': {
- 'StorageManagementClient': '2016-01-01',
- 'NetworkManagementClient': '2017-10-01',
- 'ComputeManagementClient': SDKProfile('2017-03-30'),
- 'ManagementLinkClient': '2016-09-01',
- 'ManagementLockClient': '2016-09-01',
- 'PolicyClient': '2016-12-01',
- 'ResourceManagementClient': '2018-02-01',
- 'SubscriptionClient': '2016-06-01',
- 'DnsManagementClient': '2016-04-01',
- 'KeyVaultManagementClient': '2016-10-01',
- 'AuthorizationManagementClient': SDKProfile('2015-07-01', {
- 'classic_administrators': '2015-06-01'
- }),
- 'KeyVaultClient': '2016-10-01',
- 'azure.multiapi.storage': '2017-04-17',
- 'azure.multiapi.cosmosdb': '2017-04-17'
- },
- '2017-03-09-profile': {
- 'StorageManagementClient': '2016-01-01',
- 'NetworkManagementClient': '2015-06-15',
- 'ComputeManagementClient': SDKProfile('2016-03-30'),
- 'ManagementLinkClient': '2016-09-01',
- 'ManagementLockClient': '2015-01-01',
- 'PolicyClient': '2015-10-01-preview',
- 'ResourceManagementClient': '2016-02-01',
- 'SubscriptionClient': '2016-06-01',
- 'DnsManagementClient': '2016-04-01',
- 'KeyVaultManagementClient': '2016-10-01',
- 'AuthorizationManagementClient': SDKProfile('2015-07-01', {
- 'classic_administrators': '2015-06-01'
- }),
- 'KeyVaultClient': '2016-10-01',
- 'azure.multiapi.storage': '2015-04-05'
- }
-}
-
-AZURE_TAG_ARGS = dict(
- tags=dict(type='dict'),
- append_tags=dict(type='bool', default=True),
-)
-
-AZURE_COMMON_REQUIRED_IF = [
- ('log_mode', 'file', ['log_path'])
-]
-
-ANSIBLE_USER_AGENT = 'Ansible/{0}'.format(ANSIBLE_VERSION)
-CLOUDSHELL_USER_AGENT_KEY = 'AZURE_HTTP_USER_AGENT'
-VSCODEEXT_USER_AGENT_KEY = 'VSCODEEXT_USER_AGENT'
-
-CIDR_PATTERN = re.compile(r"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1"
- r"[0-9]{2}|2[0-4][0-9]|25[0-5])(/([0-9]|[1-2][0-9]|3[0-2]))")
-
-AZURE_SUCCESS_STATE = "Succeeded"
-AZURE_FAILED_STATE = "Failed"
-
-HAS_AZURE = True
-HAS_AZURE_EXC = None
-HAS_AZURE_CLI_CORE = True
-HAS_AZURE_CLI_CORE_EXC = None
-
-HAS_MSRESTAZURE = True
-HAS_MSRESTAZURE_EXC = None
-
-try:
- import importlib
-except ImportError:
- # This passes the sanity import test, but does not provide a user friendly error message.
- # Doing so would require catching Exception for all imports of Azure dependencies in modules and module_utils.
- importlib = None
-
-try:
- from packaging.version import Version
- HAS_PACKAGING_VERSION = True
- HAS_PACKAGING_VERSION_EXC = None
-except ImportError:
- Version = None
- HAS_PACKAGING_VERSION = False
- HAS_PACKAGING_VERSION_EXC = traceback.format_exc()
-
-# NB: packaging issue sometimes cause msrestazure not to be installed, check it separately
-try:
- from msrest.serialization import Serializer
-except ImportError:
- HAS_MSRESTAZURE_EXC = traceback.format_exc()
- HAS_MSRESTAZURE = False
-
-try:
- from enum import Enum
- from msrestazure.azure_active_directory import AADTokenCredentials
- from msrestazure.azure_exceptions import CloudError
- from msrestazure.azure_active_directory import MSIAuthentication
- from msrestazure.tools import parse_resource_id, resource_id, is_valid_resource_id
- from msrestazure import azure_cloud
- from azure.common.credentials import ServicePrincipalCredentials, UserPassCredentials
- from azure.mgmt.monitor.version import VERSION as monitor_client_version
- from azure.mgmt.network.version import VERSION as network_client_version
- from azure.mgmt.storage.version import VERSION as storage_client_version
- from azure.mgmt.compute.version import VERSION as compute_client_version
- from azure.mgmt.resource.version import VERSION as resource_client_version
- from azure.mgmt.dns.version import VERSION as dns_client_version
- from azure.mgmt.web.version import VERSION as web_client_version
- from azure.mgmt.network import NetworkManagementClient
- from azure.mgmt.resource.resources import ResourceManagementClient
- from azure.mgmt.resource.subscriptions import SubscriptionClient
- from azure.mgmt.storage import StorageManagementClient
- from azure.mgmt.compute import ComputeManagementClient
- from azure.mgmt.dns import DnsManagementClient
- from azure.mgmt.monitor import MonitorManagementClient
- from azure.mgmt.web import WebSiteManagementClient
- from azure.mgmt.containerservice import ContainerServiceClient
- from azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements
- from azure.mgmt.trafficmanager import TrafficManagerManagementClient
- from azure.storage.cloudstorageaccount import CloudStorageAccount
- from azure.storage.blob import PageBlobService, BlockBlobService
- from adal.authentication_context import AuthenticationContext
- from azure.mgmt.sql import SqlManagementClient
- from azure.mgmt.servicebus import ServiceBusManagementClient
- import azure.mgmt.servicebus.models as ServicebusModel
- from azure.mgmt.rdbms.postgresql import PostgreSQLManagementClient
- from azure.mgmt.rdbms.mysql import MySQLManagementClient
- from azure.mgmt.rdbms.mariadb import MariaDBManagementClient
- from azure.mgmt.containerregistry import ContainerRegistryManagementClient
- from azure.mgmt.containerinstance import ContainerInstanceManagementClient
- from azure.mgmt.loganalytics import LogAnalyticsManagementClient
- import azure.mgmt.loganalytics.models as LogAnalyticsModels
- from azure.mgmt.automation import AutomationClient
- import azure.mgmt.automation.models as AutomationModel
- from azure.mgmt.iothub import IotHubClient
- from azure.mgmt.iothub import models as IoTHubModels
- from msrest.service_client import ServiceClient
- from msrestazure import AzureConfiguration
- from msrest.authentication import Authentication
- from azure.mgmt.resource.locks import ManagementLockClient
-except ImportError as exc:
- Authentication = object
- HAS_AZURE_EXC = traceback.format_exc()
- HAS_AZURE = False
-
-from base64 import b64encode, b64decode
-from hashlib import sha256
-from hmac import HMAC
-from time import time
-
-try:
- from urllib import (urlencode, quote_plus)
-except ImportError:
- from urllib.parse import (urlencode, quote_plus)
-
-try:
- from azure.cli.core.util import CLIError
- from azure.common.credentials import get_azure_cli_credentials, get_cli_profile
- from azure.common.cloud import get_cli_active_cloud
-except ImportError:
- HAS_AZURE_CLI_CORE = False
- HAS_AZURE_CLI_CORE_EXC = None
- CLIError = Exception
-
-
-def azure_id_to_dict(id):
- pieces = re.sub(r'^\/', '', id).split('/')
- result = {}
- index = 0
- while index < len(pieces) - 1:
- result[pieces[index]] = pieces[index + 1]
- index += 1
- return result
-
-
-def format_resource_id(val, subscription_id, namespace, types, resource_group):
- return resource_id(name=val,
- resource_group=resource_group,
- namespace=namespace,
- type=types,
- subscription=subscription_id) if not is_valid_resource_id(val) else val
-
-
-def normalize_location_name(name):
- return name.replace(' ', '').lower()
-
-
-# FUTURE: either get this from the requirements file (if we can be sure it's always available at runtime)
-# or generate the requirements files from this so we only have one source of truth to maintain...
-AZURE_PKG_VERSIONS = {
- 'StorageManagementClient': {
- 'package_name': 'storage',
- 'expected_version': '3.1.0'
- },
- 'ComputeManagementClient': {
- 'package_name': 'compute',
- 'expected_version': '4.4.0'
- },
- 'ContainerInstanceManagementClient': {
- 'package_name': 'containerinstance',
- 'expected_version': '0.4.0'
- },
- 'NetworkManagementClient': {
- 'package_name': 'network',
- 'expected_version': '2.3.0'
- },
- 'ResourceManagementClient': {
- 'package_name': 'resource',
- 'expected_version': '2.1.0'
- },
- 'DnsManagementClient': {
- 'package_name': 'dns',
- 'expected_version': '2.1.0'
- },
- 'WebSiteManagementClient': {
- 'package_name': 'web',
- 'expected_version': '0.41.0'
- },
- 'TrafficManagerManagementClient': {
- 'package_name': 'trafficmanager',
- 'expected_version': '0.50.0'
- },
-} if HAS_AZURE else {}
-
-
-AZURE_MIN_RELEASE = '2.0.0'
-
-
-class AzureRMModuleBase(object):
- def __init__(self, derived_arg_spec, bypass_checks=False, no_log=False,
- mutually_exclusive=None, required_together=None,
- required_one_of=None, add_file_common_args=False, supports_check_mode=False,
- required_if=None, supports_tags=True, facts_module=False, skip_exec=False):
-
- merged_arg_spec = dict()
- merged_arg_spec.update(AZURE_COMMON_ARGS)
- if supports_tags:
- merged_arg_spec.update(AZURE_TAG_ARGS)
-
- if derived_arg_spec:
- merged_arg_spec.update(derived_arg_spec)
-
- merged_required_if = list(AZURE_COMMON_REQUIRED_IF)
- if required_if:
- merged_required_if += required_if
-
- self.module = AnsibleModule(argument_spec=merged_arg_spec,
- bypass_checks=bypass_checks,
- no_log=no_log,
- mutually_exclusive=mutually_exclusive,
- required_together=required_together,
- required_one_of=required_one_of,
- add_file_common_args=add_file_common_args,
- supports_check_mode=supports_check_mode,
- required_if=merged_required_if)
-
- if not HAS_PACKAGING_VERSION:
- self.fail(msg=missing_required_lib('packaging'),
- exception=HAS_PACKAGING_VERSION_EXC)
-
- if not HAS_MSRESTAZURE:
- self.fail(msg=missing_required_lib('msrestazure'),
- exception=HAS_MSRESTAZURE_EXC)
-
- if not HAS_AZURE:
- self.fail(msg=missing_required_lib('ansible[azure] (azure >= {0})'.format(AZURE_MIN_RELEASE)),
- exception=HAS_AZURE_EXC)
-
- self._network_client = None
- self._storage_client = None
- self._resource_client = None
- self._compute_client = None
- self._dns_client = None
- self._web_client = None
- self._marketplace_client = None
- self._sql_client = None
- self._mysql_client = None
- self._mariadb_client = None
- self._postgresql_client = None
- self._containerregistry_client = None
- self._containerinstance_client = None
- self._containerservice_client = None
- self._managedcluster_client = None
- self._traffic_manager_management_client = None
- self._monitor_client = None
- self._resource = None
- self._log_analytics_client = None
- self._servicebus_client = None
- self._automation_client = None
- self._IoThub_client = None
- self._lock_client = None
-
- self.check_mode = self.module.check_mode
- self.api_profile = self.module.params.get('api_profile')
- self.facts_module = facts_module
- # self.debug = self.module.params.get('debug')
-
- # delegate auth to AzureRMAuth class (shared with all plugin types)
- self.azure_auth = AzureRMAuth(fail_impl=self.fail, **self.module.params)
-
- # common parameter validation
- if self.module.params.get('tags'):
- self.validate_tags(self.module.params['tags'])
-
- if not skip_exec:
- res = self.exec_module(**self.module.params)
- self.module.exit_json(**res)
-
- def check_client_version(self, client_type):
- # Ensure Azure modules are at least 2.0.0rc5.
- package_version = AZURE_PKG_VERSIONS.get(client_type.__name__, None)
- if package_version is not None:
- client_name = package_version.get('package_name')
- try:
- client_module = importlib.import_module(client_type.__module__)
- client_version = client_module.VERSION
- except (RuntimeError, AttributeError):
- # can't get at the module version for some reason, just fail silently...
- return
- expected_version = package_version.get('expected_version')
- if Version(client_version) < Version(expected_version):
- self.fail("Installed azure-mgmt-{0} client version is {1}. The minimum supported version is {2}. Try "
- "`pip install ansible[azure]`".format(client_name, client_version, expected_version))
- if Version(client_version) != Version(expected_version):
- self.module.warn("Installed azure-mgmt-{0} client version is {1}. The expected version is {2}. Try "
- "`pip install ansible[azure]`".format(client_name, client_version, expected_version))
-
- def exec_module(self, **kwargs):
- self.fail("Error: {0} failed to implement exec_module method.".format(self.__class__.__name__))
-
- def fail(self, msg, **kwargs):
- '''
- Shortcut for calling module.fail()
-
- :param msg: Error message text.
- :param kwargs: Any key=value pairs
- :return: None
- '''
- self.module.fail_json(msg=msg, **kwargs)
-
- def deprecate(self, msg, version=None, collection_name=None):
- self.module.deprecate(msg, version, collection_name=collection_name)
-
- def log(self, msg, pretty_print=False):
- if pretty_print:
- self.module.debug(json.dumps(msg, indent=4, sort_keys=True))
- else:
- self.module.debug(msg)
-
- def validate_tags(self, tags):
- '''
- Check if tags dictionary contains string:string pairs.
-
- :param tags: dictionary of string:string pairs
- :return: None
- '''
- if not self.facts_module:
- if not isinstance(tags, dict):
- self.fail("Tags must be a dictionary of string:string values.")
- for key, value in tags.items():
- if not isinstance(value, str):
- self.fail("Tags values must be strings. Found {0}:{1}".format(str(key), str(value)))
-
- def update_tags(self, tags):
- '''
- Call from the module to update metadata tags. Returns tuple
- with bool indicating if there was a change and dict of new
- tags to assign to the object.
-
- :param tags: metadata tags from the object
- :return: bool, dict
- '''
- tags = tags or dict()
- new_tags = copy.copy(tags) if isinstance(tags, dict) else dict()
- param_tags = self.module.params.get('tags') if isinstance(self.module.params.get('tags'), dict) else dict()
- append_tags = self.module.params.get('append_tags') if self.module.params.get('append_tags') is not None else True
- changed = False
- # check add or update
- for key, value in param_tags.items():
- if not new_tags.get(key) or new_tags[key] != value:
- changed = True
- new_tags[key] = value
- # check remove
- if not append_tags:
- for key, value in tags.items():
- if not param_tags.get(key):
- new_tags.pop(key)
- changed = True
- return changed, new_tags
-
- def has_tags(self, obj_tags, tag_list):
- '''
- Used in fact modules to compare object tags to list of parameter tags. Return true if list of parameter tags
- exists in object tags.
-
- :param obj_tags: dictionary of tags from an Azure object.
- :param tag_list: list of tag keys or tag key:value pairs
- :return: bool
- '''
-
- if not obj_tags and tag_list:
- return False
-
- if not tag_list:
- return True
-
- matches = 0
- result = False
- for tag in tag_list:
- tag_key = tag
- tag_value = None
- if ':' in tag:
- tag_key, tag_value = tag.split(':')
- if tag_value and obj_tags.get(tag_key) == tag_value:
- matches += 1
- elif not tag_value and obj_tags.get(tag_key):
- matches += 1
- if matches == len(tag_list):
- result = True
- return result
-
- def get_resource_group(self, resource_group):
- '''
- Fetch a resource group.
-
- :param resource_group: name of a resource group
- :return: resource group object
- '''
- try:
- return self.rm_client.resource_groups.get(resource_group)
- except CloudError as cloud_error:
- self.fail("Error retrieving resource group {0} - {1}".format(resource_group, cloud_error.message))
- except Exception as exc:
- self.fail("Error retrieving resource group {0} - {1}".format(resource_group, str(exc)))
-
- def parse_resource_to_dict(self, resource):
- '''
- Return a dict of the give resource, which contains name and resource group.
-
- :param resource: It can be a resource name, id or a dict contains name and resource group.
- '''
- resource_dict = parse_resource_id(resource) if not isinstance(resource, dict) else resource
- resource_dict['resource_group'] = resource_dict.get('resource_group', self.resource_group)
- resource_dict['subscription_id'] = resource_dict.get('subscription_id', self.subscription_id)
- return resource_dict
-
- def serialize_obj(self, obj, class_name, enum_modules=None):
- '''
- Return a JSON representation of an Azure object.
-
- :param obj: Azure object
- :param class_name: Name of the object's class
- :param enum_modules: List of module names to build enum dependencies from.
- :return: serialized result
- '''
- enum_modules = [] if enum_modules is None else enum_modules
-
- dependencies = dict()
- if enum_modules:
- for module_name in enum_modules:
- mod = importlib.import_module(module_name)
- for mod_class_name, mod_class_obj in inspect.getmembers(mod, predicate=inspect.isclass):
- dependencies[mod_class_name] = mod_class_obj
- self.log("dependencies: ")
- self.log(str(dependencies))
- serializer = Serializer(classes=dependencies)
- return serializer.body(obj, class_name, keep_readonly=True)
-
- def get_poller_result(self, poller, wait=5):
- '''
- Consistent method of waiting on and retrieving results from Azure's long poller
-
- :param poller Azure poller object
- :return object resulting from the original request
- '''
- try:
- delay = wait
- while not poller.done():
- self.log("Waiting for {0} sec".format(delay))
- poller.wait(timeout=delay)
- return poller.result()
- except Exception as exc:
- self.log(str(exc))
- raise
-
- def check_provisioning_state(self, azure_object, requested_state='present'):
- '''
- Check an Azure object's provisioning state. If something did not complete the provisioning
- process, then we cannot operate on it.
-
- :param azure_object An object such as a subnet, storageaccount, etc. Must have provisioning_state
- and name attributes.
- :return None
- '''
-
- if hasattr(azure_object, 'properties') and hasattr(azure_object.properties, 'provisioning_state') and \
- hasattr(azure_object, 'name'):
- # resource group object fits this model
- if isinstance(azure_object.properties.provisioning_state, Enum):
- if azure_object.properties.provisioning_state.value != AZURE_SUCCESS_STATE and \
- requested_state != 'absent':
- self.fail("Error {0} has a provisioning state of {1}. Expecting state to be {2}.".format(
- azure_object.name, azure_object.properties.provisioning_state, AZURE_SUCCESS_STATE))
- return
- if azure_object.properties.provisioning_state != AZURE_SUCCESS_STATE and \
- requested_state != 'absent':
- self.fail("Error {0} has a provisioning state of {1}. Expecting state to be {2}.".format(
- azure_object.name, azure_object.properties.provisioning_state, AZURE_SUCCESS_STATE))
- return
-
- if hasattr(azure_object, 'provisioning_state') or not hasattr(azure_object, 'name'):
- if isinstance(azure_object.provisioning_state, Enum):
- if azure_object.provisioning_state.value != AZURE_SUCCESS_STATE and requested_state != 'absent':
- self.fail("Error {0} has a provisioning state of {1}. Expecting state to be {2}.".format(
- azure_object.name, azure_object.provisioning_state, AZURE_SUCCESS_STATE))
- return
- if azure_object.provisioning_state != AZURE_SUCCESS_STATE and requested_state != 'absent':
- self.fail("Error {0} has a provisioning state of {1}. Expecting state to be {2}.".format(
- azure_object.name, azure_object.provisioning_state, AZURE_SUCCESS_STATE))
-
- def get_blob_client(self, resource_group_name, storage_account_name, storage_blob_type='block'):
- keys = dict()
- try:
- # Get keys from the storage account
- self.log('Getting keys')
- account_keys = self.storage_client.storage_accounts.list_keys(resource_group_name, storage_account_name)
- except Exception as exc:
- self.fail("Error getting keys for account {0} - {1}".format(storage_account_name, str(exc)))
-
- try:
- self.log('Create blob service')
- if storage_blob_type == 'page':
- return PageBlobService(endpoint_suffix=self._cloud_environment.suffixes.storage_endpoint,
- account_name=storage_account_name,
- account_key=account_keys.keys[0].value)
- elif storage_blob_type == 'block':
- return BlockBlobService(endpoint_suffix=self._cloud_environment.suffixes.storage_endpoint,
- account_name=storage_account_name,
- account_key=account_keys.keys[0].value)
- else:
- raise Exception("Invalid storage blob type defined.")
- except Exception as exc:
- self.fail("Error creating blob service client for storage account {0} - {1}".format(storage_account_name,
- str(exc)))
-
- def create_default_pip(self, resource_group, location, public_ip_name, allocation_method='Dynamic', sku=None):
- '''
- Create a default public IP address <public_ip_name> to associate with a network interface.
- If a PIP address matching <public_ip_name> exists, return it. Otherwise, create one.
-
- :param resource_group: name of an existing resource group
- :param location: a valid azure location
- :param public_ip_name: base name to assign the public IP address
- :param allocation_method: one of 'Static' or 'Dynamic'
- :param sku: sku
- :return: PIP object
- '''
- pip = None
-
- self.log("Starting create_default_pip {0}".format(public_ip_name))
- self.log("Check to see if public IP {0} exists".format(public_ip_name))
- try:
- pip = self.network_client.public_ip_addresses.get(resource_group, public_ip_name)
- except CloudError:
- pass
-
- if pip:
- self.log("Public ip {0} found.".format(public_ip_name))
- self.check_provisioning_state(pip)
- return pip
-
- params = self.network_models.PublicIPAddress(
- location=location,
- public_ip_allocation_method=allocation_method,
- sku=sku
- )
- self.log('Creating default public IP {0}'.format(public_ip_name))
- try:
- poller = self.network_client.public_ip_addresses.create_or_update(resource_group, public_ip_name, params)
- except Exception as exc:
- self.fail("Error creating {0} - {1}".format(public_ip_name, str(exc)))
-
- return self.get_poller_result(poller)
-
- def create_default_securitygroup(self, resource_group, location, security_group_name, os_type, open_ports):
- '''
- Create a default security group <security_group_name> to associate with a network interface. If a security group matching
- <security_group_name> exists, return it. Otherwise, create one.
-
- :param resource_group: Resource group name
- :param location: azure location name
- :param security_group_name: base name to use for the security group
- :param os_type: one of 'Windows' or 'Linux'. Determins any default rules added to the security group.
- :param ssh_port: for os_type 'Linux' port used in rule allowing SSH access.
- :param rdp_port: for os_type 'Windows' port used in rule allowing RDP access.
- :return: security_group object
- '''
- group = None
-
- self.log("Create security group {0}".format(security_group_name))
- self.log("Check to see if security group {0} exists".format(security_group_name))
- try:
- group = self.network_client.network_security_groups.get(resource_group, security_group_name)
- except CloudError:
- pass
-
- if group:
- self.log("Security group {0} found.".format(security_group_name))
- self.check_provisioning_state(group)
- return group
-
- parameters = self.network_models.NetworkSecurityGroup()
- parameters.location = location
-
- if not open_ports:
- # Open default ports based on OS type
- if os_type == 'Linux':
- # add an inbound SSH rule
- parameters.security_rules = [
- self.network_models.SecurityRule(protocol='Tcp',
- source_address_prefix='*',
- destination_address_prefix='*',
- access='Allow',
- direction='Inbound',
- description='Allow SSH Access',
- source_port_range='*',
- destination_port_range='22',
- priority=100,
- name='SSH')
- ]
- parameters.location = location
- else:
- # for windows add inbound RDP and WinRM rules
- parameters.security_rules = [
- self.network_models.SecurityRule(protocol='Tcp',
- source_address_prefix='*',
- destination_address_prefix='*',
- access='Allow',
- direction='Inbound',
- description='Allow RDP port 3389',
- source_port_range='*',
- destination_port_range='3389',
- priority=100,
- name='RDP01'),
- self.network_models.SecurityRule(protocol='Tcp',
- source_address_prefix='*',
- destination_address_prefix='*',
- access='Allow',
- direction='Inbound',
- description='Allow WinRM HTTPS port 5986',
- source_port_range='*',
- destination_port_range='5986',
- priority=101,
- name='WinRM01'),
- ]
- else:
- # Open custom ports
- parameters.security_rules = []
- priority = 100
- for port in open_ports:
- priority += 1
- rule_name = "Rule_{0}".format(priority)
- parameters.security_rules.append(
- self.network_models.SecurityRule(protocol='Tcp',
- source_address_prefix='*',
- destination_address_prefix='*',
- access='Allow',
- direction='Inbound',
- source_port_range='*',
- destination_port_range=str(port),
- priority=priority,
- name=rule_name)
- )
-
- self.log('Creating default security group {0}'.format(security_group_name))
- try:
- poller = self.network_client.network_security_groups.create_or_update(resource_group,
- security_group_name,
- parameters)
- except Exception as exc:
- self.fail("Error creating default security rule {0} - {1}".format(security_group_name, str(exc)))
-
- return self.get_poller_result(poller)
-
- @staticmethod
- def _validation_ignore_callback(session, global_config, local_config, **kwargs):
- session.verify = False
-
- def get_api_profile(self, client_type_name, api_profile_name):
- profile_all_clients = AZURE_API_PROFILES.get(api_profile_name)
-
- if not profile_all_clients:
- raise KeyError("unknown Azure API profile: {0}".format(api_profile_name))
-
- profile_raw = profile_all_clients.get(client_type_name, None)
-
- if not profile_raw:
- self.module.warn("Azure API profile {0} does not define an entry for {1}".format(api_profile_name, client_type_name))
-
- if isinstance(profile_raw, dict):
- if not profile_raw.get('default_api_version'):
- raise KeyError("Azure API profile {0} does not define 'default_api_version'".format(api_profile_name))
- return profile_raw
-
- # wrap basic strings in a dict that just defines the default
- return dict(default_api_version=profile_raw)
-
- def get_mgmt_svc_client(self, client_type, base_url=None, api_version=None):
- self.log('Getting management service client {0}'.format(client_type.__name__))
- self.check_client_version(client_type)
-
- client_argspec = inspect.getargspec(client_type.__init__)
-
- if not base_url:
- # most things are resource_manager, don't make everyone specify
- base_url = self.azure_auth._cloud_environment.endpoints.resource_manager
-
- client_kwargs = dict(credentials=self.azure_auth.azure_credentials, subscription_id=self.azure_auth.subscription_id, base_url=base_url)
-
- api_profile_dict = {}
-
- if self.api_profile:
- api_profile_dict = self.get_api_profile(client_type.__name__, self.api_profile)
-
- # unversioned clients won't accept profile; only send it if necessary
- # clients without a version specified in the profile will use the default
- if api_profile_dict and 'profile' in client_argspec.args:
- client_kwargs['profile'] = api_profile_dict
-
- # If the client doesn't accept api_version, it's unversioned.
- # If it does, favor explicitly-specified api_version, fall back to api_profile
- if 'api_version' in client_argspec.args:
- profile_default_version = api_profile_dict.get('default_api_version', None)
- if api_version or profile_default_version:
- client_kwargs['api_version'] = api_version or profile_default_version
- if 'profile' in client_kwargs:
- # remove profile; only pass API version if specified
- client_kwargs.pop('profile')
-
- client = client_type(**client_kwargs)
-
- # FUTURE: remove this once everything exposes models directly (eg, containerinstance)
- try:
- getattr(client, "models")
- except AttributeError:
- def _ansible_get_models(self, *arg, **kwarg):
- return self._ansible_models
-
- setattr(client, '_ansible_models', importlib.import_module(client_type.__module__).models)
- client.models = types.MethodType(_ansible_get_models, client)
-
- client.config = self.add_user_agent(client.config)
-
- if self.azure_auth._cert_validation_mode == 'ignore':
- client.config.session_configuration_callback = self._validation_ignore_callback
-
- return client
-
- def add_user_agent(self, config):
- # Add user agent for Ansible
- config.add_user_agent(ANSIBLE_USER_AGENT)
- # Add user agent when running from Cloud Shell
- if CLOUDSHELL_USER_AGENT_KEY in os.environ:
- config.add_user_agent(os.environ[CLOUDSHELL_USER_AGENT_KEY])
- # Add user agent when running from VSCode extension
- if VSCODEEXT_USER_AGENT_KEY in os.environ:
- config.add_user_agent(os.environ[VSCODEEXT_USER_AGENT_KEY])
- return config
-
- def generate_sas_token(self, **kwags):
- base_url = kwags.get('base_url', None)
- expiry = kwags.get('expiry', time() + 3600)
- key = kwags.get('key', None)
- policy = kwags.get('policy', None)
- url = quote_plus(base_url)
- ttl = int(expiry)
- sign_key = '{0}\n{1}'.format(url, ttl)
- signature = b64encode(HMAC(b64decode(key), sign_key.encode('utf-8'), sha256).digest())
- result = {
- 'sr': url,
- 'sig': signature,
- 'se': str(ttl),
- }
- if policy:
- result['skn'] = policy
- return 'SharedAccessSignature ' + urlencode(result)
-
- def get_data_svc_client(self, **kwags):
- url = kwags.get('base_url', None)
- config = AzureConfiguration(base_url='https://{0}'.format(url))
- config.credentials = AzureSASAuthentication(token=self.generate_sas_token(**kwags))
- config = self.add_user_agent(config)
- return ServiceClient(creds=config.credentials, config=config)
-
- # passthru methods to AzureAuth instance for backcompat
- @property
- def credentials(self):
- return self.azure_auth.credentials
-
- @property
- def _cloud_environment(self):
- return self.azure_auth._cloud_environment
-
- @property
- def subscription_id(self):
- return self.azure_auth.subscription_id
-
- @property
- def storage_client(self):
- self.log('Getting storage client...')
- if not self._storage_client:
- self._storage_client = self.get_mgmt_svc_client(StorageManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2018-07-01')
- return self._storage_client
-
- @property
- def storage_models(self):
- return StorageManagementClient.models("2018-07-01")
-
- @property
- def network_client(self):
- self.log('Getting network client')
- if not self._network_client:
- self._network_client = self.get_mgmt_svc_client(NetworkManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2019-06-01')
- return self._network_client
-
- @property
- def network_models(self):
- self.log("Getting network models...")
- return NetworkManagementClient.models("2018-08-01")
-
- @property
- def rm_client(self):
- self.log('Getting resource manager client')
- if not self._resource_client:
- self._resource_client = self.get_mgmt_svc_client(ResourceManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2017-05-10')
- return self._resource_client
-
- @property
- def rm_models(self):
- self.log("Getting resource manager models")
- return ResourceManagementClient.models("2017-05-10")
-
- @property
- def compute_client(self):
- self.log('Getting compute client')
- if not self._compute_client:
- self._compute_client = self.get_mgmt_svc_client(ComputeManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2019-07-01')
- return self._compute_client
-
- @property
- def compute_models(self):
- self.log("Getting compute models")
- return ComputeManagementClient.models("2019-07-01")
-
- @property
- def dns_client(self):
- self.log('Getting dns client')
- if not self._dns_client:
- self._dns_client = self.get_mgmt_svc_client(DnsManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2018-05-01')
- return self._dns_client
-
- @property
- def dns_models(self):
- self.log("Getting dns models...")
- return DnsManagementClient.models('2018-05-01')
-
- @property
- def web_client(self):
- self.log('Getting web client')
- if not self._web_client:
- self._web_client = self.get_mgmt_svc_client(WebSiteManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2018-02-01')
- return self._web_client
-
- @property
- def containerservice_client(self):
- self.log('Getting container service client')
- if not self._containerservice_client:
- self._containerservice_client = self.get_mgmt_svc_client(ContainerServiceClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2017-07-01')
- return self._containerservice_client
-
- @property
- def managedcluster_models(self):
- self.log("Getting container service models")
- return ContainerServiceClient.models('2018-03-31')
-
- @property
- def managedcluster_client(self):
- self.log('Getting container service client')
- if not self._managedcluster_client:
- self._managedcluster_client = self.get_mgmt_svc_client(ContainerServiceClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2018-03-31')
- return self._managedcluster_client
-
- @property
- def sql_client(self):
- self.log('Getting SQL client')
- if not self._sql_client:
- self._sql_client = self.get_mgmt_svc_client(SqlManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._sql_client
-
- @property
- def postgresql_client(self):
- self.log('Getting PostgreSQL client')
- if not self._postgresql_client:
- self._postgresql_client = self.get_mgmt_svc_client(PostgreSQLManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._postgresql_client
-
- @property
- def mysql_client(self):
- self.log('Getting MySQL client')
- if not self._mysql_client:
- self._mysql_client = self.get_mgmt_svc_client(MySQLManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._mysql_client
-
- @property
- def mariadb_client(self):
- self.log('Getting MariaDB client')
- if not self._mariadb_client:
- self._mariadb_client = self.get_mgmt_svc_client(MariaDBManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._mariadb_client
-
- @property
- def sql_client(self):
- self.log('Getting SQL client')
- if not self._sql_client:
- self._sql_client = self.get_mgmt_svc_client(SqlManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._sql_client
-
- @property
- def containerregistry_client(self):
- self.log('Getting container registry mgmt client')
- if not self._containerregistry_client:
- self._containerregistry_client = self.get_mgmt_svc_client(ContainerRegistryManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2017-10-01')
-
- return self._containerregistry_client
-
- @property
- def containerinstance_client(self):
- self.log('Getting container instance mgmt client')
- if not self._containerinstance_client:
- self._containerinstance_client = self.get_mgmt_svc_client(ContainerInstanceManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2018-06-01')
-
- return self._containerinstance_client
-
- @property
- def marketplace_client(self):
- self.log('Getting marketplace agreement client')
- if not self._marketplace_client:
- self._marketplace_client = self.get_mgmt_svc_client(MarketplaceOrderingAgreements,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._marketplace_client
-
- @property
- def traffic_manager_management_client(self):
- self.log('Getting traffic manager client')
- if not self._traffic_manager_management_client:
- self._traffic_manager_management_client = self.get_mgmt_svc_client(TrafficManagerManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._traffic_manager_management_client
-
- @property
- def monitor_client(self):
- self.log('Getting monitor client')
- if not self._monitor_client:
- self._monitor_client = self.get_mgmt_svc_client(MonitorManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._monitor_client
-
- @property
- def log_analytics_client(self):
- self.log('Getting log analytics client')
- if not self._log_analytics_client:
- self._log_analytics_client = self.get_mgmt_svc_client(LogAnalyticsManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._log_analytics_client
-
- @property
- def log_analytics_models(self):
- self.log('Getting log analytics models')
- return LogAnalyticsModels
-
- @property
- def servicebus_client(self):
- self.log('Getting servicebus client')
- if not self._servicebus_client:
- self._servicebus_client = self.get_mgmt_svc_client(ServiceBusManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._servicebus_client
-
- @property
- def servicebus_models(self):
- return ServicebusModel
-
- @property
- def automation_client(self):
- self.log('Getting automation client')
- if not self._automation_client:
- self._automation_client = self.get_mgmt_svc_client(AutomationClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._automation_client
-
- @property
- def automation_models(self):
- return AutomationModel
-
- @property
- def IoThub_client(self):
- self.log('Getting iothub client')
- if not self._IoThub_client:
- self._IoThub_client = self.get_mgmt_svc_client(IotHubClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._IoThub_client
-
- @property
- def IoThub_models(self):
- return IoTHubModels
-
- @property
- def automation_client(self):
- self.log('Getting automation client')
- if not self._automation_client:
- self._automation_client = self.get_mgmt_svc_client(AutomationClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
- return self._automation_client
-
- @property
- def automation_models(self):
- return AutomationModel
-
- @property
- def lock_client(self):
- self.log('Getting lock client')
- if not self._lock_client:
- self._lock_client = self.get_mgmt_svc_client(ManagementLockClient,
- base_url=self._cloud_environment.endpoints.resource_manager,
- api_version='2016-09-01')
- return self._lock_client
-
- @property
- def lock_models(self):
- self.log("Getting lock models")
- return ManagementLockClient.models('2016-09-01')
-
-
-class AzureSASAuthentication(Authentication):
- """Simple SAS Authentication.
- An implementation of Authentication in
- https://github.com/Azure/msrest-for-python/blob/0732bc90bdb290e5f58c675ffdd7dbfa9acefc93/msrest/authentication.py
-
- :param str token: SAS token
- """
- def __init__(self, token):
- self.token = token
-
- def signed_session(self):
- session = super(AzureSASAuthentication, self).signed_session()
- session.headers['Authorization'] = self.token
- return session
-
-
-class AzureRMAuthException(Exception):
- pass
-
-
-class AzureRMAuth(object):
- def __init__(self, auth_source='auto', profile=None, subscription_id=None, client_id=None, secret=None,
- tenant=None, ad_user=None, password=None, cloud_environment='AzureCloud', cert_validation_mode='validate',
- api_profile='latest', adfs_authority_url=None, fail_impl=None, **kwargs):
-
- if fail_impl:
- self._fail_impl = fail_impl
- else:
- self._fail_impl = self._default_fail_impl
-
- self._cloud_environment = None
- self._adfs_authority_url = None
-
- # authenticate
- self.credentials = self._get_credentials(
- dict(auth_source=auth_source, profile=profile, subscription_id=subscription_id, client_id=client_id, secret=secret,
- tenant=tenant, ad_user=ad_user, password=password, cloud_environment=cloud_environment,
- cert_validation_mode=cert_validation_mode, api_profile=api_profile, adfs_authority_url=adfs_authority_url))
-
- if not self.credentials:
- if HAS_AZURE_CLI_CORE:
- self.fail("Failed to get credentials. Either pass as parameters, set environment variables, "
- "define a profile in ~/.azure/credentials, or log in with Azure CLI (`az login`).")
- else:
- self.fail("Failed to get credentials. Either pass as parameters, set environment variables, "
- "define a profile in ~/.azure/credentials, or install Azure CLI and log in (`az login`).")
-
- # cert validation mode precedence: module-arg, credential profile, env, "validate"
- self._cert_validation_mode = cert_validation_mode or self.credentials.get('cert_validation_mode') or \
- os.environ.get('AZURE_CERT_VALIDATION_MODE') or 'validate'
-
- if self._cert_validation_mode not in ['validate', 'ignore']:
- self.fail('invalid cert_validation_mode: {0}'.format(self._cert_validation_mode))
-
- # if cloud_environment specified, look up/build Cloud object
- raw_cloud_env = self.credentials.get('cloud_environment')
- if self.credentials.get('credentials') is not None and raw_cloud_env is not None:
- self._cloud_environment = raw_cloud_env
- elif not raw_cloud_env:
- self._cloud_environment = azure_cloud.AZURE_PUBLIC_CLOUD # SDK default
- else:
- # try to look up "well-known" values via the name attribute on azure_cloud members
- all_clouds = [x[1] for x in inspect.getmembers(azure_cloud) if isinstance(x[1], azure_cloud.Cloud)]
- matched_clouds = [x for x in all_clouds if x.name == raw_cloud_env]
- if len(matched_clouds) == 1:
- self._cloud_environment = matched_clouds[0]
- elif len(matched_clouds) > 1:
- self.fail("Azure SDK failure: more than one cloud matched for cloud_environment name '{0}'".format(raw_cloud_env))
- else:
- if not urlparse.urlparse(raw_cloud_env).scheme:
- self.fail("cloud_environment must be an endpoint discovery URL or one of {0}".format([x.name for x in all_clouds]))
- try:
- self._cloud_environment = azure_cloud.get_cloud_from_metadata_endpoint(raw_cloud_env)
- except Exception as e:
- self.fail("cloud_environment {0} could not be resolved: {1}".format(raw_cloud_env, e.message), exception=traceback.format_exc())
-
- if self.credentials.get('subscription_id', None) is None and self.credentials.get('credentials') is None:
- self.fail("Credentials did not include a subscription_id value.")
- self.log("setting subscription_id")
- self.subscription_id = self.credentials['subscription_id']
-
- # get authentication authority
- # for adfs, user could pass in authority or not.
- # for others, use default authority from cloud environment
- if self.credentials.get('adfs_authority_url') is None:
- self._adfs_authority_url = self._cloud_environment.endpoints.active_directory
- else:
- self._adfs_authority_url = self.credentials.get('adfs_authority_url')
-
- # get resource from cloud environment
- self._resource = self._cloud_environment.endpoints.active_directory_resource_id
-
- if self.credentials.get('credentials') is not None:
- # AzureCLI credentials
- self.azure_credentials = self.credentials['credentials']
- elif self.credentials.get('client_id') is not None and \
- self.credentials.get('secret') is not None and \
- self.credentials.get('tenant') is not None:
- self.azure_credentials = ServicePrincipalCredentials(client_id=self.credentials['client_id'],
- secret=self.credentials['secret'],
- tenant=self.credentials['tenant'],
- cloud_environment=self._cloud_environment,
- verify=self._cert_validation_mode == 'validate')
-
- elif self.credentials.get('ad_user') is not None and \
- self.credentials.get('password') is not None and \
- self.credentials.get('client_id') is not None and \
- self.credentials.get('tenant') is not None:
-
- self.azure_credentials = self.acquire_token_with_username_password(
- self._adfs_authority_url,
- self._resource,
- self.credentials['ad_user'],
- self.credentials['password'],
- self.credentials['client_id'],
- self.credentials['tenant'])
-
- elif self.credentials.get('ad_user') is not None and self.credentials.get('password') is not None:
- tenant = self.credentials.get('tenant')
- if not tenant:
- tenant = 'common' # SDK default
-
- self.azure_credentials = UserPassCredentials(self.credentials['ad_user'],
- self.credentials['password'],
- tenant=tenant,
- cloud_environment=self._cloud_environment,
- verify=self._cert_validation_mode == 'validate')
- else:
- self.fail("Failed to authenticate with provided credentials. Some attributes were missing. "
- "Credentials must include client_id, secret and tenant or ad_user and password, or "
- "ad_user, password, client_id, tenant and adfs_authority_url(optional) for ADFS authentication, or "
- "be logged in using AzureCLI.")
-
- def fail(self, msg, exception=None, **kwargs):
- self._fail_impl(msg)
-
- def _default_fail_impl(self, msg, exception=None, **kwargs):
- raise AzureRMAuthException(msg)
-
- def _get_profile(self, profile="default"):
- path = expanduser("~/.azure/credentials")
- try:
- config = configparser.ConfigParser()
- config.read(path)
- except Exception as exc:
- self.fail("Failed to access {0}. Check that the file exists and you have read "
- "access. {1}".format(path, str(exc)))
- credentials = dict()
- for key in AZURE_CREDENTIAL_ENV_MAPPING:
- try:
- credentials[key] = config.get(profile, key, raw=True)
- except Exception:
- pass
-
- if credentials.get('subscription_id'):
- return credentials
-
- return None
-
- def _get_msi_credentials(self, subscription_id_param=None, **kwargs):
- client_id = kwargs.get('client_id', None)
- credentials = MSIAuthentication(client_id=client_id)
- subscription_id = subscription_id_param or os.environ.get(AZURE_CREDENTIAL_ENV_MAPPING['subscription_id'], None)
- if not subscription_id:
- try:
- # use the first subscription of the MSI
- subscription_client = SubscriptionClient(credentials)
- subscription = next(subscription_client.subscriptions.list())
- subscription_id = str(subscription.subscription_id)
- except Exception as exc:
- self.fail("Failed to get MSI token: {0}. "
- "Please check whether your machine enabled MSI or grant access to any subscription.".format(str(exc)))
- return {
- 'credentials': credentials,
- 'subscription_id': subscription_id
- }
-
- def _get_azure_cli_credentials(self):
- credentials, subscription_id = get_azure_cli_credentials()
- cloud_environment = get_cli_active_cloud()
-
- cli_credentials = {
- 'credentials': credentials,
- 'subscription_id': subscription_id,
- 'cloud_environment': cloud_environment
- }
- return cli_credentials
-
- def _get_env_credentials(self):
- env_credentials = dict()
- for attribute, env_variable in AZURE_CREDENTIAL_ENV_MAPPING.items():
- env_credentials[attribute] = os.environ.get(env_variable, None)
-
- if env_credentials['profile']:
- credentials = self._get_profile(env_credentials['profile'])
- return credentials
-
- if env_credentials.get('subscription_id') is not None:
- return env_credentials
-
- return None
-
- # TODO: use explicit kwargs instead of intermediate dict
- def _get_credentials(self, params):
- # Get authentication credentials.
- self.log('Getting credentials')
-
- arg_credentials = dict()
- for attribute, env_variable in AZURE_CREDENTIAL_ENV_MAPPING.items():
- arg_credentials[attribute] = params.get(attribute, None)
-
- auth_source = params.get('auth_source', None)
- if not auth_source:
- auth_source = os.environ.get('ANSIBLE_AZURE_AUTH_SOURCE', 'auto')
-
- if auth_source == 'msi':
- self.log('Retrieving credenitals from MSI')
- return self._get_msi_credentials(arg_credentials['subscription_id'], client_id=params.get('client_id', None))
-
- if auth_source == 'cli':
- if not HAS_AZURE_CLI_CORE:
- self.fail(msg=missing_required_lib('azure-cli', reason='for `cli` auth_source'),
- exception=HAS_AZURE_CLI_CORE_EXC)
- try:
- self.log('Retrieving credentials from Azure CLI profile')
- cli_credentials = self._get_azure_cli_credentials()
- return cli_credentials
- except CLIError as err:
- self.fail("Azure CLI profile cannot be loaded - {0}".format(err))
-
- if auth_source == 'env':
- self.log('Retrieving credentials from environment')
- env_credentials = self._get_env_credentials()
- return env_credentials
-
- if auth_source == 'credential_file':
- self.log("Retrieving credentials from credential file")
- profile = params.get('profile') or 'default'
- default_credentials = self._get_profile(profile)
- return default_credentials
-
- # auto, precedence: module parameters -> environment variables -> default profile in ~/.azure/credentials
- # try module params
- if arg_credentials['profile'] is not None:
- self.log('Retrieving credentials with profile parameter.')
- credentials = self._get_profile(arg_credentials['profile'])
- return credentials
-
- if arg_credentials['subscription_id']:
- self.log('Received credentials from parameters.')
- return arg_credentials
-
- # try environment
- env_credentials = self._get_env_credentials()
- if env_credentials:
- self.log('Received credentials from env.')
- return env_credentials
-
- # try default profile from ~./azure/credentials
- default_credentials = self._get_profile()
- if default_credentials:
- self.log('Retrieved default profile credentials from ~/.azure/credentials.')
- return default_credentials
-
- try:
- if HAS_AZURE_CLI_CORE:
- self.log('Retrieving credentials from AzureCLI profile')
- cli_credentials = self._get_azure_cli_credentials()
- return cli_credentials
- except CLIError as ce:
- self.log('Error getting AzureCLI profile credentials - {0}'.format(ce))
-
- return None
-
- def acquire_token_with_username_password(self, authority, resource, username, password, client_id, tenant):
- authority_uri = authority
-
- if tenant is not None:
- authority_uri = authority + '/' + tenant
-
- context = AuthenticationContext(authority_uri)
- token_response = context.acquire_token_with_username_password(resource, username, password, client_id)
-
- return AADTokenCredentials(token_response)
-
- def log(self, msg, pretty_print=False):
- pass
- # Use only during module development
- # if self.debug:
- # log_file = open('azure_rm.log', 'a')
- # if pretty_print:
- # log_file.write(json.dumps(msg, indent=4, sort_keys=True))
- # else:
- # log_file.write(msg + u'\n')
diff --git a/test/support/integration/plugins/module_utils/azure_rm_common_rest.py b/test/support/integration/plugins/module_utils/azure_rm_common_rest.py
deleted file mode 100644
index 4fd7eaa3b4..0000000000
--- a/test/support/integration/plugins/module_utils/azure_rm_common_rest.py
+++ /dev/null
@@ -1,97 +0,0 @@
-# Copyright (c) 2018 Zim Kalinowski, <zikalino@microsoft.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from ansible.module_utils.ansible_release import __version__ as ANSIBLE_VERSION
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrestazure.azure_configuration import AzureConfiguration
- from msrest.service_client import ServiceClient
- from msrest.pipeline import ClientRawResponse
- from msrest.polling import LROPoller
- from msrestazure.polling.arm_polling import ARMPolling
- import uuid
- import json
-except ImportError:
- # This is handled in azure_rm_common
- AzureConfiguration = object
-
-ANSIBLE_USER_AGENT = 'Ansible/{0}'.format(ANSIBLE_VERSION)
-
-
-class GenericRestClientConfiguration(AzureConfiguration):
-
- def __init__(self, credentials, subscription_id, base_url=None):
-
- if credentials is None:
- raise ValueError("Parameter 'credentials' must not be None.")
- if subscription_id is None:
- raise ValueError("Parameter 'subscription_id' must not be None.")
- if not base_url:
- base_url = 'https://management.azure.com'
-
- super(GenericRestClientConfiguration, self).__init__(base_url)
-
- self.add_user_agent(ANSIBLE_USER_AGENT)
-
- self.credentials = credentials
- self.subscription_id = subscription_id
-
-
-class GenericRestClient(object):
-
- def __init__(self, credentials, subscription_id, base_url=None):
- self.config = GenericRestClientConfiguration(credentials, subscription_id, base_url)
- self._client = ServiceClient(self.config.credentials, self.config)
- self.models = None
-
- def query(self, url, method, query_parameters, header_parameters, body, expected_status_codes, polling_timeout, polling_interval):
- # Construct and send request
- operation_config = {}
-
- request = None
-
- if header_parameters is None:
- header_parameters = {}
-
- header_parameters['x-ms-client-request-id'] = str(uuid.uuid1())
-
- if method == 'GET':
- request = self._client.get(url, query_parameters)
- elif method == 'PUT':
- request = self._client.put(url, query_parameters)
- elif method == 'POST':
- request = self._client.post(url, query_parameters)
- elif method == 'HEAD':
- request = self._client.head(url, query_parameters)
- elif method == 'PATCH':
- request = self._client.patch(url, query_parameters)
- elif method == 'DELETE':
- request = self._client.delete(url, query_parameters)
- elif method == 'MERGE':
- request = self._client.merge(url, query_parameters)
-
- response = self._client.send(request, header_parameters, body, **operation_config)
-
- if response.status_code not in expected_status_codes:
- exp = CloudError(response)
- exp.request_id = response.headers.get('x-ms-request-id')
- raise exp
- elif response.status_code == 202 and polling_timeout > 0:
- def get_long_running_output(response):
- return response
- poller = LROPoller(self._client,
- ClientRawResponse(None, response),
- get_long_running_output,
- ARMPolling(polling_interval, **operation_config))
- response = self.get_poller_result(poller, polling_timeout)
-
- return response
-
- def get_poller_result(self, poller, timeout):
- try:
- poller.wait(timeout=timeout)
- return poller.result()
- except Exception as exc:
- raise
diff --git a/test/support/integration/plugins/modules/_azure_rm_mariadbconfiguration_facts.py b/test/support/integration/plugins/modules/_azure_rm_mariadbconfiguration_facts.py
deleted file mode 120000
index f9993bfba7..0000000000
--- a/test/support/integration/plugins/modules/_azure_rm_mariadbconfiguration_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-azure_rm_mariadbconfiguration_info.py \ No newline at end of file
diff --git a/test/support/integration/plugins/modules/_azure_rm_mariadbdatabase_facts.py b/test/support/integration/plugins/modules/_azure_rm_mariadbdatabase_facts.py
deleted file mode 120000
index b8293e64df..0000000000
--- a/test/support/integration/plugins/modules/_azure_rm_mariadbdatabase_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-azure_rm_mariadbdatabase_info.py \ No newline at end of file
diff --git a/test/support/integration/plugins/modules/_azure_rm_mariadbfirewallrule_facts.py b/test/support/integration/plugins/modules/_azure_rm_mariadbfirewallrule_facts.py
deleted file mode 120000
index 4311a0c1cc..0000000000
--- a/test/support/integration/plugins/modules/_azure_rm_mariadbfirewallrule_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-azure_rm_mariadbfirewallrule_info.py \ No newline at end of file
diff --git a/test/support/integration/plugins/modules/_azure_rm_mariadbserver_facts.py b/test/support/integration/plugins/modules/_azure_rm_mariadbserver_facts.py
deleted file mode 120000
index 5f76e0e932..0000000000
--- a/test/support/integration/plugins/modules/_azure_rm_mariadbserver_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-azure_rm_mariadbserver_info.py \ No newline at end of file
diff --git a/test/support/integration/plugins/modules/_azure_rm_resource_facts.py b/test/support/integration/plugins/modules/_azure_rm_resource_facts.py
deleted file mode 120000
index 710fda1074..0000000000
--- a/test/support/integration/plugins/modules/_azure_rm_resource_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-azure_rm_resource_info.py \ No newline at end of file
diff --git a/test/support/integration/plugins/modules/_azure_rm_webapp_facts.py b/test/support/integration/plugins/modules/_azure_rm_webapp_facts.py
deleted file mode 120000
index ead87c850b..0000000000
--- a/test/support/integration/plugins/modules/_azure_rm_webapp_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-azure_rm_webapp_info.py \ No newline at end of file
diff --git a/test/support/integration/plugins/modules/azure_rm_appserviceplan.py b/test/support/integration/plugins/modules/azure_rm_appserviceplan.py
deleted file mode 100644
index ee871c352b..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_appserviceplan.py
+++ /dev/null
@@ -1,379 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018 Yunge Zhu, <yungez@microsoft.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_appserviceplan
-version_added: "2.7"
-short_description: Manage App Service Plan
-description:
- - Create, update and delete instance of App Service Plan.
-
-options:
- resource_group:
- description:
- - Name of the resource group to which the resource belongs.
- required: True
-
- name:
- description:
- - Unique name of the app service plan to create or update.
- required: True
-
- location:
- description:
- - Resource location. If not set, location from the resource group will be used as default.
-
- sku:
- description:
- - The pricing tiers, e.g., C(F1), C(D1), C(B1), C(B2), C(B3), C(S1), C(P1), C(P1V2) etc.
- - Please see U(https://azure.microsoft.com/en-us/pricing/details/app-service/plans/) for more detail.
- - For Linux app service plan, please see U(https://azure.microsoft.com/en-us/pricing/details/app-service/linux/) for more detail.
- is_linux:
- description:
- - Describe whether to host webapp on Linux worker.
- type: bool
- default: false
-
- number_of_workers:
- description:
- - Describe number of workers to be allocated.
-
- state:
- description:
- - Assert the state of the app service plan.
- - Use C(present) to create or update an app service plan and C(absent) to delete it.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
- - azure_tags
-
-author:
- - Yunge Zhu (@yungezz)
-
-'''
-
-EXAMPLES = '''
- - name: Create a windows app service plan
- azure_rm_appserviceplan:
- resource_group: myResourceGroup
- name: myAppPlan
- location: eastus
- sku: S1
-
- - name: Create a linux app service plan
- azure_rm_appserviceplan:
- resource_group: myResourceGroup
- name: myAppPlan
- location: eastus
- sku: S1
- is_linux: true
- number_of_workers: 1
-
- - name: update sku of existing windows app service plan
- azure_rm_appserviceplan:
- resource_group: myResourceGroup
- name: myAppPlan
- location: eastus
- sku: S2
-'''
-
-RETURN = '''
-azure_appserviceplan:
- description: Facts about the current state of the app service plan.
- returned: always
- type: dict
- sample: {
- "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Web/serverfarms/myAppPlan"
- }
-'''
-
-import time
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrest.polling import LROPoller
- from msrestazure.azure_operation import AzureOperationPoller
- from msrest.serialization import Model
- from azure.mgmt.web.models import (
- app_service_plan, AppServicePlan, SkuDescription
- )
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-def _normalize_sku(sku):
- if sku is None:
- return sku
-
- sku = sku.upper()
- if sku == 'FREE':
- return 'F1'
- elif sku == 'SHARED':
- return 'D1'
- return sku
-
-
-def get_sku_name(tier):
- tier = tier.upper()
- if tier == 'F1' or tier == "FREE":
- return 'FREE'
- elif tier == 'D1' or tier == "SHARED":
- return 'SHARED'
- elif tier in ['B1', 'B2', 'B3', 'BASIC']:
- return 'BASIC'
- elif tier in ['S1', 'S2', 'S3']:
- return 'STANDARD'
- elif tier in ['P1', 'P2', 'P3']:
- return 'PREMIUM'
- elif tier in ['P1V2', 'P2V2', 'P3V2']:
- return 'PREMIUMV2'
- else:
- return None
-
-
-def appserviceplan_to_dict(plan):
- return dict(
- id=plan.id,
- name=plan.name,
- kind=plan.kind,
- location=plan.location,
- reserved=plan.reserved,
- is_linux=plan.reserved,
- provisioning_state=plan.provisioning_state,
- status=plan.status,
- target_worker_count=plan.target_worker_count,
- sku=dict(
- name=plan.sku.name,
- size=plan.sku.size,
- tier=plan.sku.tier,
- family=plan.sku.family,
- capacity=plan.sku.capacity
- ),
- resource_group=plan.resource_group,
- number_of_sites=plan.number_of_sites,
- tags=plan.tags if plan.tags else None
- )
-
-
-class AzureRMAppServicePlans(AzureRMModuleBase):
- """Configuration class for an Azure RM App Service Plan resource"""
-
- def __init__(self):
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str',
- required=True
- ),
- location=dict(
- type='str'
- ),
- sku=dict(
- type='str'
- ),
- is_linux=dict(
- type='bool',
- default=False
- ),
- number_of_workers=dict(
- type='str'
- ),
- state=dict(
- type='str',
- default='present',
- choices=['present', 'absent']
- )
- )
-
- self.resource_group = None
- self.name = None
- self.location = None
-
- self.sku = None
- self.is_linux = None
- self.number_of_workers = 1
-
- self.tags = None
-
- self.results = dict(
- changed=False,
- ansible_facts=dict(azure_appserviceplan=None)
- )
- self.state = None
-
- super(AzureRMAppServicePlans, self).__init__(derived_arg_spec=self.module_arg_spec,
- supports_check_mode=True,
- supports_tags=True)
-
- def exec_module(self, **kwargs):
- """Main module execution method"""
-
- for key in list(self.module_arg_spec.keys()) + ['tags']:
- if kwargs[key]:
- setattr(self, key, kwargs[key])
-
- old_response = None
- response = None
- to_be_updated = False
-
- # set location
- resource_group = self.get_resource_group(self.resource_group)
- if not self.location:
- self.location = resource_group.location
-
- # get app service plan
- old_response = self.get_plan()
-
- # if not existing
- if not old_response:
- self.log("App Service plan doesn't exist")
-
- if self.state == "present":
- to_be_updated = True
-
- if not self.sku:
- self.fail('Please specify sku in plan when creation')
-
- else:
- # existing app service plan, do update
- self.log("App Service Plan already exists")
-
- if self.state == 'present':
- self.log('Result: {0}'.format(old_response))
-
- update_tags, newtags = self.update_tags(old_response.get('tags', dict()))
-
- if update_tags:
- to_be_updated = True
- self.tags = newtags
-
- # check if sku changed
- if self.sku and _normalize_sku(self.sku) != old_response['sku']['size']:
- to_be_updated = True
-
- # check if number_of_workers changed
- if self.number_of_workers and int(self.number_of_workers) != old_response['sku']['capacity']:
- to_be_updated = True
-
- if self.is_linux and self.is_linux != old_response['reserved']:
- self.fail("Operation not allowed: cannot update reserved of app service plan.")
-
- if old_response:
- self.results['id'] = old_response['id']
-
- if to_be_updated:
- self.log('Need to Create/Update app service plan')
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- response = self.create_or_update_plan()
- self.results['id'] = response['id']
-
- if self.state == 'absent' and old_response:
- self.log("Delete app service plan")
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- self.delete_plan()
-
- self.log('App service plan instance deleted')
-
- return self.results
-
- def get_plan(self):
- '''
- Gets app service plan
- :return: deserialized app service plan dictionary
- '''
- self.log("Get App Service Plan {0}".format(self.name))
-
- try:
- response = self.web_client.app_service_plans.get(self.resource_group, self.name)
- if response:
- self.log("Response : {0}".format(response))
- self.log("App Service Plan : {0} found".format(response.name))
-
- return appserviceplan_to_dict(response)
- except CloudError as ex:
- self.log("Didn't find app service plan {0} in resource group {1}".format(self.name, self.resource_group))
-
- return False
-
- def create_or_update_plan(self):
- '''
- Creates app service plan
- :return: deserialized app service plan dictionary
- '''
- self.log("Create App Service Plan {0}".format(self.name))
-
- try:
- # normalize sku
- sku = _normalize_sku(self.sku)
-
- sku_def = SkuDescription(tier=get_sku_name(
- sku), name=sku, capacity=self.number_of_workers)
- plan_def = AppServicePlan(
- location=self.location, app_service_plan_name=self.name, sku=sku_def, reserved=self.is_linux, tags=self.tags if self.tags else None)
-
- response = self.web_client.app_service_plans.create_or_update(self.resource_group, self.name, plan_def)
-
- if isinstance(response, LROPoller) or isinstance(response, AzureOperationPoller):
- response = self.get_poller_result(response)
-
- self.log("Response : {0}".format(response))
-
- return appserviceplan_to_dict(response)
- except CloudError as ex:
- self.fail("Failed to create app service plan {0} in resource group {1}: {2}".format(self.name, self.resource_group, str(ex)))
-
- def delete_plan(self):
- '''
- Deletes specified App service plan in the specified subscription and resource group.
-
- :return: True
- '''
- self.log("Deleting the App service plan {0}".format(self.name))
- try:
- response = self.web_client.app_service_plans.delete(resource_group_name=self.resource_group,
- name=self.name)
- except CloudError as e:
- self.log('Error attempting to delete App service plan.')
- self.fail(
- "Error deleting the App service plan : {0}".format(str(e)))
-
- return True
-
-
-def main():
- """Main execution"""
- AzureRMAppServicePlans()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_functionapp.py b/test/support/integration/plugins/modules/azure_rm_functionapp.py
deleted file mode 100644
index 0c372a88de..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_functionapp.py
+++ /dev/null
@@ -1,421 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2016, Thomas Stringer <tomstr@microsoft.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_functionapp
-version_added: "2.4"
-short_description: Manage Azure Function Apps
-description:
- - Create, update or delete an Azure Function App.
-options:
- resource_group:
- description:
- - Name of resource group.
- required: true
- aliases:
- - resource_group_name
- name:
- description:
- - Name of the Azure Function App.
- required: true
- location:
- description:
- - Valid Azure location. Defaults to location of the resource group.
- plan:
- description:
- - App service plan.
- - It can be name of existing app service plan in same resource group as function app.
- - It can be resource id of existing app service plan.
- - Resource id. For example /subscriptions/<subs_id>/resourceGroups/<resource_group>/providers/Microsoft.Web/serverFarms/<plan_name>.
- - It can be a dict which contains C(name), C(resource_group).
- - C(name). Name of app service plan.
- - C(resource_group). Resource group name of app service plan.
- version_added: "2.8"
- container_settings:
- description: Web app container settings.
- suboptions:
- name:
- description:
- - Name of container. For example "imagename:tag".
- registry_server_url:
- description:
- - Container registry server url. For example C(mydockerregistry.io).
- registry_server_user:
- description:
- - The container registry server user name.
- registry_server_password:
- description:
- - The container registry server password.
- version_added: "2.8"
- storage_account:
- description:
- - Name of the storage account to use.
- required: true
- aliases:
- - storage
- - storage_account_name
- app_settings:
- description:
- - Dictionary containing application settings.
- state:
- description:
- - Assert the state of the Function App. Use C(present) to create or update a Function App and C(absent) to delete.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
- - azure_tags
-
-author:
- - Thomas Stringer (@trstringer)
-'''
-
-EXAMPLES = '''
-- name: Create a function app
- azure_rm_functionapp:
- resource_group: myResourceGroup
- name: myFunctionApp
- storage_account: myStorageAccount
-
-- name: Create a function app with app settings
- azure_rm_functionapp:
- resource_group: myResourceGroup
- name: myFunctionApp
- storage_account: myStorageAccount
- app_settings:
- setting1: value1
- setting2: value2
-
-- name: Create container based function app
- azure_rm_functionapp:
- resource_group: myResourceGroup
- name: myFunctionApp
- storage_account: myStorageAccount
- plan:
- resource_group: myResourceGroup
- name: myAppPlan
- container_settings:
- name: httpd
- registry_server_url: index.docker.io
-
-- name: Delete a function app
- azure_rm_functionapp:
- resource_group: myResourceGroup
- name: myFunctionApp
- state: absent
-'''
-
-RETURN = '''
-state:
- description:
- - Current state of the Azure Function App.
- returned: success
- type: dict
- example:
- id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Web/sites/myFunctionApp
- name: myfunctionapp
- kind: functionapp
- location: East US
- type: Microsoft.Web/sites
- state: Running
- host_names:
- - myfunctionapp.azurewebsites.net
- repository_site_name: myfunctionapp
- usage_state: Normal
- enabled: true
- enabled_host_names:
- - myfunctionapp.azurewebsites.net
- - myfunctionapp.scm.azurewebsites.net
- availability_state: Normal
- host_name_ssl_states:
- - name: myfunctionapp.azurewebsites.net
- ssl_state: Disabled
- host_type: Standard
- - name: myfunctionapp.scm.azurewebsites.net
- ssl_state: Disabled
- host_type: Repository
- server_farm_id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Web/serverfarms/EastUSPlan
- reserved: false
- last_modified_time_utc: 2017-08-22T18:54:01.190Z
- scm_site_also_stopped: false
- client_affinity_enabled: true
- client_cert_enabled: false
- host_names_disabled: false
- outbound_ip_addresses: ............
- container_size: 1536
- daily_memory_time_quota: 0
- resource_group: myResourceGroup
- default_host_name: myfunctionapp.azurewebsites.net
-''' # NOQA
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from azure.mgmt.web.models import (
- site_config, app_service_plan, Site, SiteConfig, NameValuePair, SiteSourceControl,
- AppServicePlan, SkuDescription
- )
- from azure.mgmt.resource.resources import ResourceManagementClient
- from msrest.polling import LROPoller
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-container_settings_spec = dict(
- name=dict(type='str', required=True),
- registry_server_url=dict(type='str'),
- registry_server_user=dict(type='str'),
- registry_server_password=dict(type='str', no_log=True)
-)
-
-
-class AzureRMFunctionApp(AzureRMModuleBase):
-
- def __init__(self):
-
- self.module_arg_spec = dict(
- resource_group=dict(type='str', required=True, aliases=['resource_group_name']),
- name=dict(type='str', required=True),
- state=dict(type='str', default='present', choices=['present', 'absent']),
- location=dict(type='str'),
- storage_account=dict(
- type='str',
- aliases=['storage', 'storage_account_name']
- ),
- app_settings=dict(type='dict'),
- plan=dict(
- type='raw'
- ),
- container_settings=dict(
- type='dict',
- options=container_settings_spec
- )
- )
-
- self.results = dict(
- changed=False,
- state=dict()
- )
-
- self.resource_group = None
- self.name = None
- self.state = None
- self.location = None
- self.storage_account = None
- self.app_settings = None
- self.plan = None
- self.container_settings = None
-
- required_if = [('state', 'present', ['storage_account'])]
-
- super(AzureRMFunctionApp, self).__init__(
- self.module_arg_spec,
- supports_check_mode=True,
- required_if=required_if
- )
-
- def exec_module(self, **kwargs):
-
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
- if self.app_settings is None:
- self.app_settings = dict()
-
- try:
- resource_group = self.rm_client.resource_groups.get(self.resource_group)
- except CloudError:
- self.fail('Unable to retrieve resource group')
-
- self.location = self.location or resource_group.location
-
- try:
- function_app = self.web_client.web_apps.get(
- resource_group_name=self.resource_group,
- name=self.name
- )
- # Newer SDK versions (0.40.0+) seem to return None if it doesn't exist instead of raising CloudError
- exists = function_app is not None
- except CloudError as exc:
- exists = False
-
- if self.state == 'absent':
- if exists:
- if self.check_mode:
- self.results['changed'] = True
- return self.results
- try:
- self.web_client.web_apps.delete(
- resource_group_name=self.resource_group,
- name=self.name
- )
- self.results['changed'] = True
- except CloudError as exc:
- self.fail('Failure while deleting web app: {0}'.format(exc))
- else:
- self.results['changed'] = False
- else:
- kind = 'functionapp'
- linux_fx_version = None
- if self.container_settings and self.container_settings.get('name'):
- kind = 'functionapp,linux,container'
- linux_fx_version = 'DOCKER|'
- if self.container_settings.get('registry_server_url'):
- self.app_settings['DOCKER_REGISTRY_SERVER_URL'] = 'https://' + self.container_settings['registry_server_url']
- linux_fx_version += self.container_settings['registry_server_url'] + '/'
- linux_fx_version += self.container_settings['name']
- if self.container_settings.get('registry_server_user'):
- self.app_settings['DOCKER_REGISTRY_SERVER_USERNAME'] = self.container_settings.get('registry_server_user')
-
- if self.container_settings.get('registry_server_password'):
- self.app_settings['DOCKER_REGISTRY_SERVER_PASSWORD'] = self.container_settings.get('registry_server_password')
-
- if not self.plan and function_app:
- self.plan = function_app.server_farm_id
-
- if not exists:
- function_app = Site(
- location=self.location,
- kind=kind,
- site_config=SiteConfig(
- app_settings=self.aggregated_app_settings(),
- scm_type='LocalGit'
- )
- )
- self.results['changed'] = True
- else:
- self.results['changed'], function_app = self.update(function_app)
-
- # get app service plan
- if self.plan:
- if isinstance(self.plan, dict):
- self.plan = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Web/serverfarms/{2}".format(
- self.subscription_id,
- self.plan.get('resource_group', self.resource_group),
- self.plan.get('name')
- )
- function_app.server_farm_id = self.plan
-
- # set linux fx version
- if linux_fx_version:
- function_app.site_config.linux_fx_version = linux_fx_version
-
- if self.check_mode:
- self.results['state'] = function_app.as_dict()
- elif self.results['changed']:
- try:
- new_function_app = self.web_client.web_apps.create_or_update(
- resource_group_name=self.resource_group,
- name=self.name,
- site_envelope=function_app
- ).result()
- self.results['state'] = new_function_app.as_dict()
- except CloudError as exc:
- self.fail('Error creating or updating web app: {0}'.format(exc))
-
- return self.results
-
- def update(self, source_function_app):
- """Update the Site object if there are any changes"""
-
- source_app_settings = self.web_client.web_apps.list_application_settings(
- resource_group_name=self.resource_group,
- name=self.name
- )
-
- changed, target_app_settings = self.update_app_settings(source_app_settings.properties)
-
- source_function_app.site_config = SiteConfig(
- app_settings=target_app_settings,
- scm_type='LocalGit'
- )
-
- return changed, source_function_app
-
- def update_app_settings(self, source_app_settings):
- """Update app settings"""
-
- target_app_settings = self.aggregated_app_settings()
- target_app_settings_dict = dict([(i.name, i.value) for i in target_app_settings])
- return target_app_settings_dict != source_app_settings, target_app_settings
-
- def necessary_functionapp_settings(self):
- """Construct the necessary app settings required for an Azure Function App"""
-
- function_app_settings = []
-
- if self.container_settings is None:
- for key in ['AzureWebJobsStorage', 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING', 'AzureWebJobsDashboard']:
- function_app_settings.append(NameValuePair(name=key, value=self.storage_connection_string))
- function_app_settings.append(NameValuePair(name='FUNCTIONS_EXTENSION_VERSION', value='~1'))
- function_app_settings.append(NameValuePair(name='WEBSITE_NODE_DEFAULT_VERSION', value='6.5.0'))
- function_app_settings.append(NameValuePair(name='WEBSITE_CONTENTSHARE', value=self.name))
- else:
- function_app_settings.append(NameValuePair(name='FUNCTIONS_EXTENSION_VERSION', value='~2'))
- function_app_settings.append(NameValuePair(name='WEBSITES_ENABLE_APP_SERVICE_STORAGE', value=False))
- function_app_settings.append(NameValuePair(name='AzureWebJobsStorage', value=self.storage_connection_string))
-
- return function_app_settings
-
- def aggregated_app_settings(self):
- """Combine both system and user app settings"""
-
- function_app_settings = self.necessary_functionapp_settings()
- for app_setting_key in self.app_settings:
- found_setting = None
- for s in function_app_settings:
- if s.name == app_setting_key:
- found_setting = s
- break
- if found_setting:
- found_setting.value = self.app_settings[app_setting_key]
- else:
- function_app_settings.append(NameValuePair(
- name=app_setting_key,
- value=self.app_settings[app_setting_key]
- ))
- return function_app_settings
-
- @property
- def storage_connection_string(self):
- """Construct the storage account connection string"""
-
- return 'DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}'.format(
- self.storage_account,
- self.storage_key
- )
-
- @property
- def storage_key(self):
- """Retrieve the storage account key"""
-
- return self.storage_client.storage_accounts.list_keys(
- resource_group_name=self.resource_group,
- account_name=self.storage_account
- ).keys[0].value
-
-
-def main():
- """Main function execution"""
-
- AzureRMFunctionApp()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_functionapp_info.py b/test/support/integration/plugins/modules/azure_rm_functionapp_info.py
deleted file mode 100644
index 40672f952d..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_functionapp_info.py
+++ /dev/null
@@ -1,207 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2016 Thomas Stringer, <tomstr@microsoft.com>
-
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_functionapp_info
-version_added: "2.9"
-short_description: Get Azure Function App facts
-description:
- - Get facts for one Azure Function App or all Function Apps within a resource group.
-options:
- name:
- description:
- - Only show results for a specific Function App.
- resource_group:
- description:
- - Limit results to a resource group. Required when filtering by name.
- aliases:
- - resource_group_name
- tags:
- description:
- - Limit results by providing a list of tags. Format tags as 'key' or 'key:value'.
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Thomas Stringer (@trstringer)
-'''
-
-EXAMPLES = '''
- - name: Get facts for one Function App
- azure_rm_functionapp_info:
- resource_group: myResourceGroup
- name: myfunctionapp
-
- - name: Get facts for all Function Apps in a resource group
- azure_rm_functionapp_info:
- resource_group: myResourceGroup
-
- - name: Get facts for all Function Apps by tags
- azure_rm_functionapp_info:
- tags:
- - testing
-'''
-
-RETURN = '''
-azure_functionapps:
- description:
- - List of Azure Function Apps dicts.
- returned: always
- type: list
- example:
- id: /subscriptions/.../resourceGroups/ansible-rg/providers/Microsoft.Web/sites/myfunctionapp
- name: myfunctionapp
- kind: functionapp
- location: East US
- type: Microsoft.Web/sites
- state: Running
- host_names:
- - myfunctionapp.azurewebsites.net
- repository_site_name: myfunctionapp
- usage_state: Normal
- enabled: true
- enabled_host_names:
- - myfunctionapp.azurewebsites.net
- - myfunctionapp.scm.azurewebsites.net
- availability_state: Normal
- host_name_ssl_states:
- - name: myfunctionapp.azurewebsites.net
- ssl_state: Disabled
- host_type: Standard
- - name: myfunctionapp.scm.azurewebsites.net
- ssl_state: Disabled
- host_type: Repository
- server_farm_id: /subscriptions/.../resourceGroups/ansible-rg/providers/Microsoft.Web/serverfarms/EastUSPlan
- reserved: false
- last_modified_time_utc: 2017-08-22T18:54:01.190Z
- scm_site_also_stopped: false
- client_affinity_enabled: true
- client_cert_enabled: false
- host_names_disabled: false
- outbound_ip_addresses: ............
- container_size: 1536
- daily_memory_time_quota: 0
- resource_group: myResourceGroup
- default_host_name: myfunctionapp.azurewebsites.net
-'''
-
-try:
- from msrestazure.azure_exceptions import CloudError
-except Exception:
- # This is handled in azure_rm_common
- pass
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-
-class AzureRMFunctionAppInfo(AzureRMModuleBase):
- def __init__(self):
-
- self.module_arg_spec = dict(
- name=dict(type='str'),
- resource_group=dict(type='str', aliases=['resource_group_name']),
- tags=dict(type='list'),
- )
-
- self.results = dict(
- changed=False,
- ansible_info=dict(azure_functionapps=[])
- )
-
- self.name = None
- self.resource_group = None
- self.tags = None
-
- super(AzureRMFunctionAppInfo, self).__init__(
- self.module_arg_spec,
- supports_tags=False,
- facts_module=True
- )
-
- def exec_module(self, **kwargs):
-
- is_old_facts = self.module._name == 'azure_rm_functionapp_facts'
- if is_old_facts:
- self.module.deprecate("The 'azure_rm_functionapp_facts' module has been renamed to 'azure_rm_functionapp_info'",
- version='2.13', collection_name='ansible.builtin')
-
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
-
- if self.name and not self.resource_group:
- self.fail("Parameter error: resource group required when filtering by name.")
-
- if self.name:
- self.results['ansible_info']['azure_functionapps'] = self.get_functionapp()
- elif self.resource_group:
- self.results['ansible_info']['azure_functionapps'] = self.list_resource_group()
- else:
- self.results['ansible_info']['azure_functionapps'] = self.list_all()
-
- return self.results
-
- def get_functionapp(self):
- self.log('Get properties for Function App {0}'.format(self.name))
- function_app = None
- result = []
-
- try:
- function_app = self.web_client.web_apps.get(
- self.resource_group,
- self.name
- )
- except CloudError:
- pass
-
- if function_app and self.has_tags(function_app.tags, self.tags):
- result = function_app.as_dict()
-
- return [result]
-
- def list_resource_group(self):
- self.log('List items')
- try:
- response = self.web_client.web_apps.list_by_resource_group(self.resource_group)
- except Exception as exc:
- self.fail("Error listing for resource group {0} - {1}".format(self.resource_group, str(exc)))
-
- results = []
- for item in response:
- if self.has_tags(item.tags, self.tags):
- results.append(item.as_dict())
- return results
-
- def list_all(self):
- self.log('List all items')
- try:
- response = self.web_client.web_apps.list_by_resource_group(self.resource_group)
- except Exception as exc:
- self.fail("Error listing all items - {0}".format(str(exc)))
-
- results = []
- for item in response:
- if self.has_tags(item.tags, self.tags):
- results.append(item.as_dict())
- return results
-
-
-def main():
- AzureRMFunctionAppInfo()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_mariadbconfiguration.py b/test/support/integration/plugins/modules/azure_rm_mariadbconfiguration.py
deleted file mode 100644
index 212cf7959d..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_mariadbconfiguration.py
+++ /dev/null
@@ -1,241 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2019 Zim Kalinowski, (@zikalino)
-# Copyright (c) 2019 Matti Ranta, (@techknowlogick)
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_mariadbconfiguration
-version_added: "2.8"
-short_description: Manage Configuration instance
-description:
- - Create, update and delete instance of Configuration.
-
-options:
- resource_group:
- description:
- - The name of the resource group that contains the resource.
- required: True
- server_name:
- description:
- - The name of the server.
- required: True
- name:
- description:
- - The name of the server configuration.
- required: True
- value:
- description:
- - Value of the configuration.
- state:
- description:
- - Assert the state of the MariaDB configuration. Use C(present) to update setting, or C(absent) to reset to default value.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
- - Matti Ranta (@techknowlogick)
-'''
-
-EXAMPLES = '''
- - name: Update SQL Server setting
- azure_rm_mariadbconfiguration:
- resource_group: myResourceGroup
- server_name: myServer
- name: event_scheduler
- value: "ON"
-'''
-
-RETURN = '''
-id:
- description:
- - Resource ID.
- returned: always
- type: str
- sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.DBforMariaDB/servers/myServer/confi
- gurations/event_scheduler"
-'''
-
-import time
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrest.polling import LROPoller
- from azure.mgmt.rdbms.mysql import MariaDBManagementClient
- from msrest.serialization import Model
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class Actions:
- NoAction, Create, Update, Delete = range(4)
-
-
-class AzureRMMariaDbConfiguration(AzureRMModuleBase):
-
- def __init__(self):
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- server_name=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str',
- required=True
- ),
- value=dict(
- type='str'
- ),
- state=dict(
- type='str',
- default='present',
- choices=['present', 'absent']
- )
- )
-
- self.resource_group = None
- self.server_name = None
- self.name = None
- self.value = None
-
- self.results = dict(changed=False)
- self.state = None
- self.to_do = Actions.NoAction
-
- super(AzureRMMariaDbConfiguration, self).__init__(derived_arg_spec=self.module_arg_spec,
- supports_check_mode=True,
- supports_tags=False)
-
- def exec_module(self, **kwargs):
-
- for key in list(self.module_arg_spec.keys()):
- if hasattr(self, key):
- setattr(self, key, kwargs[key])
-
- old_response = None
- response = None
-
- old_response = self.get_configuration()
-
- if not old_response:
- self.log("Configuration instance doesn't exist")
- if self.state == 'absent':
- self.log("Old instance didn't exist")
- else:
- self.to_do = Actions.Create
- else:
- self.log("Configuration instance already exists")
- if self.state == 'absent' and old_response['source'] == 'user-override':
- self.to_do = Actions.Delete
- elif self.state == 'present':
- self.log("Need to check if Configuration instance has to be deleted or may be updated")
- if self.value != old_response.get('value'):
- self.to_do = Actions.Update
-
- if (self.to_do == Actions.Create) or (self.to_do == Actions.Update):
- self.log("Need to Create / Update the Configuration instance")
-
- if self.check_mode:
- self.results['changed'] = True
- return self.results
-
- response = self.create_update_configuration()
-
- self.results['changed'] = True
- self.log("Creation / Update done")
- elif self.to_do == Actions.Delete:
- self.log("Configuration instance deleted")
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- self.delete_configuration()
- else:
- self.log("Configuration instance unchanged")
- self.results['changed'] = False
- response = old_response
-
- if response:
- self.results["id"] = response["id"]
-
- return self.results
-
- def create_update_configuration(self):
- self.log("Creating / Updating the Configuration instance {0}".format(self.name))
-
- try:
- response = self.mariadb_client.configurations.create_or_update(resource_group_name=self.resource_group,
- server_name=self.server_name,
- configuration_name=self.name,
- value=self.value,
- source='user-override')
- if isinstance(response, LROPoller):
- response = self.get_poller_result(response)
-
- except CloudError as exc:
- self.log('Error attempting to create the Configuration instance.')
- self.fail("Error creating the Configuration instance: {0}".format(str(exc)))
- return response.as_dict()
-
- def delete_configuration(self):
- self.log("Deleting the Configuration instance {0}".format(self.name))
- try:
- response = self.mariadb_client.configurations.create_or_update(resource_group_name=self.resource_group,
- server_name=self.server_name,
- configuration_name=self.name,
- source='system-default')
- except CloudError as e:
- self.log('Error attempting to delete the Configuration instance.')
- self.fail("Error deleting the Configuration instance: {0}".format(str(e)))
-
- return True
-
- def get_configuration(self):
- self.log("Checking if the Configuration instance {0} is present".format(self.name))
- found = False
- try:
- response = self.mariadb_client.configurations.get(resource_group_name=self.resource_group,
- server_name=self.server_name,
- configuration_name=self.name)
- found = True
- self.log("Response : {0}".format(response))
- self.log("Configuration instance : {0} found".format(response.name))
- except CloudError as e:
- self.log('Did not find the Configuration instance.')
- if found is True:
- return response.as_dict()
-
- return False
-
-
-def main():
- """Main execution"""
- AzureRMMariaDbConfiguration()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_mariadbconfiguration_info.py b/test/support/integration/plugins/modules/azure_rm_mariadbconfiguration_info.py
deleted file mode 100644
index 3faac5eb5a..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_mariadbconfiguration_info.py
+++ /dev/null
@@ -1,217 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2019 Zim Kalinowski, (@zikalino)
-# Copyright (c) 2019 Matti Ranta, (@techknowlogick)
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_mariadbconfiguration_info
-version_added: "2.9"
-short_description: Get Azure MariaDB Configuration facts
-description:
- - Get facts of Azure MariaDB Configuration.
-
-options:
- resource_group:
- description:
- - The name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal.
- required: True
- type: str
- server_name:
- description:
- - The name of the server.
- required: True
- type: str
- name:
- description:
- - Setting name.
- type: str
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
- - Matti Ranta (@techknowlogick)
-
-'''
-
-EXAMPLES = '''
- - name: Get specific setting of MariaDB Server
- azure_rm_mariadbconfiguration_info:
- resource_group: myResourceGroup
- server_name: testserver
- name: deadlock_timeout
-
- - name: Get all settings of MariaDB Server
- azure_rm_mariadbconfiguration_info:
- resource_group: myResourceGroup
- server_name: server_name
-'''
-
-RETURN = '''
-settings:
- description:
- - A list of dictionaries containing MariaDB Server settings.
- returned: always
- type: complex
- contains:
- id:
- description:
- - Setting resource ID.
- returned: always
- type: str
- sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.DBforMariaDB/servers/testserver
- /configurations/deadlock_timeout"
- name:
- description:
- - Setting name.
- returned: always
- type: str
- sample: deadlock_timeout
- value:
- description:
- - Setting value.
- returned: always
- type: raw
- sample: 1000
- description:
- description:
- - Description of the configuration.
- returned: always
- type: str
- sample: Deadlock timeout.
- source:
- description:
- - Source of the configuration.
- returned: always
- type: str
- sample: system-default
-'''
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrestazure.azure_operation import AzureOperationPoller
- from azure.mgmt.rdbms.mariadb import MariaDBManagementClient
- from msrest.serialization import Model
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class AzureRMMariaDbConfigurationInfo(AzureRMModuleBase):
- def __init__(self):
- # define user inputs into argument
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- server_name=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str'
- )
- )
- # store the results of the module operation
- self.results = dict(changed=False)
- self.mgmt_client = None
- self.resource_group = None
- self.server_name = None
- self.name = None
- super(AzureRMMariaDbConfigurationInfo, self).__init__(self.module_arg_spec, supports_tags=False)
-
- def exec_module(self, **kwargs):
- is_old_facts = self.module._name == 'azure_rm_mariadbconfiguration_facts'
- if is_old_facts:
- self.module.deprecate("The 'azure_rm_mariadbconfiguration_facts' module has been renamed to 'azure_rm_mariadbconfiguration_info'",
- version='2.13', collection_name='ansible.builtin')
-
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
- self.mgmt_client = self.get_mgmt_svc_client(MariaDBManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
-
- if self.name is not None:
- self.results['settings'] = self.get()
- else:
- self.results['settings'] = self.list_by_server()
- return self.results
-
- def get(self):
- '''
- Gets facts of the specified MariaDB Configuration.
-
- :return: deserialized MariaDB Configurationinstance state dictionary
- '''
- response = None
- results = []
- try:
- response = self.mgmt_client.configurations.get(resource_group_name=self.resource_group,
- server_name=self.server_name,
- configuration_name=self.name)
- self.log("Response : {0}".format(response))
- except CloudError as e:
- self.log('Could not get facts for Configurations.')
-
- if response is not None:
- results.append(self.format_item(response))
-
- return results
-
- def list_by_server(self):
- '''
- Gets facts of the specified MariaDB Configuration.
-
- :return: deserialized MariaDB Configurationinstance state dictionary
- '''
- response = None
- results = []
- try:
- response = self.mgmt_client.configurations.list_by_server(resource_group_name=self.resource_group,
- server_name=self.server_name)
- self.log("Response : {0}".format(response))
- except CloudError as e:
- self.log('Could not get facts for Configurations.')
-
- if response is not None:
- for item in response:
- results.append(self.format_item(item))
-
- return results
-
- def format_item(self, item):
- d = item.as_dict()
- d = {
- 'resource_group': self.resource_group,
- 'server_name': self.server_name,
- 'id': d['id'],
- 'name': d['name'],
- 'value': d['value'],
- 'description': d['description'],
- 'source': d['source']
- }
- return d
-
-
-def main():
- AzureRMMariaDbConfigurationInfo()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_mariadbdatabase.py b/test/support/integration/plugins/modules/azure_rm_mariadbdatabase.py
deleted file mode 100644
index 8492b96854..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_mariadbdatabase.py
+++ /dev/null
@@ -1,304 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2017 Zim Kalinowski, <zikalino@microsoft.com>
-# Copyright (c) 2019 Matti Ranta, (@techknowlogick)
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_mariadbdatabase
-version_added: "2.8"
-short_description: Manage MariaDB Database instance
-description:
- - Create, update and delete instance of MariaDB Database.
-
-options:
- resource_group:
- description:
- - The name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal.
- required: True
- server_name:
- description:
- - The name of the server.
- required: True
- name:
- description:
- - The name of the database.
- required: True
- charset:
- description:
- - The charset of the database. Check MariaDB documentation for possible values.
- - This is only set on creation, use I(force_update) to recreate a database if the values don't match.
- collation:
- description:
- - The collation of the database. Check MariaDB documentation for possible values.
- - This is only set on creation, use I(force_update) to recreate a database if the values don't match.
- force_update:
- description:
- - When set to C(true), will delete and recreate the existing MariaDB database if any of the properties don't match what is set.
- - When set to C(false), no change will occur to the database even if any of the properties do not match.
- type: bool
- default: 'no'
- state:
- description:
- - Assert the state of the MariaDB Database. Use C(present) to create or update a database and C(absent) to delete it.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
- - Matti Ranta (@techknowlogick)
-
-'''
-
-EXAMPLES = '''
- - name: Create (or update) MariaDB Database
- azure_rm_mariadbdatabase:
- resource_group: myResourceGroup
- server_name: testserver
- name: db1
-'''
-
-RETURN = '''
-id:
- description:
- - Resource ID.
- returned: always
- type: str
- sample: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.DBforMariaDB/servers/testserver/databases/db1
-name:
- description:
- - Resource name.
- returned: always
- type: str
- sample: db1
-'''
-
-import time
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from azure.mgmt.rdbms.mariadb import MariaDBManagementClient
- from msrestazure.azure_exceptions import CloudError
- from msrest.polling import LROPoller
- from msrest.serialization import Model
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class Actions:
- NoAction, Create, Update, Delete = range(4)
-
-
-class AzureRMMariaDbDatabase(AzureRMModuleBase):
- """Configuration class for an Azure RM MariaDB Database resource"""
-
- def __init__(self):
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- server_name=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str',
- required=True
- ),
- charset=dict(
- type='str'
- ),
- collation=dict(
- type='str'
- ),
- force_update=dict(
- type='bool',
- default=False
- ),
- state=dict(
- type='str',
- default='present',
- choices=['present', 'absent']
- )
- )
-
- self.resource_group = None
- self.server_name = None
- self.name = None
- self.force_update = None
- self.parameters = dict()
-
- self.results = dict(changed=False)
- self.mgmt_client = None
- self.state = None
- self.to_do = Actions.NoAction
-
- super(AzureRMMariaDbDatabase, self).__init__(derived_arg_spec=self.module_arg_spec,
- supports_check_mode=True,
- supports_tags=False)
-
- def exec_module(self, **kwargs):
- """Main module execution method"""
-
- for key in list(self.module_arg_spec.keys()):
- if hasattr(self, key):
- setattr(self, key, kwargs[key])
- elif kwargs[key] is not None:
- if key == "charset":
- self.parameters["charset"] = kwargs[key]
- elif key == "collation":
- self.parameters["collation"] = kwargs[key]
-
- old_response = None
- response = None
-
- self.mgmt_client = self.get_mgmt_svc_client(MariaDBManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
-
- resource_group = self.get_resource_group(self.resource_group)
-
- old_response = self.get_mariadbdatabase()
-
- if not old_response:
- self.log("MariaDB Database instance doesn't exist")
- if self.state == 'absent':
- self.log("Old instance didn't exist")
- else:
- self.to_do = Actions.Create
- else:
- self.log("MariaDB Database instance already exists")
- if self.state == 'absent':
- self.to_do = Actions.Delete
- elif self.state == 'present':
- self.log("Need to check if MariaDB Database instance has to be deleted or may be updated")
- if ('collation' in self.parameters) and (self.parameters['collation'] != old_response['collation']):
- self.to_do = Actions.Update
- if ('charset' in self.parameters) and (self.parameters['charset'] != old_response['charset']):
- self.to_do = Actions.Update
- if self.to_do == Actions.Update:
- if self.force_update:
- if not self.check_mode:
- self.delete_mariadbdatabase()
- else:
- self.fail("Database properties cannot be updated without setting 'force_update' option")
- self.to_do = Actions.NoAction
-
- if (self.to_do == Actions.Create) or (self.to_do == Actions.Update):
- self.log("Need to Create / Update the MariaDB Database instance")
-
- if self.check_mode:
- self.results['changed'] = True
- return self.results
-
- response = self.create_update_mariadbdatabase()
- self.results['changed'] = True
- self.log("Creation / Update done")
- elif self.to_do == Actions.Delete:
- self.log("MariaDB Database instance deleted")
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- self.delete_mariadbdatabase()
- # make sure instance is actually deleted, for some Azure resources, instance is hanging around
- # for some time after deletion -- this should be really fixed in Azure
- while self.get_mariadbdatabase():
- time.sleep(20)
- else:
- self.log("MariaDB Database instance unchanged")
- self.results['changed'] = False
- response = old_response
-
- if response:
- self.results["id"] = response["id"]
- self.results["name"] = response["name"]
-
- return self.results
-
- def create_update_mariadbdatabase(self):
- '''
- Creates or updates MariaDB Database with the specified configuration.
-
- :return: deserialized MariaDB Database instance state dictionary
- '''
- self.log("Creating / Updating the MariaDB Database instance {0}".format(self.name))
-
- try:
- response = self.mgmt_client.databases.create_or_update(resource_group_name=self.resource_group,
- server_name=self.server_name,
- database_name=self.name,
- parameters=self.parameters)
- if isinstance(response, LROPoller):
- response = self.get_poller_result(response)
-
- except CloudError as exc:
- self.log('Error attempting to create the MariaDB Database instance.')
- self.fail("Error creating the MariaDB Database instance: {0}".format(str(exc)))
- return response.as_dict()
-
- def delete_mariadbdatabase(self):
- '''
- Deletes specified MariaDB Database instance in the specified subscription and resource group.
-
- :return: True
- '''
- self.log("Deleting the MariaDB Database instance {0}".format(self.name))
- try:
- response = self.mgmt_client.databases.delete(resource_group_name=self.resource_group,
- server_name=self.server_name,
- database_name=self.name)
- except CloudError as e:
- self.log('Error attempting to delete the MariaDB Database instance.')
- self.fail("Error deleting the MariaDB Database instance: {0}".format(str(e)))
-
- return True
-
- def get_mariadbdatabase(self):
- '''
- Gets the properties of the specified MariaDB Database.
-
- :return: deserialized MariaDB Database instance state dictionary
- '''
- self.log("Checking if the MariaDB Database instance {0} is present".format(self.name))
- found = False
- try:
- response = self.mgmt_client.databases.get(resource_group_name=self.resource_group,
- server_name=self.server_name,
- database_name=self.name)
- found = True
- self.log("Response : {0}".format(response))
- self.log("MariaDB Database instance : {0} found".format(response.name))
- except CloudError as e:
- self.log('Did not find the MariaDB Database instance.')
- if found is True:
- return response.as_dict()
-
- return False
-
-
-def main():
- """Main execution"""
- AzureRMMariaDbDatabase()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_mariadbdatabase_info.py b/test/support/integration/plugins/modules/azure_rm_mariadbdatabase_info.py
deleted file mode 100644
index e9c99c1483..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_mariadbdatabase_info.py
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2017 Zim Kalinowski, <zikalino@microsoft.com>
-# Copyright (c) 2019 Matti Ranta, (@techknowlogick)
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_mariadbdatabase_info
-version_added: "2.9"
-short_description: Get Azure MariaDB Database facts
-description:
- - Get facts of MariaDB Database.
-
-options:
- resource_group:
- description:
- - The name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal.
- required: True
- type: str
- server_name:
- description:
- - The name of the server.
- required: True
- type: str
- name:
- description:
- - The name of the database.
- type: str
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
- - Matti Ranta (@techknowlogick)
-
-'''
-
-EXAMPLES = '''
- - name: Get instance of MariaDB Database
- azure_rm_mariadbdatabase_info:
- resource_group: myResourceGroup
- server_name: server_name
- name: database_name
-
- - name: List instances of MariaDB Database
- azure_rm_mariadbdatabase_info:
- resource_group: myResourceGroup
- server_name: server_name
-'''
-
-RETURN = '''
-databases:
- description:
- - A list of dictionaries containing facts for MariaDB Databases.
- returned: always
- type: complex
- contains:
- id:
- description:
- - Resource ID.
- returned: always
- type: str
- sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.DBforMariaDB/servers/testser
- ver/databases/db1"
- resource_group:
- description:
- - Resource group name.
- returned: always
- type: str
- sample: testrg
- server_name:
- description:
- - Server name.
- returned: always
- type: str
- sample: testserver
- name:
- description:
- - Resource name.
- returned: always
- type: str
- sample: db1
- charset:
- description:
- - The charset of the database.
- returned: always
- type: str
- sample: UTF8
- collation:
- description:
- - The collation of the database.
- returned: always
- type: str
- sample: English_United States.1252
-'''
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from azure.mgmt.rdbms.mariadb import MariaDBManagementClient
- from msrest.serialization import Model
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class AzureRMMariaDbDatabaseInfo(AzureRMModuleBase):
- def __init__(self):
- # define user inputs into argument
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- server_name=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str'
- )
- )
- # store the results of the module operation
- self.results = dict(
- changed=False
- )
- self.resource_group = None
- self.server_name = None
- self.name = None
- super(AzureRMMariaDbDatabaseInfo, self).__init__(self.module_arg_spec, supports_tags=False)
-
- def exec_module(self, **kwargs):
- is_old_facts = self.module._name == 'azure_rm_mariadbdatabase_facts'
- if is_old_facts:
- self.module.deprecate("The 'azure_rm_mariadbdatabase_facts' module has been renamed to 'azure_rm_mariadbdatabase_info'",
- version='2.13', collection_name='ansible.builtin')
-
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
-
- if (self.resource_group is not None and
- self.server_name is not None and
- self.name is not None):
- self.results['databases'] = self.get()
- elif (self.resource_group is not None and
- self.server_name is not None):
- self.results['databases'] = self.list_by_server()
- return self.results
-
- def get(self):
- response = None
- results = []
- try:
- response = self.mariadb_client.databases.get(resource_group_name=self.resource_group,
- server_name=self.server_name,
- database_name=self.name)
- self.log("Response : {0}".format(response))
- except CloudError as e:
- self.log('Could not get facts for Databases.')
-
- if response is not None:
- results.append(self.format_item(response))
-
- return results
-
- def list_by_server(self):
- response = None
- results = []
- try:
- response = self.mariadb_client.databases.list_by_server(resource_group_name=self.resource_group,
- server_name=self.server_name)
- self.log("Response : {0}".format(response))
- except CloudError as e:
- self.fail("Error listing for server {0} - {1}".format(self.server_name, str(e)))
-
- if response is not None:
- for item in response:
- results.append(self.format_item(item))
-
- return results
-
- def format_item(self, item):
- d = item.as_dict()
- d = {
- 'resource_group': self.resource_group,
- 'server_name': self.server_name,
- 'name': d['name'],
- 'charset': d['charset'],
- 'collation': d['collation']
- }
- return d
-
-
-def main():
- AzureRMMariaDbDatabaseInfo()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_mariadbfirewallrule.py b/test/support/integration/plugins/modules/azure_rm_mariadbfirewallrule.py
deleted file mode 100644
index 1fc8c5e79e..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_mariadbfirewallrule.py
+++ /dev/null
@@ -1,277 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018 Zim Kalinowski, <zikalino@microsoft.com>
-# Copyright (c) 2019 Matti Ranta, (@techknowlogick)
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_mariadbfirewallrule
-version_added: "2.8"
-short_description: Manage MariaDB firewall rule instance
-description:
- - Create, update and delete instance of MariaDB firewall rule.
-
-options:
- resource_group:
- description:
- - The name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal.
- required: True
- server_name:
- description:
- - The name of the server.
- required: True
- name:
- description:
- - The name of the MariaDB firewall rule.
- required: True
- start_ip_address:
- description:
- - The start IP address of the MariaDB firewall rule. Must be IPv4 format.
- end_ip_address:
- description:
- - The end IP address of the MariaDB firewall rule. Must be IPv4 format.
- state:
- description:
- - Assert the state of the MariaDB firewall rule. Use C(present) to create or update a rule and C(absent) to ensure it is not present.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
- - Matti Ranta (@techknowlogick)
-
-'''
-
-EXAMPLES = '''
- - name: Create (or update) MariaDB firewall rule
- azure_rm_mariadbfirewallrule:
- resource_group: myResourceGroup
- server_name: testserver
- name: rule1
- start_ip_address: 10.0.0.17
- end_ip_address: 10.0.0.20
-'''
-
-RETURN = '''
-id:
- description:
- - Resource ID.
- returned: always
- type: str
- sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.DBforMariaDB/servers/testserver/fire
- wallRules/rule1"
-'''
-
-import time
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrest.polling import LROPoller
- from azure.mgmt.rdbms.mariadb import MariaDBManagementClient
- from msrest.serialization import Model
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class Actions:
- NoAction, Create, Update, Delete = range(4)
-
-
-class AzureRMMariaDbFirewallRule(AzureRMModuleBase):
- """Configuration class for an Azure RM MariaDB firewall rule resource"""
-
- def __init__(self):
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- server_name=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str',
- required=True
- ),
- start_ip_address=dict(
- type='str'
- ),
- end_ip_address=dict(
- type='str'
- ),
- state=dict(
- type='str',
- default='present',
- choices=['present', 'absent']
- )
- )
-
- self.resource_group = None
- self.server_name = None
- self.name = None
- self.start_ip_address = None
- self.end_ip_address = None
-
- self.results = dict(changed=False)
- self.state = None
- self.to_do = Actions.NoAction
-
- super(AzureRMMariaDbFirewallRule, self).__init__(derived_arg_spec=self.module_arg_spec,
- supports_check_mode=True,
- supports_tags=False)
-
- def exec_module(self, **kwargs):
- """Main module execution method"""
-
- for key in list(self.module_arg_spec.keys()):
- if hasattr(self, key):
- setattr(self, key, kwargs[key])
-
- old_response = None
- response = None
-
- resource_group = self.get_resource_group(self.resource_group)
-
- old_response = self.get_firewallrule()
-
- if not old_response:
- self.log("MariaDB firewall rule instance doesn't exist")
- if self.state == 'absent':
- self.log("Old instance didn't exist")
- else:
- self.to_do = Actions.Create
- else:
- self.log("MariaDB firewall rule instance already exists")
- if self.state == 'absent':
- self.to_do = Actions.Delete
- elif self.state == 'present':
- self.log("Need to check if MariaDB firewall rule instance has to be deleted or may be updated")
- if (self.start_ip_address is not None) and (self.start_ip_address != old_response['start_ip_address']):
- self.to_do = Actions.Update
- if (self.end_ip_address is not None) and (self.end_ip_address != old_response['end_ip_address']):
- self.to_do = Actions.Update
-
- if (self.to_do == Actions.Create) or (self.to_do == Actions.Update):
- self.log("Need to Create / Update the MariaDB firewall rule instance")
-
- if self.check_mode:
- self.results['changed'] = True
- return self.results
-
- response = self.create_update_firewallrule()
-
- if not old_response:
- self.results['changed'] = True
- else:
- self.results['changed'] = old_response.__ne__(response)
- self.log("Creation / Update done")
- elif self.to_do == Actions.Delete:
- self.log("MariaDB firewall rule instance deleted")
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- self.delete_firewallrule()
- # make sure instance is actually deleted, for some Azure resources, instance is hanging around
- # for some time after deletion -- this should be really fixed in Azure
- while self.get_firewallrule():
- time.sleep(20)
- else:
- self.log("MariaDB firewall rule instance unchanged")
- self.results['changed'] = False
- response = old_response
-
- if response:
- self.results["id"] = response["id"]
-
- return self.results
-
- def create_update_firewallrule(self):
- '''
- Creates or updates MariaDB firewall rule with the specified configuration.
-
- :return: deserialized MariaDB firewall rule instance state dictionary
- '''
- self.log("Creating / Updating the MariaDB firewall rule instance {0}".format(self.name))
-
- try:
- response = self.mariadb_client.firewall_rules.create_or_update(resource_group_name=self.resource_group,
- server_name=self.server_name,
- firewall_rule_name=self.name,
- start_ip_address=self.start_ip_address,
- end_ip_address=self.end_ip_address)
- if isinstance(response, LROPoller):
- response = self.get_poller_result(response)
-
- except CloudError as exc:
- self.log('Error attempting to create the MariaDB firewall rule instance.')
- self.fail("Error creating the MariaDB firewall rule instance: {0}".format(str(exc)))
- return response.as_dict()
-
- def delete_firewallrule(self):
- '''
- Deletes specified MariaDB firewall rule instance in the specified subscription and resource group.
-
- :return: True
- '''
- self.log("Deleting the MariaDB firewall rule instance {0}".format(self.name))
- try:
- response = self.mariadb_client.firewall_rules.delete(resource_group_name=self.resource_group,
- server_name=self.server_name,
- firewall_rule_name=self.name)
- except CloudError as e:
- self.log('Error attempting to delete the MariaDB firewall rule instance.')
- self.fail("Error deleting the MariaDB firewall rule instance: {0}".format(str(e)))
-
- return True
-
- def get_firewallrule(self):
- '''
- Gets the properties of the specified MariaDB firewall rule.
-
- :return: deserialized MariaDB firewall rule instance state dictionary
- '''
- self.log("Checking if the MariaDB firewall rule instance {0} is present".format(self.name))
- found = False
- try:
- response = self.mariadb_client.firewall_rules.get(resource_group_name=self.resource_group,
- server_name=self.server_name,
- firewall_rule_name=self.name)
- found = True
- self.log("Response : {0}".format(response))
- self.log("MariaDB firewall rule instance : {0} found".format(response.name))
- except CloudError as e:
- self.log('Did not find the MariaDB firewall rule instance.')
- if found is True:
- return response.as_dict()
-
- return False
-
-
-def main():
- """Main execution"""
- AzureRMMariaDbFirewallRule()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_mariadbfirewallrule_info.py b/test/support/integration/plugins/modules/azure_rm_mariadbfirewallrule_info.py
deleted file mode 100644
index ef71be8dce..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_mariadbfirewallrule_info.py
+++ /dev/null
@@ -1,208 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018 Zim Kalinowski, <zikalino@microsoft.com>
-# Copyright (c) 2019 Matti Ranta, (@techknowlogick)
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_mariadbfirewallrule_info
-version_added: "2.9"
-short_description: Get Azure MariaDB Firewall Rule facts
-description:
- - Get facts of Azure MariaDB Firewall Rule.
-
-options:
- resource_group:
- description:
- - The name of the resource group.
- required: True
- type: str
- server_name:
- description:
- - The name of the server.
- required: True
- type: str
- name:
- description:
- - The name of the server firewall rule.
- type: str
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
- - Matti Ranta (@techknowlogick)
-
-'''
-
-EXAMPLES = '''
- - name: Get instance of MariaDB Firewall Rule
- azure_rm_mariadbfirewallrule_info:
- resource_group: myResourceGroup
- server_name: server_name
- name: firewall_rule_name
-
- - name: List instances of MariaDB Firewall Rule
- azure_rm_mariadbfirewallrule_info:
- resource_group: myResourceGroup
- server_name: server_name
-'''
-
-RETURN = '''
-rules:
- description:
- - A list of dictionaries containing facts for MariaDB Firewall Rule.
- returned: always
- type: complex
- contains:
- id:
- description:
- - Resource ID.
- returned: always
- type: str
- sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/TestGroup/providers/Microsoft.DBforMariaDB/servers/testserver/fire
- wallRules/rule1"
- server_name:
- description:
- - The name of the server.
- returned: always
- type: str
- sample: testserver
- name:
- description:
- - Resource name.
- returned: always
- type: str
- sample: rule1
- start_ip_address:
- description:
- - The start IP address of the MariaDB firewall rule.
- returned: always
- type: str
- sample: 10.0.0.16
- end_ip_address:
- description:
- - The end IP address of the MariaDB firewall rule.
- returned: always
- type: str
- sample: 10.0.0.18
-'''
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrestazure.azure_operation import AzureOperationPoller
- from azure.mgmt.rdbms.mariadb import MariaDBManagementClient
- from msrest.serialization import Model
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class AzureRMMariaDbFirewallRuleInfo(AzureRMModuleBase):
- def __init__(self):
- # define user inputs into argument
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- server_name=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str'
- )
- )
- # store the results of the module operation
- self.results = dict(
- changed=False
- )
- self.mgmt_client = None
- self.resource_group = None
- self.server_name = None
- self.name = None
- super(AzureRMMariaDbFirewallRuleInfo, self).__init__(self.module_arg_spec, supports_tags=False)
-
- def exec_module(self, **kwargs):
- is_old_facts = self.module._name == 'azure_rm_mariadbfirewallrule_facts'
- if is_old_facts:
- self.module.deprecate("The 'azure_rm_mariadbfirewallrule_facts' module has been renamed to 'azure_rm_mariadbfirewallrule_info'",
- version='2.13', collection_name='ansible.builtin')
-
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
- self.mgmt_client = self.get_mgmt_svc_client(MariaDBManagementClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
-
- if (self.name is not None):
- self.results['rules'] = self.get()
- else:
- self.results['rules'] = self.list_by_server()
- return self.results
-
- def get(self):
- response = None
- results = []
- try:
- response = self.mgmt_client.firewall_rules.get(resource_group_name=self.resource_group,
- server_name=self.server_name,
- firewall_rule_name=self.name)
- self.log("Response : {0}".format(response))
- except CloudError as e:
- self.log('Could not get facts for FirewallRules.')
-
- if response is not None:
- results.append(self.format_item(response))
-
- return results
-
- def list_by_server(self):
- response = None
- results = []
- try:
- response = self.mgmt_client.firewall_rules.list_by_server(resource_group_name=self.resource_group,
- server_name=self.server_name)
- self.log("Response : {0}".format(response))
- except CloudError as e:
- self.log('Could not get facts for FirewallRules.')
-
- if response is not None:
- for item in response:
- results.append(self.format_item(item))
-
- return results
-
- def format_item(self, item):
- d = item.as_dict()
- d = {
- 'resource_group': self.resource_group,
- 'id': d['id'],
- 'server_name': self.server_name,
- 'name': d['name'],
- 'start_ip_address': d['start_ip_address'],
- 'end_ip_address': d['end_ip_address']
- }
- return d
-
-
-def main():
- AzureRMMariaDbFirewallRuleInfo()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_mariadbserver_info.py b/test/support/integration/plugins/modules/azure_rm_mariadbserver_info.py
deleted file mode 100644
index 464aa4d8a5..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_mariadbserver_info.py
+++ /dev/null
@@ -1,265 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2017 Zim Kalinowski, <zikalino@microsoft.com>
-# Copyright (c) 2019 Matti Ranta, (@techknowlogick)
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_mariadbserver_info
-version_added: "2.9"
-short_description: Get Azure MariaDB Server facts
-description:
- - Get facts of MariaDB Server.
-
-options:
- resource_group:
- description:
- - The name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal.
- required: True
- type: str
- name:
- description:
- - The name of the server.
- type: str
- tags:
- description:
- - Limit results by providing a list of tags. Format tags as 'key' or 'key:value'.
- type: list
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
- - Matti Ranta (@techknowlogick)
-
-'''
-
-EXAMPLES = '''
- - name: Get instance of MariaDB Server
- azure_rm_mariadbserver_info:
- resource_group: myResourceGroup
- name: server_name
-
- - name: List instances of MariaDB Server
- azure_rm_mariadbserver_info:
- resource_group: myResourceGroup
-'''
-
-RETURN = '''
-servers:
- description:
- - A list of dictionaries containing facts for MariaDB servers.
- returned: always
- type: complex
- contains:
- id:
- description:
- - Resource ID.
- returned: always
- type: str
- sample: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.DBforMariaDB/servers/myabdud1223
- resource_group:
- description:
- - Resource group name.
- returned: always
- type: str
- sample: myResourceGroup
- name:
- description:
- - Resource name.
- returned: always
- type: str
- sample: myabdud1223
- location:
- description:
- - The location the resource resides in.
- returned: always
- type: str
- sample: eastus
- sku:
- description:
- - The SKU of the server.
- returned: always
- type: complex
- contains:
- name:
- description:
- - The name of the SKU.
- returned: always
- type: str
- sample: GP_Gen4_2
- tier:
- description:
- - The tier of the particular SKU.
- returned: always
- type: str
- sample: GeneralPurpose
- capacity:
- description:
- - The scale capacity.
- returned: always
- type: int
- sample: 2
- storage_mb:
- description:
- - The maximum storage allowed for a server.
- returned: always
- type: int
- sample: 128000
- enforce_ssl:
- description:
- - Enable SSL enforcement.
- returned: always
- type: bool
- sample: False
- admin_username:
- description:
- - The administrator's login name of a server.
- returned: always
- type: str
- sample: serveradmin
- version:
- description:
- - Server version.
- returned: always
- type: str
- sample: "9.6"
- user_visible_state:
- description:
- - A state of a server that is visible to user.
- returned: always
- type: str
- sample: Ready
- fully_qualified_domain_name:
- description:
- - The fully qualified domain name of a server.
- returned: always
- type: str
- sample: myabdud1223.mys.database.azure.com
- tags:
- description:
- - Tags assigned to the resource. Dictionary of string:string pairs.
- type: dict
- sample: { tag1: abc }
-'''
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from azure.mgmt.rdbms.mariadb import MariaDBManagementClient
- from msrest.serialization import Model
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class AzureRMMariaDbServerInfo(AzureRMModuleBase):
- def __init__(self):
- # define user inputs into argument
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str'
- ),
- tags=dict(
- type='list'
- )
- )
- # store the results of the module operation
- self.results = dict(
- changed=False
- )
- self.resource_group = None
- self.name = None
- self.tags = None
- super(AzureRMMariaDbServerInfo, self).__init__(self.module_arg_spec, supports_tags=False)
-
- def exec_module(self, **kwargs):
- is_old_facts = self.module._name == 'azure_rm_mariadbserver_facts'
- if is_old_facts:
- self.module.deprecate("The 'azure_rm_mariadbserver_facts' module has been renamed to 'azure_rm_mariadbserver_info'",
- version='2.13', collection_name='ansible.builtin')
-
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
-
- if (self.resource_group is not None and
- self.name is not None):
- self.results['servers'] = self.get()
- elif (self.resource_group is not None):
- self.results['servers'] = self.list_by_resource_group()
- return self.results
-
- def get(self):
- response = None
- results = []
- try:
- response = self.mariadb_client.servers.get(resource_group_name=self.resource_group,
- server_name=self.name)
- self.log("Response : {0}".format(response))
- except CloudError as e:
- self.log('Could not get facts for MariaDB Server.')
-
- if response and self.has_tags(response.tags, self.tags):
- results.append(self.format_item(response))
-
- return results
-
- def list_by_resource_group(self):
- response = None
- results = []
- try:
- response = self.mariadb_client.servers.list_by_resource_group(resource_group_name=self.resource_group)
- self.log("Response : {0}".format(response))
- except CloudError as e:
- self.log('Could not get facts for MariaDB Servers.')
-
- if response is not None:
- for item in response:
- if self.has_tags(item.tags, self.tags):
- results.append(self.format_item(item))
-
- return results
-
- def format_item(self, item):
- d = item.as_dict()
- d = {
- 'id': d['id'],
- 'resource_group': self.resource_group,
- 'name': d['name'],
- 'sku': d['sku'],
- 'location': d['location'],
- 'storage_mb': d['storage_profile']['storage_mb'],
- 'version': d['version'],
- 'enforce_ssl': (d['ssl_enforcement'] == 'Enabled'),
- 'admin_username': d['administrator_login'],
- 'user_visible_state': d['user_visible_state'],
- 'fully_qualified_domain_name': d['fully_qualified_domain_name'],
- 'tags': d.get('tags')
- }
-
- return d
-
-
-def main():
- AzureRMMariaDbServerInfo()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_resource.py b/test/support/integration/plugins/modules/azure_rm_resource.py
deleted file mode 100644
index 6ea3e3bb9b..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_resource.py
+++ /dev/null
@@ -1,427 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018 Zim Kalinowski, <zikalino@microsoft.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_resource
-version_added: "2.6"
-short_description: Create any Azure resource
-description:
- - Create, update or delete any Azure resource using Azure REST API.
- - This module gives access to resources that are not supported via Ansible modules.
- - Refer to U(https://docs.microsoft.com/en-us/rest/api/) regarding details related to specific resource REST API.
-
-options:
- url:
- description:
- - Azure RM Resource URL.
- api_version:
- description:
- - Specific API version to be used.
- provider:
- description:
- - Provider type.
- - Required if URL is not specified.
- resource_group:
- description:
- - Resource group to be used.
- - Required if URL is not specified.
- resource_type:
- description:
- - Resource type.
- - Required if URL is not specified.
- resource_name:
- description:
- - Resource name.
- - Required if URL Is not specified.
- subresource:
- description:
- - List of subresources.
- suboptions:
- namespace:
- description:
- - Subresource namespace.
- type:
- description:
- - Subresource type.
- name:
- description:
- - Subresource name.
- body:
- description:
- - The body of the HTTP request/response to the web service.
- method:
- description:
- - The HTTP method of the request or response. It must be uppercase.
- choices:
- - GET
- - PUT
- - POST
- - HEAD
- - PATCH
- - DELETE
- - MERGE
- default: "PUT"
- status_code:
- description:
- - A valid, numeric, HTTP status code that signifies success of the request. Can also be comma separated list of status codes.
- type: list
- default: [ 200, 201, 202 ]
- idempotency:
- description:
- - If enabled, idempotency check will be done by using I(method=GET) first and then comparing with I(body).
- default: no
- type: bool
- polling_timeout:
- description:
- - If enabled, idempotency check will be done by using I(method=GET) first and then comparing with I(body).
- default: 0
- type: int
- version_added: "2.8"
- polling_interval:
- description:
- - If enabled, idempotency check will be done by using I(method=GET) first and then comparing with I(body).
- default: 60
- type: int
- version_added: "2.8"
- state:
- description:
- - Assert the state of the resource. Use C(present) to create or update resource or C(absent) to delete resource.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
-
-'''
-
-EXAMPLES = '''
- - name: Update scaleset info using azure_rm_resource
- azure_rm_resource:
- resource_group: myResourceGroup
- provider: compute
- resource_type: virtualmachinescalesets
- resource_name: myVmss
- api_version: "2017-12-01"
- body: { body }
-'''
-
-RETURN = '''
-response:
- description:
- - Response specific to resource type.
- returned: always
- type: complex
- contains:
- id:
- description:
- - Resource ID.
- type: str
- returned: always
- sample: "/subscriptions/xxxx...xxxx/resourceGroups/v-xisuRG/providers/Microsoft.Storage/storageAccounts/staccb57dc95183"
- kind:
- description:
- - The kind of storage.
- type: str
- returned: always
- sample: Storage
- location:
- description:
- - The resource location, defaults to location of the resource group.
- type: str
- returned: always
- sample: eastus
- name:
- description:
- The storage account name.
- type: str
- returned: always
- sample: staccb57dc95183
- properties:
- description:
- - The storage account's related properties.
- type: dict
- returned: always
- sample: {
- "creationTime": "2019-06-13T06:34:33.0996676Z",
- "encryption": {
- "keySource": "Microsoft.Storage",
- "services": {
- "blob": {
- "enabled": true,
- "lastEnabledTime": "2019-06-13T06:34:33.1934074Z"
- },
- "file": {
- "enabled": true,
- "lastEnabledTime": "2019-06-13T06:34:33.1934074Z"
- }
- }
- },
- "networkAcls": {
- "bypass": "AzureServices",
- "defaultAction": "Allow",
- "ipRules": [],
- "virtualNetworkRules": []
- },
- "primaryEndpoints": {
- "blob": "https://staccb57dc95183.blob.core.windows.net/",
- "file": "https://staccb57dc95183.file.core.windows.net/",
- "queue": "https://staccb57dc95183.queue.core.windows.net/",
- "table": "https://staccb57dc95183.table.core.windows.net/"
- },
- "primaryLocation": "eastus",
- "provisioningState": "Succeeded",
- "secondaryLocation": "westus",
- "statusOfPrimary": "available",
- "statusOfSecondary": "available",
- "supportsHttpsTrafficOnly": false
- }
- sku:
- description:
- - The storage account SKU.
- type: dict
- returned: always
- sample: {
- "name": "Standard_GRS",
- "tier": "Standard"
- }
- tags:
- description:
- - Resource tags.
- type: dict
- returned: always
- sample: { 'key1': 'value1' }
- type:
- description:
- - The resource type.
- type: str
- returned: always
- sample: "Microsoft.Storage/storageAccounts"
-
-'''
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-from ansible.module_utils.azure_rm_common_rest import GenericRestClient
-from ansible.module_utils.common.dict_transformations import dict_merge
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrest.service_client import ServiceClient
- from msrestazure.tools import resource_id, is_valid_resource_id
- import json
-
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class AzureRMResource(AzureRMModuleBase):
- def __init__(self):
- # define user inputs into argument
- self.module_arg_spec = dict(
- url=dict(
- type='str'
- ),
- provider=dict(
- type='str',
- ),
- resource_group=dict(
- type='str',
- ),
- resource_type=dict(
- type='str',
- ),
- resource_name=dict(
- type='str',
- ),
- subresource=dict(
- type='list',
- default=[]
- ),
- api_version=dict(
- type='str'
- ),
- method=dict(
- type='str',
- default='PUT',
- choices=["GET", "PUT", "POST", "HEAD", "PATCH", "DELETE", "MERGE"]
- ),
- body=dict(
- type='raw'
- ),
- status_code=dict(
- type='list',
- default=[200, 201, 202]
- ),
- idempotency=dict(
- type='bool',
- default=False
- ),
- polling_timeout=dict(
- type='int',
- default=0
- ),
- polling_interval=dict(
- type='int',
- default=60
- ),
- state=dict(
- type='str',
- default='present',
- choices=['present', 'absent']
- )
- )
- # store the results of the module operation
- self.results = dict(
- changed=False,
- response=None
- )
- self.mgmt_client = None
- self.url = None
- self.api_version = None
- self.provider = None
- self.resource_group = None
- self.resource_type = None
- self.resource_name = None
- self.subresource_type = None
- self.subresource_name = None
- self.subresource = []
- self.method = None
- self.status_code = []
- self.idempotency = False
- self.polling_timeout = None
- self.polling_interval = None
- self.state = None
- self.body = None
- super(AzureRMResource, self).__init__(self.module_arg_spec, supports_tags=False)
-
- def exec_module(self, **kwargs):
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
- self.mgmt_client = self.get_mgmt_svc_client(GenericRestClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
-
- if self.state == 'absent':
- self.method = 'DELETE'
- self.status_code.append(204)
-
- if self.url is None:
- orphan = None
- rargs = dict()
- rargs['subscription'] = self.subscription_id
- rargs['resource_group'] = self.resource_group
- if not (self.provider is None or self.provider.lower().startswith('.microsoft')):
- rargs['namespace'] = "Microsoft." + self.provider
- else:
- rargs['namespace'] = self.provider
-
- if self.resource_type is not None and self.resource_name is not None:
- rargs['type'] = self.resource_type
- rargs['name'] = self.resource_name
- for i in range(len(self.subresource)):
- resource_ns = self.subresource[i].get('namespace', None)
- resource_type = self.subresource[i].get('type', None)
- resource_name = self.subresource[i].get('name', None)
- if resource_type is not None and resource_name is not None:
- rargs['child_namespace_' + str(i + 1)] = resource_ns
- rargs['child_type_' + str(i + 1)] = resource_type
- rargs['child_name_' + str(i + 1)] = resource_name
- else:
- orphan = resource_type
- else:
- orphan = self.resource_type
-
- self.url = resource_id(**rargs)
-
- if orphan is not None:
- self.url += '/' + orphan
-
- # if api_version was not specified, get latest one
- if not self.api_version:
- try:
- # extract provider and resource type
- if "/providers/" in self.url:
- provider = self.url.split("/providers/")[1].split("/")[0]
- resourceType = self.url.split(provider + "/")[1].split("/")[0]
- url = "/subscriptions/" + self.subscription_id + "/providers/" + provider
- api_versions = json.loads(self.mgmt_client.query(url, "GET", {'api-version': '2015-01-01'}, None, None, [200], 0, 0).text)
- for rt in api_versions['resourceTypes']:
- if rt['resourceType'].lower() == resourceType.lower():
- self.api_version = rt['apiVersions'][0]
- break
- else:
- # if there's no provider in API version, assume Microsoft.Resources
- self.api_version = '2018-05-01'
- if not self.api_version:
- self.fail("Couldn't find api version for {0}/{1}".format(provider, resourceType))
- except Exception as exc:
- self.fail("Failed to obtain API version: {0}".format(str(exc)))
-
- query_parameters = {}
- query_parameters['api-version'] = self.api_version
-
- header_parameters = {}
- header_parameters['Content-Type'] = 'application/json; charset=utf-8'
-
- needs_update = True
- response = None
-
- if self.idempotency:
- original = self.mgmt_client.query(self.url, "GET", query_parameters, None, None, [200, 404], 0, 0)
-
- if original.status_code == 404:
- if self.state == 'absent':
- needs_update = False
- else:
- try:
- response = json.loads(original.text)
- needs_update = (dict_merge(response, self.body) != response)
- except Exception:
- pass
-
- if needs_update:
- response = self.mgmt_client.query(self.url,
- self.method,
- query_parameters,
- header_parameters,
- self.body,
- self.status_code,
- self.polling_timeout,
- self.polling_interval)
- if self.state == 'present':
- try:
- response = json.loads(response.text)
- except Exception:
- response = response.text
- else:
- response = None
-
- self.results['response'] = response
- self.results['changed'] = needs_update
-
- return self.results
-
-
-def main():
- AzureRMResource()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_resource_info.py b/test/support/integration/plugins/modules/azure_rm_resource_info.py
deleted file mode 100644
index f797f66219..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_resource_info.py
+++ /dev/null
@@ -1,432 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018 Zim Kalinowski, <zikalino@microsoft.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_resource_info
-version_added: "2.9"
-short_description: Generic facts of Azure resources
-description:
- - Obtain facts of any resource using Azure REST API.
- - This module gives access to resources that are not supported via Ansible modules.
- - Refer to U(https://docs.microsoft.com/en-us/rest/api/) regarding details related to specific resource REST API.
-
-options:
- url:
- description:
- - Azure RM Resource URL.
- api_version:
- description:
- - Specific API version to be used.
- provider:
- description:
- - Provider type, should be specified in no URL is given.
- resource_group:
- description:
- - Resource group to be used.
- - Required if URL is not specified.
- resource_type:
- description:
- - Resource type.
- resource_name:
- description:
- - Resource name.
- subresource:
- description:
- - List of subresources.
- suboptions:
- namespace:
- description:
- - Subresource namespace.
- type:
- description:
- - Subresource type.
- name:
- description:
- - Subresource name.
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Zim Kalinowski (@zikalino)
-
-'''
-
-EXAMPLES = '''
- - name: Get scaleset info
- azure_rm_resource_info:
- resource_group: myResourceGroup
- provider: compute
- resource_type: virtualmachinescalesets
- resource_name: myVmss
- api_version: "2017-12-01"
-
- - name: Query all the resources in the resource group
- azure_rm_resource_info:
- resource_group: "{{ resource_group }}"
- resource_type: resources
-'''
-
-RETURN = '''
-response:
- description:
- - Response specific to resource type.
- returned: always
- type: complex
- contains:
- id:
- description:
- - Id of the Azure resource.
- type: str
- returned: always
- sample: "/subscriptions/xxxx...xxxx/resourceGroups/v-xisuRG/providers/Microsoft.Compute/virtualMachines/myVM"
- location:
- description:
- - Resource location.
- type: str
- returned: always
- sample: eastus
- name:
- description:
- - Resource name.
- type: str
- returned: always
- sample: myVM
- properties:
- description:
- - Specifies the virtual machine's property.
- type: complex
- returned: always
- contains:
- diagnosticsProfile:
- description:
- - Specifies the boot diagnostic settings state.
- type: complex
- returned: always
- contains:
- bootDiagnostics:
- description:
- - A debugging feature, which to view Console Output and Screenshot to diagnose VM status.
- type: dict
- returned: always
- sample: {
- "enabled": true,
- "storageUri": "https://vxisurgdiag.blob.core.windows.net/"
- }
- hardwareProfile:
- description:
- - Specifies the hardware settings for the virtual machine.
- type: dict
- returned: always
- sample: {
- "vmSize": "Standard_D2s_v3"
- }
- networkProfile:
- description:
- - Specifies the network interfaces of the virtual machine.
- type: complex
- returned: always
- contains:
- networkInterfaces:
- description:
- - Describes a network interface reference.
- type: list
- returned: always
- sample:
- - {
- "id": "/subscriptions/xxxx...xxxx/resourceGroups/v-xisuRG/providers/Microsoft.Network/networkInterfaces/myvm441"
- }
- osProfile:
- description:
- - Specifies the operating system settings for the virtual machine.
- type: complex
- returned: always
- contains:
- adminUsername:
- description:
- - Specifies the name of the administrator account.
- type: str
- returned: always
- sample: azureuser
- allowExtensionOperations:
- description:
- - Specifies whether extension operations should be allowed on the virtual machine.
- - This may only be set to False when no extensions are present on the virtual machine.
- type: bool
- returned: always
- sample: true
- computerName:
- description:
- - Specifies the host OS name of the virtual machine.
- type: str
- returned: always
- sample: myVM
- requireGuestProvisionSignale:
- description:
- - Specifies the host require guest provision signal or not.
- type: bool
- returned: always
- sample: true
- secrets:
- description:
- - Specifies set of certificates that should be installed onto the virtual machine.
- type: list
- returned: always
- sample: []
- linuxConfiguration:
- description:
- - Specifies the Linux operating system settings on the virtual machine.
- type: dict
- returned: when OS type is Linux
- sample: {
- "disablePasswordAuthentication": false,
- "provisionVMAgent": true
- }
- provisioningState:
- description:
- - The provisioning state.
- type: str
- returned: always
- sample: Succeeded
- vmID:
- description:
- - Specifies the VM unique ID which is a 128-bits identifier that is encoded and stored in all Azure laaS VMs SMBIOS.
- - It can be read using platform BIOS commands.
- type: str
- returned: always
- sample: "eb86d9bb-6725-4787-a487-2e497d5b340c"
- storageProfile:
- description:
- - Specifies the storage account type for the managed disk.
- type: complex
- returned: always
- contains:
- dataDisks:
- description:
- - Specifies the parameters that are used to add a data disk to virtual machine.
- type: list
- returned: always
- sample:
- - {
- "caching": "None",
- "createOption": "Attach",
- "diskSizeGB": 1023,
- "lun": 2,
- "managedDisk": {
- "id": "/subscriptions/xxxx....xxxx/resourceGroups/V-XISURG/providers/Microsoft.Compute/disks/testdisk2",
- "storageAccountType": "StandardSSD_LRS"
- },
- "name": "testdisk2"
- }
- - {
- "caching": "None",
- "createOption": "Attach",
- "diskSizeGB": 1023,
- "lun": 1,
- "managedDisk": {
- "id": "/subscriptions/xxxx...xxxx/resourceGroups/V-XISURG/providers/Microsoft.Compute/disks/testdisk3",
- "storageAccountType": "StandardSSD_LRS"
- },
- "name": "testdisk3"
- }
-
- imageReference:
- description:
- - Specifies information about the image to use.
- type: dict
- returned: always
- sample: {
- "offer": "UbuntuServer",
- "publisher": "Canonical",
- "sku": "18.04-LTS",
- "version": "latest"
- }
- osDisk:
- description:
- - Specifies information about the operating system disk used by the virtual machine.
- type: dict
- returned: always
- sample: {
- "caching": "ReadWrite",
- "createOption": "FromImage",
- "diskSizeGB": 30,
- "managedDisk": {
- "id": "/subscriptions/xxx...xxxx/resourceGroups/v-xisuRG/providers/Microsoft.Compute/disks/myVM_disk1_xxx",
- "storageAccountType": "Premium_LRS"
- },
- "name": "myVM_disk1_xxx",
- "osType": "Linux"
- }
- type:
- description:
- - The type of identity used for the virtual machine.
- type: str
- returned: always
- sample: "Microsoft.Compute/virtualMachines"
-'''
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-from ansible.module_utils.azure_rm_common_rest import GenericRestClient
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrest.service_client import ServiceClient
- from msrestazure.tools import resource_id, is_valid_resource_id
- import json
-
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class AzureRMResourceInfo(AzureRMModuleBase):
- def __init__(self):
- # define user inputs into argument
- self.module_arg_spec = dict(
- url=dict(
- type='str'
- ),
- provider=dict(
- type='str'
- ),
- resource_group=dict(
- type='str'
- ),
- resource_type=dict(
- type='str'
- ),
- resource_name=dict(
- type='str'
- ),
- subresource=dict(
- type='list',
- default=[]
- ),
- api_version=dict(
- type='str'
- )
- )
- # store the results of the module operation
- self.results = dict(
- response=[]
- )
- self.mgmt_client = None
- self.url = None
- self.api_version = None
- self.provider = None
- self.resource_group = None
- self.resource_type = None
- self.resource_name = None
- self.subresource = []
- super(AzureRMResourceInfo, self).__init__(self.module_arg_spec, supports_tags=False)
-
- def exec_module(self, **kwargs):
- is_old_facts = self.module._name == 'azure_rm_resource_facts'
- if is_old_facts:
- self.module.deprecate("The 'azure_rm_resource_facts' module has been renamed to 'azure_rm_resource_info'",
- version='2.13', collection_name='ansible.builtin')
-
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
- self.mgmt_client = self.get_mgmt_svc_client(GenericRestClient,
- base_url=self._cloud_environment.endpoints.resource_manager)
-
- if self.url is None:
- orphan = None
- rargs = dict()
- rargs['subscription'] = self.subscription_id
- rargs['resource_group'] = self.resource_group
- if not (self.provider is None or self.provider.lower().startswith('.microsoft')):
- rargs['namespace'] = "Microsoft." + self.provider
- else:
- rargs['namespace'] = self.provider
-
- if self.resource_type is not None and self.resource_name is not None:
- rargs['type'] = self.resource_type
- rargs['name'] = self.resource_name
- for i in range(len(self.subresource)):
- resource_ns = self.subresource[i].get('namespace', None)
- resource_type = self.subresource[i].get('type', None)
- resource_name = self.subresource[i].get('name', None)
- if resource_type is not None and resource_name is not None:
- rargs['child_namespace_' + str(i + 1)] = resource_ns
- rargs['child_type_' + str(i + 1)] = resource_type
- rargs['child_name_' + str(i + 1)] = resource_name
- else:
- orphan = resource_type
- else:
- orphan = self.resource_type
-
- self.url = resource_id(**rargs)
-
- if orphan is not None:
- self.url += '/' + orphan
-
- # if api_version was not specified, get latest one
- if not self.api_version:
- try:
- # extract provider and resource type
- if "/providers/" in self.url:
- provider = self.url.split("/providers/")[1].split("/")[0]
- resourceType = self.url.split(provider + "/")[1].split("/")[0]
- url = "/subscriptions/" + self.subscription_id + "/providers/" + provider
- api_versions = json.loads(self.mgmt_client.query(url, "GET", {'api-version': '2015-01-01'}, None, None, [200], 0, 0).text)
- for rt in api_versions['resourceTypes']:
- if rt['resourceType'].lower() == resourceType.lower():
- self.api_version = rt['apiVersions'][0]
- break
- else:
- # if there's no provider in API version, assume Microsoft.Resources
- self.api_version = '2018-05-01'
- if not self.api_version:
- self.fail("Couldn't find api version for {0}/{1}".format(provider, resourceType))
- except Exception as exc:
- self.fail("Failed to obtain API version: {0}".format(str(exc)))
-
- self.results['url'] = self.url
-
- query_parameters = {}
- query_parameters['api-version'] = self.api_version
-
- header_parameters = {}
- header_parameters['Content-Type'] = 'application/json; charset=utf-8'
- skiptoken = None
-
- while True:
- if skiptoken:
- query_parameters['skiptoken'] = skiptoken
- response = self.mgmt_client.query(self.url, "GET", query_parameters, header_parameters, None, [200, 404], 0, 0)
- try:
- response = json.loads(response.text)
- if isinstance(response, dict):
- if response.get('value'):
- self.results['response'] = self.results['response'] + response['value']
- skiptoken = response.get('nextLink')
- else:
- self.results['response'] = self.results['response'] + [response]
- except Exception as e:
- self.fail('Failed to parse response: ' + str(e))
- if not skiptoken:
- break
- return self.results
-
-
-def main():
- AzureRMResourceInfo()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_storageaccount.py b/test/support/integration/plugins/modules/azure_rm_storageaccount.py
deleted file mode 100644
index d4158bbda8..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_storageaccount.py
+++ /dev/null
@@ -1,684 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2016 Matt Davis, <mdavis@ansible.com>
-# Chris Houseknecht, <house@redhat.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_storageaccount
-version_added: "2.1"
-short_description: Manage Azure storage accounts
-description:
- - Create, update or delete a storage account.
-options:
- resource_group:
- description:
- - Name of the resource group to use.
- required: true
- aliases:
- - resource_group_name
- name:
- description:
- - Name of the storage account to update or create.
- state:
- description:
- - State of the storage account. Use C(present) to create or update a storage account and use C(absent) to delete an account.
- default: present
- choices:
- - absent
- - present
- location:
- description:
- - Valid Azure location. Defaults to location of the resource group.
- account_type:
- description:
- - Type of storage account. Required when creating a storage account.
- - C(Standard_ZRS) and C(Premium_LRS) accounts cannot be changed to other account types.
- - Other account types cannot be changed to C(Standard_ZRS) or C(Premium_LRS).
- choices:
- - Premium_LRS
- - Standard_GRS
- - Standard_LRS
- - StandardSSD_LRS
- - Standard_RAGRS
- - Standard_ZRS
- - Premium_ZRS
- aliases:
- - type
- custom_domain:
- description:
- - User domain assigned to the storage account.
- - Must be a dictionary with I(name) and I(use_sub_domain) keys where I(name) is the CNAME source.
- - Only one custom domain is supported per storage account at this time.
- - To clear the existing custom domain, use an empty string for the custom domain name property.
- - Can be added to an existing storage account. Will be ignored during storage account creation.
- aliases:
- - custom_dns_domain_suffix
- kind:
- description:
- - The kind of storage.
- default: 'Storage'
- choices:
- - Storage
- - StorageV2
- - BlobStorage
- version_added: "2.2"
- access_tier:
- description:
- - The access tier for this storage account. Required when I(kind=BlobStorage).
- choices:
- - Hot
- - Cool
- version_added: "2.4"
- force_delete_nonempty:
- description:
- - Attempt deletion if resource already exists and cannot be updated.
- type: bool
- aliases:
- - force
- https_only:
- description:
- - Allows https traffic only to storage service when set to C(true).
- type: bool
- version_added: "2.8"
- blob_cors:
- description:
- - Specifies CORS rules for the Blob service.
- - You can include up to five CorsRule elements in the request.
- - If no blob_cors elements are included in the argument list, nothing about CORS will be changed.
- - If you want to delete all CORS rules and disable CORS for the Blob service, explicitly set I(blob_cors=[]).
- type: list
- version_added: "2.8"
- suboptions:
- allowed_origins:
- description:
- - A list of origin domains that will be allowed via CORS, or "*" to allow all domains.
- type: list
- required: true
- allowed_methods:
- description:
- - A list of HTTP methods that are allowed to be executed by the origin.
- type: list
- required: true
- max_age_in_seconds:
- description:
- - The number of seconds that the client/browser should cache a preflight response.
- type: int
- required: true
- exposed_headers:
- description:
- - A list of response headers to expose to CORS clients.
- type: list
- required: true
- allowed_headers:
- description:
- - A list of headers allowed to be part of the cross-origin request.
- type: list
- required: true
-
-extends_documentation_fragment:
- - azure
- - azure_tags
-
-author:
- - Chris Houseknecht (@chouseknecht)
- - Matt Davis (@nitzmahone)
-'''
-
-EXAMPLES = '''
- - name: remove account, if it exists
- azure_rm_storageaccount:
- resource_group: myResourceGroup
- name: clh0002
- state: absent
-
- - name: create an account
- azure_rm_storageaccount:
- resource_group: myResourceGroup
- name: clh0002
- type: Standard_RAGRS
- tags:
- testing: testing
- delete: on-exit
-
- - name: create an account with blob CORS
- azure_rm_storageaccount:
- resource_group: myResourceGroup
- name: clh002
- type: Standard_RAGRS
- blob_cors:
- - allowed_origins:
- - http://www.example.com/
- allowed_methods:
- - GET
- - POST
- allowed_headers:
- - x-ms-meta-data*
- - x-ms-meta-target*
- - x-ms-meta-abc
- exposed_headers:
- - x-ms-meta-*
- max_age_in_seconds: 200
-'''
-
-
-RETURN = '''
-state:
- description:
- - Current state of the storage account.
- returned: always
- type: complex
- contains:
- account_type:
- description:
- - Type of storage account.
- returned: always
- type: str
- sample: Standard_RAGRS
- custom_domain:
- description:
- - User domain assigned to the storage account.
- returned: always
- type: complex
- contains:
- name:
- description:
- - CNAME source.
- returned: always
- type: str
- sample: testaccount
- use_sub_domain:
- description:
- - Whether to use sub domain.
- returned: always
- type: bool
- sample: true
- id:
- description:
- - Resource ID.
- returned: always
- type: str
- sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Storage/storageAccounts/clh0003"
- location:
- description:
- - Valid Azure location. Defaults to location of the resource group.
- returned: always
- type: str
- sample: eastus2
- name:
- description:
- - Name of the storage account to update or create.
- returned: always
- type: str
- sample: clh0003
- primary_endpoints:
- description:
- - The URLs to retrieve the public I(blob), I(queue), or I(table) object from the primary location.
- returned: always
- type: dict
- sample: {
- "blob": "https://clh0003.blob.core.windows.net/",
- "queue": "https://clh0003.queue.core.windows.net/",
- "table": "https://clh0003.table.core.windows.net/"
- }
- primary_location:
- description:
- - The location of the primary data center for the storage account.
- returned: always
- type: str
- sample: eastus2
- provisioning_state:
- description:
- - The status of the storage account.
- - Possible values include C(Creating), C(ResolvingDNS), C(Succeeded).
- returned: always
- type: str
- sample: Succeeded
- resource_group:
- description:
- - The resource group's name.
- returned: always
- type: str
- sample: Testing
- secondary_endpoints:
- description:
- - The URLs to retrieve the public I(blob), I(queue), or I(table) object from the secondary location.
- returned: always
- type: dict
- sample: {
- "blob": "https://clh0003-secondary.blob.core.windows.net/",
- "queue": "https://clh0003-secondary.queue.core.windows.net/",
- "table": "https://clh0003-secondary.table.core.windows.net/"
- }
- secondary_location:
- description:
- - The location of the geo-replicated secondary for the storage account.
- returned: always
- type: str
- sample: centralus
- status_of_primary:
- description:
- - The status of the primary location of the storage account; either C(available) or C(unavailable).
- returned: always
- type: str
- sample: available
- status_of_secondary:
- description:
- - The status of the secondary location of the storage account; either C(available) or C(unavailable).
- returned: always
- type: str
- sample: available
- tags:
- description:
- - Resource tags.
- returned: always
- type: dict
- sample: { 'tags1': 'value1' }
- type:
- description:
- - The storage account type.
- returned: always
- type: str
- sample: "Microsoft.Storage/storageAccounts"
-'''
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from azure.storage.cloudstorageaccount import CloudStorageAccount
- from azure.common import AzureMissingResourceHttpError
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-import copy
-from ansible.module_utils.azure_rm_common import AZURE_SUCCESS_STATE, AzureRMModuleBase
-from ansible.module_utils._text import to_native
-
-cors_rule_spec = dict(
- allowed_origins=dict(type='list', elements='str', required=True),
- allowed_methods=dict(type='list', elements='str', required=True),
- max_age_in_seconds=dict(type='int', required=True),
- exposed_headers=dict(type='list', elements='str', required=True),
- allowed_headers=dict(type='list', elements='str', required=True),
-)
-
-
-def compare_cors(cors1, cors2):
- if len(cors1) != len(cors2):
- return False
- copy2 = copy.copy(cors2)
- for rule1 in cors1:
- matched = False
- for rule2 in copy2:
- if (rule1['max_age_in_seconds'] == rule2['max_age_in_seconds']
- and set(rule1['allowed_methods']) == set(rule2['allowed_methods'])
- and set(rule1['allowed_origins']) == set(rule2['allowed_origins'])
- and set(rule1['allowed_headers']) == set(rule2['allowed_headers'])
- and set(rule1['exposed_headers']) == set(rule2['exposed_headers'])):
- matched = True
- copy2.remove(rule2)
- if not matched:
- return False
- return True
-
-
-class AzureRMStorageAccount(AzureRMModuleBase):
-
- def __init__(self):
-
- self.module_arg_spec = dict(
- account_type=dict(type='str',
- choices=['Premium_LRS', 'Standard_GRS', 'Standard_LRS', 'StandardSSD_LRS', 'Standard_RAGRS', 'Standard_ZRS', 'Premium_ZRS'],
- aliases=['type']),
- custom_domain=dict(type='dict', aliases=['custom_dns_domain_suffix']),
- location=dict(type='str'),
- name=dict(type='str', required=True),
- resource_group=dict(required=True, type='str', aliases=['resource_group_name']),
- state=dict(default='present', choices=['present', 'absent']),
- force_delete_nonempty=dict(type='bool', default=False, aliases=['force']),
- tags=dict(type='dict'),
- kind=dict(type='str', default='Storage', choices=['Storage', 'StorageV2', 'BlobStorage']),
- access_tier=dict(type='str', choices=['Hot', 'Cool']),
- https_only=dict(type='bool', default=False),
- blob_cors=dict(type='list', options=cors_rule_spec, elements='dict')
- )
-
- self.results = dict(
- changed=False,
- state=dict()
- )
-
- self.account_dict = None
- self.resource_group = None
- self.name = None
- self.state = None
- self.location = None
- self.account_type = None
- self.custom_domain = None
- self.tags = None
- self.force_delete_nonempty = None
- self.kind = None
- self.access_tier = None
- self.https_only = None
- self.blob_cors = None
-
- super(AzureRMStorageAccount, self).__init__(self.module_arg_spec,
- supports_check_mode=True)
-
- def exec_module(self, **kwargs):
-
- for key in list(self.module_arg_spec.keys()) + ['tags']:
- setattr(self, key, kwargs[key])
-
- resource_group = self.get_resource_group(self.resource_group)
- if not self.location:
- # Set default location
- self.location = resource_group.location
-
- if len(self.name) < 3 or len(self.name) > 24:
- self.fail("Parameter error: name length must be between 3 and 24 characters.")
-
- if self.custom_domain:
- if self.custom_domain.get('name', None) is None:
- self.fail("Parameter error: expecting custom_domain to have a name attribute of type string.")
- if self.custom_domain.get('use_sub_domain', None) is None:
- self.fail("Parameter error: expecting custom_domain to have a use_sub_domain "
- "attribute of type boolean.")
-
- self.account_dict = self.get_account()
-
- if self.state == 'present' and self.account_dict and \
- self.account_dict['provisioning_state'] != AZURE_SUCCESS_STATE:
- self.fail("Error: storage account {0} has not completed provisioning. State is {1}. Expecting state "
- "to be {2}.".format(self.name, self.account_dict['provisioning_state'], AZURE_SUCCESS_STATE))
-
- if self.account_dict is not None:
- self.results['state'] = self.account_dict
- else:
- self.results['state'] = dict()
-
- if self.state == 'present':
- if not self.account_dict:
- self.results['state'] = self.create_account()
- else:
- self.update_account()
- elif self.state == 'absent' and self.account_dict:
- self.delete_account()
- self.results['state'] = dict(Status='Deleted')
-
- return self.results
-
- def check_name_availability(self):
- self.log('Checking name availability for {0}'.format(self.name))
- try:
- response = self.storage_client.storage_accounts.check_name_availability(self.name)
- except CloudError as e:
- self.log('Error attempting to validate name.')
- self.fail("Error checking name availability: {0}".format(str(e)))
- if not response.name_available:
- self.log('Error name not available.')
- self.fail("{0} - {1}".format(response.message, response.reason))
-
- def get_account(self):
- self.log('Get properties for account {0}'.format(self.name))
- account_obj = None
- blob_service_props = None
- account_dict = None
-
- try:
- account_obj = self.storage_client.storage_accounts.get_properties(self.resource_group, self.name)
- blob_service_props = self.storage_client.blob_services.get_service_properties(self.resource_group, self.name)
- except CloudError:
- pass
-
- if account_obj:
- account_dict = self.account_obj_to_dict(account_obj, blob_service_props)
-
- return account_dict
-
- def account_obj_to_dict(self, account_obj, blob_service_props=None):
- account_dict = dict(
- id=account_obj.id,
- name=account_obj.name,
- location=account_obj.location,
- resource_group=self.resource_group,
- type=account_obj.type,
- access_tier=(account_obj.access_tier.value
- if account_obj.access_tier is not None else None),
- sku_tier=account_obj.sku.tier.value,
- sku_name=account_obj.sku.name.value,
- provisioning_state=account_obj.provisioning_state.value,
- secondary_location=account_obj.secondary_location,
- status_of_primary=(account_obj.status_of_primary.value
- if account_obj.status_of_primary is not None else None),
- status_of_secondary=(account_obj.status_of_secondary.value
- if account_obj.status_of_secondary is not None else None),
- primary_location=account_obj.primary_location,
- https_only=account_obj.enable_https_traffic_only
- )
- account_dict['custom_domain'] = None
- if account_obj.custom_domain:
- account_dict['custom_domain'] = dict(
- name=account_obj.custom_domain.name,
- use_sub_domain=account_obj.custom_domain.use_sub_domain
- )
-
- account_dict['primary_endpoints'] = None
- if account_obj.primary_endpoints:
- account_dict['primary_endpoints'] = dict(
- blob=account_obj.primary_endpoints.blob,
- queue=account_obj.primary_endpoints.queue,
- table=account_obj.primary_endpoints.table
- )
- account_dict['secondary_endpoints'] = None
- if account_obj.secondary_endpoints:
- account_dict['secondary_endpoints'] = dict(
- blob=account_obj.secondary_endpoints.blob,
- queue=account_obj.secondary_endpoints.queue,
- table=account_obj.secondary_endpoints.table
- )
- account_dict['tags'] = None
- if account_obj.tags:
- account_dict['tags'] = account_obj.tags
- if blob_service_props and blob_service_props.cors and blob_service_props.cors.cors_rules:
- account_dict['blob_cors'] = [dict(
- allowed_origins=[to_native(y) for y in x.allowed_origins],
- allowed_methods=[to_native(y) for y in x.allowed_methods],
- max_age_in_seconds=x.max_age_in_seconds,
- exposed_headers=[to_native(y) for y in x.exposed_headers],
- allowed_headers=[to_native(y) for y in x.allowed_headers]
- ) for x in blob_service_props.cors.cors_rules]
- return account_dict
-
- def update_account(self):
- self.log('Update storage account {0}'.format(self.name))
- if bool(self.https_only) != bool(self.account_dict.get('https_only')):
- self.results['changed'] = True
- self.account_dict['https_only'] = self.https_only
- if not self.check_mode:
- try:
- parameters = self.storage_models.StorageAccountUpdateParameters(enable_https_traffic_only=self.https_only)
- self.storage_client.storage_accounts.update(self.resource_group,
- self.name,
- parameters)
- except Exception as exc:
- self.fail("Failed to update account type: {0}".format(str(exc)))
-
- if self.account_type:
- if self.account_type != self.account_dict['sku_name']:
- # change the account type
- SkuName = self.storage_models.SkuName
- if self.account_dict['sku_name'] in [SkuName.premium_lrs, SkuName.standard_zrs]:
- self.fail("Storage accounts of type {0} and {1} cannot be changed.".format(
- SkuName.premium_lrs, SkuName.standard_zrs))
- if self.account_type in [SkuName.premium_lrs, SkuName.standard_zrs]:
- self.fail("Storage account of type {0} cannot be changed to a type of {1} or {2}.".format(
- self.account_dict['sku_name'], SkuName.premium_lrs, SkuName.standard_zrs))
-
- self.results['changed'] = True
- self.account_dict['sku_name'] = self.account_type
-
- if self.results['changed'] and not self.check_mode:
- # Perform the update. The API only allows changing one attribute per call.
- try:
- self.log("sku_name: %s" % self.account_dict['sku_name'])
- self.log("sku_tier: %s" % self.account_dict['sku_tier'])
- sku = self.storage_models.Sku(name=SkuName(self.account_dict['sku_name']))
- sku.tier = self.storage_models.SkuTier(self.account_dict['sku_tier'])
- parameters = self.storage_models.StorageAccountUpdateParameters(sku=sku)
- self.storage_client.storage_accounts.update(self.resource_group,
- self.name,
- parameters)
- except Exception as exc:
- self.fail("Failed to update account type: {0}".format(str(exc)))
-
- if self.custom_domain:
- if not self.account_dict['custom_domain'] or self.account_dict['custom_domain'] != self.custom_domain:
- self.results['changed'] = True
- self.account_dict['custom_domain'] = self.custom_domain
-
- if self.results['changed'] and not self.check_mode:
- new_domain = self.storage_models.CustomDomain(name=self.custom_domain['name'],
- use_sub_domain=self.custom_domain['use_sub_domain'])
- parameters = self.storage_models.StorageAccountUpdateParameters(custom_domain=new_domain)
- try:
- self.storage_client.storage_accounts.update(self.resource_group, self.name, parameters)
- except Exception as exc:
- self.fail("Failed to update custom domain: {0}".format(str(exc)))
-
- if self.access_tier:
- if not self.account_dict['access_tier'] or self.account_dict['access_tier'] != self.access_tier:
- self.results['changed'] = True
- self.account_dict['access_tier'] = self.access_tier
-
- if self.results['changed'] and not self.check_mode:
- parameters = self.storage_models.StorageAccountUpdateParameters(access_tier=self.access_tier)
- try:
- self.storage_client.storage_accounts.update(self.resource_group, self.name, parameters)
- except Exception as exc:
- self.fail("Failed to update access tier: {0}".format(str(exc)))
-
- update_tags, self.account_dict['tags'] = self.update_tags(self.account_dict['tags'])
- if update_tags:
- self.results['changed'] = True
- if not self.check_mode:
- parameters = self.storage_models.StorageAccountUpdateParameters(tags=self.account_dict['tags'])
- try:
- self.storage_client.storage_accounts.update(self.resource_group, self.name, parameters)
- except Exception as exc:
- self.fail("Failed to update tags: {0}".format(str(exc)))
-
- if self.blob_cors and not compare_cors(self.account_dict.get('blob_cors', []), self.blob_cors):
- self.results['changed'] = True
- if not self.check_mode:
- self.set_blob_cors()
-
- def create_account(self):
- self.log("Creating account {0}".format(self.name))
-
- if not self.location:
- self.fail('Parameter error: location required when creating a storage account.')
-
- if not self.account_type:
- self.fail('Parameter error: account_type required when creating a storage account.')
-
- if not self.access_tier and self.kind == 'BlobStorage':
- self.fail('Parameter error: access_tier required when creating a storage account of type BlobStorage.')
-
- self.check_name_availability()
- self.results['changed'] = True
-
- if self.check_mode:
- account_dict = dict(
- location=self.location,
- account_type=self.account_type,
- name=self.name,
- resource_group=self.resource_group,
- enable_https_traffic_only=self.https_only,
- tags=dict()
- )
- if self.tags:
- account_dict['tags'] = self.tags
- if self.blob_cors:
- account_dict['blob_cors'] = self.blob_cors
- return account_dict
- sku = self.storage_models.Sku(name=self.storage_models.SkuName(self.account_type))
- sku.tier = self.storage_models.SkuTier.standard if 'Standard' in self.account_type else \
- self.storage_models.SkuTier.premium
- parameters = self.storage_models.StorageAccountCreateParameters(sku=sku,
- kind=self.kind,
- location=self.location,
- tags=self.tags,
- access_tier=self.access_tier)
- self.log(str(parameters))
- try:
- poller = self.storage_client.storage_accounts.create(self.resource_group, self.name, parameters)
- self.get_poller_result(poller)
- except CloudError as e:
- self.log('Error creating storage account.')
- self.fail("Failed to create account: {0}".format(str(e)))
- if self.blob_cors:
- self.set_blob_cors()
- # the poller doesn't actually return anything
- return self.get_account()
-
- def delete_account(self):
- if self.account_dict['provisioning_state'] == self.storage_models.ProvisioningState.succeeded.value and \
- not self.force_delete_nonempty and self.account_has_blob_containers():
- self.fail("Account contains blob containers. Is it in use? Use the force_delete_nonempty option to attempt deletion.")
-
- self.log('Delete storage account {0}'.format(self.name))
- self.results['changed'] = True
- if not self.check_mode:
- try:
- status = self.storage_client.storage_accounts.delete(self.resource_group, self.name)
- self.log("delete status: ")
- self.log(str(status))
- except CloudError as e:
- self.fail("Failed to delete the account: {0}".format(str(e)))
- return True
-
- def account_has_blob_containers(self):
- '''
- If there are blob containers, then there are likely VMs depending on this account and it should
- not be deleted.
- '''
- self.log('Checking for existing blob containers')
- blob_service = self.get_blob_client(self.resource_group, self.name)
- try:
- response = blob_service.list_containers()
- except AzureMissingResourceHttpError:
- # No blob storage available?
- return False
-
- if len(response.items) > 0:
- return True
- return False
-
- def set_blob_cors(self):
- try:
- cors_rules = self.storage_models.CorsRules(cors_rules=[self.storage_models.CorsRule(**x) for x in self.blob_cors])
- self.storage_client.blob_services.set_service_properties(self.resource_group,
- self.name,
- self.storage_models.BlobServiceProperties(cors=cors_rules))
- except Exception as exc:
- self.fail("Failed to set CORS rules: {0}".format(str(exc)))
-
-
-def main():
- AzureRMStorageAccount()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_webapp.py b/test/support/integration/plugins/modules/azure_rm_webapp.py
deleted file mode 100644
index 4f185f4580..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_webapp.py
+++ /dev/null
@@ -1,1070 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018 Yunge Zhu, <yungez@microsoft.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_webapp
-version_added: "2.7"
-short_description: Manage Web App instances
-description:
- - Create, update and delete instance of Web App.
-
-options:
- resource_group:
- description:
- - Name of the resource group to which the resource belongs.
- required: True
- name:
- description:
- - Unique name of the app to create or update. To create or update a deployment slot, use the {slot} parameter.
- required: True
-
- location:
- description:
- - Resource location. If not set, location from the resource group will be used as default.
-
- plan:
- description:
- - App service plan. Required for creation.
- - Can be name of existing app service plan in same resource group as web app.
- - Can be the resource ID of an existing app service plan. For example
- /subscriptions/<subs_id>/resourceGroups/<resource_group>/providers/Microsoft.Web/serverFarms/<plan_name>.
- - Can be a dict containing five parameters, defined below.
- - C(name), name of app service plan.
- - C(resource_group), resource group of the app service plan.
- - C(sku), SKU of app service plan, allowed values listed on U(https://azure.microsoft.com/en-us/pricing/details/app-service/linux/).
- - C(is_linux), whether or not the app service plan is Linux. defaults to C(False).
- - C(number_of_workers), number of workers for app service plan.
-
- frameworks:
- description:
- - Set of run time framework settings. Each setting is a dictionary.
- - See U(https://docs.microsoft.com/en-us/azure/app-service/app-service-web-overview) for more info.
- suboptions:
- name:
- description:
- - Name of the framework.
- - Supported framework list for Windows web app and Linux web app is different.
- - Windows web apps support C(java), C(net_framework), C(php), C(python), and C(node) from June 2018.
- - Windows web apps support multiple framework at the same time.
- - Linux web apps support C(java), C(ruby), C(php), C(dotnetcore), and C(node) from June 2018.
- - Linux web apps support only one framework.
- - Java framework is mutually exclusive with others.
- choices:
- - java
- - net_framework
- - php
- - python
- - ruby
- - dotnetcore
- - node
- version:
- description:
- - Version of the framework. For Linux web app supported value, see U(https://aka.ms/linux-stacks) for more info.
- - C(net_framework) supported value sample, C(v4.0) for .NET 4.6 and C(v3.0) for .NET 3.5.
- - C(php) supported value sample, C(5.5), C(5.6), C(7.0).
- - C(python) supported value sample, C(5.5), C(5.6), C(7.0).
- - C(node) supported value sample, C(6.6), C(6.9).
- - C(dotnetcore) supported value sample, C(1.0), C(1.1), C(1.2).
- - C(ruby) supported value sample, C(2.3).
- - C(java) supported value sample, C(1.9) for Windows web app. C(1.8) for Linux web app.
- settings:
- description:
- - List of settings of the framework.
- suboptions:
- java_container:
- description:
- - Name of Java container.
- - Supported only when I(frameworks=java). Sample values C(Tomcat), C(Jetty).
- java_container_version:
- description:
- - Version of Java container.
- - Supported only when I(frameworks=java).
- - Sample values for C(Tomcat), C(8.0), C(8.5), C(9.0). For C(Jetty,), C(9.1), C(9.3).
-
- container_settings:
- description:
- - Web app container settings.
- suboptions:
- name:
- description:
- - Name of container, for example C(imagename:tag).
- registry_server_url:
- description:
- - Container registry server URL, for example C(mydockerregistry.io).
- registry_server_user:
- description:
- - The container registry server user name.
- registry_server_password:
- description:
- - The container registry server password.
-
- scm_type:
- description:
- - Repository type of deployment source, for example C(LocalGit), C(GitHub).
- - List of supported values maintained at U(https://docs.microsoft.com/en-us/rest/api/appservice/webapps/createorupdate#scmtype).
-
- deployment_source:
- description:
- - Deployment source for git.
- suboptions:
- url:
- description:
- - Repository url of deployment source.
-
- branch:
- description:
- - The branch name of the repository.
- startup_file:
- description:
- - The web's startup file.
- - Used only for Linux web apps.
-
- client_affinity_enabled:
- description:
- - Whether or not to send session affinity cookies, which route client requests in the same session to the same instance.
- type: bool
- default: True
-
- https_only:
- description:
- - Configures web site to accept only https requests.
- type: bool
-
- dns_registration:
- description:
- - Whether or not the web app hostname is registered with DNS on creation. Set to C(false) to register.
- type: bool
-
- skip_custom_domain_verification:
- description:
- - Whether or not to skip verification of custom (non *.azurewebsites.net) domains associated with web app. Set to C(true) to skip.
- type: bool
-
- ttl_in_seconds:
- description:
- - Time to live in seconds for web app default domain name.
-
- app_settings:
- description:
- - Configure web app application settings. Suboptions are in key value pair format.
-
- purge_app_settings:
- description:
- - Purge any existing application settings. Replace web app application settings with app_settings.
- type: bool
-
- app_state:
- description:
- - Start/Stop/Restart the web app.
- type: str
- choices:
- - started
- - stopped
- - restarted
- default: started
-
- state:
- description:
- - State of the Web App.
- - Use C(present) to create or update a Web App and C(absent) to delete it.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
- - azure_tags
-
-author:
- - Yunge Zhu (@yungezz)
-
-'''
-
-EXAMPLES = '''
- - name: Create a windows web app with non-exist app service plan
- azure_rm_webapp:
- resource_group: myResourceGroup
- name: myWinWebapp
- plan:
- resource_group: myAppServicePlan_rg
- name: myAppServicePlan
- is_linux: false
- sku: S1
-
- - name: Create a docker web app with some app settings, with docker image
- azure_rm_webapp:
- resource_group: myResourceGroup
- name: myDockerWebapp
- plan:
- resource_group: myAppServicePlan_rg
- name: myAppServicePlan
- is_linux: true
- sku: S1
- number_of_workers: 2
- app_settings:
- testkey: testvalue
- testkey2: testvalue2
- container_settings:
- name: ansible/ansible:ubuntu1404
-
- - name: Create a docker web app with private acr registry
- azure_rm_webapp:
- resource_group: myResourceGroup
- name: myDockerWebapp
- plan: myAppServicePlan
- app_settings:
- testkey: testvalue
- container_settings:
- name: ansible/ubuntu1404
- registry_server_url: myregistry.io
- registry_server_user: user
- registry_server_password: pass
-
- - name: Create a linux web app with Node 6.6 framework
- azure_rm_webapp:
- resource_group: myResourceGroup
- name: myLinuxWebapp
- plan:
- resource_group: myAppServicePlan_rg
- name: myAppServicePlan
- app_settings:
- testkey: testvalue
- frameworks:
- - name: "node"
- version: "6.6"
-
- - name: Create a windows web app with node, php
- azure_rm_webapp:
- resource_group: myResourceGroup
- name: myWinWebapp
- plan:
- resource_group: myAppServicePlan_rg
- name: myAppServicePlan
- app_settings:
- testkey: testvalue
- frameworks:
- - name: "node"
- version: 6.6
- - name: "php"
- version: "7.0"
-
- - name: Create a stage deployment slot for an existing web app
- azure_rm_webapp:
- resource_group: myResourceGroup
- name: myWebapp/slots/stage
- plan:
- resource_group: myAppServicePlan_rg
- name: myAppServicePlan
- app_settings:
- testkey:testvalue
-
- - name: Create a linux web app with java framework
- azure_rm_webapp:
- resource_group: myResourceGroup
- name: myLinuxWebapp
- plan:
- resource_group: myAppServicePlan_rg
- name: myAppServicePlan
- app_settings:
- testkey: testvalue
- frameworks:
- - name: "java"
- version: "8"
- settings:
- java_container: "Tomcat"
- java_container_version: "8.5"
-'''
-
-RETURN = '''
-azure_webapp:
- description:
- - ID of current web app.
- returned: always
- type: str
- sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Web/sites/myWebApp"
-'''
-
-import time
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrest.polling import LROPoller
- from msrest.serialization import Model
- from azure.mgmt.web.models import (
- site_config, app_service_plan, Site,
- AppServicePlan, SkuDescription, NameValuePair
- )
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-container_settings_spec = dict(
- name=dict(type='str', required=True),
- registry_server_url=dict(type='str'),
- registry_server_user=dict(type='str'),
- registry_server_password=dict(type='str', no_log=True)
-)
-
-deployment_source_spec = dict(
- url=dict(type='str'),
- branch=dict(type='str')
-)
-
-
-framework_settings_spec = dict(
- java_container=dict(type='str', required=True),
- java_container_version=dict(type='str', required=True)
-)
-
-
-framework_spec = dict(
- name=dict(
- type='str',
- required=True,
- choices=['net_framework', 'java', 'php', 'node', 'python', 'dotnetcore', 'ruby']),
- version=dict(type='str', required=True),
- settings=dict(type='dict', options=framework_settings_spec)
-)
-
-
-def _normalize_sku(sku):
- if sku is None:
- return sku
-
- sku = sku.upper()
- if sku == 'FREE':
- return 'F1'
- elif sku == 'SHARED':
- return 'D1'
- return sku
-
-
-def get_sku_name(tier):
- tier = tier.upper()
- if tier == 'F1' or tier == "FREE":
- return 'FREE'
- elif tier == 'D1' or tier == "SHARED":
- return 'SHARED'
- elif tier in ['B1', 'B2', 'B3', 'BASIC']:
- return 'BASIC'
- elif tier in ['S1', 'S2', 'S3']:
- return 'STANDARD'
- elif tier in ['P1', 'P2', 'P3']:
- return 'PREMIUM'
- elif tier in ['P1V2', 'P2V2', 'P3V2']:
- return 'PREMIUMV2'
- else:
- return None
-
-
-def appserviceplan_to_dict(plan):
- return dict(
- id=plan.id,
- name=plan.name,
- kind=plan.kind,
- location=plan.location,
- reserved=plan.reserved,
- is_linux=plan.reserved,
- provisioning_state=plan.provisioning_state,
- tags=plan.tags if plan.tags else None
- )
-
-
-def webapp_to_dict(webapp):
- return dict(
- id=webapp.id,
- name=webapp.name,
- location=webapp.location,
- client_cert_enabled=webapp.client_cert_enabled,
- enabled=webapp.enabled,
- reserved=webapp.reserved,
- client_affinity_enabled=webapp.client_affinity_enabled,
- server_farm_id=webapp.server_farm_id,
- host_names_disabled=webapp.host_names_disabled,
- https_only=webapp.https_only if hasattr(webapp, 'https_only') else None,
- skip_custom_domain_verification=webapp.skip_custom_domain_verification if hasattr(webapp, 'skip_custom_domain_verification') else None,
- ttl_in_seconds=webapp.ttl_in_seconds if hasattr(webapp, 'ttl_in_seconds') else None,
- state=webapp.state,
- tags=webapp.tags if webapp.tags else None
- )
-
-
-class Actions:
- CreateOrUpdate, UpdateAppSettings, Delete = range(3)
-
-
-class AzureRMWebApps(AzureRMModuleBase):
- """Configuration class for an Azure RM Web App resource"""
-
- def __init__(self):
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str',
- required=True
- ),
- location=dict(
- type='str'
- ),
- plan=dict(
- type='raw'
- ),
- frameworks=dict(
- type='list',
- elements='dict',
- options=framework_spec
- ),
- container_settings=dict(
- type='dict',
- options=container_settings_spec
- ),
- scm_type=dict(
- type='str',
- ),
- deployment_source=dict(
- type='dict',
- options=deployment_source_spec
- ),
- startup_file=dict(
- type='str'
- ),
- client_affinity_enabled=dict(
- type='bool',
- default=True
- ),
- dns_registration=dict(
- type='bool'
- ),
- https_only=dict(
- type='bool'
- ),
- skip_custom_domain_verification=dict(
- type='bool'
- ),
- ttl_in_seconds=dict(
- type='int'
- ),
- app_settings=dict(
- type='dict'
- ),
- purge_app_settings=dict(
- type='bool',
- default=False
- ),
- app_state=dict(
- type='str',
- choices=['started', 'stopped', 'restarted'],
- default='started'
- ),
- state=dict(
- type='str',
- default='present',
- choices=['present', 'absent']
- )
- )
-
- mutually_exclusive = [['container_settings', 'frameworks']]
-
- self.resource_group = None
- self.name = None
- self.location = None
-
- # update in create_or_update as parameters
- self.client_affinity_enabled = True
- self.dns_registration = None
- self.skip_custom_domain_verification = None
- self.ttl_in_seconds = None
- self.https_only = None
-
- self.tags = None
-
- # site config, e.g app settings, ssl
- self.site_config = dict()
- self.app_settings = dict()
- self.app_settings_strDic = None
-
- # app service plan
- self.plan = None
-
- # siteSourceControl
- self.deployment_source = dict()
-
- # site, used at level creation, or update. e.g windows/linux, client_affinity etc first level args
- self.site = None
-
- # property for internal usage, not used for sdk
- self.container_settings = None
-
- self.purge_app_settings = False
- self.app_state = 'started'
-
- self.results = dict(
- changed=False,
- id=None,
- )
- self.state = None
- self.to_do = []
-
- self.frameworks = None
-
- # set site_config value from kwargs
- self.site_config_updatable_properties = ["net_framework_version",
- "java_version",
- "php_version",
- "python_version",
- "scm_type"]
-
- # updatable_properties
- self.updatable_properties = ["client_affinity_enabled",
- "force_dns_registration",
- "https_only",
- "skip_custom_domain_verification",
- "ttl_in_seconds"]
-
- self.supported_linux_frameworks = ['ruby', 'php', 'dotnetcore', 'node', 'java']
- self.supported_windows_frameworks = ['net_framework', 'php', 'python', 'node', 'java']
-
- super(AzureRMWebApps, self).__init__(derived_arg_spec=self.module_arg_spec,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True,
- supports_tags=True)
-
- def exec_module(self, **kwargs):
- """Main module execution method"""
-
- for key in list(self.module_arg_spec.keys()) + ['tags']:
- if hasattr(self, key):
- setattr(self, key, kwargs[key])
- elif kwargs[key] is not None:
- if key == "scm_type":
- self.site_config[key] = kwargs[key]
-
- old_response = None
- response = None
- to_be_updated = False
-
- # set location
- resource_group = self.get_resource_group(self.resource_group)
- if not self.location:
- self.location = resource_group.location
-
- # get existing web app
- old_response = self.get_webapp()
-
- if old_response:
- self.results['id'] = old_response['id']
-
- if self.state == 'present':
- if not self.plan and not old_response:
- self.fail("Please specify plan for newly created web app.")
-
- if not self.plan:
- self.plan = old_response['server_farm_id']
-
- self.plan = self.parse_resource_to_dict(self.plan)
-
- # get app service plan
- is_linux = False
- old_plan = self.get_app_service_plan()
- if old_plan:
- is_linux = old_plan['reserved']
- else:
- is_linux = self.plan['is_linux'] if 'is_linux' in self.plan else False
-
- if self.frameworks:
- # java is mutually exclusive with other frameworks
- if len(self.frameworks) > 1 and any(f['name'] == 'java' for f in self.frameworks):
- self.fail('Java is mutually exclusive with other frameworks.')
-
- if is_linux:
- if len(self.frameworks) != 1:
- self.fail('Can specify one framework only for Linux web app.')
-
- if self.frameworks[0]['name'] not in self.supported_linux_frameworks:
- self.fail('Unsupported framework {0} for Linux web app.'.format(self.frameworks[0]['name']))
-
- self.site_config['linux_fx_version'] = (self.frameworks[0]['name'] + '|' + self.frameworks[0]['version']).upper()
-
- if self.frameworks[0]['name'] == 'java':
- if self.frameworks[0]['version'] != '8':
- self.fail("Linux web app only supports java 8.")
- if self.frameworks[0]['settings'] and self.frameworks[0]['settings']['java_container'].lower() != 'tomcat':
- self.fail("Linux web app only supports tomcat container.")
-
- if self.frameworks[0]['settings'] and self.frameworks[0]['settings']['java_container'].lower() == 'tomcat':
- self.site_config['linux_fx_version'] = 'TOMCAT|' + self.frameworks[0]['settings']['java_container_version'] + '-jre8'
- else:
- self.site_config['linux_fx_version'] = 'JAVA|8-jre8'
- else:
- for fx in self.frameworks:
- if fx.get('name') not in self.supported_windows_frameworks:
- self.fail('Unsupported framework {0} for Windows web app.'.format(fx.get('name')))
- else:
- self.site_config[fx.get('name') + '_version'] = fx.get('version')
-
- if 'settings' in fx and fx['settings'] is not None:
- for key, value in fx['settings'].items():
- self.site_config[key] = value
-
- if not self.app_settings:
- self.app_settings = dict()
-
- if self.container_settings:
- linux_fx_version = 'DOCKER|'
-
- if self.container_settings.get('registry_server_url'):
- self.app_settings['DOCKER_REGISTRY_SERVER_URL'] = 'https://' + self.container_settings['registry_server_url']
-
- linux_fx_version += self.container_settings['registry_server_url'] + '/'
-
- linux_fx_version += self.container_settings['name']
-
- self.site_config['linux_fx_version'] = linux_fx_version
-
- if self.container_settings.get('registry_server_user'):
- self.app_settings['DOCKER_REGISTRY_SERVER_USERNAME'] = self.container_settings['registry_server_user']
-
- if self.container_settings.get('registry_server_password'):
- self.app_settings['DOCKER_REGISTRY_SERVER_PASSWORD'] = self.container_settings['registry_server_password']
-
- # init site
- self.site = Site(location=self.location, site_config=self.site_config)
-
- if self.https_only is not None:
- self.site.https_only = self.https_only
-
- if self.client_affinity_enabled:
- self.site.client_affinity_enabled = self.client_affinity_enabled
-
- # check if the web app already present in the resource group
- if not old_response:
- self.log("Web App instance doesn't exist")
-
- to_be_updated = True
- self.to_do.append(Actions.CreateOrUpdate)
- self.site.tags = self.tags
-
- # service plan is required for creation
- if not self.plan:
- self.fail("Please specify app service plan in plan parameter.")
-
- if not old_plan:
- # no existing service plan, create one
- if (not self.plan.get('name') or not self.plan.get('sku')):
- self.fail('Please specify name, is_linux, sku in plan')
-
- if 'location' not in self.plan:
- plan_resource_group = self.get_resource_group(self.plan['resource_group'])
- self.plan['location'] = plan_resource_group.location
-
- old_plan = self.create_app_service_plan()
-
- self.site.server_farm_id = old_plan['id']
-
- # if linux, setup startup_file
- if old_plan['is_linux']:
- if hasattr(self, 'startup_file'):
- self.site_config['app_command_line'] = self.startup_file
-
- # set app setting
- if self.app_settings:
- app_settings = []
- for key in self.app_settings.keys():
- app_settings.append(NameValuePair(name=key, value=self.app_settings[key]))
-
- self.site_config['app_settings'] = app_settings
- else:
- # existing web app, do update
- self.log("Web App instance already exists")
-
- self.log('Result: {0}'.format(old_response))
-
- update_tags, self.site.tags = self.update_tags(old_response.get('tags', None))
-
- if update_tags:
- to_be_updated = True
-
- # check if root level property changed
- if self.is_updatable_property_changed(old_response):
- to_be_updated = True
- self.to_do.append(Actions.CreateOrUpdate)
-
- # check if site_config changed
- old_config = self.get_webapp_configuration()
-
- if self.is_site_config_changed(old_config):
- to_be_updated = True
- self.to_do.append(Actions.CreateOrUpdate)
-
- # check if linux_fx_version changed
- if old_config.linux_fx_version != self.site_config.get('linux_fx_version', ''):
- to_be_updated = True
- self.to_do.append(Actions.CreateOrUpdate)
-
- self.app_settings_strDic = self.list_app_settings()
-
- # purge existing app_settings:
- if self.purge_app_settings:
- to_be_updated = True
- self.app_settings_strDic = dict()
- self.to_do.append(Actions.UpdateAppSettings)
-
- # check if app settings changed
- if self.purge_app_settings or self.is_app_settings_changed():
- to_be_updated = True
- self.to_do.append(Actions.UpdateAppSettings)
-
- if self.app_settings:
- for key in self.app_settings.keys():
- self.app_settings_strDic[key] = self.app_settings[key]
-
- elif self.state == 'absent':
- if old_response:
- self.log("Delete Web App instance")
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- self.delete_webapp()
-
- self.log('Web App instance deleted')
-
- else:
- self.fail("Web app {0} not exists.".format(self.name))
-
- if to_be_updated:
- self.log('Need to Create/Update web app')
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- if Actions.CreateOrUpdate in self.to_do:
- response = self.create_update_webapp()
-
- self.results['id'] = response['id']
-
- if Actions.UpdateAppSettings in self.to_do:
- update_response = self.update_app_settings()
- self.results['id'] = update_response.id
-
- webapp = None
- if old_response:
- webapp = old_response
- if response:
- webapp = response
-
- if webapp:
- if (webapp['state'] != 'Stopped' and self.app_state == 'stopped') or \
- (webapp['state'] != 'Running' and self.app_state == 'started') or \
- self.app_state == 'restarted':
-
- self.results['changed'] = True
- if self.check_mode:
- return self.results
-
- self.set_webapp_state(self.app_state)
-
- return self.results
-
- # compare existing web app with input, determine weather it's update operation
- def is_updatable_property_changed(self, existing_webapp):
- for property_name in self.updatable_properties:
- if hasattr(self, property_name) and getattr(self, property_name) is not None and \
- getattr(self, property_name) != existing_webapp.get(property_name, None):
- return True
-
- return False
-
- # compare xxx_version
- def is_site_config_changed(self, existing_config):
- for fx_version in self.site_config_updatable_properties:
- if self.site_config.get(fx_version):
- if not getattr(existing_config, fx_version) or \
- getattr(existing_config, fx_version).upper() != self.site_config.get(fx_version).upper():
- return True
-
- return False
-
- # comparing existing app setting with input, determine whether it's changed
- def is_app_settings_changed(self):
- if self.app_settings:
- if self.app_settings_strDic:
- for key in self.app_settings.keys():
- if self.app_settings[key] != self.app_settings_strDic.get(key, None):
- return True
- else:
- return True
- return False
-
- # comparing deployment source with input, determine wheather it's changed
- def is_deployment_source_changed(self, existing_webapp):
- if self.deployment_source:
- if self.deployment_source.get('url') \
- and self.deployment_source['url'] != existing_webapp.get('site_source_control')['url']:
- return True
-
- if self.deployment_source.get('branch') \
- and self.deployment_source['branch'] != existing_webapp.get('site_source_control')['branch']:
- return True
-
- return False
-
- def create_update_webapp(self):
- '''
- Creates or updates Web App with the specified configuration.
-
- :return: deserialized Web App instance state dictionary
- '''
- self.log(
- "Creating / Updating the Web App instance {0}".format(self.name))
-
- try:
- skip_dns_registration = self.dns_registration
- force_dns_registration = None if self.dns_registration is None else not self.dns_registration
-
- response = self.web_client.web_apps.create_or_update(resource_group_name=self.resource_group,
- name=self.name,
- site_envelope=self.site,
- skip_dns_registration=skip_dns_registration,
- skip_custom_domain_verification=self.skip_custom_domain_verification,
- force_dns_registration=force_dns_registration,
- ttl_in_seconds=self.ttl_in_seconds)
- if isinstance(response, LROPoller):
- response = self.get_poller_result(response)
-
- except CloudError as exc:
- self.log('Error attempting to create the Web App instance.')
- self.fail(
- "Error creating the Web App instance: {0}".format(str(exc)))
- return webapp_to_dict(response)
-
- def delete_webapp(self):
- '''
- Deletes specified Web App instance in the specified subscription and resource group.
-
- :return: True
- '''
- self.log("Deleting the Web App instance {0}".format(self.name))
- try:
- response = self.web_client.web_apps.delete(resource_group_name=self.resource_group,
- name=self.name)
- except CloudError as e:
- self.log('Error attempting to delete the Web App instance.')
- self.fail(
- "Error deleting the Web App instance: {0}".format(str(e)))
-
- return True
-
- def get_webapp(self):
- '''
- Gets the properties of the specified Web App.
-
- :return: deserialized Web App instance state dictionary
- '''
- self.log(
- "Checking if the Web App instance {0} is present".format(self.name))
-
- response = None
-
- try:
- response = self.web_client.web_apps.get(resource_group_name=self.resource_group,
- name=self.name)
-
- # Newer SDK versions (0.40.0+) seem to return None if it doesn't exist instead of raising CloudError
- if response is not None:
- self.log("Response : {0}".format(response))
- self.log("Web App instance : {0} found".format(response.name))
- return webapp_to_dict(response)
-
- except CloudError as ex:
- pass
-
- self.log("Didn't find web app {0} in resource group {1}".format(
- self.name, self.resource_group))
-
- return False
-
- def get_app_service_plan(self):
- '''
- Gets app service plan
- :return: deserialized app service plan dictionary
- '''
- self.log("Get App Service Plan {0}".format(self.plan['name']))
-
- try:
- response = self.web_client.app_service_plans.get(
- resource_group_name=self.plan['resource_group'],
- name=self.plan['name'])
-
- # Newer SDK versions (0.40.0+) seem to return None if it doesn't exist instead of raising CloudError
- if response is not None:
- self.log("Response : {0}".format(response))
- self.log("App Service Plan : {0} found".format(response.name))
-
- return appserviceplan_to_dict(response)
- except CloudError as ex:
- pass
-
- self.log("Didn't find app service plan {0} in resource group {1}".format(
- self.plan['name'], self.plan['resource_group']))
-
- return False
-
- def create_app_service_plan(self):
- '''
- Creates app service plan
- :return: deserialized app service plan dictionary
- '''
- self.log("Create App Service Plan {0}".format(self.plan['name']))
-
- try:
- # normalize sku
- sku = _normalize_sku(self.plan['sku'])
-
- sku_def = SkuDescription(tier=get_sku_name(
- sku), name=sku, capacity=(self.plan.get('number_of_workers', None)))
- plan_def = AppServicePlan(
- location=self.plan['location'], app_service_plan_name=self.plan['name'], sku=sku_def, reserved=(self.plan.get('is_linux', None)))
-
- poller = self.web_client.app_service_plans.create_or_update(
- self.plan['resource_group'], self.plan['name'], plan_def)
-
- if isinstance(poller, LROPoller):
- response = self.get_poller_result(poller)
-
- self.log("Response : {0}".format(response))
-
- return appserviceplan_to_dict(response)
- except CloudError as ex:
- self.fail("Failed to create app service plan {0} in resource group {1}: {2}".format(
- self.plan['name'], self.plan['resource_group'], str(ex)))
-
- def list_app_settings(self):
- '''
- List application settings
- :return: deserialized list response
- '''
- self.log("List application setting")
-
- try:
-
- response = self.web_client.web_apps.list_application_settings(
- resource_group_name=self.resource_group, name=self.name)
- self.log("Response : {0}".format(response))
-
- return response.properties
- except CloudError as ex:
- self.fail("Failed to list application settings for web app {0} in resource group {1}: {2}".format(
- self.name, self.resource_group, str(ex)))
-
- def update_app_settings(self):
- '''
- Update application settings
- :return: deserialized updating response
- '''
- self.log("Update application setting")
-
- try:
- response = self.web_client.web_apps.update_application_settings(
- resource_group_name=self.resource_group, name=self.name, properties=self.app_settings_strDic)
- self.log("Response : {0}".format(response))
-
- return response
- except CloudError as ex:
- self.fail("Failed to update application settings for web app {0} in resource group {1}: {2}".format(
- self.name, self.resource_group, str(ex)))
-
- def create_or_update_source_control(self):
- '''
- Update site source control
- :return: deserialized updating response
- '''
- self.log("Update site source control")
-
- if self.deployment_source is None:
- return False
-
- self.deployment_source['is_manual_integration'] = False
- self.deployment_source['is_mercurial'] = False
-
- try:
- response = self.web_client.web_client.create_or_update_source_control(
- self.resource_group, self.name, self.deployment_source)
- self.log("Response : {0}".format(response))
-
- return response.as_dict()
- except CloudError as ex:
- self.fail("Failed to update site source control for web app {0} in resource group {1}".format(
- self.name, self.resource_group))
-
- def get_webapp_configuration(self):
- '''
- Get web app configuration
- :return: deserialized web app configuration response
- '''
- self.log("Get web app configuration")
-
- try:
-
- response = self.web_client.web_apps.get_configuration(
- resource_group_name=self.resource_group, name=self.name)
- self.log("Response : {0}".format(response))
-
- return response
- except CloudError as ex:
- self.log("Failed to get configuration for web app {0} in resource group {1}: {2}".format(
- self.name, self.resource_group, str(ex)))
-
- return False
-
- def set_webapp_state(self, appstate):
- '''
- Start/stop/restart web app
- :return: deserialized updating response
- '''
- try:
- if appstate == 'started':
- response = self.web_client.web_apps.start(resource_group_name=self.resource_group, name=self.name)
- elif appstate == 'stopped':
- response = self.web_client.web_apps.stop(resource_group_name=self.resource_group, name=self.name)
- elif appstate == 'restarted':
- response = self.web_client.web_apps.restart(resource_group_name=self.resource_group, name=self.name)
- else:
- self.fail("Invalid web app state {0}".format(appstate))
-
- self.log("Response : {0}".format(response))
-
- return response
- except CloudError as ex:
- request_id = ex.request_id if ex.request_id else ''
- self.log("Failed to {0} web app {1} in resource group {2}, request_id {3} - {4}".format(
- appstate, self.name, self.resource_group, request_id, str(ex)))
-
-
-def main():
- """Main execution"""
- AzureRMWebApps()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_webapp_info.py b/test/support/integration/plugins/modules/azure_rm_webapp_info.py
deleted file mode 100644
index 2228680306..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_webapp_info.py
+++ /dev/null
@@ -1,489 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018 Yunge Zhu, <yungez@microsoft.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_webapp_info
-
-version_added: "2.9"
-
-short_description: Get Azure web app facts
-
-description:
- - Get facts for a specific web app or all web app in a resource group, or all web app in current subscription.
-
-options:
- name:
- description:
- - Only show results for a specific web app.
- resource_group:
- description:
- - Limit results by resource group.
- return_publish_profile:
- description:
- - Indicate whether to return publishing profile of the web app.
- default: False
- type: bool
- tags:
- description:
- - Limit results by providing a list of tags. Format tags as 'key' or 'key:value'.
-
-extends_documentation_fragment:
- - azure
-
-author:
- - Yunge Zhu (@yungezz)
-'''
-
-EXAMPLES = '''
- - name: Get facts for web app by name
- azure_rm_webapp_info:
- resource_group: myResourceGroup
- name: winwebapp1
-
- - name: Get facts for web apps in resource group
- azure_rm_webapp_info:
- resource_group: myResourceGroup
-
- - name: Get facts for web apps with tags
- azure_rm_webapp_info:
- tags:
- - testtag
- - foo:bar
-'''
-
-RETURN = '''
-webapps:
- description:
- - List of web apps.
- returned: always
- type: complex
- contains:
- id:
- description:
- - ID of the web app.
- returned: always
- type: str
- sample: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Web/sites/myWebApp
- name:
- description:
- - Name of the web app.
- returned: always
- type: str
- sample: winwebapp1
- resource_group:
- description:
- - Resource group of the web app.
- returned: always
- type: str
- sample: myResourceGroup
- location:
- description:
- - Location of the web app.
- returned: always
- type: str
- sample: eastus
- plan:
- description:
- - ID of app service plan used by the web app.
- returned: always
- type: str
- sample: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Web/serverfarms/myAppServicePlan
- app_settings:
- description:
- - App settings of the application. Only returned when web app has app settings.
- returned: always
- type: dict
- sample: {
- "testkey": "testvalue",
- "testkey2": "testvalue2"
- }
- frameworks:
- description:
- - Frameworks of the application. Only returned when web app has frameworks.
- returned: always
- type: list
- sample: [
- {
- "name": "net_framework",
- "version": "v4.0"
- },
- {
- "name": "java",
- "settings": {
- "java_container": "tomcat",
- "java_container_version": "8.5"
- },
- "version": "1.7"
- },
- {
- "name": "php",
- "version": "5.6"
- }
- ]
- availability_state:
- description:
- - Availability of this web app.
- returned: always
- type: str
- sample: Normal
- default_host_name:
- description:
- - Host name of the web app.
- returned: always
- type: str
- sample: vxxisurg397winapp4.azurewebsites.net
- enabled:
- description:
- - Indicates the web app enabled or not.
- returned: always
- type: bool
- sample: true
- enabled_host_names:
- description:
- - Enabled host names of the web app.
- returned: always
- type: list
- sample: [
- "vxxisurg397winapp4.azurewebsites.net",
- "vxxisurg397winapp4.scm.azurewebsites.net"
- ]
- host_name_ssl_states:
- description:
- - SSL state per host names of the web app.
- returned: always
- type: list
- sample: [
- {
- "hostType": "Standard",
- "name": "vxxisurg397winapp4.azurewebsites.net",
- "sslState": "Disabled"
- },
- {
- "hostType": "Repository",
- "name": "vxxisurg397winapp4.scm.azurewebsites.net",
- "sslState": "Disabled"
- }
- ]
- host_names:
- description:
- - Host names of the web app.
- returned: always
- type: list
- sample: [
- "vxxisurg397winapp4.azurewebsites.net"
- ]
- outbound_ip_addresses:
- description:
- - Outbound IP address of the web app.
- returned: always
- type: str
- sample: "40.71.11.131,40.85.166.200,168.62.166.67,137.135.126.248,137.135.121.45"
- ftp_publish_url:
- description:
- - Publishing URL of the web app when deployment type is FTP.
- returned: always
- type: str
- sample: ftp://xxxx.ftp.azurewebsites.windows.net
- state:
- description:
- - State of the web app.
- returned: always
- type: str
- sample: running
- publishing_username:
- description:
- - Publishing profile user name.
- returned: only when I(return_publish_profile=True).
- type: str
- sample: "$vxxisuRG397winapp4"
- publishing_password:
- description:
- - Publishing profile password.
- returned: only when I(return_publish_profile=True).
- type: str
- sample: "uvANsPQpGjWJmrFfm4Ssd5rpBSqGhjMk11pMSgW2vCsQtNx9tcgZ0xN26s9A"
- tags:
- description:
- - Tags assigned to the resource. Dictionary of string:string pairs.
- returned: always
- type: dict
- sample: { tag1: abc }
-'''
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrest.polling import LROPoller
- from azure.common import AzureMissingResourceHttpError, AzureHttpError
-except Exception:
- # This is handled in azure_rm_common
- pass
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-AZURE_OBJECT_CLASS = 'WebApp'
-
-
-class AzureRMWebAppInfo(AzureRMModuleBase):
-
- def __init__(self):
-
- self.module_arg_spec = dict(
- name=dict(type='str'),
- resource_group=dict(type='str'),
- tags=dict(type='list'),
- return_publish_profile=dict(type='bool', default=False),
- )
-
- self.results = dict(
- changed=False,
- webapps=[],
- )
-
- self.name = None
- self.resource_group = None
- self.tags = None
- self.return_publish_profile = False
-
- self.framework_names = ['net_framework', 'java', 'php', 'node', 'python', 'dotnetcore', 'ruby']
-
- super(AzureRMWebAppInfo, self).__init__(self.module_arg_spec,
- supports_tags=False,
- facts_module=True)
-
- def exec_module(self, **kwargs):
- is_old_facts = self.module._name == 'azure_rm_webapp_facts'
- if is_old_facts:
- self.module.deprecate("The 'azure_rm_webapp_facts' module has been renamed to 'azure_rm_webapp_info'",
- version='2.13', collection_name='ansible.builtin')
-
- for key in self.module_arg_spec:
- setattr(self, key, kwargs[key])
-
- if self.name:
- self.results['webapps'] = self.list_by_name()
- elif self.resource_group:
- self.results['webapps'] = self.list_by_resource_group()
- else:
- self.results['webapps'] = self.list_all()
-
- return self.results
-
- def list_by_name(self):
- self.log('Get web app {0}'.format(self.name))
- item = None
- result = []
-
- try:
- item = self.web_client.web_apps.get(self.resource_group, self.name)
- except CloudError:
- pass
-
- if item and self.has_tags(item.tags, self.tags):
- curated_result = self.get_curated_webapp(self.resource_group, self.name, item)
- result = [curated_result]
-
- return result
-
- def list_by_resource_group(self):
- self.log('List web apps in resource groups {0}'.format(self.resource_group))
- try:
- response = list(self.web_client.web_apps.list_by_resource_group(self.resource_group))
- except CloudError as exc:
- request_id = exc.request_id if exc.request_id else ''
- self.fail("Error listing web apps in resource groups {0}, request id: {1} - {2}".format(self.resource_group, request_id, str(exc)))
-
- results = []
- for item in response:
- if self.has_tags(item.tags, self.tags):
- curated_output = self.get_curated_webapp(self.resource_group, item.name, item)
- results.append(curated_output)
- return results
-
- def list_all(self):
- self.log('List web apps in current subscription')
- try:
- response = list(self.web_client.web_apps.list())
- except CloudError as exc:
- request_id = exc.request_id if exc.request_id else ''
- self.fail("Error listing web apps, request id {0} - {1}".format(request_id, str(exc)))
-
- results = []
- for item in response:
- if self.has_tags(item.tags, self.tags):
- curated_output = self.get_curated_webapp(item.resource_group, item.name, item)
- results.append(curated_output)
- return results
-
- def list_webapp_configuration(self, resource_group, name):
- self.log('Get web app {0} configuration'.format(name))
-
- response = []
-
- try:
- response = self.web_client.web_apps.get_configuration(resource_group_name=resource_group, name=name)
- except CloudError as ex:
- request_id = ex.request_id if ex.request_id else ''
- self.fail('Error getting web app {0} configuration, request id {1} - {2}'.format(name, request_id, str(ex)))
-
- return response.as_dict()
-
- def list_webapp_appsettings(self, resource_group, name):
- self.log('Get web app {0} app settings'.format(name))
-
- response = []
-
- try:
- response = self.web_client.web_apps.list_application_settings(resource_group_name=resource_group, name=name)
- except CloudError as ex:
- request_id = ex.request_id if ex.request_id else ''
- self.fail('Error getting web app {0} app settings, request id {1} - {2}'.format(name, request_id, str(ex)))
-
- return response.as_dict()
-
- def get_publish_credentials(self, resource_group, name):
- self.log('Get web app {0} publish credentials'.format(name))
- try:
- poller = self.web_client.web_apps.list_publishing_credentials(resource_group, name)
- if isinstance(poller, LROPoller):
- response = self.get_poller_result(poller)
- except CloudError as ex:
- request_id = ex.request_id if ex.request_id else ''
- self.fail('Error getting web app {0} publishing credentials - {1}'.format(request_id, str(ex)))
- return response
-
- def get_webapp_ftp_publish_url(self, resource_group, name):
- import xmltodict
-
- self.log('Get web app {0} app publish profile'.format(name))
-
- url = None
- try:
- content = self.web_client.web_apps.list_publishing_profile_xml_with_secrets(resource_group_name=resource_group, name=name)
- if not content:
- return url
-
- full_xml = ''
- for f in content:
- full_xml += f.decode()
- profiles = xmltodict.parse(full_xml, xml_attribs=True)['publishData']['publishProfile']
-
- if not profiles:
- return url
-
- for profile in profiles:
- if profile['@publishMethod'] == 'FTP':
- url = profile['@publishUrl']
-
- except CloudError as ex:
- self.fail('Error getting web app {0} app settings'.format(name))
-
- return url
-
- def get_curated_webapp(self, resource_group, name, webapp):
- pip = self.serialize_obj(webapp, AZURE_OBJECT_CLASS)
-
- try:
- site_config = self.list_webapp_configuration(resource_group, name)
- app_settings = self.list_webapp_appsettings(resource_group, name)
- publish_cred = self.get_publish_credentials(resource_group, name)
- ftp_publish_url = self.get_webapp_ftp_publish_url(resource_group, name)
- except CloudError as ex:
- pass
- return self.construct_curated_webapp(webapp=pip,
- configuration=site_config,
- app_settings=app_settings,
- deployment_slot=None,
- ftp_publish_url=ftp_publish_url,
- publish_credentials=publish_cred)
-
- def construct_curated_webapp(self,
- webapp,
- configuration=None,
- app_settings=None,
- deployment_slot=None,
- ftp_publish_url=None,
- publish_credentials=None):
- curated_output = dict()
- curated_output['id'] = webapp['id']
- curated_output['name'] = webapp['name']
- curated_output['resource_group'] = webapp['properties']['resourceGroup']
- curated_output['location'] = webapp['location']
- curated_output['plan'] = webapp['properties']['serverFarmId']
- curated_output['tags'] = webapp.get('tags', None)
-
- # important properties from output. not match input arguments.
- curated_output['app_state'] = webapp['properties']['state']
- curated_output['availability_state'] = webapp['properties']['availabilityState']
- curated_output['default_host_name'] = webapp['properties']['defaultHostName']
- curated_output['host_names'] = webapp['properties']['hostNames']
- curated_output['enabled'] = webapp['properties']['enabled']
- curated_output['enabled_host_names'] = webapp['properties']['enabledHostNames']
- curated_output['host_name_ssl_states'] = webapp['properties']['hostNameSslStates']
- curated_output['outbound_ip_addresses'] = webapp['properties']['outboundIpAddresses']
-
- # curated site_config
- if configuration:
- curated_output['frameworks'] = []
- for fx_name in self.framework_names:
- fx_version = configuration.get(fx_name + '_version', None)
- if fx_version:
- fx = {
- 'name': fx_name,
- 'version': fx_version
- }
- # java container setting
- if fx_name == 'java':
- if configuration['java_container'] and configuration['java_container_version']:
- settings = {
- 'java_container': configuration['java_container'].lower(),
- 'java_container_version': configuration['java_container_version']
- }
- fx['settings'] = settings
-
- curated_output['frameworks'].append(fx)
-
- # linux_fx_version
- if configuration.get('linux_fx_version', None):
- tmp = configuration.get('linux_fx_version').split("|")
- if len(tmp) == 2:
- curated_output['frameworks'].append({'name': tmp[0].lower(), 'version': tmp[1]})
-
- # curated app_settings
- if app_settings and app_settings.get('properties', None):
- curated_output['app_settings'] = dict()
- for item in app_settings['properties']:
- curated_output['app_settings'][item] = app_settings['properties'][item]
-
- # curated deploymenet_slot
- if deployment_slot:
- curated_output['deployment_slot'] = deployment_slot
-
- # ftp_publish_url
- if ftp_publish_url:
- curated_output['ftp_publish_url'] = ftp_publish_url
-
- # curated publish credentials
- if publish_credentials and self.return_publish_profile:
- curated_output['publishing_username'] = publish_credentials.publishing_user_name
- curated_output['publishing_password'] = publish_credentials.publishing_password
- return curated_output
-
-
-def main():
- AzureRMWebAppInfo()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/support/integration/plugins/modules/azure_rm_webappslot.py b/test/support/integration/plugins/modules/azure_rm_webappslot.py
deleted file mode 100644
index ddba710b9d..0000000000
--- a/test/support/integration/plugins/modules/azure_rm_webappslot.py
+++ /dev/null
@@ -1,1058 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2018 Yunge Zhu, <yungez@microsoft.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_webappslot
-version_added: "2.8"
-short_description: Manage Azure Web App slot
-description:
- - Create, update and delete Azure Web App slot.
-
-options:
- resource_group:
- description:
- - Name of the resource group to which the resource belongs.
- required: True
- name:
- description:
- - Unique name of the deployment slot to create or update.
- required: True
- webapp_name:
- description:
- - Web app name which this deployment slot belongs to.
- required: True
- location:
- description:
- - Resource location. If not set, location from the resource group will be used as default.
- configuration_source:
- description:
- - Source slot to clone configurations from when creating slot. Use webapp's name to refer to the production slot.
- auto_swap_slot_name:
- description:
- - Used to configure target slot name to auto swap, or disable auto swap.
- - Set it target slot name to auto swap.
- - Set it to False to disable auto slot swap.
- swap:
- description:
- - Swap deployment slots of a web app.
- suboptions:
- action:
- description:
- - Swap types.
- - C(preview) is to apply target slot settings on source slot first.
- - C(swap) is to complete swapping.
- - C(reset) is to reset the swap.
- choices:
- - preview
- - swap
- - reset
- default: preview
- target_slot:
- description:
- - Name of target slot to swap. If set to None, then swap with production slot.
- preserve_vnet:
- description:
- - C(True) to preserve virtual network to the slot during swap. Otherwise C(False).
- type: bool
- default: True
- frameworks:
- description:
- - Set of run time framework settings. Each setting is a dictionary.
- - See U(https://docs.microsoft.com/en-us/azure/app-service/app-service-web-overview) for more info.
- suboptions:
- name:
- description:
- - Name of the framework.
- - Supported framework list for Windows web app and Linux web app is different.
- - Windows web apps support C(java), C(net_framework), C(php), C(python), and C(node) from June 2018.
- - Windows web apps support multiple framework at same time.
- - Linux web apps support C(java), C(ruby), C(php), C(dotnetcore), and C(node) from June 2018.
- - Linux web apps support only one framework.
- - Java framework is mutually exclusive with others.
- choices:
- - java
- - net_framework
- - php
- - python
- - ruby
- - dotnetcore
- - node
- version:
- description:
- - Version of the framework. For Linux web app supported value, see U(https://aka.ms/linux-stacks) for more info.
- - C(net_framework) supported value sample, C(v4.0) for .NET 4.6 and C(v3.0) for .NET 3.5.
- - C(php) supported value sample, C(5.5), C(5.6), C(7.0).
- - C(python) supported value sample, C(5.5), C(5.6), C(7.0).
- - C(node) supported value sample, C(6.6), C(6.9).
- - C(dotnetcore) supported value sample, C(1.0), C(1.1), C(1.2).
- - C(ruby) supported value sample, 2.3.
- - C(java) supported value sample, C(1.9) for Windows web app. C(1.8) for Linux web app.
- settings:
- description:
- - List of settings of the framework.
- suboptions:
- java_container:
- description:
- - Name of Java container. This is supported by specific framework C(java) onlys, for example C(Tomcat), C(Jetty).
- java_container_version:
- description:
- - Version of Java container. This is supported by specific framework C(java) only.
- - For C(Tomcat), for example C(8.0), C(8.5), C(9.0). For C(Jetty), for example C(9.1), C(9.3).
- container_settings:
- description:
- - Web app slot container settings.
- suboptions:
- name:
- description:
- - Name of container, for example C(imagename:tag).
- registry_server_url:
- description:
- - Container registry server URL, for example C(mydockerregistry.io).
- registry_server_user:
- description:
- - The container registry server user name.
- registry_server_password:
- description:
- - The container registry server password.
- startup_file:
- description:
- - The slot startup file.
- - This only applies for Linux web app slot.
- app_settings:
- description:
- - Configure web app slot application settings. Suboptions are in key value pair format.
- purge_app_settings:
- description:
- - Purge any existing application settings. Replace slot application settings with app_settings.
- type: bool
- deployment_source:
- description:
- - Deployment source for git.
- suboptions:
- url:
- description:
- - Repository URL of deployment source.
- branch:
- description:
- - The branch name of the repository.
- app_state:
- description:
- - Start/Stop/Restart the slot.
- type: str
- choices:
- - started
- - stopped
- - restarted
- default: started
- state:
- description:
- - State of the Web App deployment slot.
- - Use C(present) to create or update a slot and C(absent) to delete it.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
- - azure_tags
-
-author:
- - Yunge Zhu(@yungezz)
-
-'''
-
-EXAMPLES = '''
- - name: Create a webapp slot
- azure_rm_webappslot:
- resource_group: myResourceGroup
- webapp_name: myJavaWebApp
- name: stage
- configuration_source: myJavaWebApp
- app_settings:
- testkey: testvalue
-
- - name: swap the slot with production slot
- azure_rm_webappslot:
- resource_group: myResourceGroup
- webapp_name: myJavaWebApp
- name: stage
- swap:
- action: swap
-
- - name: stop the slot
- azure_rm_webappslot:
- resource_group: myResourceGroup
- webapp_name: myJavaWebApp
- name: stage
- app_state: stopped
-
- - name: udpate a webapp slot app settings
- azure_rm_webappslot:
- resource_group: myResourceGroup
- webapp_name: myJavaWebApp
- name: stage
- app_settings:
- testkey: testvalue2
-
- - name: udpate a webapp slot frameworks
- azure_rm_webappslot:
- resource_group: myResourceGroup
- webapp_name: myJavaWebApp
- name: stage
- frameworks:
- - name: "node"
- version: "10.1"
-'''
-
-RETURN = '''
-id:
- description:
- - ID of current slot.
- returned: always
- type: str
- sample: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Web/sites/testapp/slots/stage1
-'''
-
-import time
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- from msrestazure.azure_exceptions import CloudError
- from msrest.polling import LROPoller
- from msrest.serialization import Model
- from azure.mgmt.web.models import (
- site_config, app_service_plan, Site,
- AppServicePlan, SkuDescription, NameValuePair
- )
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-swap_spec = dict(
- action=dict(
- type='str',
- choices=[
- 'preview',
- 'swap',
- 'reset'
- ],
- default='preview'
- ),
- target_slot=dict(
- type='str'
- ),
- preserve_vnet=dict(
- type='bool',
- default=True
- )
-)
-
-container_settings_spec = dict(
- name=dict(type='str', required=True),
- registry_server_url=dict(type='str'),
- registry_server_user=dict(type='str'),
- registry_server_password=dict(type='str', no_log=True)
-)
-
-deployment_source_spec = dict(
- url=dict(type='str'),
- branch=dict(type='str')
-)
-
-
-framework_settings_spec = dict(
- java_container=dict(type='str', required=True),
- java_container_version=dict(type='str', required=True)
-)
-
-
-framework_spec = dict(
- name=dict(
- type='str',
- required=True,
- choices=['net_framework', 'java', 'php', 'node', 'python', 'dotnetcore', 'ruby']),
- version=dict(type='str', required=True),
- settings=dict(type='dict', options=framework_settings_spec)
-)
-
-
-def webapp_to_dict(webapp):
- return dict(
- id=webapp.id,
- name=webapp.name,
- location=webapp.location,
- client_cert_enabled=webapp.client_cert_enabled,
- enabled=webapp.enabled,
- reserved=webapp.reserved,
- client_affinity_enabled=webapp.client_affinity_enabled,
- server_farm_id=webapp.server_farm_id,
- host_names_disabled=webapp.host_names_disabled,
- https_only=webapp.https_only if hasattr(webapp, 'https_only') else None,
- skip_custom_domain_verification=webapp.skip_custom_domain_verification if hasattr(webapp, 'skip_custom_domain_verification') else None,
- ttl_in_seconds=webapp.ttl_in_seconds if hasattr(webapp, 'ttl_in_seconds') else None,
- state=webapp.state,
- tags=webapp.tags if webapp.tags else None
- )
-
-
-def slot_to_dict(slot):
- return dict(
- id=slot.id,
- resource_group=slot.resource_group,
- server_farm_id=slot.server_farm_id,
- target_swap_slot=slot.target_swap_slot,
- enabled_host_names=slot.enabled_host_names,
- slot_swap_status=slot.slot_swap_status,
- name=slot.name,
- location=slot.location,
- enabled=slot.enabled,
- reserved=slot.reserved,
- host_names_disabled=slot.host_names_disabled,
- state=slot.state,
- repository_site_name=slot.repository_site_name,
- default_host_name=slot.default_host_name,
- kind=slot.kind,
- site_config=slot.site_config,
- tags=slot.tags if slot.tags else None
- )
-
-
-class Actions:
- NoAction, CreateOrUpdate, UpdateAppSettings, Delete = range(4)
-
-
-class AzureRMWebAppSlots(AzureRMModuleBase):
- """Configuration class for an Azure RM Web App slot resource"""
-
- def __init__(self):
- self.module_arg_spec = dict(
- resource_group=dict(
- type='str',
- required=True
- ),
- name=dict(
- type='str',
- required=True
- ),
- webapp_name=dict(
- type='str',
- required=True
- ),
- location=dict(
- type='str'
- ),
- configuration_source=dict(
- type='str'
- ),
- auto_swap_slot_name=dict(
- type='raw'
- ),
- swap=dict(
- type='dict',
- options=swap_spec
- ),
- frameworks=dict(
- type='list',
- elements='dict',
- options=framework_spec
- ),
- container_settings=dict(
- type='dict',
- options=container_settings_spec
- ),
- deployment_source=dict(
- type='dict',
- options=deployment_source_spec
- ),
- startup_file=dict(
- type='str'
- ),
- app_settings=dict(
- type='dict'
- ),
- purge_app_settings=dict(
- type='bool',
- default=False
- ),
- app_state=dict(
- type='str',
- choices=['started', 'stopped', 'restarted'],
- default='started'
- ),
- state=dict(
- type='str',
- default='present',
- choices=['present', 'absent']
- )
- )
-
- mutually_exclusive = [['container_settings', 'frameworks']]
-
- self.resource_group = None
- self.name = None
- self.webapp_name = None
- self.location = None
-
- self.auto_swap_slot_name = None
- self.swap = None
- self.tags = None
- self.startup_file = None
- self.configuration_source = None
- self.clone = False
-
- # site config, e.g app settings, ssl
- self.site_config = dict()
- self.app_settings = dict()
- self.app_settings_strDic = None
-
- # siteSourceControl
- self.deployment_source = dict()
-
- # site, used at level creation, or update.
- self.site = None
-
- # property for internal usage, not used for sdk
- self.container_settings = None
-
- self.purge_app_settings = False
- self.app_state = 'started'
-
- self.results = dict(
- changed=False,
- id=None,
- )
- self.state = None
- self.to_do = Actions.NoAction
-
- self.frameworks = None
-
- # set site_config value from kwargs
- self.site_config_updatable_frameworks = ["net_framework_version",
- "java_version",
- "php_version",
- "python_version",
- "linux_fx_version"]
-
- self.supported_linux_frameworks = ['ruby', 'php', 'dotnetcore', 'node', 'java']
- self.supported_windows_frameworks = ['net_framework', 'php', 'python', 'node', 'java']
-
- super(AzureRMWebAppSlots, self).__init__(derived_arg_spec=self.module_arg_spec,
- mutually_exclusive=mutually_exclusive,
- supports_check_mode=True,
- supports_tags=True)
-
- def exec_module(self, **kwargs):
- """Main module execution method"""
-
- for key in list(self.module_arg_spec.keys()) + ['tags']:
- if hasattr(self, key):
- setattr(self, key, kwargs[key])
- elif kwargs[key] is not None:
- if key == "scm_type":
- self.site_config[key] = kwargs[key]
-
- old_response = None
- response = None
- to_be_updated = False
-
- # set location
- resource_group = self.get_resource_group(self.resource_group)
- if not self.location:
- self.location = resource_group.location
-
- # get web app
- webapp_response = self.get_webapp()
-
- if not webapp_response:
- self.fail("Web app {0} does not exist in resource group {1}.".format(self.webapp_name, self.resource_group))
-
- # get slot
- old_response = self.get_slot()
-
- # set is_linux
- is_linux = True if webapp_response['reserved'] else False
-
- if self.state == 'present':
- if self.frameworks:
- # java is mutually exclusive with other frameworks
- if len(self.frameworks) > 1 and any(f['name'] == 'java' for f in self.frameworks):
- self.fail('Java is mutually exclusive with other frameworks.')
-
- if is_linux:
- if len(self.frameworks) != 1:
- self.fail('Can specify one framework only for Linux web app.')
-
- if self.frameworks[0]['name'] not in self.supported_linux_frameworks:
- self.fail('Unsupported framework {0} for Linux web app.'.format(self.frameworks[0]['name']))
-
- self.site_config['linux_fx_version'] = (self.frameworks[0]['name'] + '|' + self.frameworks[0]['version']).upper()
-
- if self.frameworks[0]['name'] == 'java':
- if self.frameworks[0]['version'] != '8':
- self.fail("Linux web app only supports java 8.")
-
- if self.frameworks[0].get('settings', {}) and self.frameworks[0]['settings'].get('java_container', None) and \
- self.frameworks[0]['settings']['java_container'].lower() != 'tomcat':
- self.fail("Linux web app only supports tomcat container.")
-
- if self.frameworks[0].get('settings', {}) and self.frameworks[0]['settings'].get('java_container', None) and \
- self.frameworks[0]['settings']['java_container'].lower() == 'tomcat':
- self.site_config['linux_fx_version'] = 'TOMCAT|' + self.frameworks[0]['settings']['java_container_version'] + '-jre8'
- else:
- self.site_config['linux_fx_version'] = 'JAVA|8-jre8'
- else:
- for fx in self.frameworks:
- if fx.get('name') not in self.supported_windows_frameworks:
- self.fail('Unsupported framework {0} for Windows web app.'.format(fx.get('name')))
- else:
- self.site_config[fx.get('name') + '_version'] = fx.get('version')
-
- if 'settings' in fx and fx['settings'] is not None:
- for key, value in fx['settings'].items():
- self.site_config[key] = value
-
- if not self.app_settings:
- self.app_settings = dict()
-
- if self.container_settings:
- linux_fx_version = 'DOCKER|'
-
- if self.container_settings.get('registry_server_url'):
- self.app_settings['DOCKER_REGISTRY_SERVER_URL'] = 'https://' + self.container_settings['registry_server_url']
-
- linux_fx_version += self.container_settings['registry_server_url'] + '/'
-
- linux_fx_version += self.container_settings['name']
-
- self.site_config['linux_fx_version'] = linux_fx_version
-
- if self.container_settings.get('registry_server_user'):
- self.app_settings['DOCKER_REGISTRY_SERVER_USERNAME'] = self.container_settings['registry_server_user']
-
- if self.container_settings.get('registry_server_password'):
- self.app_settings['DOCKER_REGISTRY_SERVER_PASSWORD'] = self.container_settings['registry_server_password']
-
- # set auto_swap_slot_name
- if self.auto_swap_slot_name and isinstance(self.auto_swap_slot_name, str):
- self.site_config['auto_swap_slot_name'] = self.auto_swap_slot_name
- if self.auto_swap_slot_name is False:
- self.site_config['auto_swap_slot_name'] = None
-
- # init site
- self.site = Site(location=self.location, site_config=self.site_config)
-
- # check if the slot already present in the webapp
- if not old_response:
- self.log("Web App slot doesn't exist")
-
- to_be_updated = True
- self.to_do = Actions.CreateOrUpdate
- self.site.tags = self.tags
-
- # if linux, setup startup_file
- if self.startup_file:
- self.site_config['app_command_line'] = self.startup_file
-
- # set app setting
- if self.app_settings:
- app_settings = []
- for key in self.app_settings.keys():
- app_settings.append(NameValuePair(name=key, value=self.app_settings[key]))
-
- self.site_config['app_settings'] = app_settings
-
- # clone slot
- if self.configuration_source:
- self.clone = True
-
- else:
- # existing slot, do update
- self.log("Web App slot already exists")
-
- self.log('Result: {0}'.format(old_response))
-
- update_tags, self.site.tags = self.update_tags(old_response.get('tags', None))
-
- if update_tags:
- to_be_updated = True
-
- # check if site_config changed
- old_config = self.get_configuration_slot(self.name)
-
- if self.is_site_config_changed(old_config):
- to_be_updated = True
- self.to_do = Actions.CreateOrUpdate
-
- self.app_settings_strDic = self.list_app_settings_slot(self.name)
-
- # purge existing app_settings:
- if self.purge_app_settings:
- to_be_updated = True
- self.to_do = Actions.UpdateAppSettings
- self.app_settings_strDic = dict()
-
- # check if app settings changed
- if self.purge_app_settings or self.is_app_settings_changed():
- to_be_updated = True
- self.to_do = Actions.UpdateAppSettings
-
- if self.app_settings:
- for key in self.app_settings.keys():
- self.app_settings_strDic[key] = self.app_settings[key]
-
- elif self.state == 'absent':
- if old_response:
- self.log("Delete Web App slot")
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- self.delete_slot()
-
- self.log('Web App slot deleted')
-
- else:
- self.log("Web app slot {0} not exists.".format(self.name))
-
- if to_be_updated:
- self.log('Need to Create/Update web app')
- self.results['changed'] = True
-
- if self.check_mode:
- return self.results
-
- if self.to_do == Actions.CreateOrUpdate:
- response = self.create_update_slot()
-
- self.results['id'] = response['id']
-
- if self.clone:
- self.clone_slot()
-
- if self.to_do == Actions.UpdateAppSettings:
- self.update_app_settings_slot()
-
- slot = None
- if response:
- slot = response
- if old_response:
- slot = old_response
-
- if slot:
- if (slot['state'] != 'Stopped' and self.app_state == 'stopped') or \
- (slot['state'] != 'Running' and self.app_state == 'started') or \
- self.app_state == 'restarted':
-
- self.results['changed'] = True
- if self.check_mode:
- return self.results
-
- self.set_state_slot(self.app_state)
-
- if self.swap:
- self.results['changed'] = True
- if self.check_mode:
- return self.results
-
- self.swap_slot()
-
- return self.results
-
- # compare site config
- def is_site_config_changed(self, existing_config):
- for fx_version in self.site_config_updatable_frameworks:
- if self.site_config.get(fx_version):
- if not getattr(existing_config, fx_version) or \
- getattr(existing_config, fx_version).upper() != self.site_config.get(fx_version).upper():
- return True
-
- if self.auto_swap_slot_name is False and existing_config.auto_swap_slot_name is not None:
- return True
- elif self.auto_swap_slot_name and self.auto_swap_slot_name != getattr(existing_config, 'auto_swap_slot_name', None):
- return True
- return False
-
- # comparing existing app setting with input, determine whether it's changed
- def is_app_settings_changed(self):
- if self.app_settings:
- if len(self.app_settings_strDic) != len(self.app_settings):
- return True
-
- if self.app_settings_strDic != self.app_settings:
- return True
- return False
-
- # comparing deployment source with input, determine whether it's changed
- def is_deployment_source_changed(self, existing_webapp):
- if self.deployment_source:
- if self.deployment_source.get('url') \
- and self.deployment_source['url'] != existing_webapp.get('site_source_control')['url']:
- return True
-
- if self.deployment_source.get('branch') \
- and self.deployment_source['branch'] != existing_webapp.get('site_source_control')['branch']:
- return True
-
- return False
-
- def create_update_slot(self):
- '''
- Creates or updates Web App slot with the specified configuration.
-
- :return: deserialized Web App instance state dictionary
- '''
- self.log(
- "Creating / Updating the Web App slot {0}".format(self.name))
-
- try:
- response = self.web_client.web_apps.create_or_update_slot(resource_group_name=self.resource_group,
- slot=self.name,
- name=self.webapp_name,
- site_envelope=self.site)
- if isinstance(response, LROPoller):
- response = self.get_poller_result(response)
-
- except CloudError as exc:
- self.log('Error attempting to create the Web App slot instance.')
- self.fail("Error creating the Web App slot: {0}".format(str(exc)))
- return slot_to_dict(response)
-
- def delete_slot(self):
- '''
- Deletes specified Web App slot in the specified subscription and resource group.
-
- :return: True
- '''
- self.log("Deleting the Web App slot {0}".format(self.name))
- try:
- response = self.web_client.web_apps.delete_slot(resource_group_name=self.resource_group,
- name=self.webapp_name,
- slot=self.name)
- except CloudError as e:
- self.log('Error attempting to delete the Web App slot.')
- self.fail(
- "Error deleting the Web App slots: {0}".format(str(e)))
-
- return True
-
- def get_webapp(self):
- '''
- Gets the properties of the specified Web App.
-
- :return: deserialized Web App instance state dictionary
- '''
- self.log(
- "Checking if the Web App instance {0} is present".format(self.webapp_name))
-
- response = None
-
- try:
- response = self.web_client.web_apps.get(resource_group_name=self.resource_group,
- name=self.webapp_name)
-
- # Newer SDK versions (0.40.0+) seem to return None if it doesn't exist instead of raising CloudError
- if response is not None:
- self.log("Response : {0}".format(response))
- self.log("Web App instance : {0} found".format(response.name))
- return webapp_to_dict(response)
-
- except CloudError as ex:
- pass
-
- self.log("Didn't find web app {0} in resource group {1}".format(
- self.webapp_name, self.resource_group))
-
- return False
-
- def get_slot(self):
- '''
- Gets the properties of the specified Web App slot.
-
- :return: deserialized Web App slot state dictionary
- '''
- self.log(
- "Checking if the Web App slot {0} is present".format(self.name))
-
- response = None
-
- try:
- response = self.web_client.web_apps.get_slot(resource_group_name=self.resource_group,
- name=self.webapp_name,
- slot=self.name)
-
- # Newer SDK versions (0.40.0+) seem to return None if it doesn't exist instead of raising CloudError
- if response is not None:
- self.log("Response : {0}".format(response))
- self.log("Web App slot: {0} found".format(response.name))
- return slot_to_dict(response)
-
- except CloudError as ex:
- pass
-
- self.log("Does not find web app slot {0} in resource group {1}".format(self.name, self.resource_group))
-
- return False
-
- def list_app_settings(self):
- '''
- List webapp application settings
- :return: deserialized list response
- '''
- self.log("List webapp application setting")
-
- try:
-
- response = self.web_client.web_apps.list_application_settings(
- resource_group_name=self.resource_group, name=self.webapp_name)
- self.log("Response : {0}".format(response))
-
- return response.properties
- except CloudError as ex:
- self.fail("Failed to list application settings for web app {0} in resource group {1}: {2}".format(
- self.name, self.resource_group, str(ex)))
-
- def list_app_settings_slot(self, slot_name):
- '''
- List application settings
- :return: deserialized list response
- '''
- self.log("List application setting")
-
- try:
-
- response = self.web_client.web_apps.list_application_settings_slot(
- resource_group_name=self.resource_group, name=self.webapp_name, slot=slot_name)
- self.log("Response : {0}".format(response))
-
- return response.properties
- except CloudError as ex:
- self.fail("Failed to list application settings for web app slot {0} in resource group {1}: {2}".format(
- self.name, self.resource_group, str(ex)))
-
- def update_app_settings_slot(self, slot_name=None, app_settings=None):
- '''
- Update application settings
- :return: deserialized updating response
- '''
- self.log("Update application setting")
-
- if slot_name is None:
- slot_name = self.name
- if app_settings is None:
- app_settings = self.app_settings_strDic
- try:
- response = self.web_client.web_apps.update_application_settings_slot(resource_group_name=self.resource_group,
- name=self.webapp_name,
- slot=slot_name,
- kind=None,
- properties=app_settings)
- self.log("Response : {0}".format(response))
-
- return response.as_dict()
- except CloudError as ex:
- self.fail("Failed to update application settings for web app slot {0} in resource group {1}: {2}".format(
- self.name, self.resource_group, str(ex)))
-
- return response
-
- def create_or_update_source_control_slot(self):
- '''
- Update site source control
- :return: deserialized updating response
- '''
- self.log("Update site source control")
-
- if self.deployment_source is None:
- return False
-
- self.deployment_source['is_manual_integration'] = False
- self.deployment_source['is_mercurial'] = False
-
- try:
- response = self.web_client.web_client.create_or_update_source_control_slot(
- resource_group_name=self.resource_group,
- name=self.webapp_name,
- site_source_control=self.deployment_source,
- slot=self.name)
- self.log("Response : {0}".format(response))
-
- return response.as_dict()
- except CloudError as ex:
- self.fail("Failed to update site source control for web app slot {0} in resource group {1}: {2}".format(
- self.name, self.resource_group, str(ex)))
-
- def get_configuration(self):
- '''
- Get web app configuration
- :return: deserialized web app configuration response
- '''
- self.log("Get web app configuration")
-
- try:
-
- response = self.web_client.web_apps.get_configuration(
- resource_group_name=self.resource_group, name=self.webapp_name)
- self.log("Response : {0}".format(response))
-
- return response
- except CloudError as ex:
- self.fail("Failed to get configuration for web app {0} in resource group {1}: {2}".format(
- self.webapp_name, self.resource_group, str(ex)))
-
- def get_configuration_slot(self, slot_name):
- '''
- Get slot configuration
- :return: deserialized slot configuration response
- '''
- self.log("Get web app slot configuration")
-
- try:
-
- response = self.web_client.web_apps.get_configuration_slot(
- resource_group_name=self.resource_group, name=self.webapp_name, slot=slot_name)
- self.log("Response : {0}".format(response))
-
- return response
- except CloudError as ex:
- self.fail("Failed to get configuration for web app slot {0} in resource group {1}: {2}".format(
- slot_name, self.resource_group, str(ex)))
-
- def update_configuration_slot(self, slot_name=None, site_config=None):
- '''
- Update slot configuration
- :return: deserialized slot configuration response
- '''
- self.log("Update web app slot configuration")
-
- if slot_name is None:
- slot_name = self.name
- if site_config is None:
- site_config = self.site_config
- try:
-
- response = self.web_client.web_apps.update_configuration_slot(
- resource_group_name=self.resource_group, name=self.webapp_name, slot=slot_name, site_config=site_config)
- self.log("Response : {0}".format(response))
-
- return response
- except CloudError as ex:
- self.fail("Failed to update configuration for web app slot {0} in resource group {1}: {2}".format(
- slot_name, self.resource_group, str(ex)))
-
- def set_state_slot(self, appstate):
- '''
- Start/stop/restart web app slot
- :return: deserialized updating response
- '''
- try:
- if appstate == 'started':
- response = self.web_client.web_apps.start_slot(resource_group_name=self.resource_group, name=self.webapp_name, slot=self.name)
- elif appstate == 'stopped':
- response = self.web_client.web_apps.stop_slot(resource_group_name=self.resource_group, name=self.webapp_name, slot=self.name)
- elif appstate == 'restarted':
- response = self.web_client.web_apps.restart_slot(resource_group_name=self.resource_group, name=self.webapp_name, slot=self.name)
- else:
- self.fail("Invalid web app slot state {0}".format(appstate))
-
- self.log("Response : {0}".format(response))
-
- return response
- except CloudError as ex:
- request_id = ex.request_id if ex.request_id else ''
- self.fail("Failed to {0} web app slot {1} in resource group {2}, request_id {3} - {4}".format(
- appstate, self.name, self.resource_group, request_id, str(ex)))
-
- def swap_slot(self):
- '''
- Swap slot
- :return: deserialized response
- '''
- self.log("Swap slot")
-
- try:
- if self.swap['action'] == 'swap':
- if self.swap['target_slot'] is None:
- response = self.web_client.web_apps.swap_slot_with_production(resource_group_name=self.resource_group,
- name=self.webapp_name,
- target_slot=self.name,
- preserve_vnet=self.swap['preserve_vnet'])
- else:
- response = self.web_client.web_apps.swap_slot_slot(resource_group_name=self.resource_group,
- name=self.webapp_name,
- slot=self.name,
- target_slot=self.swap['target_slot'],
- preserve_vnet=self.swap['preserve_vnet'])
- elif self.swap['action'] == 'preview':
- if self.swap['target_slot'] is None:
- response = self.web_client.web_apps.apply_slot_config_to_production(resource_group_name=self.resource_group,
- name=self.webapp_name,
- target_slot=self.name,
- preserve_vnet=self.swap['preserve_vnet'])
- else:
- response = self.web_client.web_apps.apply_slot_configuration_slot(resource_group_name=self.resource_group,
- name=self.webapp_name,
- slot=self.name,
- target_slot=self.swap['target_slot'],
- preserve_vnet=self.swap['preserve_vnet'])
- elif self.swap['action'] == 'reset':
- if self.swap['target_slot'] is None:
- response = self.web_client.web_apps.reset_production_slot_config(resource_group_name=self.resource_group,
- name=self.webapp_name)
- else:
- response = self.web_client.web_apps.reset_slot_configuration_slot(resource_group_name=self.resource_group,
- name=self.webapp_name,
- slot=self.swap['target_slot'])
- response = self.web_client.web_apps.reset_slot_configuration_slot(resource_group_name=self.resource_group,
- name=self.webapp_name,
- slot=self.name)
-
- self.log("Response : {0}".format(response))
-
- return response
- except CloudError as ex:
- self.fail("Failed to swap web app slot {0} in resource group {1}: {2}".format(self.name, self.resource_group, str(ex)))
-
- def clone_slot(self):
- if self.configuration_source:
- src_slot = None if self.configuration_source.lower() == self.webapp_name.lower() else self.configuration_source
-
- if src_slot is None:
- site_config_clone_from = self.get_configuration()
- else:
- site_config_clone_from = self.get_configuration_slot(slot_name=src_slot)
-
- self.update_configuration_slot(site_config=site_config_clone_from)
-
- if src_slot is None:
- app_setting_clone_from = self.list_app_settings()
- else:
- app_setting_clone_from = self.list_app_settings_slot(src_slot)
-
- if self.app_settings:
- app_setting_clone_from.update(self.app_settings)
-
- self.update_app_settings_slot(app_settings=app_setting_clone_from)
-
-
-def main():
- """Main execution"""
- AzureRMWebAppSlots()
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/utils/shippable/incidental/azure.sh b/test/utils/shippable/incidental/azure.sh
deleted file mode 120000
index 700ad3edcf..0000000000
--- a/test/utils/shippable/incidental/azure.sh
+++ /dev/null
@@ -1 +0,0 @@
-cloud.sh \ No newline at end of file