azure_rm_networkinterface: support the multiple ip configuration (#32882)

* support the mutilple ip configuration

* Update azure_rm_networkinterface.py

* add test

* fix spell

* make the virtual network name more flexiable

* add test

* fix

* fix lint

* add test

* fix parameter

* deprecate the flatten ip configuration

* fix lint

* fix encoding

* fix mirror

* fix

* load model from common
This commit is contained in:
Yuwei Zhou 2018-01-24 12:57:08 +08:00 committed by Jordan Borean
parent e970ae102c
commit 6f67d68f5a
6 changed files with 416 additions and 213 deletions

View file

@ -356,6 +356,9 @@ class AzureRMModuleBase(object):
''' '''
self.module.fail_json(msg=msg, **kwargs) self.module.fail_json(msg=msg, **kwargs)
def deprecate(self, msg, version=None):
self.module.deprecate(msg, version)
def log(self, msg, pretty_print=False): def log(self, msg, pretty_print=False):
pass pass
# Use only during module development # Use only during module development
@ -654,18 +657,17 @@ class AzureRMModuleBase(object):
self.fail("Error creating blob service client for storage account {0} - {1}".format(storage_account_name, self.fail("Error creating blob service client for storage account {0} - {1}".format(storage_account_name,
str(exc))) str(exc)))
def create_default_pip(self, resource_group, location, name, allocation_method='Dynamic'): def create_default_pip(self, resource_group, location, public_ip_name, allocation_method='Dynamic'):
''' '''
Create a default public IP address <name>01 to associate with a network interface. Create a default public IP address <public_ip_name> to associate with a network interface.
If a PIP address matching <vm name>01 exists, return it. Otherwise, create one. If a PIP address matching <public_ip_name> exists, return it. Otherwise, create one.
:param resource_group: name of an existing resource group :param resource_group: name of an existing resource group
:param location: a valid azure location :param location: a valid azure location
:param name: base name to assign the public IP address :param public_ip_name: base name to assign the public IP address
:param allocation_method: one of 'Static' or 'Dynamic' :param allocation_method: one of 'Static' or 'Dynamic'
:return: PIP object :return: PIP object
''' '''
public_ip_name = name + '01'
pip = None pip = None
self.log("Starting create_default_pip {0}".format(public_ip_name)) self.log("Starting create_default_pip {0}".format(public_ip_name))
@ -692,20 +694,19 @@ class AzureRMModuleBase(object):
return self.get_poller_result(poller) return self.get_poller_result(poller)
def create_default_securitygroup(self, resource_group, location, name, os_type, open_ports): def create_default_securitygroup(self, resource_group, location, security_group_name, os_type, open_ports):
''' '''
Create a default security group <name>01 to associate with a network interface. If a security group matching Create a default security group <security_group_name> to associate with a network interface. If a security group matching
<name>01 exists, return it. Otherwise, create one. <security_group_name> exists, return it. Otherwise, create one.
:param resource_group: Resource group name :param resource_group: Resource group name
:param location: azure location name :param location: azure location name
:param name: base name to use for the security group :param security_group_name: base name to use for the security group
:param os_type: one of 'Windows' or 'Linux'. Determins any default rules added to the security group. :param os_type: one of 'Windows' or 'Linux'. Determins any default rules added to the security group.
:param ssh_port: for os_type 'Linux' port used in rule allowing SSH access. :param ssh_port: for os_type 'Linux' port used in rule allowing SSH access.
:param rdp_port: for os_type 'Windows' port used in rule allowing RDP access. :param rdp_port: for os_type 'Windows' port used in rule allowing RDP access.
:return: security_group object :return: security_group object
''' '''
security_group_name = name + '01'
group = None group = None
self.log("Create security group {0}".format(security_group_name)) self.log("Create security group {0}".format(security_group_name))

View file

@ -53,12 +53,11 @@ options:
required: false required: false
virtual_network_name: virtual_network_name:
description: description:
- Name of an existing virtual network with which the network interface will be associated. Required - Name or id of an existing virtual network with which the network interface will be associated. Required
when creating a network interface. when creating a network interface.
aliases: aliases:
- virtual_network - virtual_network
required: true required: true
default: null
subnet_name: subnet_name:
description: description:
- Name of an existing subnet within the specified virtual network. Required when creating a network - Name of an existing subnet within the specified virtual network. Required when creating a network
@ -77,58 +76,90 @@ options:
- Windows - Windows
- Linux - Linux
default: Linux default: Linux
required: false
private_ip_address: private_ip_address:
description: description:
- Valid IPv4 address that falls within the specified subnet. - (Deprecate) Valid IPv4 address that falls within the specified subnet.
required: false - This option will be deprecated in 2.9, use I(ip_configurations) instead.
private_ip_allocation_method: private_ip_allocation_method:
description: description:
- "Specify whether or not the assigned IP address is permanent. NOTE: when creating a network interface - "(Deprecate) Specify whether or not the assigned IP address is permanent. NOTE: when creating a network interface
specifying a value of 'Static' requires that a private_ip_address value be provided. You can update specifying a value of 'Static' requires that a private_ip_address value be provided. You can update
the allocation method to 'Static' after a dynamic private ip address has been assigned." the allocation method to 'Static' after a dynamic private ip address has been assigned."
- This option will be deprecated in 2.9, use I(ip_configurations) instead.
default: Dynamic default: Dynamic
choices: choices:
- Dynamic - Dynamic
- Static - Static
required: false
public_ip: public_ip:
description: description:
- When creating a network interface, if no public IP address name is provided a default public IP - (Deprecate) When creating a network interface, if no public IP address name is provided a default public IP
address will be created. Set to false, if you do not want a public IP address automatically created. address will be created. Set to false, if you do not want a public IP address automatically created.
- This option will be deprecated in 2.9, use I(ip_configurations) instead.
default: true default: true
required: false
public_ip_address_name: public_ip_address_name:
description: description:
- Name of an existing public IP address object to associate with the security group. - (Deprecate) Name of an existing public IP address object to associate with the security group.
- This option will be deprecated in 2.9, use I(ip_configurations) instead.
aliases: aliases:
- public_ip_address - public_ip_address
- public_ip_name - public_ip_name
required: false
default: null default: null
public_ip_allocation_method: public_ip_allocation_method:
description: description:
- If a public_ip_address_name is not provided, a default public IP address will be created. The allocation - (Deprecate) If a public_ip_address_name is not provided, a default public IP address will be created. The allocation
method determines whether or not the public IP address assigned to the network interface is permanent. method determines whether or not the public IP address assigned to the network interface is permanent.
- This option will be deprecated in 2.9, use I(ip_configurations) instead.
choices: choices:
- Dynamic - Dynamic
- Static - Static
default: Dynamic default: Dynamic
required: false ip_configurations:
description:
- List of ip configuration if contains mutilple configuration, should contain configuration object include
field private_ip_address, private_ip_allocation_method, public_ip_address_name, public_ip, subnet_name,
virtual_network_name, public_ip_allocation_method, name
suboptions:
name:
description:
- Name of the ip configuration.
required: true
private_ip_address:
description:
- Private ip address for the ip configuration.
private_ip_allocation_method:
description:
- private ip allocation method.
choices:
- Dynamic
- Static
default: Dynamic
public_ip_address_name:
description:
- Name of the public ip address. None for disable ip address.
public_ip_allocation_method:
description:
- public ip allocation method.
choices:
- Dynamic
- Static
default: Dynamic
primary:
description:
- Whether the ip configuration is the primary one in the list.
default: False
version_added: 2.5
security_group_name: security_group_name:
description: description:
- Name of an existing security group with which to associate the network interface. If not provided, a - Name of an existing security group with which to associate the network interface. If not provided, a
default security group will be created. default security group will be created.
aliases: aliases:
- security_group - security_group
required: false
default: null default: null
open_ports: open_ports:
description: description:
- When a default security group is created for a Linux host a rule will be added allowing inbound TCP - When a default security group is created for a Linux host a rule will be added allowing inbound TCP
connections to the default SSH port 22, and for a Windows host rules will be added allowing inbound connections to the default SSH port 22, and for a Windows host rules will be added allowing inbound
access to RDP ports 3389 and 5986. Override the default ports by providing a list of open ports. access to RDP ports 3389 and 5986. Override the default ports by providing a list of open ports.
required: false
default: null default: null
extends_documentation_fragment: extends_documentation_fragment:
- azure - azure
@ -146,6 +177,10 @@ EXAMPLES = '''
resource_group: Testing resource_group: Testing
virtual_network_name: vnet001 virtual_network_name: vnet001
subnet_name: subnet001 subnet_name: subnet001
ip_configurations:
name: ipconfig1
public_ip_address_name: publicip001
primary: True
- name: Create a network interface with private IP address only (no Public IP) - name: Create a network interface with private IP address only (no Public IP)
azure_rm_networkinterface: azure_rm_networkinterface:
@ -153,7 +188,9 @@ EXAMPLES = '''
resource_group: Testing resource_group: Testing
virtual_network_name: vnet001 virtual_network_name: vnet001
subnet_name: subnet001 subnet_name: subnet001
public_ip: no ip_configurations:
name: ipconfig1
primary: True
- name: Create a network interface for use in a Windows host (opens RDP port) with custom RDP port - name: Create a network interface for use in a Windows host (opens RDP port) with custom RDP port
azure_rm_networkinterface: azure_rm_networkinterface:
@ -163,6 +200,10 @@ EXAMPLES = '''
subnet_name: subnet001 subnet_name: subnet001
os_type: Windows os_type: Windows
rdp_port: 3399 rdp_port: 3399
ip_configurations:
name: ipconfig1
public_ip_address_name: publicip001
primary: True
- name: Create a network interface using existing security group and public IP - name: Create a network interface using existing security group and public IP
azure_rm_networkinterface: azure_rm_networkinterface:
@ -171,7 +212,23 @@ EXAMPLES = '''
virtual_network_name: vnet001 virtual_network_name: vnet001
subnet_name: subnet001 subnet_name: subnet001
security_group_name: secgroup001 security_group_name: secgroup001
public_ip_address_name: publicip001 ip_configurations:
name: ipconfig1
public_ip_address_name: publicip001
primary: True
- name: Create a network with mutilple ip configurations
azure_rm_networkinterface:
name: nic004
resource_group: Testing
subnet_name: subnet001
virtual_network_name: vnet001
security_group_name: secgroup001
ip_configurations:
- name: ipconfig1
public_ip_address_name: publicip001
primary: True
- name: ipconfig2
- name: Delete network interface - name: Delete network interface
azure_rm_networkinterface: azure_rm_networkinterface:
@ -195,7 +252,7 @@ state:
"enable_ip_forwarding": false, "enable_ip_forwarding": false,
"etag": 'W/"be115a43-2148-4545-a324-f33ad444c926"', "etag": 'W/"be115a43-2148-4545-a324-f33ad444c926"',
"id": "/subscriptions/XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX/resourceGroups/Testing/providers/Microsoft.Network/networkInterfaces/nic003", "id": "/subscriptions/XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX/resourceGroups/Testing/providers/Microsoft.Network/networkInterfaces/nic003",
"ip_configuration": { "ip_configurations": [{
"name": "default", "name": "default",
"private_ip_address": "10.1.0.10", "private_ip_address": "10.1.0.10",
"private_ip_allocation_method": "Static", "private_ip_allocation_method": "Static",
@ -204,7 +261,7 @@ state:
"name": "publicip001" "name": "publicip001"
}, },
"subnet": {} "subnet": {}
}, }],
"location": "eastus2", "location": "eastus2",
"mac_address": null, "mac_address": null,
"name": "nic003", "name": "nic003",
@ -217,61 +274,84 @@ state:
''' '''
try: try:
from msrestazure.tools import parse_resource_id
from msrestazure.azure_exceptions import CloudError from msrestazure.azure_exceptions import CloudError
except ImportError: except ImportError:
# This is handled in azure_rm_common # This is handled in azure_rm_common
pass pass
from ansible.module_utils.azure_rm_common import AzureRMModuleBase, azure_id_to_dict from ansible.module_utils.azure_rm_common import AzureRMModuleBase, azure_id_to_dict
from ansible.module_utils._text import to_native
def subnet_to_dict(subnet):
dic = azure_id_to_dict(subnet.id)
return dict(
id=subnet.id,
virtual_network_name=dic.get('virtualNetworks'),
resource_group=dic.get('resourceGroups'),
name=dic.get('subnets')
)
def nic_to_dict(nic): def nic_to_dict(nic):
result = dict( ip_configurations = [
dict(
name=config.name,
private_ip_address=config.private_ip_address,
private_ip_allocation_method=config.private_ip_allocation_method,
subnet=subnet_to_dict(config.subnet),
primary=config.primary,
public_ip_address=dict(
id=config.public_ip_address.id,
name=azure_id_to_dict(config.public_ip_address.id).get('publicIPAddresses'),
public_ip_allocation_method=config.public_ip_address.public_ip_allocation_method
) if config.public_ip_address else None
) for config in nic.ip_configurations
]
return dict(
id=nic.id, id=nic.id,
name=nic.name, name=nic.name,
type=nic.type, type=nic.type,
location=nic.location, location=nic.location,
tags=nic.tags, tags=nic.tags,
network_security_group=dict(), network_security_group=dict(
ip_configuration=dict( id=nic.network_security_group.id,
name=nic.ip_configurations[0].name, name=azure_id_to_dict(nic.network_security_group.id).get('networkSecurityGroups')
private_ip_address=nic.ip_configurations[0].private_ip_address, ) if nic.network_security_group else None,
private_ip_allocation_method=nic.ip_configurations[0].private_ip_allocation_method,
subnet=dict(),
public_ip_address=dict(),
),
dns_settings=dict( dns_settings=dict(
dns_servers=nic.dns_settings.dns_servers, dns_servers=nic.dns_settings.dns_servers,
applied_dns_servers=nic.dns_settings.applied_dns_servers, applied_dns_servers=nic.dns_settings.applied_dns_servers,
internal_dns_name_label=nic.dns_settings.internal_dns_name_label, internal_dns_name_label=nic.dns_settings.internal_dns_name_label,
internal_fqdn=nic.dns_settings.internal_fqdn internal_fqdn=nic.dns_settings.internal_fqdn
), ),
ip_configurations=ip_configurations,
ip_configuration=ip_configurations[0] if len(ip_configurations) == 1 else None, # for compatiable issue, keep this field
mac_address=nic.mac_address, mac_address=nic.mac_address,
primary=nic.primary,
enable_ip_forwarding=nic.enable_ip_forwarding, enable_ip_forwarding=nic.enable_ip_forwarding,
provisioning_state=nic.provisioning_state, provisioning_state=nic.provisioning_state,
etag=nic.etag, etag=nic.etag,
) )
if nic.network_security_group:
result['network_security_group']['id'] = nic.network_security_group.id
id_keys = azure_id_to_dict(nic.network_security_group.id)
result['network_security_group']['name'] = id_keys['networkSecurityGroups']
if nic.ip_configurations[0].subnet: def construct_ip_configuration_set(raw):
result['ip_configuration']['subnet']['id'] = \ configurations = [str(dict(
nic.ip_configurations[0].subnet.id private_ip_allocation_method=to_native(item.get('private_ip_allocation_method')),
id_keys = azure_id_to_dict(nic.ip_configurations[0].subnet.id) public_ip_address_name=(to_native(item.get('public_ip_address').get('name'))
result['ip_configuration']['subnet']['virtual_network_name'] = id_keys['virtualNetworks'] if item.get('public_ip_address') else to_native(item.get('public_ip_address_name'))),
result['ip_configuration']['subnet']['name'] = id_keys['subnets'] primary=item.get('primary'),
name=to_native(item.get('name'))
)) for item in raw]
return set(configurations)
if nic.ip_configurations[0].public_ip_address: ip_configuration_spec = dict(
result['ip_configuration']['public_ip_address']['id'] = \ name=dict(type='str', required=True),
nic.ip_configurations[0].public_ip_address.id private_ip_address=dict(type='str'),
id_keys = azure_id_to_dict(nic.ip_configurations[0].public_ip_address.id) private_ip_allocation_method=dict(type='str', choices=['Dynamic', 'Static'], default='Dynamic'),
result['ip_configuration']['public_ip_address']['name'] = id_keys['publicIPAddresses'] public_ip_address_name=dict(type='str', aliases=['public_ip_address', 'public_ip_name']),
public_ip_allocation_method=dict(type='str', choices=['Dynamic', 'Static'], default='Dynamic'),
return result primary=dict(type='bool', default=False)
)
class AzureRMNetworkInterface(AzureRMModuleBase): class AzureRMNetworkInterface(AzureRMModuleBase):
@ -290,11 +370,16 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
public_ip=dict(type='bool', default=True), public_ip=dict(type='bool', default=True),
subnet_name=dict(type='str', aliases=['subnet']), subnet_name=dict(type='str', aliases=['subnet']),
virtual_network_name=dict(type='str', aliases=['virtual_network']), virtual_network_name=dict(type='str', aliases=['virtual_network']),
public_ip_allocation_method=dict(type='str', choices=['Dynamic', 'Static'], default='Dynamic'),
ip_configurations=dict(type='list', default=None, elements='dict', options=ip_configuration_spec),
os_type=dict(type='str', choices=['Windows', 'Linux'], default='Linux'), os_type=dict(type='str', choices=['Windows', 'Linux'], default='Linux'),
open_ports=dict(type='list'), open_ports=dict(type='list'),
public_ip_allocation_method=dict(type='str', choices=['Dynamic', 'Static'], default='Dynamic'),
) )
required_if = [
('state', 'present', ['subnet_name', 'virtual_network_name'])
]
self.resource_group = None self.resource_group = None
self.name = None self.name = None
self.location = None self.location = None
@ -302,15 +387,16 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
self.private_ip_address = None self.private_ip_address = None
self.private_ip_allocation_method = None self.private_ip_allocation_method = None
self.public_ip_address_name = None self.public_ip_address_name = None
self.state = None self.public_ip = None
self.subnet_name = None self.subnet_name = None
self.tags = None
self.virtual_network_name = None self.virtual_network_name = None
self.public_ip_allocation_method = None
self.state = None
self.tags = None
self.security_group_name = None self.security_group_name = None
self.os_type = None self.os_type = None
self.open_ports = None self.open_ports = None
self.public_ip_allocation_method = None self.ip_configurations = None
self.public_ip = None
self.results = dict( self.results = dict(
changed=False, changed=False,
@ -318,40 +404,42 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
) )
super(AzureRMNetworkInterface, self).__init__(derived_arg_spec=self.module_arg_spec, super(AzureRMNetworkInterface, self).__init__(derived_arg_spec=self.module_arg_spec,
supports_check_mode=True) supports_check_mode=True,
required_if=required_if)
def exec_module(self, **kwargs): def exec_module(self, **kwargs):
for key in list(self.module_arg_spec.keys()) + ['tags']: for key in list(self.module_arg_spec.keys()) + ['tags']:
setattr(self, key, kwargs[key]) setattr(self, key, kwargs[key])
results = dict() results = None
changed = False changed = False
nic = None nic = None
subnet = None
nsg = None nsg = None
pip = None
resource_group = self.get_resource_group(self.resource_group) resource_group = self.get_resource_group(self.resource_group)
if not self.location: if not self.location:
# Set default location # Set default location
self.location = resource_group.location self.location = resource_group.location
if self.state == 'present': # parse the virtual network resource group and name
if self.virtual_network_name and not self.subnet_name: virtual_network_dict = parse_resource_id(self.virtual_network_name)
self.fail("Parameter error: a subnet is required when passing a virtual_network_name.") virtual_network_name = virtual_network_dict.get('name')
virtual_network_resource_group = virtual_network_dict.get('resource_group', self.resource_group)
if self.subnet_name and not self.virtual_network_name: if self.state == 'present' and not self.ip_configurations:
self.fail("Parameter error: virtual_network_name is required when passing a subnet value.") # construct the ip_configurations array for compatiable
self.deprecate('Setting ip_configuration flatten is deprecated and will be removed.'
if self.virtual_network_name and self.subnet_name: ' Using ip_configurations list to define the ip configuration', version='2.9')
subnet = self.get_subnet(self.virtual_network_name, self.subnet_name) self.ip_configurations = [
dict(
if self.public_ip_address_name: private_ip_address=self.private_ip_address,
pip = self.get_public_ip_address(self.public_ip_address_name) private_ip_allocation_method=self.private_ip_allocation_method,
public_ip_address_name=self.public_ip_address_name if self.public_ip else None,
if self.security_group_name: public_ip_allocation_method=self.public_ip_allocation_method,
nsg = self.get_security_group(self.security_group_name) name='default'
)
]
try: try:
self.log('Fetching network interface {0}'.format(self.name)) self.log('Fetching network interface {0}'.format(self.name))
@ -362,47 +450,40 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
results = nic_to_dict(nic) results = nic_to_dict(nic)
self.log(results, pretty_print=True) self.log(results, pretty_print=True)
nsg = None
if self.state == 'present': if self.state == 'present':
# check for update
update_tags, results['tags'] = self.update_tags(results['tags']) update_tags, results['tags'] = self.update_tags(results['tags'])
if update_tags: if update_tags:
changed = True changed = True
if self.private_ip_address:
if results['ip_configuration']['private_ip_address'] != self.private_ip_address:
self.log("CHANGED: network interface {0} private ip".format(self.name))
changed = True
results['ip_configuration']['private_ip_address'] = self.private_ip_address
if self.public_ip_address_name:
if results['ip_configuration']['public_ip_address'].get('id') != pip.id:
self.log("CHANGED: network interface {0} public ip".format(self.name))
changed = True
results['ip_configuration']['public_ip_address']['id'] = pip.id
results['ip_configuration']['public_ip_address']['name'] = pip.name
if self.security_group_name: if self.security_group_name:
if results['network_security_group'].get('id') != nsg.id: nsg = self.get_security_group(self.security_group_name)
if nsg and results['network_security_group'].get('id') != nsg.id:
self.log("CHANGED: network interface {0} network security group".format(self.name)) self.log("CHANGED: network interface {0} network security group".format(self.name))
changed = True changed = True
results['network_security_group']['id'] = nsg.id
results['network_security_group']['name'] = nsg.name
if self.private_ip_allocation_method: if results['ip_configurations'][0]['subnet']['virtual_network_name'] != virtual_network_name:
if results['ip_configuration']['private_ip_allocation_method'] != self.private_ip_allocation_method: self.log("CHANGED: network interface {0} virtual network name".format(self.name))
self.log("CHANGED: network interface {0} private ip allocation".format(self.name)) changed = True
changed = True
results['ip_configuration']['private_ip_allocation_method'] = self.private_ip_allocation_method
if self.private_ip_allocation_method == 'Dynamic':
results['ip_configuration']['private_ip_address'] = None
if self.subnet_name: if results['ip_configurations'][0]['subnet']['resource_group'] != virtual_network_resource_group:
if results['ip_configuration']['subnet'].get('id') != subnet.id: self.log("CHANGED: network interface {0} virtual network resource group".format(self.name))
changed = True changed = True
self.log("CHANGED: network interface {0} subnet".format(self.name))
results['ip_configuration']['subnet']['id'] = subnet.id if results['ip_configurations'][0]['subnet']['name'] != self.subnet_name:
results['ip_configuration']['subnet']['name'] = subnet.name self.log("CHANGED: network interface {0} subnet name".format(self.name))
results['ip_configuration']['subnet']['virtual_network_name'] = self.virtual_network_name changed = True
# check the ip_configuration is changed
# construct two set with the same structure and then compare
# the list should contains:
# name, private_ip_address, public_ip_address_name, private_ip_allocation_method, subnet_name
ip_configuration_result = construct_ip_configuration_set(results['ip_configurations'])
ip_configuration_request = construct_ip_configuration_set(self.ip_configurations)
if ip_configuration_result != ip_configuration_request:
self.log("CHANGED: network interface {0} ip configurations".format(self.name))
changed = True
elif self.state == 'absent': elif self.state == 'absent':
self.log("CHANGED: network interface {0} exists but requested state is 'absent'".format(self.name)) self.log("CHANGED: network interface {0} exists but requested state is 'absent'".format(self.name))
@ -410,8 +491,7 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
except CloudError: except CloudError:
self.log('Network interface {0} does not exist'.format(self.name)) self.log('Network interface {0} does not exist'.format(self.name))
if self.state == 'present': if self.state == 'present':
self.log("CHANGED: network interface {0} does not exist but requested state is " self.log("CHANGED: network interface {0} does not exist but requested state is 'present'".format(self.name))
"'present'".format(self.name))
changed = True changed = True
self.results['changed'] = changed self.results['changed'] = changed
@ -422,141 +502,89 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
if changed: if changed:
if self.state == 'present': if self.state == 'present':
if not nic: subnet = self.get_subnet(virtual_network_resource_group, virtual_network_name, self.subnet_name)
# create network interface if not subnet:
self.log("Creating network interface {0}.".format(self.name)) self.fail('subnet {0} is not exist'.format(self.subnet_name))
nic_ip_configurations = [
# check required parameters self.network_models.NetworkInterfaceIPConfiguration(
if not self.subnet_name: private_ip_allocation_method=ip_config.get('private_ip_allocation_method'),
self.fail("parameter error: subnet_name required when creating a network interface.") private_ip_address=ip_config.get('private_ip_address'),
if not self.virtual_network_name: name=ip_config.get('name'),
self.fail("parameter error: virtual_network_name required when creating a network interface.") subnet=subnet,
public_ip_address=self.get_or_create_public_ip_address(ip_config),
if not self.security_group_name: primary=ip_config.get('primary')
# create default security group ) for ip_config in self.ip_configurations
nsg = self.create_default_securitygroup(self.resource_group, self.location, self.name, ]
self.os_type, self.open_ports)
if not pip and self.public_ip:
# create a default public_ip
pip = self.create_default_pip(self.resource_group, self.location, self.name,
self.public_ip_allocation_method)
nic = self.network_models.NetworkInterface(
location=self.location,
tags=self.tags,
ip_configurations=[
self.network_models.NetworkInterfaceIPConfiguration(
private_ip_allocation_method=self.private_ip_allocation_method,
)
]
)
# nic.name = self.name
nic.ip_configurations[0].subnet = self.network_models.Subnet(id=subnet.id)
nic.ip_configurations[0].name = 'default'
nic.network_security_group = self.network_models.NetworkSecurityGroup(id=nsg.id,
location=nsg.location,
resource_guid=nsg.resource_guid)
if self.private_ip_address:
nic.ip_configurations[0].private_ip_address = self.private_ip_address
if pip:
nic.ip_configurations[0].public_ip_address = self.network_models.PublicIPAddress(
id=pip.id,
location=pip.location,
resource_guid=pip.resource_guid)
else:
self.log("Updating network interface {0}.".format(self.name))
nic = self.network_models.NetworkInterface(
id=results['id'],
location=results['location'],
tags=results['tags'],
ip_configurations=[
self.network_models.NetworkInterfaceIPConfiguration(
private_ip_allocation_method=results['ip_configuration']['private_ip_allocation_method']
)
]
)
subnet = self.get_subnet(results['ip_configuration']['subnet']['virtual_network_name'],
results['ip_configuration']['subnet']['name'])
nic.ip_configurations[0].subnet = self.network_models.Subnet(id=subnet.id)
nic.ip_configurations[0].name = results['ip_configuration']['name']
# nic.name = name=results['name'],
if results['ip_configuration'].get('private_ip_address'):
nic.ip_configurations[0].private_ip_address = results['ip_configuration']['private_ip_address']
if results['ip_configuration']['public_ip_address'].get('id'):
pip = \
self.get_public_ip_address(results['ip_configuration']['public_ip_address']['name'])
nic.ip_configurations[0].public_ip_address = self.network_models.PublicIPAddress(
id=pip.id,
location=pip.location,
resource_guid=pip.resource_guid)
# name=pip.name,
if results['network_security_group'].get('id'):
nsg = self.get_security_group(results['network_security_group']['name'])
nic.network_security_group = self.network_models.NetworkSecurityGroup(id=nsg.id,
location=nsg.location,
resource_guid=nsg.resource_guid)
# See what actually gets sent to the API
request = self.serialize_obj(nic, 'NetworkInterface')
self.log(request, pretty_print=True)
nsg = nsg or self.create_default_securitygroup(self.resource_group, self.location, self.name, self.os_type, self.open_ports)
self.log('Creating or updating network interface {0}'.format(self.name))
nic = self.network_models.NetworkInterface(
id=results['id'] if results else None,
location=self.location,
tags=self.tags,
ip_configurations=nic_ip_configurations,
network_security_group=nsg
)
self.results['state'] = self.create_or_update_nic(nic) self.results['state'] = self.create_or_update_nic(nic)
elif self.state == 'absent': elif self.state == 'absent':
self.log('Deleting network interface {0}'.format(self.name)) self.log('Deleting network interface {0}'.format(self.name))
self.delete_nic() self.delete_nic()
# Delete doesn't return anything. If we get this far, assume success
self.results['state']['status'] = 'Deleted'
return self.results return self.results
def get_or_create_public_ip_address(self, ip_config):
name = ip_config.get('public_ip_address_name')
pip = self.get_public_ip_address(name)
if not pip:
params = self.network_models.PublicIPAddress(
location=self.location,
public_ip_allocation_method=ip_config.get('public_ip_allocation_method'),
)
try:
poller = self.network_client.public_ip_addresses.create_or_update(self.resource_group, name, params)
pip = self.get_poller_result(poller)
except CloudError as exc:
self.fail("Error creating {0} - {1}".format(name, str(exc)))
return pip
def create_or_update_nic(self, nic): def create_or_update_nic(self, nic):
try: try:
poller = self.network_client.network_interfaces.create_or_update(self.resource_group, self.name, nic) poller = self.network_client.network_interfaces.create_or_update(self.resource_group, self.name, nic)
new_nic = self.get_poller_result(poller) new_nic = self.get_poller_result(poller)
return nic_to_dict(new_nic)
except Exception as exc: except Exception as exc:
self.fail("Error creating or updating network interface {0} - {1}".format(self.name, str(exc))) self.fail("Error creating or updating network interface {0} - {1}".format(self.name, str(exc)))
return nic_to_dict(new_nic)
def delete_nic(self): def delete_nic(self):
try: try:
poller = self.network_client.network_interfaces.delete(self.resource_group, self.name) poller = self.network_client.network_interfaces.delete(self.resource_group, self.name)
self.get_poller_result(poller) self.get_poller_result(poller)
except Exception as exc: except Exception as exc:
self.fail("Error deleting network interface {0} - {1}".format(self.name, str(exc))) self.fail("Error deleting network interface {0} - {1}".format(self.name, str(exc)))
# Delete doesn't return anything. If we get this far, assume success
self.results['state']['status'] = 'Deleted'
return True return True
def get_public_ip_address(self, name): def get_public_ip_address(self, name):
self.log("Fetching public ip address {0}".format(name)) self.log("Fetching public ip address {0}".format(name))
try: try:
public_ip = self.network_client.public_ip_addresses.get(self.resource_group, name) return self.network_client.public_ip_addresses.get(self.resource_group, name)
except Exception as exc: except Exception as exc:
self.fail("Error: fetching public ip address {0} - {1}".format(self.name, str(exc))) return None
return public_ip
def get_subnet(self, vnet_name, subnet_name): def get_subnet(self, resource_group, vnet_name, subnet_name):
self.log("Fetching subnet {0} in virtual network {1}".format(subnet_name, vnet_name)) self.log("Fetching subnet {0} in virtual network {1}".format(subnet_name, vnet_name))
try: try:
subnet = self.network_client.subnets.get(self.resource_group, vnet_name, subnet_name) return self.network_client.subnets.get(resource_group, vnet_name, subnet_name)
except Exception as exc: except Exception as exc:
self.fail("Error: fetching subnet {0} in virtual network {1} - {2}".format(subnet_name, return None
vnet_name,
str(exc)))
return subnet
def get_security_group(self, name): def get_security_group(self, name):
self.log("Fetching security group {0}".format(name)) self.log("Fetching security group {0}".format(name))
try: try:
nsg = self.network_client.network_security_groups.get(self.resource_group, name) return self.network_client.network_security_groups.get(self.resource_group, name)
except Exception as exc: except Exception as exc:
self.fail("Error: fetching network security group {0} - {1}.".format(name, str(exc))) return None
return nsg
def main(): def main():

View file

@ -1648,10 +1648,10 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
self.fail(no_subnets_msg) self.fail(no_subnets_msg)
self.results['actions'].append('Created default public IP {0}'.format(self.name + '01')) self.results['actions'].append('Created default public IP {0}'.format(self.name + '01'))
pip = self.create_default_pip(self.resource_group, self.location, self.name, self.public_ip_allocation_method) pip = self.create_default_pip(self.resource_group, self.location, self.name + '01', self.public_ip_allocation_method)
self.results['actions'].append('Created default security group {0}'.format(self.name + '01')) self.results['actions'].append('Created default security group {0}'.format(self.name + '01'))
group = self.create_default_securitygroup(self.resource_group, self.location, self.name, self.os_type, group = self.create_default_securitygroup(self.resource_group, self.location, self.name + '01', self.os_type,
self.open_ports) self.open_ports)
parameters = self.network_models.NetworkInterface( parameters = self.network_models.NetworkInterface(

View file

@ -0,0 +1,3 @@
cloud/azure
posix/ci/cloud/group2/azure
destructive

View file

@ -0,0 +1,2 @@
dependencies:
- setup_azure

View file

@ -0,0 +1,169 @@
- name: Create virtual network
azure_rm_virtualnetwork:
resource_group: "{{ resource_group_secondary }}"
name: testnic001
address_prefixes: "10.10.0.0/16"
register: vn
- name: Add subnet
azure_rm_subnet:
resource_group: "{{ resource_group_secondary }}"
name: testnic001
address_prefix: "10.10.0.0/24"
virtual_network: testnic001
- name: Create NIC (check mode)
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
public_ip_name: testnic001
public_ip_allocation_method: Static
security_group: testnic001
register: output
check_mode: yes
- assert:
that:
- output.changed
- name: Create NIC
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
public_ip_name: testnic001
public_ip_allocation_method: Static
security_group: testnic001
register: output
- assert:
that:
- output.changed
- output.state.ip_configuration.subnet.name == 'testnic001'
- name: Update the NIC with mutilple ip configurations (check mode)
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
security_group: testnic001
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
- name: ipconfig-add
public_ip_name: testnic002
- name: default
public_ip_name: testnic001
primary: True
public_ip_allocation_method: Static
- name: ipconfig1
public_ip_name: testnic003
register: output
check_mode: yes
- assert:
that:
- output.changed
- name: Update the NIC with mutilple ip configurations
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
security_group: testnic001
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
- name: ipconfig-add
public_ip_name: testnic002
- name: default
public_ip_name: testnic001
primary: True
public_ip_allocation_method: Static
- name: ipconfig1
public_ip_name: testnic003
register: output
- assert:
that:
- output.changed
- not output.state.ip_configuration
- output.state.ip_configurations | length == 3
- name: Update the NIC with mutilple ip configurations (idempotent)
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
security_group: testnic001
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
- name: ipconfig-add
public_ip_name: testnic002
- name: default
public_ip_name: testnic001
primary: True
public_ip_allocation_method: Static
- name: ipconfig1
public_ip_name: testnic003
register: output
- assert:
that:
- not output.changed
- name: Remove one ip configuration
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
security_group: testnic001
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
- name: ipconfig-add
public_ip_name: testnic002
- name: default
public_ip_name: testnic001
public_ip_allocation_method: Static
primary: True
register: output
- assert:
that:
- not output.state.ip_configuration
- output.state.ip_configurations | length == 2
- name: Delete the NIC (check mode)
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
state: absent
check_mode: yes
register: output
- assert:
that:
- output.changed
- name: Delete the NIC
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
state: absent
register: output
- assert:
that:
- output.changed
- name: Delete the NIC (idempotent)
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
state: absent
register: output
- assert:
that:
- not output.changed