[new module] Azure Traffic Manager profile module (#43812)

* add traffic manager client and models in azure_rm_common
- add traffic manager management client
- import traffic manager models to 'traffic_manager_models' proprety
- azure.mgmt.trafficmanager doesn't have models(), so use direct import
for now

* add traffic manager facts module

* add traffic manager module

* add integration test for two modules

* fix package info in requirements

* fix sanity check

* fix monitor config default value

* fix facts module doc

* move model import into module

* resolve comments except seprating endpoint

* remove endpoint operation

* fix test after removing endpoint operation

* change module name to azure_rm_trafficmanagerprofile/facts

* fix sanity test

* seperate endpoint into delegate module

* fix typo

* fix lint

* fix lint

* fix test

* fix test

* resolve comments

* fix test

* fix test

* fix test

* fix bug in return

* resolve comments

* fix lint

* fix lint

* add sample in endpoint module
pull/44719/head
Hai Cao 6 years ago committed by Jordan Borean
parent fbcdf8ba5b
commit ccb7909cc5

@ -150,6 +150,7 @@ try:
from azure.mgmt.web import WebSiteManagementClient from azure.mgmt.web import WebSiteManagementClient
from azure.mgmt.containerservice import ContainerServiceClient from azure.mgmt.containerservice import ContainerServiceClient
from azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements from azure.mgmt.marketplaceordering import MarketplaceOrderingAgreements
from azure.mgmt.trafficmanager import TrafficManagerManagementClient
from azure.storage.cloudstorageaccount import CloudStorageAccount from azure.storage.cloudstorageaccount import CloudStorageAccount
from adal.authentication_context import AuthenticationContext from adal.authentication_context import AuthenticationContext
from azure.mgmt.rdbms.postgresql import PostgreSQLManagementClient from azure.mgmt.rdbms.postgresql import PostgreSQLManagementClient
@ -222,6 +223,10 @@ AZURE_PKG_VERSIONS = {
'package_name': 'web', 'package_name': 'web',
'expected_version': '0.32.0' 'expected_version': '0.32.0'
}, },
'TrafficManagerManagementClient': {
'package_name': 'trafficmanager',
'expected_version': '0.50.0'
},
} if HAS_AZURE else {} } if HAS_AZURE else {}
@ -282,6 +287,8 @@ class AzureRMModuleBase(object):
self._postgresql_client = None self._postgresql_client = None
self._containerregistry_client = None self._containerregistry_client = None
self._containerinstance_client = None self._containerinstance_client = None
self._traffic_manager_management_client = None
self._adfs_authority_url = None self._adfs_authority_url = None
self._resource = None self._resource = None
@ -1109,3 +1116,11 @@ class AzureRMModuleBase(object):
self._marketplace_client = self.get_mgmt_svc_client(MarketplaceOrderingAgreements, self._marketplace_client = self.get_mgmt_svc_client(MarketplaceOrderingAgreements,
base_url=self._cloud_environment.endpoints.resource_manager) base_url=self._cloud_environment.endpoints.resource_manager)
return self._marketplace_client 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

@ -0,0 +1,371 @@
#!/usr/bin/python
#
# Copyright (c) 2018 Hai Cao, <t-haicao@microsoft.com>, 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_trafficmanagerendpoint
version_added: "2.7"
short_description: Manage Azure Traffic Manager endpoint.
description:
- Create, update and delete Azure Traffic Manager endpoint.
options:
resource_group:
description:
- Name of a resource group where the Traffic Manager endpoint exists or will be created.
type: str
required: true
name:
description:
- The name of the endpoint.
type: str
required: true
profile_name:
description: Name of Traffic Manager profile where this endpoints attaches to.
type: str
required: true
type:
description:
- The type of the endpoint.
required: true
choices:
- azure_endpoints
- external_endpoints
- nested_endpoints
target_resource_id:
description:
- The Azure Resource URI of the of the endpoint.
- Not applicable to endpoints of I(type) C(external_endpoints).
type: str
target:
description:
- The fully-qualified DNS name of the endpoint.
type: str
enabled:
description:
- The status of the endpoint.
type: bool
default: true
weight:
description:
- The weight of this endpoint when traffic manager profile has routing_method of C(weighted).
- Possible values are from 1 to 1000.
type: int
priority:
description:
- The priority of this endpoint when traffic manager profile has routing_method of C(priority).
- Possible values are from 1 to 1000, lower values represent higher priority.
- This is an optional parameter. If specified, it must be specified on all endpoints.
- No two endpoints can share the same priority value.
type: int
location:
description:
- Specifies the location of the external or nested endpoints when using the 'Performance' traffic routing method.
type: str
min_child_endpoints:
description:
- The minimum number of endpoints that must be available in the child profile in order for the parent profile to be considered available.
- Only applicable to endpoint of I(type) (nested_endpoints).
type: int
geo_mapping:
description:
- The list of countries/regions mapped to this endpoint when traffic manager profile has routing_method of C(geographic).
type: str
state:
description:
- Assert the state of the Traffic Manager endpoint. Use C(present) to create or update a Traffic Manager endpoint and C(absent) to delete it.
default: present
choices:
- absent
- present
extends_documentation_fragment:
- azure
author:
- "Hai Cao <t-haicao@microsoft.com>"
- "Yunge Zhu <yungez@microsoft.com>"
'''
EXAMPLES = '''
- name: create a endpoint for a traffic manager profile
azure_rm_trafficmanagerendpoint:
resource_group: testresourcegroup
profile_name: myprofilename
name: testendpoint1
type: external_endpoints
location: westus
priority: 2
weight: 1
target: 1.2.3.4
'''
RETURN = '''
id:
description: The ID of the traffic manager endpoint
returned: when traffic manager endpoint exists
type: str
example:
"/subscriptions/<subsid>/resourceGroups/testRg/providers/Microsoft.Network/trafficManagerProfiles/testProfile/externalEndpoints/testendpoint"
'''
from ansible.module_utils.azure_rm_common import AzureRMModuleBase, normalize_location_name
from ansible.module_utils.common.dict_transformations import _snake_to_camel
try:
from msrestazure.azure_exceptions import CloudError
from azure.mgmt.trafficmanager.models import (
Endpoint, DnsConfig, MonitorConfig
)
except ImportError:
# This is handled in azure_rm_common
pass
def traffic_manager_endpoint_to_dict(endpoint):
return dict(
id=endpoint.id,
name=endpoint.name,
type=endpoint.type,
target_resource_id=endpoint.target_resource_id,
target=endpoint.target,
status=endpoint.endpoint_status,
weight=endpoint.weight,
priority=endpoint.priority,
location=endpoint.endpoint_location,
monitor_status=endpoint.endpoint_monitor_status,
min_child_endpoints=endpoint.min_child_endpoints,
geo_mapping=endpoint.geo_mapping
)
class Actions:
NoAction, CreateOrUpdate, Delete = range(3)
class AzureRMTrafficManagerEndpoint(AzureRMModuleBase):
def __init__(self):
self.module_arg_spec = dict(
resource_group=dict(
type='str',
required=True
),
name=dict(
type='str',
required=True
),
profile_name=dict(
type='str',
required=True
),
type=dict(
type='str',
choices=['azure_endpoints', 'external_endpoints', 'nested_endpoints'],
required=True
),
target=dict(type='str'),
target_resource_id=dict(type='str'),
enabled=dict(type='bool', default=True),
weight=dict(type='int'),
priority=dict(type='int'),
location=dict(type='str'),
min_child_endpoints=dict(type='int'),
geo_mapping=dict(type='list', elements='str'),
state=dict(
type='str',
default='present',
choices=['present', 'absent']
),
)
self.resource_group = None
self.name = None
self.state = None
self.profile_name = None
self.type = None
self.target_resource_id = None
self.enabled = None
self.weight = None
self.priority = None
self.location = None
self.min_child_endpoints = None
self.geo_mapping = None
self.endpoint_status = 'Enabled'
self.action = Actions.NoAction
self.results = dict(
changed=False
)
super(AzureRMTrafficManagerEndpoint, 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()):
setattr(self, key, kwargs[key])
if self.type:
self.type = _snake_to_camel(self.type)
to_be_updated = False
resource_group = self.get_resource_group(self.resource_group)
if not self.location:
self.location = resource_group.location
if self.enabled is not None and self.enabled is False:
self.endpoint_status = 'Disabled'
response = self.get_traffic_manager_endpoint()
if response:
self.log('Results : {0}'.format(response))
self.results['id'] = response['id']
if self.state == 'present':
# check update
to_be_update = self.check_update(response)
if to_be_update:
self.action = Actions.CreateOrUpdate
elif self.state == 'absent':
# delete
self.action = Actions.Delete
else:
if self.state == 'present':
self.action = Actions.CreateOrUpdate
elif self.state == 'absent':
# delete when no exists
self.fail("Traffic Manager endpoint {0} not exists.".format(self.name))
if self.action == Actions.CreateOrUpdate:
self.results['changed'] = True
if self.check_mode:
return self.results
response = self.create_update_traffic_manager_endpoint()
self.results['id'] = response['id']
if self.action == Actions.Delete:
self.results['changed'] = True
if self.check_mode:
return self.results
response = self.delete_traffic_manager_endpoint()
return self.results
def get_traffic_manager_endpoint(self):
'''
Gets the properties of the specified Traffic Manager endpoint
:return: deserialized Traffic Manager endpoint dict
'''
self.log("Checking if Traffic Manager endpoint {0} is present".format(self.name))
try:
response = self.traffic_manager_management_client.endpoints.get(self.resource_group, self.profile_name, self.type, self.name)
self.log("Response : {0}".format(response))
return traffic_manager_endpoint_to_dict(response)
except CloudError:
self.log('Did not find the Traffic Manager endpoint.')
return False
def delete_traffic_manager_endpoint(self):
'''
Deletes the specified Traffic Manager endpoint.
:return: True
'''
self.log("Deleting the Traffic Manager endpoint {0}".format(self.name))
try:
operation_result = self.traffic_manager_management_client.endpoints.delete(self.resource_group, self.profile_name, self.type, self.name)
return True
except CloudError as exc:
request_id = exc.request_id if exc.request_id else ''
self.fail("Error deleting the Traffic Manager endpoint {0}, request id {1} - {2}".format(self.name, request_id, str(exc)))
return False
def create_update_traffic_manager_endpoint(self):
'''
Creates or updates a Traffic Manager endpoint.
:return: deserialized Traffic Manager endpoint state dictionary
'''
self.log("Creating / Updating the Traffic Manager endpoint {0}".format(self.name))
parameters = Endpoint(target_resource_id=self.target_resource_id,
target=self.target,
endpoint_status=self.endpoint_status,
weight=self.weight,
priority=self.priority,
endpoint_location=self.location,
min_child_endpoints=self.min_child_endpoints,
geo_mapping=self.geo_mapping)
try:
response = self.traffic_manager_management_client.endpoints.create_or_update(self.resource_group,
self.profile_name,
self.type,
self.name,
parameters)
return traffic_manager_endpoint_to_dict(response)
except CloudError as exc:
request_id = exc.request_id if exc.request_id else ''
self.fail("Error creating the Traffic Manager endpoint {0}, request id {1} - {2}".format(self.name, request_id, str(exc)))
def check_update(self, response):
if self.endpoint_status is not None and response['status'].lower() != self.endpoint_status.lower():
self.log("Status Diff - Origin {0} / Update {1}".format(response['status'], self.endpoint_status))
return True
if self.type and response['type'].lower() != "Microsoft.network/TrafficManagerProfiles/{0}".format(self.type).lower():
self.log("Type Diff - Origin {0} / Update {1}".format(response['type'], self.type))
return True
if self.target_resource_id and response['target_resource_id'] != self.target_resource_id:
self.log("target_resource_id Diff - Origin {0} / Update {1}".format(response['target_resource_id'], self.target_resource_id))
return True
if self.target and response['target'] != self.target:
self.log("target Diff - Origin {0} / Update {1}".format(response['target'], self.target))
return True
if self.weight and int(response['weight']) != self.weight:
self.log("weight Diff - Origin {0} / Update {1}".format(response['weight'], self.weight))
return True
if self.priority and int(response['priority']) != self.priority:
self.log("priority Diff - Origin {0} / Update {1}".format(response['priority'], self.priority))
return True
if self.min_child_endpoints and int(response['min_child_endpoints']) != self.min_child_endpoints:
self.log("min_child_endpoints Diff - Origin {0} / Update {1}".format(response['min_child_endpoints'], self.min_child_endpoints))
return True
if self.geo_mapping and response['geo_mapping'] != self.geo_mapping:
self.log("geo_mapping Diff - Origin {0} / Update {1}".format(response['geo_mapping'], self.geo_mapping))
return True
return False
def main():
"""Main execution"""
AzureRMTrafficManagerEndpoint()
if __name__ == '__main__':
main()

@ -0,0 +1,297 @@
#!/usr/bin/python
#
# Copyright (c) 2018 Hai Cao, <t-haicao@microsoft.com>, 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_trafficmanagerendpoint_facts
version_added: "2.7"
short_description: Get Azure Traffic Manager endpoint facts
description:
- Get facts for a specific Traffic Manager endpoints or all endpoints in a Traffic Manager profile
options:
name:
description:
- Limit results to a specific Traffic Manager endpoint.
resource_group:
description:
- The resource group to search for the desired Traffic Manager profile
required: True
profile_name:
description:
- Name of Traffic Manager Profile
required: True
type:
description:
- Type of endpoint.
choices:
- azure_endpoints
- external_endpoints
- nested_endpoints
extends_documentation_fragment:
- azure
author:
- "Hai Cao <t-haicao@microsoft.com>"
- "Yunge Zhu <yungez@microsoft.com>"
'''
EXAMPLES = '''
- name: Get endpoints facts of a Traffic Manager profile
azure_rm_trafficmanagerendpoint_facts:
resource_group: TestRG
profile_name: Testing
- name: Get specific endpoint of a Traffic Manager profie
azure_rm_trafficmanager_facts:
resource_group: TestRG
profile_name: Testing
name: test_external_endpoint
'''
RETURN = '''
endpoints:
description: List of Traffic Manager endpoints.
returned: always
type: complex
contains:
resource_group:
description:
- Name of a resource group.
returned: always
type: str
sample: testGroup
name:
description:
- Name of the Traffic Manager endpoint.
returned: always
type: str
sample: testendpoint
type:
description:
- The type of the endpoint.
type: str
sample: external_endpoints
target_resource_id:
description:
- The Azure Resource URI of the of the endpoint.
type: str
sample: /subscriptions/XXXXXX...XXXXXXXXX/resourceGroups/vscjavaci/providers/Microsoft.ClassicCompute/domainNames/vscjavaci
target:
description:
- The fully-qualified DNS name of the endpoint.
type: str
sample: 8.8.8.8
enabled:
description:
- The status of the endpoint.
type: str
sample: Enabled
weight:
description:
- The weight of this endpoint when using the 'Weighted' traffic routing method.
type: int
sample: 10
priority:
description:
- The priority of this endpoint when using the 'Priority' traffic routing method.
type: str
sample: 3
location:
description:
- The location of the external or nested endpoints when using the 'Performance' traffic routing method.
type: str
sample: East US
min_child_endpoints:
description:
- The minimum number of endpoints that must be available in the child profile to make the parent profile available.
type: int
sample: 3
geo_mapping:
description:
- The list of countries/regions mapped to this endpoint when using the 'Geographic' traffic routing method.
type: list
sample: [
"GEO-NA",
"GEO-AS"
]
'''
from ansible.module_utils.azure_rm_common import AzureRMModuleBase
from ansible.module_utils.common.dict_transformations import (
_snake_to_camel, _camel_to_snake
)
try:
from msrestazure.azure_exceptions import CloudError
from azure.common import AzureHttpError
except:
# handled in azure_rm_common
pass
import re
AZURE_OBJECT_CLASS = 'TrafficManagerEndpoints'
def serialize_endpoint(endpoint, resource_group):
result = dict(
id=endpoint.id,
name=endpoint.name,
target_resource_id=endpoint.target_resource_id,
target=endpoint.target,
enabled=True,
weight=endpoint.weight,
priority=endpoint.priority,
location=endpoint.endpoint_location,
min_child_endpoints=endpoint.min_child_endpoints,
geo_mapping=endpoint.geo_mapping,
monitor_status=endpoint.endpoint_monitor_status,
resource_group=resource_group
)
if endpoint.endpoint_status and endpoint.endpoint_status == 'Disabled':
result['enabled'] = False
if endpoint.type:
result['type'] = _camel_to_snake(endpoint.type.split("/")[-1])
return result
class AzureRMTrafficManagerEndpointFacts(AzureRMModuleBase):
"""Utility class to get Azure Traffic Manager Endpoint facts"""
def __init__(self):
self.module_args = dict(
profile_name=dict(
type='str',
required=True),
resource_group=dict(
type='str',
required=True),
name=dict(type='str'),
type=dict(
type='str',
choices=[
'azure_endpoints',
'external_endpoints',
'nested_endpoints'
])
)
self.results = dict(
changed=False,
endpoints=[]
)
self.profile_name = None
self.name = None
self.resource_group = None
self.type = None
super(AzureRMTrafficManagerEndpointFacts, self).__init__(
derived_arg_spec=self.module_args,
supports_tags=False,
facts_module=True
)
def exec_module(self, **kwargs):
for key in self.module_args:
setattr(self, key, kwargs[key])
if self.type:
self.type = _snake_to_camel(self.type)
if self.name and not self.resource_group:
self.fail("Parameter error: resource group required when filtering by name.")
if self.name:
self.results['endpoints'] = self.get_item()
elif self.type:
self.results['endpoints'] = self.list_by_type()
else:
self.results['endpoints'] = self.list_by_profile()
return self.results
def get_item(self):
"""Get a single Azure Traffic Manager endpoint"""
self.log('Get properties for {0}'.format(self.name))
item = None
result = []
try:
item = self.traffic_manager_management_client.endpoints.get(
self.resource_group, self.profile_name, self.type, self.name)
except CloudError:
pass
if item:
if (self.type and self.type == item.type) or self.type is None:
result = [self.serialize_tm(item)]
return result
def list_by_profile(self):
"""Get all Azure Traffic Manager endpoints of a profile"""
self.log('List all endpoints belongs to a Traffic Manager profile')
try:
response = self.traffic_manager_management_client.profiles.get(self.resource_group, self.profile_name)
except AzureHttpError as exc:
self.fail('Failed to list all items - {0}'.format(str(exc)))
results = []
if response and response.endpoints:
for endpoint in response.endpoints:
results.append(serialize_endpoint(endpoint, self.resource_group))
return results
def list_by_type(self):
"""Get all Azure Traffic Managers endpoints of a profile by type"""
self.log('List all Traffic Manager endpoints of a profile by type')
try:
response = self.traffic_manager_management_client.profiles.get(self.resource_group, self.profile_name)
except AzureHttpError as exc:
self.fail('Failed to list all items - {0}'.format(str(exc)))
results = []
for item in response:
if item.endpoints:
for endpoint in item.endpoints:
if endpoint.type == self.type:
results.append(serialize_endpoint(endpoint, self.resource_group))
return results
def main():
"""Main module execution code path"""
AzureRMTrafficManagerEndpointFacts()
if __name__ == '__main__':
main()

@ -0,0 +1,457 @@
#!/usr/bin/python
#
# Copyright (c) 2018 Hai Cao, <t-haicao@microsoft.com> 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_trafficmanagerprofile
version_added: "2.7"
short_description: Manage Azure Traffic Manager profile.
description:
- Create, update and delete a Traffic Manager profile.
options:
resource_group:
description:
- Name of a resource group where the Traffic Manager profile exists or will be created.
required: true
name:
description:
- Name of the Traffic Manager profile.
required: true
state:
description:
- Assert the state of the Traffic Manager profile. Use C(present) to create or update a Traffic Manager profile and C(absent) to delete it.
default: present
choices:
- absent
- present
location:
description:
- Valid azure location. Defaults to 'global' because in default public Azure cloud, Traffic Manager profile can only be deployed globally.
- Reference https://docs.microsoft.com/en-us/azure/traffic-manager/quickstart-create-traffic-manager-profile#create-a-traffic-manager-profile
default: global
profile_status:
description:
- The status of the Traffic Manager profile.
default: enabled
choices:
- enabled
- disabled
routing_method:
description:
- The traffic routing method of the Traffic Manager profile.
default: performance
choices:
- performance
- priority
- weighted
- geographic
dns_config:
description:
- The DNS settings of the Traffic Manager profile.
suboptions:
relative_name:
description:
- The relative DNS name provided by this Traffic Manager profile.
- If not provided, name of the Traffic Manager will be used
ttl:
description:
- The DNS Time-To-Live (TTL), in seconds.
default: 60
monitor_config:
description:
- The endpoint monitoring settings of the Traffic Manager profile.
suboptions:
protocol:
description:
- The protocol (HTTP, HTTPS or TCP) used to probe for endpoint health.
choices:
- HTTP
- HTTPS
- TCP
port:
description:
- The TCP port used to probe for endpoint health.
path:
description:
- The path relative to the endpoint domain name used to probe for endpoint health.
interval:
description:
- The monitor interval for endpoints in this profile in seconds.
timeout:
description:
- The monitor timeout for endpoints in this profile in seconds.
tolerated_failures:
description:
- The number of consecutive failed health check before declaring an endpoint in this profile Degraded after the next failed health check.
default:
protocol: HTTP
port: 80
path: /
extends_documentation_fragment:
- azure
- azure_tags
author:
- "Hai Cao <t-haicao@microsoft.com>"
- "Yunge Zhu <yungez@microsoft.com>"
'''
EXAMPLES = '''
- name: Create a Traffic Manager Profile
azure_rm_trafficmanager:
name: tmtest
resource_group: tmt
location: global
profile_status: enabled
routing_method: priority
dns_config:
relative_name: tmtest
ttl: 60
monitor_config:
protocol: HTTPS
port: 80
path: '/'
tags:
Environment: Test
- name: Delete a Traffic Manager Profile
azure_rm_trafficmanager:
state: absent
name: tmtest
resource_group: tmt
'''
RETURN = '''
id:
description: The ID of the traffic manager profile
returned: when traffic manager profile exists
type: str
example: "/subscriptions/XXXXXX...XXXXXXXXX/resourceGroups/tmt/providers/Microsoft.Network/trafficManagerProfiles/tmtest"
endpoints:
description: List of endpoint IDs attached to the profile
returned: when traffic manager endpoints exists
type: list
sample: [
"/subscriptions/XXXXXX...XXXXXXXXX/resourceGroups/tmt/providers/Microsoft.Network/trafficManagerProfiles/tm049b1ae293/externalEndpoints/e2",
"/subscriptions/XXXXXX...XXXXXXXXX/resourceGroups/tmt/providers/Microsoft.Network/trafficManagerProfiles/tm049b1ae293/externalEndpoints/e1"
]
'''
from ansible.module_utils.azure_rm_common import AzureRMModuleBase, normalize_location_name
try:
from msrestazure.azure_exceptions import CloudError
from azure.mgmt.trafficmanager.models import (
Profile, Endpoint, DnsConfig, MonitorConfig
)
except ImportError:
# This is handled in azure_rm_common
pass
def shorten_traffic_manager_dict(tmd):
return dict(
id=tmd['id'],
endpoints=[endpoint['id'] for endpoint in tmd['endpoints']] if tmd['endpoints'] else []
)
def traffic_manager_profile_to_dict(tmp):
result = dict(
id=tmp.id,
name=tmp.name,
type=tmp.type,
tags=tmp.tags,
location=tmp.location,
profile_status=tmp.profile_status,
routing_method=tmp.traffic_routing_method,
dns_config=dict(),
monitor_config=dict(),
endpoints=[]
)
if tmp.dns_config:
result['dns_config']['relative_name'] = tmp.dns_config.relative_name
result['dns_config']['fqdn'] = tmp.dns_config.fqdn
result['dns_config']['ttl'] = tmp.dns_config.ttl
if tmp.monitor_config:
result['monitor_config']['profile_monitor_status'] = tmp.monitor_config.profile_monitor_status
result['monitor_config']['protocol'] = tmp.monitor_config.protocol
result['monitor_config']['port'] = tmp.monitor_config.port
result['monitor_config']['path'] = tmp.monitor_config.path
result['monitor_config']['interval'] = tmp.monitor_config.interval_in_seconds
result['monitor_config']['timeout'] = tmp.monitor_config.timeout_in_seconds
result['monitor_config']['tolerated_failures'] = tmp.monitor_config.tolerated_number_of_failures
if tmp.endpoints:
for endpoint in tmp.endpoints:
result['endpoints'].append(dict(
id=endpoint.id,
name=endpoint.name,
type=endpoint.type,
target_resource_id=endpoint.target_resource_id,
target=endpoint.target,
endpoint_status=endpoint.endpoint_status,
weight=endpoint.weight,
priority=endpoint.priority,
endpoint_location=endpoint.endpoint_location,
endpoint_monitor_status=endpoint.endpoint_monitor_status,
min_child_endpoints=endpoint.min_child_endpoints,
geo_mapping=endpoint.geo_mapping
))
return result
def create_dns_config_instance(dns_config):
return DnsConfig(
relative_name=dns_config['relative_name'],
ttl=dns_config['ttl']
)
def create_monitor_config_instance(monitor_config):
return MonitorConfig(
profile_monitor_status=monitor_config['profile_monitor_status'],
protocol=monitor_config['protocol'],
port=monitor_config['port'],
path=monitor_config['path'],
interval_in_seconds=monitor_config['interval'],
timeout_in_seconds=monitor_config['timeout'],
tolerated_number_of_failures=monitor_config['tolerated_failures']
)
dns_config_spec = dict(
relative_name=dict(type='str'),
ttl=dict(type='int')
)
monitor_config_spec = dict(
profile_monitor_status=dict(type='str'),
protocol=dict(type='str'),
port=dict(type='int'),
path=dict(type='str'),
interval=dict(type='int'),
timeout=dict(type='int'),
tolerated_failures=dict(type='int')
)
class AzureRMTrafficManagerProfile(AzureRMModuleBase):
def __init__(self):
self.module_arg_spec = dict(
resource_group=dict(
type='str',
required=True
),
name=dict(
type='str',
required=True
),
state=dict(
type='str',
default='present',
choices=['present', 'absent']
),
location=dict(
type='str',
default='global'
),
profile_status=dict(
type='str',
default='enabled',
choices=['enabled', 'disabled']
),
routing_method=dict(
type='str',
default='performance',
choices=['performance', 'priority', 'weighted', 'geographic']
),
dns_config=dict(
type='dict',
options=dns_config_spec
),
monitor_config=dict(
type='dict',
default=dict(
protocol='HTTP',
port=80,
path='/'
),
options=monitor_config_spec
),
)
self.resource_group = None
self.name = None
self.state = None
self.tags = None
self.location = None
self.profile_status = None
self.routing_method = None
self.dns_config = None
self.monitor_config = None
self.endpoints_copy = None
self.results = dict(
changed=False
)
super(AzureRMTrafficManagerProfile, self).__init__(derived_arg_spec=self.module_arg_spec,
supports_check_mode=True,
supports_tags=True)
def exec_module(self, **kwargs):
for key in list(self.module_arg_spec.keys()) + ['tags']:
setattr(self, key, kwargs[key])
to_be_updated = False
if not self.dns_config:
self.dns_config = dict(
relative_name=self.name,
ttl=60
)
if not self.location:
self.location = 'global'
response = self.get_traffic_manager_profile()
if self.state == 'present':
if not response:
to_be_updated = True
else:
self.results = shorten_traffic_manager_dict(response)
self.log('Results : {0}'.format(response))
update_tags, response['tags'] = self.update_tags(response['tags'])
if update_tags:
to_be_updated = True
to_be_updated = to_be_updated or self.check_update(response)
if to_be_updated:
self.log("Need to Create / Update the Traffic Manager profile")
if not self.check_mode:
self.results = shorten_traffic_manager_dict(self.create_update_traffic_manager_profile())
self.log("Creation / Update done.")
self.results['changed'] = True
return self.results
elif self.state == 'absent' and response:
self.log("Need to delete the Traffic Manager profile")
self.results = shorten_traffic_manager_dict(response)
self.results['changed'] = True
if self.check_mode:
return self.results
self.delete_traffic_manager_profile()
self.log("Traffic Manager profile deleted")
return self.results
def get_traffic_manager_profile(self):
'''
Gets the properties of the specified Traffic Manager profile
:return: deserialized Traffic Manager profile dict
'''
self.log("Checking if Traffic Manager profile {0} is present".format(self.name))
try:
response = self.traffic_manager_management_client.profiles.get(self.resource_group, self.name)
self.log("Response : {0}".format(response))
self.log("Traffic Manager profile : {0} found".format(response.name))
self.endpoints_copy = response.endpoints if response and response.endpoints else None
return traffic_manager_profile_to_dict(response)
except CloudError:
self.log('Did not find the Traffic Manager profile.')
return False
def delete_traffic_manager_profile(self):
'''
Deletes the specified Traffic Manager profile in the specified subscription and resource group.
:return: True
'''
self.log("Deleting the Traffic Manager profile {0}".format(self.name))
try:
operation_result = self.traffic_manager_management_client.profiles.delete(self.resource_group, self.name)
return True
except CloudError as e:
self.log('Error attempting to delete the Traffic Manager profile.')
self.fail("Error deleting the Traffic Manager profile: {0}".format(e.message))
return False
def create_update_traffic_manager_profile(self):
'''
Creates or updates a Traffic Manager profile.
:return: deserialized Traffic Manager profile state dictionary
'''
self.log("Creating / Updating the Traffic Manager profile {0}".format(self.name))
parameters = Profile(
tags=self.tags,
location=self.location,
profile_status=self.profile_status,
traffic_routing_method=self.routing_method,
dns_config=create_dns_config_instance(self.dns_config) if self.dns_config else None,
monitor_config=create_monitor_config_instance(self.monitor_config) if self.monitor_config else None,
endpoints=self.endpoints_copy
)
try:
response = self.traffic_manager_management_client.profiles.create_or_update(self.resource_group, self.name, parameters)
return traffic_manager_profile_to_dict(response)
except CloudError as exc:
self.log('Error attempting to create the Traffic Manager.')
self.fail("Error creating the Traffic Manager: {0}".format(exc.message))
def check_update(self, response):
if self.location and normalize_location_name(response['location']) != normalize_location_name(self.location):
self.log("Location Diff - Origin {0} / Update {1}".format(response['location'], self.location))
return True
if self.profile_status and response['profile_status'].lower() != self.profile_status:
self.log("Profile Status Diff - Origin {0} / Update {1}".format(response['profile_status'], self.profile_status))
return True
if self.routing_method and response['routing_method'].lower() != self.routing_method:
self.log("Traffic Routing Method Diff - Origin {0} / Update {1}".format(response['routing_method'], self.routing_method))
return True
if self.dns_config and \
(response['dns_config']['relative_name'] != self.dns_config['relative_name'] or response['dns_config']['ttl'] != self.dns_config['ttl']):
self.log("DNS Config Diff - Origin {0} / Update {1}".format(response['dns_config'], self.dns_config))
return True
for k, v in self.monitor_config.items():
if v:
if str(v).lower() != str(response['monitor_config'][k]).lower():
self.log("Monitor Config Diff - Origin {0} / Update {1}".format(response['monitor_config'], self.monitor_config))
return True
return False
def main():
"""Main execution"""
AzureRMTrafficManagerProfile()
if __name__ == '__main__':
main()

@ -0,0 +1,378 @@
#!/usr/bin/python
#
# Copyright (c) 2018 Hai Cao, <t-haicao@microsoft.com>, 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_trafficmanagerprofile_facts
version_added: "2.7"
short_description: Get Azure Traffic Manager profile facts
description:
- Get facts for a Azure specific Traffic Manager profile or all Traffic Manager profiles.
options:
name:
description:
- Limit results to a specific Traffic Manager profile.
resource_group:
description:
- The resource group to search for the desired Traffic Manager profile
tags:
description:
- Limit results by providing a list of tags. Format tags as 'key' or 'key:value'.
extends_documentation_fragment:
- azure
author:
- "Hai Cao <t-haicao@microsoft.com>"
- "Yunge Zhu <yungez@microsoft.com>"
'''
EXAMPLES = '''
- name: Get facts for one Traffic Manager profile
azure_rm_trafficmanager_facts:
name: Testing
resource_group: TestRG
- name: Get facts for all Traffic Manager profiles
azure_rm_trafficmanager_facts:
- name: Get facts by tags
azure_rm_trafficmanager_facts:
tags:
- Environment:Test
'''
RETURN = '''
tms:
description: List of Traffic Manager profiles.
returned: always
type: complex
contains:
resource_group:
description:
- Name of a resource group where the Traffic Manager profile exists.
returned: always
type: str
sample: testGroup
name:
description:
- Name of the Traffic Manager profile.
returned: always
type: str
sample: testTm
state:
description:
- The state of the Traffic Manager profile.
type: str
sample: present
location:
description:
- Location of the Traffic Manager profile.
type: str
sample: global
profile_status:
description:
- The status of the Traffic Manager profile.
type: str
sample: Enabled
routing_method:
description:
- The traffic routing method of the Traffic Manager profile.
type: str
sample: performance
dns_config:
description:
- The DNS settings of the Traffic Manager profile.
type: complex
sample:
relative_name: testTm
fqdn: testTm.trafficmanager.net
ttl: 60
monitor_config:
description:
- The endpoint monitoring settings of the Traffic Manager profile.
type: complex
contains:
protocol:
description:
- The protocol (HTTP, HTTPS or TCP) used to probe for endpoint health.
type: str
sample: HTTP
port:
description:
- The TCP port used to probe for endpoint health.
type: int
sample: 80
path:
description:
- The path relative to the endpoint domain name used to probe for endpoint health.
type: str
sample: /
interval:
description:
- The monitor interval for endpoints in this profile in seconds.
type: int
sample: 10
timeout:
description:
- The monitor timeout for endpoints in this profile in seconds.
type: int
sample: 30
tolerated_failures:
description:
- The number of consecutive failed health check before declaring an endpoint Degraded after the next failed health check.
type: int
sample: 3
endpoints:
description:
- The list of endpoints in the Traffic Manager profile.
type: list
element: complex
contains:
id:
description:
- Fully qualified resource Id for the resource.
type: str
sample: /subscriptions/XXXXXX...XXXXXXXXX/resourceGroups/tmt/providers/Microsoft.Network/trafficManagerProfiles/tmtest/externalEndpoints/e1
name:
description:
- The name of the endpoint.
type: str
sample: e1
type:
description:
- The type of the endpoint.
type: str
sample: external_endpoints
target_resource_id:
description:
- The Azure Resource URI of the of the endpoint.
type: str
sample: /subscriptions/XXXXXX...XXXXXXXXX/resourceGroups/vscjavaci/providers/Microsoft.ClassicCompute/domainNames/vscjavaci
target:
description:
- The fully-qualified DNS name of the endpoint.
type: str
sample: 8.8.8.8
status:
description:
- The status of the endpoint.
type: str
sample: Enabled
weight:
description:
- The weight of this endpoint when the profile has routing_method C(weighted).
type: int
sample: 10
priority:
description:
- The priority of this endpoint when the profile has routing_method C(priority).
type: str
sample: 3
location:
description:
- The location of endpoints when type is C(external_endpoints) or C(nested_endpoints), and profile routing_method is (performance).
type: str
sample: East US
min_child_endpoints:
description:
- The minimum number of endpoints that must be available in the child profile to make the parent profile available.
type: int
sample: 3
geo_mapping:
description:
- The list of countries/regions mapped to this endpoint when the profile has routing_method C(geographic).
type: list
sample: [
"GEO-NA",
"GEO-AS"
]
'''
from ansible.module_utils.azure_rm_common import AzureRMModuleBase
from ansible.module_utils.common.dict_transformations import _camel_to_snake
try:
from msrestazure.azure_exceptions import CloudError
from azure.common import AzureHttpError
except:
# handled in azure_rm_common
pass
import re
AZURE_OBJECT_CLASS = 'trafficManagerProfiles'
def serialize_endpoint(endpoint):
result = dict(
id=endpoint.id,
name=endpoint.name,
target_resource_id=endpoint.target_resource_id,
target=endpoint.target,
status=endpoint.endpoint_status,
weight=endpoint.weight,
priority=endpoint.priority,
location=endpoint.endpoint_location,
min_child_endpoints=endpoint.min_child_endpoints,
geo_mapping=endpoint.geo_mapping,
)
if endpoint.type:
result['type'] = _camel_to_snake(endpoint.type.split("/")[-1])
return result
class AzureRMTrafficManagerProfileFacts(AzureRMModuleBase):
"""Utility class to get Azure Traffic Manager profile facts"""
def __init__(self):
self.module_args = dict(
name=dict(type='str'),
resource_group=dict(type='str'),
tags=dict(type='list')
)
self.results = dict(
changed=False,
tms=[]
)
self.name = None
self.resource_group = None
self.tags = None
super(AzureRMTrafficManagerProfileFacts, self).__init__(
derived_arg_spec=self.module_args,
supports_tags=False,
facts_module=True
)
def exec_module(self, **kwargs):
for key in self.module_args:
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['tms'] = self.get_item()
elif self.resource_group:
self.results['tms'] = self.list_resource_group()
else:
self.results['tms'] = self.list_all()
return self.results
def get_item(self):
"""Get a single Azure Traffic Manager profile"""
self.log('Get properties for {0}'.format(self.name))
item = None
result = []
try:
item = self.traffic_manager_management_client.profiles.get(
self.resource_group, self.name)
except CloudError:
pass
if item and self.has_tags(item.tags, self.tags):
result = [self.serialize_tm(item)]
return result
def list_resource_group(self):
"""Get all Azure Traffic Managers profiles within a resource group"""
self.log('List all Azure Traffic Managers within a resource group')
try:
response = self.traffic_manager_management_client.profiles.list_by_resource_group(
self.resource_group)
except AzureHttpError as exc:
self.fail('Failed to list all items - {0}'.format(str(exc)))
results = []
for item in response:
if self.has_tags(item.tags, self.tags):
results.append(self.serialize_tm(item))
return results
def list_all(self):
"""Get all Azure Traffic Manager profiles within a subscription"""
self.log('List all Traffic Manager profiles within a subscription')
try:
response = self.traffic_manager_management_client.profiles.list_by_subscription()
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(self.serialize_tm(item))
return results
def serialize_tm(self, tm):
'''
Convert a Traffic Manager profile object to dict.
:param tm: Traffic Manager profile object
:return: dict
'''
result = self.serialize_obj(tm, AZURE_OBJECT_CLASS)
new_result = {}
new_result['id'] = tm.id
new_result['resource_group'] = re.sub('\\/.*', '', re.sub('.*resourceGroups\\/', '', result['id']))
new_result['name'] = tm.name
new_result['state'] = 'present'
new_result['location'] = tm.location
new_result['profile_status'] = tm.profile_status
new_result['routing_method'] = tm.traffic_routing_method.lower()
new_result['dns_config'] = dict(
relative_name=tm.dns_config.relative_name,
fqdn=tm.dns_config.fqdn,
ttl=tm.dns_config.ttl
)
new_result['monitor_config'] = dict(
profile_monitor_status=tm.monitor_config.profile_monitor_status,
protocol=tm.monitor_config.protocol,
port=tm.monitor_config.port,
path=tm.monitor_config.path,
interval=tm.monitor_config.interval_in_seconds,
timeout=tm.monitor_config.timeout_in_seconds,
tolerated_failures=tm.monitor_config.tolerated_number_of_failures
)
new_result['endpoints'] = [serialize_endpoint(endpoint) for endpoint in tm.endpoints]
new_result['tags'] = tm.tags
return new_result
def main():
"""Main module execution code path"""
AzureRMTrafficManagerProfileFacts()
if __name__ == '__main__':
main()

@ -17,6 +17,7 @@ azure-mgmt-rdbms==1.2.0
azure-mgmt-resource==1.2.2 azure-mgmt-resource==1.2.2
azure-mgmt-sql==0.7.1 azure-mgmt-sql==0.7.1
azure-mgmt-storage==1.5.0 azure-mgmt-storage==1.5.0
azure-mgmt-trafficmanager==0.50.0
azure-mgmt-web==0.32.0 azure-mgmt-web==0.32.0
azure-nspkg==2.0.0 azure-nspkg==2.0.0
azure-storage==0.35.1 azure-storage==0.35.1

@ -0,0 +1,3 @@
cloud/azure
shippable/azure/group4
destructive

@ -0,0 +1,289 @@
- name: Prepare random number
set_fact:
tmname: "tm{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}"
endpointname1: "ep1{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}"
endpointname2: "ep2{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}"
run_once: yes
- name: Create a Traffic Manager profile(check mode)
azure_rm_trafficmanagerprofile:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
tags:
testing: testing
delete: on-exit
foo: bar
location: global
profile_status: enabled
routing_method: performance
dns_config:
relative_name: "{{ tmname }}"
ttl: 60
monitor_config:
protocol: HTTPS
port: 80
path: '/'
check_mode: yes
- name: Check there is no Traffic Manager profile created
azure_rm_trafficmanagerprofile_facts:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
register: fact
- name: Check there is no Traffic Manager profile created
assert: { that: "{{ fact.tms | length }} == 0" }
- name: Create a Traffic Manager profile
azure_rm_trafficmanagerprofile:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
tags:
testing: testing
delete: on-exit
foo: bar
location: global
profile_status: enabled
routing_method: performance
dns_config:
relative_name: "{{ tmname }}"
ttl: 60
monitor_config:
protocol: HTTPS
port: 80
path: '/'
register: tm
- name: Assert the Traffic Manager profile is well created
assert:
that:
- tm.changed
- name: Gather Traffic Manager profile facts
azure_rm_trafficmanagerprofile_facts:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
register: fact
- name: Assert fact returns the created one
assert:
that:
- "fact.tms | length == 1"
- fact.tms[0].id == tm.id
- fact.tms[0].endpoints | length == 0
- name: Create a Traffic Manager profile (idempotent)
azure_rm_trafficmanagerprofile:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
tags:
testing: testing
delete: on-exit
foo: bar
location: global
profile_status: enabled
routing_method: performance
dns_config:
relative_name: "{{ tmname }}"
ttl: 60
monitor_config:
protocol: HTTPS
port: 80
path: '/'
register: output
- name: Assert idempotent
assert:
that:
- not output.changed
- name: Update the Traffic Manager profile
azure_rm_trafficmanagerprofile:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
tags:
testing: testing
delete: on-exit
foo: bar
location: global
profile_status: disabled
routing_method: priority
dns_config:
relative_name: "{{ tmname }}"
ttl: 60
monitor_config:
protocol: HTTPS
port: 80
path: '/'
register: output
- name: Assert the Traffic Manager profile is updated
assert:
that:
- output.changed
- name: Create Traffic Manager endpoint(check mode)
azure_rm_trafficmanagerendpoint:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
name: "{{ endpointname1 }}"
type: external_endpoints
location: westus
priority: 2
weight: 1
target: 1.2.3.4
check_mode: yes
register: output
- name: Assert check mode changed
assert:
that:
- output.changed
- name: Get endpoint
azure_rm_trafficmanagerendpoint_facts:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
register: facts
- name: Check no endpoint created in check mode
assert:
that:
- facts.endpoints | length == 0
- name: Create Traffic Manager endpoint
azure_rm_trafficmanagerendpoint:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
name: "{{ endpointname1 }}"
type: external_endpoints
location: westus
priority: 2
weight: 1
target: 1.2.3.4
register: output
- name: Assert endpoint create changed
assert:
that:
- output.changed
- name: Get endpoint
azure_rm_trafficmanagerendpoint_facts:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
register: facts
- name: Check endpoint created
assert:
that:
- facts.endpoints | length == 1
- facts.endpoints[0].name == "{{ endpointname1 }}"
- name: Create second Traffic Manager endpoint
azure_rm_trafficmanagerendpoint:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
name: "{{ endpointname2 }}"
type: external_endpoints
location: westus
priority: 1
weight: 3
target: 4.3.2.1
- name: Get endpoint
azure_rm_trafficmanagerendpoint_facts:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
register: facts
- name: Check 2 endpoint in profile
assert:
that:
- facts.endpoints | length == 2
- name: Create endpoint (idempotent)
azure_rm_trafficmanagerendpoint:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
name: "{{ endpointname2 }}"
type: external_endpoints
location: westus
priority: 1
weight: 3
target: 4.3.2.1
register: output
- name: Assert endpoint creation idempotent
assert:
that:
- output.changed == False
- name: Delete second endpoint
azure_rm_trafficmanagerendpoint:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
name: "{{ endpointname2 }}"
type: external_endpoints
state: absent
register: output
- name: Assert endpoint deletion changed
assert:
that:
- output.changed
- name: Get endpoint
azure_rm_trafficmanagerendpoint_facts:
resource_group: "{{ resource_group }}"
profile_name: "{{ tmname }}"
register: facts
- name: Check 1 endpoint left in profile
assert:
that:
- facts.endpoints | length == 1
- name: Delete the Traffic Manager profile(check mode)
azure_rm_trafficmanagerprofile:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
state: absent
check_mode: yes
- name: Gather Traffic Manager profile facts
azure_rm_trafficmanagerprofile_facts:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
register: fact
- name: Assert the traffic manager profile is still there
assert:
that:
- "fact.tms | length == 1"
- fact.tms[0].id == tm.id
- fact.tms[0].endpoints | length == 1
- name: Delete the Traffic Manager profile
azure_rm_trafficmanagerprofile:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
state: absent
register: output
- name: Assert the Traffic Manager profile is well deleted
assert:
that:
- output.changed
- name: Get Traffic Manager profile fact
azure_rm_trafficmanagerprofile_facts:
resource_group: "{{ resource_group }}"
name: "{{ tmname }}"
register: fact
- name: Assert fact returns empty
assert:
that:
- "fact.tms | length == 0"

@ -17,6 +17,7 @@ azure-mgmt-rdbms==1.2.0
azure-mgmt-resource==1.2.2 azure-mgmt-resource==1.2.2
azure-mgmt-sql==0.7.1 azure-mgmt-sql==0.7.1
azure-mgmt-storage==1.5.0 azure-mgmt-storage==1.5.0
azure-mgmt-trafficmanager==0.50.0
azure-mgmt-web==0.32.0 azure-mgmt-web==0.32.0
azure-nspkg==2.0.0 azure-nspkg==2.0.0
azure-storage==0.35.1 azure-storage==0.35.1

Loading…
Cancel
Save