From ccb7909cc565c28633e03ba55821c4d5300d054d Mon Sep 17 00:00:00 2001
From: Hai Cao <imcaohai@gmail.com>
Date: Thu, 30 Aug 2018 00:18:53 -0400
Subject: [PATCH] [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
---
 lib/ansible/module_utils/azure_rm_common.py   |  15 +
 .../azure/azure_rm_trafficmanagerendpoint.py  | 371 ++++++++++++++
 .../azure_rm_trafficmanagerendpoint_facts.py  | 297 ++++++++++++
 .../azure/azure_rm_trafficmanagerprofile.py   | 457 ++++++++++++++++++
 .../azure_rm_trafficmanagerprofile_facts.py   | 378 +++++++++++++++
 packaging/requirements/requirements-azure.txt |   1 +
 .../azure_rm_trafficmanagerprofile/aliases    |   3 +
 .../meta/main.yml                             |   2 +
 .../tasks/main.yml                            | 289 +++++++++++
 .../requirements/integration.cloud.azure.txt  |   1 +
 10 files changed, 1814 insertions(+)
 create mode 100644 lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerendpoint.py
 create mode 100644 lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerendpoint_facts.py
 create mode 100644 lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerprofile.py
 create mode 100644 lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerprofile_facts.py
 create mode 100644 test/integration/targets/azure_rm_trafficmanagerprofile/aliases
 create mode 100644 test/integration/targets/azure_rm_trafficmanagerprofile/meta/main.yml
 create mode 100644 test/integration/targets/azure_rm_trafficmanagerprofile/tasks/main.yml

diff --git a/lib/ansible/module_utils/azure_rm_common.py b/lib/ansible/module_utils/azure_rm_common.py
index 248b5d8eae0..fb97186b548 100644
--- a/lib/ansible/module_utils/azure_rm_common.py
+++ b/lib/ansible/module_utils/azure_rm_common.py
@@ -150,6 +150,7 @@ try:
     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 adal.authentication_context import AuthenticationContext
     from azure.mgmt.rdbms.postgresql import PostgreSQLManagementClient
@@ -222,6 +223,10 @@ AZURE_PKG_VERSIONS = {
         'package_name': 'web',
         'expected_version': '0.32.0'
     },
+    'TrafficManagerManagementClient': {
+        'package_name': 'trafficmanager',
+        'expected_version': '0.50.0'
+    },
 } if HAS_AZURE else {}
 
 
@@ -282,6 +287,8 @@ class AzureRMModuleBase(object):
         self._postgresql_client = None
         self._containerregistry_client = None
         self._containerinstance_client = None
+        self._traffic_manager_management_client = None
+
         self._adfs_authority_url = None
         self._resource = None
 
@@ -1109,3 +1116,11 @@ class AzureRMModuleBase(object):
             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
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerendpoint.py b/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerendpoint.py
new file mode 100644
index 00000000000..37a7d0884d7
--- /dev/null
+++ b/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerendpoint.py
@@ -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()
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerendpoint_facts.py b/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerendpoint_facts.py
new file mode 100644
index 00000000000..566828fbea8
--- /dev/null
+++ b/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerendpoint_facts.py
@@ -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()
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerprofile.py b/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerprofile.py
new file mode 100644
index 00000000000..046bb293f96
--- /dev/null
+++ b/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerprofile.py
@@ -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()
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerprofile_facts.py b/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerprofile_facts.py
new file mode 100644
index 00000000000..c4f6044e211
--- /dev/null
+++ b/lib/ansible/modules/cloud/azure/azure_rm_trafficmanagerprofile_facts.py
@@ -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()
diff --git a/packaging/requirements/requirements-azure.txt b/packaging/requirements/requirements-azure.txt
index 80d167835e6..f897d86b4be 100644
--- a/packaging/requirements/requirements-azure.txt
+++ b/packaging/requirements/requirements-azure.txt
@@ -17,6 +17,7 @@ azure-mgmt-rdbms==1.2.0
 azure-mgmt-resource==1.2.2
 azure-mgmt-sql==0.7.1
 azure-mgmt-storage==1.5.0
+azure-mgmt-trafficmanager==0.50.0
 azure-mgmt-web==0.32.0
 azure-nspkg==2.0.0
 azure-storage==0.35.1
diff --git a/test/integration/targets/azure_rm_trafficmanagerprofile/aliases b/test/integration/targets/azure_rm_trafficmanagerprofile/aliases
new file mode 100644
index 00000000000..239e3657797
--- /dev/null
+++ b/test/integration/targets/azure_rm_trafficmanagerprofile/aliases
@@ -0,0 +1,3 @@
+cloud/azure
+shippable/azure/group4
+destructive
diff --git a/test/integration/targets/azure_rm_trafficmanagerprofile/meta/main.yml b/test/integration/targets/azure_rm_trafficmanagerprofile/meta/main.yml
new file mode 100644
index 00000000000..95e1952f989
--- /dev/null
+++ b/test/integration/targets/azure_rm_trafficmanagerprofile/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+  - setup_azure
diff --git a/test/integration/targets/azure_rm_trafficmanagerprofile/tasks/main.yml b/test/integration/targets/azure_rm_trafficmanagerprofile/tasks/main.yml
new file mode 100644
index 00000000000..dba81c0e259
--- /dev/null
+++ b/test/integration/targets/azure_rm_trafficmanagerprofile/tasks/main.yml
@@ -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"
diff --git a/test/runner/requirements/integration.cloud.azure.txt b/test/runner/requirements/integration.cloud.azure.txt
index 80d167835e6..f897d86b4be 100644
--- a/test/runner/requirements/integration.cloud.azure.txt
+++ b/test/runner/requirements/integration.cloud.azure.txt
@@ -17,6 +17,7 @@ azure-mgmt-rdbms==1.2.0
 azure-mgmt-resource==1.2.2
 azure-mgmt-sql==0.7.1
 azure-mgmt-storage==1.5.0
+azure-mgmt-trafficmanager==0.50.0
 azure-mgmt-web==0.32.0
 azure-nspkg==2.0.0
 azure-storage==0.35.1