Repository: ansible/ansible
Pull request: Fixes some NIC problems: create without nsg, support loadbalancer
##### SUMMARY
<!--- Describe the change, including rationale and design decisions -->
Fixes #37917
Fixes #37734

<!---
If you are fixing an existing issue, please include "Fixes #nnn" in your
commit message and your description; but you should still explain what
the change does.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Feature Pull Request

##### COMPONENT NAME
<!--- Name of the module, plugin, module or task -->
azure_rm_networkinterface

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
2.5.0
```


##### ADDITIONAL INFORMATION
<!---
Include additional information to help people understand the change here.
For bugs that don't have a linked bug report, a step-by-step reproduction
of the problem is helpful.
  -->

<!--- Paste verbatim command output below, e.g. before and after your change -->
```

```


Problem statement:
Add network interface to Load Balancer Backend pool in azure_rm_networkinterface
##### ISSUE TYPE
 - Feature Idea

##### COMPONENT NAME
azure_rm_networkinterface

##### ANSIBLE VERSION
```
ansible --version
ansible 2.4.3.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/dgermain/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]
```

##### CONFIGURATION
```
ansible-config dump --only-changed
#empty return
```

##### OS / ENVIRONMENT
N/A

##### SUMMARY
In current azure loadbalancer module, you can create Backend pools, but you don't have the possibility to add network interfaces in this Backend pool, neither in *azure_rm_networkinterface* nor in *azure_rm_loadbalancer*.
As an example, this feature is present in Powershell azure CLI, when handling network interfaces :
```
    $nic = Get-AzurermNetworkInterface -name $virtualnetworkcardname" -resourcegroupname $resourceGroup
    $nic.IpConfigurations[0].LoadBalancerBackendAddressPools=$backend
    Set-AzureRmNetworkInterface -NetworkInterface $nic
```

##### STEPS TO REPRODUCE
As far as I can tell, you don't have this option in the ansible module

##### EXPECTED RESULTS
Have an option to allow this

##### ACTUAL RESULTS
No option to do so

Have option to create Network Interface without NSG attached
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
Always add information AFTER of these html comments.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Feature Idea

##### COMPONENT NAME
<!---
Insert below this comment the name of the module, plugin, task or feature.
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->
azure_rm_networkinterface

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.6.0 (devel 7cd3d9cc1a) last updated 2018/03/26 11:40:33 (GMT +100)
  config file = None
  configured module search path = [u'/Users/alan/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/alan/ansible/lib/ansible
  executable location = /Users/alan/ansible/bin/ansible
  python version = 2.7.14 (default, Mar  9 2018, 23:57:12) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
Running Ansible on MacOS High Sierra, creating a new virtual machine in Azure.

##### SUMMARY
<!--- Explain the problem briefly -->
When creating a new network interface the default behaviour is to create a network security group with the same name if a name is not specified. In my case I have a NSG associated with the subnet so don't need additional NSGs for every virtual machine being created within the subnet.

Request to make this behaviour optional so that the NIC is not associated with any NSG.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```

```

Hints from issue discussion:
Files identified in the description:
* [lib/ansible/modules/cloud/azure/azure_rm_networkinterface.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/azure/azure_rm_networkinterface.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @haroldwongms @nitzmahone @trstringer @xscript @yuwzho @zikalino
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@zwindler Actually it is the network ip configurations, a nic can have mutil ipConfigurations. I will add a suboption `backend_ip_configurations` under the `backend_address_pools`. Together with the other issue you created #37731
You are absolutely right, sorry for the confusion between ipConfigurations and nic.

Thanks!
@zwindler I check the SDK interface, I cannot add `backend_ip_configurations` to a load balancer's `backend_address_pools`:  https://github.com/Azure/azure-sdk-for-python/blob/master/azure-mgmt-network/azure/mgmt/network/v2018_01_01/models/backend_address_pool.py#L64

I need to associate the load balancer to  ip configuration when creating NIC: https://github.com/Azure/azure-sdk-for-python/blob/master/azure-mgmt-network/azure/mgmt/network/v2018_01_01/models/network_interface_ip_configuration.py#L89-L90

So I may move this issue to next iteration's backlog (April). And currently support create internal load balancer only.
Ok, I get that

Thanks!
I've taken a look to your PR. There are a lot of things in it, but as far as I'm concerned (adding NICs in loadbalancer backend pools), it works and I'm already using it ;)
@zwindler Thanks a lot
Files identified in the description:
* [lib/ansible/modules/cloud/azure/azure_rm_networkinterface.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/azure/azure_rm_networkinterface.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @haroldwongms @nitzmahone @trstringer @xscript @yuwzho @zikalino
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@aykay76 So your request is creating a NIC without NSG? Am I right? Could you please modify the title more detailed? It is really confused

Commit message: add sample

Patch to review:
diff --git a/lib/ansible/module_utils/azure_rm_common.py b/lib/ansible/module_utils/azure_rm_common.py
index c9b058412d1fbe..cc959af5df6f62 100644
--- a/lib/ansible/module_utils/azure_rm_common.py
+++ b/lib/ansible/module_utils/azure_rm_common.py
@@ -128,7 +128,7 @@
     from enum import Enum
     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
@@ -603,6 +603,17 @@ def _get_credentials(self, params):
 
         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.
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_networkinterface.py b/lib/ansible/modules/cloud/azure/azure_rm_networkinterface.py
index caf327fcd4628a..a8349bdc7692bd 100644
--- a/lib/ansible/modules/cloud/azure/azure_rm_networkinterface.py
+++ b/lib/ansible/modules/cloud/azure/azure_rm_networkinterface.py
@@ -52,25 +52,22 @@
             - Valid azure location. Defaults to location of the resource group.
         default: resource_group location
         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
@@ -124,8 +121,7 @@
     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:
@@ -151,18 +147,34 @@
                     - 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
@@ -183,7 +195,7 @@
       azure_rm_networkinterface:
         name: nic001
         resource_group: Testing
-        virtual_network_name: vnet001
+        virtual_network: vnet001
         subnet_name: subnet001
         ip_configurations:
           - name: ipconfig1
@@ -194,8 +206,9 @@
       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
@@ -204,10 +217,11 @@
       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
@@ -217,9 +231,9 @@
       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
@@ -230,13 +244,19 @@
         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:
@@ -274,7 +294,10 @@
         "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,
@@ -283,7 +306,7 @@
 '''
 
 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
@@ -311,6 +334,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'),
@@ -349,6 +374,7 @@ def nic_to_dict(nic):
     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)
 )
 
@@ -361,15 +387,15 @@ def __init__(self):
             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'),
@@ -377,24 +403,23 @@ def __init__(self):
         )
 
         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
@@ -424,15 +449,10 @@ def exec_module(self, **kwargs):
             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
@@ -465,16 +485,21 @@ def exec_module(self, **kwargs):
                 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
 
@@ -511,9 +536,9 @@ def exec_module(self, **kwargs):
             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 = [
@@ -523,15 +548,19 @@ def exec_module(self, **kwargs):
                         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,
@@ -591,19 +620,36 @@ def get_public_ip_address(self, name):
         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)
diff --git a/test/integration/targets/azure_rm_networkinterface/tasks/main.yml b/test/integration/targets/azure_rm_networkinterface/tasks/main.yml
index ef96eea4f1e1bf..7a130730a1f861 100644
--- a/test/integration/targets/azure_rm_networkinterface/tasks/main.yml
+++ b/test/integration/targets/azure_rm_networkinterface/tasks/main.yml
@@ -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,15 @@
       - 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:
+        name: testnic002
+        resource_group: "{{ resource_group_secondary }}"
       virtual_network: "{{ vn.state.id }}"
       subnet: testnic001
       ip_configurations:
@@ -146,6 +195,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 +209,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 +232,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 +247,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:


Code review comments:
diff_hunk: @@ -122,19 +164,26 @@
           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:
     that:
       - 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:
+        name: testnic002
+        resource_group: "{{ resource_group_secondary }}"
path: test/integration/targets/azure_rm_networkinterface/tasks/main.yml
text: @user1:
update one to test id?