1#!/usr/bin/python 2# 3# Copyright (c) 2018 Yuwei Zhou, <yuwzho@microsoft.com> 4# 5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 7from __future__ import absolute_import, division, print_function 8__metaclass__ = type 9 10 11ANSIBLE_METADATA = {'metadata_version': '1.1', 12 'status': ['preview'], 13 'supported_by': 'community'} 14 15 16DOCUMENTATION = ''' 17--- 18module: azure_rm_route 19version_added: "2.7" 20short_description: Manage Azure route resource 21description: 22 - Create, update or delete a route. 23options: 24 resource_group: 25 description: 26 - Name of resource group. 27 required: true 28 name: 29 description: 30 - Name of the route. 31 required: true 32 state: 33 description: 34 - Assert the state of the route. Use C(present) to create or update and C(absent) to delete. 35 default: present 36 choices: 37 - absent 38 - present 39 address_prefix: 40 description: 41 - The destination CIDR to which the route applies. 42 next_hop_type: 43 description: 44 - The type of Azure hop the packet should be sent to. 45 choices: 46 - virtual_network_gateway 47 - vnet_local 48 - internet 49 - virtual_appliance 50 - none 51 default: 'none' 52 next_hop_ip_address: 53 description: 54 - The IP address packets should be forwarded to. 55 - Next hop values are only allowed in routes where the next hop type is VirtualAppliance. 56 route_table_name: 57 description: 58 - The name of the route table. 59 required: true 60 61 62extends_documentation_fragment: 63 - azure 64 - azure_tags 65 66author: 67 - Yuwei Zhou (@yuwzho) 68 69''' 70 71EXAMPLES = ''' 72 - name: Create a route 73 azure_rm_route: 74 resource_group: myResourceGroup 75 name: myRoute 76 address_prefix: 10.1.0.0/16 77 next_hop_type: virtual_network_gateway 78 route_table_name: table 79 80 - name: Delete a route 81 azure_rm_route: 82 resource_group: myResourceGroup 83 name: myRoute 84 route_table_name: table 85 state: absent 86''' 87RETURN = ''' 88id: 89 description: 90 - Current state of the route. 91 returned: success 92 type: str 93 sample: "/subscriptions/xxxx...xxxx/resourceGroups/v-xisuRG/providers/Microsoft.Network/routeTables/tableb57/routes/routeb57" 94''' 95 96try: 97 from msrestazure.azure_exceptions import CloudError 98except ImportError: 99 # This is handled in azure_rm_common 100 pass 101 102from ansible.module_utils.azure_rm_common import AzureRMModuleBase 103from ansible.module_utils.common.dict_transformations import _snake_to_camel 104 105 106class AzureRMRoute(AzureRMModuleBase): 107 108 def __init__(self): 109 110 self.module_arg_spec = dict( 111 resource_group=dict(type='str', required=True), 112 name=dict(type='str', required=True), 113 state=dict(type='str', default='present', choices=['present', 'absent']), 114 address_prefix=dict(type='str'), 115 next_hop_type=dict(type='str', 116 choices=['virtual_network_gateway', 117 'vnet_local', 118 'internet', 119 'virtual_appliance', 120 'none'], 121 default='none'), 122 next_hop_ip_address=dict(type='str'), 123 route_table_name=dict(type='str', required=True) 124 ) 125 126 required_if = [ 127 ('state', 'present', ['next_hop_type']) 128 ] 129 130 self.resource_group = None 131 self.name = None 132 self.state = None 133 self.address_prefix = None 134 self.next_hop_type = None 135 self.next_hop_ip_address = None 136 self.route_table_name = None 137 138 self.results = dict( 139 changed=False, 140 id=None 141 ) 142 143 super(AzureRMRoute, self).__init__(self.module_arg_spec, 144 required_if=required_if, 145 supports_check_mode=True) 146 147 def exec_module(self, **kwargs): 148 149 for key in list(self.module_arg_spec.keys()): 150 setattr(self, key, kwargs[key]) 151 152 result = dict() 153 changed = False 154 155 self.next_hop_type = _snake_to_camel(self.next_hop_type, capitalize_first=True) 156 157 result = self.get_route() 158 if self.state == 'absent' and result: 159 changed = True 160 if not self.check_mode: 161 self.delete_route() 162 elif self.state == 'present': 163 if not result: 164 changed = True # create new route 165 else: # check update 166 if result.next_hop_type != self.next_hop_type: 167 self.log('Update: {0} next_hop_type from {1} to {2}'.format(self.name, result.next_hop_type, self.next_hop_type)) 168 changed = True 169 if result.next_hop_ip_address != self.next_hop_ip_address: 170 self.log('Update: {0} next_hop_ip_address from {1} to {2}'.format(self.name, result.next_hop_ip_address, self.next_hop_ip_address)) 171 changed = True 172 if result.address_prefix != self.address_prefix: 173 self.log('Update: {0} address_prefix from {1} to {2}'.format(self.name, result.address_prefix, self.address_prefix)) 174 changed = True 175 if changed: 176 result = self.network_models.Route(name=self.name, 177 address_prefix=self.address_prefix, 178 next_hop_type=self.next_hop_type, 179 next_hop_ip_address=self.next_hop_ip_address) 180 if not self.check_mode: 181 result = self.create_or_update_route(result) 182 183 self.results['id'] = result.id if result else None 184 self.results['changed'] = changed 185 return self.results 186 187 def create_or_update_route(self, param): 188 try: 189 poller = self.network_client.routes.create_or_update(self.resource_group, self.route_table_name, self.name, param) 190 return self.get_poller_result(poller) 191 except Exception as exc: 192 self.fail("Error creating or updating route {0} - {1}".format(self.name, str(exc))) 193 194 def delete_route(self): 195 try: 196 poller = self.network_client.routes.delete(self.resource_group, self.route_table_name, self.name) 197 result = self.get_poller_result(poller) 198 return result 199 except Exception as exc: 200 self.fail("Error deleting route {0} - {1}".format(self.name, str(exc))) 201 202 def get_route(self): 203 try: 204 return self.network_client.routes.get(self.resource_group, self.route_table_name, self.name) 205 except CloudError as cloud_err: 206 # Return None iff the resource is not found 207 if cloud_err.status_code == 404: 208 self.log('{0}'.format(str(cloud_err))) 209 return None 210 self.fail('Error: failed to get resource {0} - {1}'.format(self.name, str(cloud_err))) 211 except Exception as exc: 212 self.fail('Error: failed to get resource {0} - {1}'.format(self.name, str(exc))) 213 214 215def main(): 216 AzureRMRoute() 217 218 219if __name__ == '__main__': 220 main() 221