Fixes some NIC problems: create without nsg, support loadbalancer (#38643)

* add loadbalancer

* dict check nullable

* add default vallue when get list

* create backend addr pool

* fix the set

* fix to dict

* fix ideponement

* use param security group name when create

* nic can has no nsg

* add test

* fix

* fix

* fix

* add document

* add configuration

* fix

* fix

* remove all resources

* fix

* fix test

* add version added

* fix lint

* fix lint

* Fixes some NIC bugs (#39213)

* add loadbalancer

* dict check nullable

* add default vallue when get list

* create backend addr pool

* fix the set

* fix to dict

* fix ideponement

* use param security group name when create

* nic can has no nsg

* add test

* fix

* fix

* fix

* fix idemponet

* add document

* fix test

* add configuration

* fix

* fix

* remove all resources

* fix

* fix test

* add version added

* fix lint

* fix lint

* fix lint

* remove new feature and only submit bugfix

* remove useless test

* fix

* fix indent

* Update azure_rm_networkinterface.py

* fix comment

* support 3 types to specific name and resource group

* avoid test racing

* fix test

* add sample

* add resource id test
pull/40643/head
Yuwei Zhou 6 years ago committed by Jordan Borean
parent 4fbdc1a497
commit c95724fb0a

@ -132,7 +132,7 @@ try:
from msrestazure.azure_active_directory import AADTokenCredentials
from msrestazure.azure_exceptions import CloudError
from msrestazure.azure_active_directory import MSIAuthentication
from msrestazure.tools import resource_id, is_valid_resource_id
from msrestazure.tools import parse_resource_id, resource_id, is_valid_resource_id
from msrestazure import azure_cloud
from azure.common.credentials import ServicePrincipalCredentials, UserPassCredentials
from azure.mgmt.network.version import VERSION as network_client_version
@ -651,6 +651,17 @@ class AzureRMModuleBase(object):
return None
def parse_resource_to_dict(self, resource):
'''
Return a dict of the give resource, which contains name and resource group.
:param resource: It can be a resource name, id or a dict contains name and resource group.
'''
resource_dict = parse_resource_id(resource) if not isinstance(resource, dict) else resource
resource_dict['resource_group'] = resource_dict.get('resource_group', self.resource_group)
resource_dict['subscription_id'] = resource_dict.get('subscription_id', self.subscription_id)
return resource_dict
def serialize_obj(self, obj, class_name, enum_modules=None):
'''
Return a JSON representation of an Azure object.

@ -51,25 +51,22 @@ options:
description:
- Valid azure location. Defaults to location of the resource group.
required: false
virtual_network_resource_group:
virtual_network:
description:
- The resource group of I(virtual_network_name).
- If not set then this is the same resource group as I(resource_group).
- This can be used to specify the resource group of a virtual network that is in another resource group
than the network interface.
- If I(virtual_network_name) is specified as a virtual network id, this parameter is ignored.
version_added: 2.6
virtual_network_name:
description:
- Name or id of an existing virtual network with which the network interface will be associated. Required
- An existing virtual network with which the network interface will be associated. Required
when creating a network interface.
- It can be the virtual network's name.
- Make sure your virtual network is in the same resource group as NIC when you give only the name.
- It can be the virtual network's resource id.
- It can be a dict which contains C(name) and C(resource_group) of the virtual network.
aliases:
- virtual_network
- virtual_network_name
required: true
subnet_name:
description:
- Name of an existing subnet within the specified virtual network. Required when creating a network
interface
- Use the C(virtual_network)'s resource group.
aliases:
- subnet
required: true
@ -123,8 +120,7 @@ options:
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
field private_ip_address, private_ip_allocation_method, public_ip_address_name, public_ip, public_ip_allocation_method, name
suboptions:
name:
description:
@ -150,18 +146,34 @@ options:
- Dynamic
- Static
default: Dynamic
load_balancer_backend_address_pools:
description:
- List of an existing load-balancer backend address pool id to associate with the network interface.
- It can be write as a resource id.
- Also can be a dict of I(name) and I(load_balancer).
version_added: 2.6
primary:
description:
- Whether the ip configuration is the primary one in the list.
type: bool
default: 'no'
version_added: 2.5
security_group_name:
create_with_security_group:
description:
- Specifies whether a default security group should be be created with the NIC. Only applies when creating a new NIC.
type: bool
version_added: 2.6
default: True
security_group:
description:
- Name of an existing security group with which to associate the network interface. If not provided, a
default security group will be created.
- An existing security group with which to associate the network interface. If not provided, a
default security group will be created when C(create_with_security_group) is true.
- It can be the name of security group.
- Make sure the security group is in the same resource group when you only give its name.
- It can be the resource id.
- It can be a dict contains security_group's C(name) and C(resource_group).
aliases:
- security_group
- security_group_name
open_ports:
description:
- When a default security group is created for a Linux host a rule will be added allowing inbound TCP
@ -182,7 +194,7 @@ EXAMPLES = '''
azure_rm_networkinterface:
name: nic001
resource_group: Testing
virtual_network_name: vnet001
virtual_network: vnet001
subnet_name: subnet001
ip_configurations:
- name: ipconfig1
@ -193,8 +205,9 @@ EXAMPLES = '''
azure_rm_networkinterface:
name: nic001
resource_group: Testing
virtual_network_name: vnet001
virtual_network: vnet001
subnet_name: subnet001
create_with_security_group: False
ip_configurations:
- name: ipconfig1
primary: True
@ -203,10 +216,11 @@ EXAMPLES = '''
azure_rm_networkinterface:
name: nic002
resource_group: Testing
virtual_network_name: vnet001
virtual_network: vnet001
subnet_name: subnet001
os_type: Windows
rdp_port: 3399
security_group: "/subscriptions/XXXXXXX/resourceGroups/Testing/providers/Microsoft.Network/networkSecurityGroups/nsg001"
ip_configurations:
- name: ipconfig1
public_ip_address_name: publicip001
@ -216,9 +230,9 @@ EXAMPLES = '''
azure_rm_networkinterface:
name: nic003
resource_group: Testing
virtual_network_name: vnet001
virtual_network: vnet001
subnet_name: subnet001
security_group_name: secgroup001
security_group: secgroup001
ip_configurations:
- name: ipconfig1
public_ip_address_name: publicip001
@ -229,13 +243,19 @@ EXAMPLES = '''
name: nic004
resource_group: Testing
subnet_name: subnet001
virtual_network_name: vnet001
security_group_name: secgroup001
virtual_network: vnet001
security_group:
name: testnic002
resource_group: Testing1
ip_configurations:
- name: ipconfig1
public_ip_address_name: publicip001
primary: True
- name: ipconfig2
load_balancer_backend_address_pools:
- "{{ loadbalancer001.state.backend_address_pools[0].id }}"
- name: backendaddrpool1
load_balancer: loadbalancer001
- name: Delete network interface
azure_rm_networkinterface:
@ -273,7 +293,10 @@ state:
"location": "eastus2",
"mac_address": null,
"name": "nic003",
"network_security_group": {},
"network_security_group": {
"id": "/subscriptions//XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX/resourceGroups/Testing/providers/Microsoft.Network/networkSecurityGroups/nsg001",
"name": "nsg001"
},
"primary": null,
"provisioning_state": "Succeeded",
"tags": null,
@ -282,7 +305,7 @@ state:
'''
try:
from msrestazure.tools import parse_resource_id
from msrestazure.tools import parse_resource_id, resource_id
from msrestazure.azure_exceptions import CloudError
except ImportError:
# This is handled in azure_rm_common
@ -310,6 +333,8 @@ def nic_to_dict(nic):
private_ip_allocation_method=config.private_ip_allocation_method,
subnet=subnet_to_dict(config.subnet),
primary=config.primary,
load_balancer_backend_address_pools=([item.id for item in config.load_balancer_backend_address_pools]
if config.load_balancer_backend_address_pools else None),
public_ip_address=dict(
id=config.public_ip_address.id,
name=azure_id_to_dict(config.public_ip_address.id).get('publicIPAddresses'),
@ -348,6 +373,7 @@ ip_configuration_spec = dict(
private_ip_allocation_method=dict(type='str', choices=['Dynamic', 'Static'], default='Dynamic'),
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'),
load_balancer_backend_address_pools=dict(type='list'),
primary=dict(type='bool', default=False)
)
@ -360,15 +386,15 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
resource_group=dict(type='str', required=True),
name=dict(type='str', required=True),
location=dict(type='str'),
security_group_name=dict(type='str', aliases=['security_group']),
create_with_security_group=dict(type='bool', default=True),
security_group=dict(type='raw', aliases=['security_group_name']),
state=dict(default='present', choices=['present', 'absent']),
private_ip_address=dict(type='str'),
private_ip_allocation_method=dict(type='str', choices=['Dynamic', 'Static'], default='Dynamic'),
public_ip_address_name=dict(type='str', aliases=['public_ip_address', 'public_ip_name']),
public_ip=dict(type='bool', default=True),
subnet_name=dict(type='str', aliases=['subnet']),
virtual_network_resource_group=dict(type='str'),
virtual_network_name=dict(type='str', aliases=['virtual_network']),
virtual_network=dict(type='raw', aliases=['virtual_network_name']),
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'),
@ -376,24 +402,23 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
)
required_if = [
('state', 'present', ['subnet_name', 'virtual_network_name'])
('state', 'present', ['subnet_name', 'virtual_network'])
]
self.resource_group = None
self.name = None
self.location = None
self.security_group_name = None
self.create_with_security_group = None
self.security_group = None
self.private_ip_address = None
self.private_ip_allocation_method = None
self.public_ip_address_name = None
self.public_ip = None
self.subnet_name = None
self.virtual_network_resource_group = None
self.virtual_network_name = None
self.virtual_network = None
self.public_ip_allocation_method = None
self.state = None
self.tags = None
self.security_group_name = None
self.os_type = None
self.open_ports = None
self.ip_configurations = None
@ -423,15 +448,10 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
self.location = resource_group.location
# parse the virtual network resource group and name
virtual_network_dict = parse_resource_id(self.virtual_network_name)
virtual_network_name = virtual_network_dict.get('name')
virtual_network_resource_group = virtual_network_dict.get('resource_group', self.virtual_network_resource_group)
if virtual_network_resource_group is None:
virtual_network_resource_group = self.resource_group
self.virtual_network = self.parse_resource_to_dict(self.virtual_network)
# if not set the security group name, use nic name for default
self.security_group_name = self.security_group_name or self.name
self.security_group = self.parse_resource_to_dict(self.security_group or self.name)
if self.state == 'present' and not self.ip_configurations:
# construct the ip_configurations array for compatiable
@ -464,16 +484,21 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
if update_tags:
changed = True
nsg = self.get_security_group(self.security_group_name)
if nsg and results.get('network_security_group') and results['network_security_group'].get('id') != nsg.id:
self.log("CHANGED: network interface {0} network security group".format(self.name))
if self.create_with_security_group != bool(results.get('network_security_group')):
self.log("CHANGED: add or remove network interface {0} network security group".format(self.name))
changed = True
if results['ip_configurations'][0]['subnet']['virtual_network_name'] != virtual_network_name:
if not changed:
nsg = self.get_security_group(self.security_group['resource_group'], self.security_group['name'])
if nsg and results.get('network_security_group') and results['network_security_group'].get('id') != nsg.id:
self.log("CHANGED: network interface {0} network security group".format(self.name))
changed = True
if results['ip_configurations'][0]['subnet']['virtual_network_name'] != self.virtual_network['name']:
self.log("CHANGED: network interface {0} virtual network name".format(self.name))
changed = True
if results['ip_configurations'][0]['subnet']['resource_group'] != virtual_network_resource_group:
if results['ip_configurations'][0]['subnet']['resource_group'] != self.virtual_network['resource_group']:
self.log("CHANGED: network interface {0} virtual network resource group".format(self.name))
changed = True
@ -510,9 +535,9 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
if self.state == 'present':
subnet = self.network_models.SubResource(
'/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/virtualNetworks/{2}/subnets/{3}'.format(
self.subscription_id,
virtual_network_resource_group,
virtual_network_name,
self.virtual_network['subscription_id'],
self.virtual_network['resource_group'],
self.virtual_network['name'],
self.subnet_name))
nic_ip_configurations = [
@ -522,15 +547,19 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
name=ip_config.get('name'),
subnet=subnet,
public_ip_address=self.get_or_create_public_ip_address(ip_config),
load_balancer_backend_address_pools=([self.network_models.BackendAddressPool(id=self.backend_addr_pool_id(bap_id))
for bap_id in ip_config.get('load_balancer_backend_address_pools')]
if ip_config.get('load_balancer_backend_address_pools') else None),
primary=ip_config.get('primary')
) for ip_config in self.ip_configurations
]
nsg = self.create_default_securitygroup(self.resource_group,
nsg = self.create_default_securitygroup(self.security_group['resource_group'],
self.location,
self.security_group_name,
self.security_group['name'],
self.os_type,
self.open_ports)
self.open_ports) if self.create_with_security_group else None
self.log('Creating or updating network interface {0}'.format(self.name))
nic = self.network_models.NetworkInterface(
id=results['id'] if results else None,
@ -590,19 +619,36 @@ class AzureRMNetworkInterface(AzureRMModuleBase):
except Exception as exc:
return None
def get_security_group(self, name):
def get_security_group(self, resource_group, name):
self.log("Fetching security group {0}".format(name))
try:
return self.network_client.network_security_groups.get(self.resource_group, name)
return self.network_client.network_security_groups.get(resource_group, name)
except Exception as exc:
return None
def backend_addr_pool_id(self, val):
if isinstance(val, dict):
lb = val.get('load_balancer', None)
name = val.get('name', None)
if lb and name:
return resource_id(subscription=self.subscription_id,
resource_group=self.resource_group,
namespace='Microsoft.Network',
type='loadBalancers',
name=lb,
child_type_1='backendAddressPools',
child_name_1=name)
return val
def construct_ip_configuration_set(self, raw):
configurations = [str(dict(
private_ip_allocation_method=to_native(item.get('private_ip_allocation_method')),
public_ip_address_name=(to_native(item.get('public_ip_address').get('name'))
if item.get('public_ip_address') else to_native(item.get('public_ip_address_name'))),
primary=item.get('primary'),
load_balancer_backend_address_pools=(set([to_native(self.backend_addr_pool_id(id))
for id in item.get('load_balancer_backend_address_pools')])
if item.get('load_balancer_backend_address_pools') else None),
name=to_native(item.get('name'))
)) for item in raw]
return set(configurations)

@ -17,6 +17,40 @@
name: ansiblepip3
resource_group: '{{ resource_group }}'
- name: create load balancer with multiple parameters
azure_rm_loadbalancer:
resource_group: '{{ resource_group }}'
name: lbtestfromansible
frontend_ip_configurations:
- name: frontendipconf0
public_ip_address: ansiblepip3
backend_address_pools:
- name: backendaddrpool0
- name: backendaddrpool1
probes:
- name: prob0
port: 80
inbound_nat_pools:
- name: inboundnatpool0
frontend_ip_configuration_name: frontendipconf0
protocol: Tcp
frontend_port_range_start: 80
frontend_port_range_end: 81
backend_port: 8080
load_balancing_rules:
- name: lbrbalancingrule0
frontend_ip_configuration: frontendipconf0
backend_address_pool: backendaddrpool0
frontend_port: 80
backend_port: 80
probe: prob0
register: lb
- name: create public ip
azure_rm_publicipaddress:
name: ansiblepip3
resource_group: '{{ resource_group }}'
- name: Create NIC (check mode)
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
@ -33,26 +67,28 @@
that:
- output.changed
- name: Create NIC using virtual_network_resource_group parameter
- name: Create NIC using virtual_network resource_group parameter
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001rg
virtual_network: testnic001
virtual_network_resource_group: "{{ resource_group_secondary }}"
virtual_network:
name: testnic001
resource_group: "{{ resource_group_secondary }}"
subnet: testnic001
public_ip_name: testnic001
public_ip_name: testnic001rg
public_ip_allocation_method: Static
security_group: testnic001
register: output
- name: Create NIC using virtual_network_resource_group parameter (idempotent)
- name: Create NIC using virtual_network resource_group parameter (idempotent)
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001rg
virtual_network: testnic001
virtual_network_resource_group: "{{ resource_group_secondary }}"
virtual_network:
name: testnic001
resource_group: "{{ resource_group_secondary }}"
subnet: testnic001
public_ip_name: testnic001
public_ip_name: testnic001rg
public_ip_allocation_method: Static
security_group: testnic001
register: output
@ -66,7 +102,7 @@
resource_group: "{{ resource_group }}"
name: testnic001rg
state: absent
- name: Create NIC
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
@ -75,7 +111,9 @@
subnet: testnic001
public_ip_name: testnic001
public_ip_allocation_method: Static
security_group: testnic001
security_group:
name: testnic002
resource_group: "{{ resource_group_secondary }}"
register: output
- assert:
@ -87,7 +125,9 @@
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
security_group: testnic001
security_group:
name: testnic002
resource_group: "{{ resource_group_secondary }}"
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
@ -110,7 +150,9 @@
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
security_group: testnic001
security_group:
name: testnic002
resource_group: "{{ resource_group_secondary }}"
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
@ -122,6 +164,10 @@
public_ip_allocation_method: Static
- name: ipconfig1
public_ip_name: testnic003
load_balancer_backend_address_pools:
- "{{ lb.state.backend_address_pools[0].id }}"
- name: backendaddrpool1
load_balancer: lbtestfromansible
register: output
- assert:
@ -129,12 +175,13 @@
- output.changed
- not output.state.ip_configuration
- output.state.ip_configurations | length == 3
- output.state.network_security_group.name == 'testnic002'
- name: Update the NIC with mutilple ip configurations (idempotent)
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
security_group: testnic001
security_group: "{{ output.state.network_security_group.id }}"
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
@ -146,6 +193,10 @@
public_ip_allocation_method: Static
- name: ipconfig1
public_ip_name: testnic003
load_balancer_backend_address_pools:
- "{{ lb.state.backend_address_pools[0].id }}"
- name: backendaddrpool1
load_balancer: lbtestfromansible
register: output
- assert:
@ -156,12 +207,18 @@
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001
security_group: testnic001
security_group:
name: testnic002
resource_group: "{{ resource_group_secondary }}"
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
- name: ipconfig1
public_ip_name: testnic003
load_balancer_backend_address_pools:
- "{{ lb.state.backend_address_pools[0].id }}"
- name: backendaddrpool1
load_balancer: lbtestfromansible
- name: default
public_ip_name: testnic001
public_ip_allocation_method: Static
@ -173,10 +230,11 @@
- not output.state.ip_configuration
- output.state.ip_configurations | length == 2
- name: IP configuration without public IP
- name: IP configuration without public IP and NSG
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: testnic001noip
create_with_security_group: False
virtual_network: "{{ vn.state.id }}"
subnet: testnic001
ip_configurations:
@ -187,6 +245,7 @@
- assert:
that:
- output.state.ip_configurations[0].public_ip_address == None
- output.state.network_security_group == None
- name: Delete the NIC (check mode)
azure_rm_networkinterface:

Loading…
Cancel
Save