The published NSX modules from VMware lack certain functionality that I’ve needed as I worked on the Infrastructure-as-Code project over the holiday break. A few of the things I need to be able to do include:
- Enable Edge firewall and add/delete rules
- Enable DHCP and add IP pools
- Search for DVS VXLAN port group
- Associate vNIC with default gateway
- Create Edge SNAT/DNAT rules
As I investigated methods for accomplishing these tasks, I found another VMware repository of Python scripts that had some of the functionality. The library is designed as a command-line tool, but I was able to take several of the code blocks and modify them for use within an Ansible playbook. In order to track the changes that I’ve made to the Ansible modules, I’ve forked the vmware/nsxansible repo into virtualelephant/nsxansible on Github. After a bit of work over the holiday, I’ve managed to add functionality for all but the SNAT/DNAT rule creation.
In addition to writing the Python modules, I have modified the Docker ubuntu-ansible container I spoke about previously to include my forked branch of the vmware/nsxansible modules.
Creating DHCP Pools
The module nsx_edge_dhcp.py allows an Ansible playbook to create a new IP pool and enable the DHCP service on a previously deployed NSX Edge. The playbook can currently support all of the basic IP pool options, as seen in the following image:
The playbook can contain the following code:
1 --- 2 - hosts: localhost 3 connection: local 4 gather_facts: False 5 vars_files: 6 - nsxanswer.yml 7 - envanswer.yml 8 9 tasks: 10 - name: Create DHCP pool on NSX Edge 11 nsx_edge_dhcp: 12 nsxmanager_spec: "{{ nsxmanager_spec }}" 13 name: '{{ edge_name }}' 14 mode: 'create_pool' 15 ip_range: '{{ ip_range }}' 16 subnet: '{{ netmask }}' 17 default_gateway: '{{ gateway }}' 18 domain_name: '{{ domain }}' 19 dns_server_1: '{{ dns1_ip }}' 20 dns_server_2: '{{ dns2_ip }}' 21 lease_time: '{{ lease_time }}' 22 next_server: '{{ tftp_server }}' 23 bootfile: '{{ bootfile }}'
A future enhancement to the module will allow for the DHCP Options variables to be updated as well. This is key for the project so that the scope points to the TFTP server where Core OS is installed from.
Update: The ability to add a TFTP next-server and specify the filename for downloading has been added and is contained in the Github repo virtualelephant/nsxansible.
Edge Firewall Rules
Fortunately, another author on Github already wrote this module — they even submitted a pull request to have it included in the vmware/nsxansible repo last year, but since it had yet to be included, I forked it into my own repo for use.
The nsx_edge_firewall.py module allows you to modify the default rule and create new rules on a NSX Edge device.
The Ansible playbook contains the following to create the default firewall policy:
1 --- 2 - hosts: localhost 3 connection: local 4 gather_facts: False 5 vars_files: 6 - nsxanswer.yml 7 - envanswer.yml 8 9 tasks: 10 - name: Set default firewall rule policy 11 nsx_edge_firewall: 12 nsxmanager_spec: "{{ nsxmanager_spec }}" 13 mode: 'set_default_action' 14 edge_name: '{{ edge_name }}' 15 default_action: 'accept'
Specify vNIC for Default Gateway
The original nsx_edge_router.py module included code to create the default gateway, however it did not allow you to modify the MTU or specify which vNIC should be associated with the default gateway. The forked nsx_edge_router.py version in the VirtualElephant Github repo includes the necessary code to specify both of those options.
150 def config_def_gw(client_session, esg_id, dfgw, vnic, mtu, dfgw_adminDistance): 151 if not mtu: 152 mtu = '1500' 153 rtg_cfg = client_session.read('routingConfigStatic', uri_parameters={'edgeId': esg_id})['body'] 154 if dfgw: 155 try: 156 rtg_cfg['staticRouting']['defaultRoute'] = {'gatewayAddress': dfgw, 'vnic': vnic, 'mtu': mtu, 'adminDistance': dfgw_adminDistance} 157 except KeyError: 158 rtg_cfg['staticRouting']['defaultRoute'] = {'gatewayAddress': dfgw, 'vnic': vnic, 'adminDistance': dfgw_adminDistance, 'mtu': mtu} 159 else: 160 rtg_cfg['staticRouting']['defaultRoute'] = None 161 162 cfg_result = client_session.update('routingConfigStatic', uri_parameters={'edgeId': esg_id}, 163 request_body_dict=rtg_cfg) 164 if cfg_result['status'] == 204: 165 return True 166 else: 167 return False
The Ansible playbook is then able to include the following bits to create the default gateway with the preferred settings:
42 - name: NSX Edge creation 43 nsx_edge_router: 44 nsxmanager_spec: "{{ nsxmanager_spec }}" 45 state: present 46 name: "{{ edge_name }}" 47 description: "{{ description }}" 48 resourcepool_moid: "{{ gather_moids_cl.object_id }}" 49 datastore_moid: "{{ gather_moids_ds.object_id }}" 50 datacenter_moid: "{{ gather_moids_cl.datacenter_moid }}" 51 interfaces: 52 vnic0: {ip: "{{ ext_ip }}", prefix_len: 26, logical_switch: "{{ uplink }}", name: 'uplink0', iftype: 'uplink', fence_param: 'ethernet0.filter1.param1=1'} 53 vnic1: {ip: '192.168.0.1', prefix_len: 20, logical_switch: "{{ switch_name }}", name: 'int0', iftype: 'internal', fence_param: 'ethernet0.filter1.param1=1'} 54 default_gateway: "{{ default_route }}" 55 default_gateway_vnic: '0' 56 mtu: '9000' 57 remote_access: 'true' 58 username: 'admin' 59 password: "{{ nsx_pass }}" 60 firewall: 'true' 61 ha_enabled: 'true' 62 register: create_esg 63 tags: esg_create
When specifying the vNIC to use for the default gateway, the value is not the name the Ansible playbook gives the vNIC — uplink0 — but rather the vNIC number within the Edge — which will be 0 if you are using my playbook.
Once I have the SNAT/DNAT functionality added, I will write another blog post and progress on the Infrastructure-as-Code project will be nearly complete.
Enjoy!