Add Pure Storage FlashBlade module to manage network subnets (#44422)

* Add Pure Storage FlashBlade module to manage network interfaces

* Add Pure Storage FlashBlade module to manage subnets
This commit is contained in:
Simon Dodsley 2018-10-30 05:44:33 -04:00 committed by John R Barker
parent e5b6abadaf
commit 9034c0786d

View file

@ -0,0 +1,258 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: purefb_subnet
version_added: "2.8"
short_description: Manage network subnets in a Pure Storage FlashBlade
description:
- This module manages network subnets on Pure Storage FlashBlade.
author: Simon Dodsley (@sdodsley)
options:
name:
description:
- Subnet Name.
required: true
state:
description:
- Create, delete or modifies a subnet.
required: false
default: present
choices: [ "present", "absent" ]
gateway:
description:
- IPv4 or IPv6 address of subnet gateway.
required: false
mtu:
description:
- MTU size of the subnet. Range is 1280 to 9216.
required: false
default: 1500
prefix:
description:
- IPv4 or IPv6 address associated with the subnet.
- Supply the prefix length (CIDR) as well as the IP address.
required: false
vlan:
description:
- VLAN ID of the subnet.
required: false
default: 0
extends_documentation_fragment:
- purestorage.fb
notes:
- Requires the netaddr Python package on the host.
requirements:
- netaddr
'''
EXAMPLES = '''
- name: Create new network subnet named foo
purefb_subnet:
name: foo
prefix: "10.21.200.3/24"
gateway: 10.21.200.1
mtu: 9000
vlan: 2200
state: present
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Change configuration of existing subnet foo
purefb_network:
name: foo
state: present
prefix: "10.21.100.3/24"
gateway: 10.21.100.1
mtu: 1500
address: 10.21.200.123
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Delete network subnet named foo
purefb_subnet:
name: foo
state: absent
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641'''
RETURN = '''
'''
HAS_PURITY_FB = True
try:
from purity_fb import Subnet
except ImportError:
HAS_PURITY_FB = False
try:
import netaddr
HAS_NETADDR = True
except ImportError:
HAS_NETADDR = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MINIMUM_API_VERSION = '1.3'
def get_subnet(module, blade):
"""Return Subnet or None"""
subnet = []
subnet.append(module.params['name'])
try:
res = blade.subnets.list_subnets(names=subnet)
return res.items[0]
except:
return None
def create_subnet(module, blade):
"""Create Subnet"""
subnet = []
subnet.append(module.params['name'])
try:
blade.subnets.create_subnets(names=subnet,
subnet=Subnet(prefix=module.params['prefix'],
vlan=module.params['vlan'],
mtu=module.params['mtu'],
gateway=module.params['gateway']
)
)
changed = True
except:
module.fail_json(msg='Failed to create subnet {0}. Confirm supplied parameters'.format(module.params['name']))
module.exit_json(changed=changed)
def modify_subnet(module, blade):
"""Modify Subnet settings"""
changed = False
subnet = get_subnet(module, blade)
subnet_new = []
subnet_new.append(module.params['name'])
if module.params['prefix']:
if module.params['prefix'] != subnet.prefix:
try:
blade.subnets.update_subnets(names=subnet_new,
subnet=Subnet(prefix=module.params['prefix']))
changed = True
except:
module.fail_json(msg='Failed to change subnet {0} prefix to {1}'.format(module.params['name'],
module.params['prefix']))
if module.params['vlan']:
if module.params['vlan'] != subnet.vlan:
try:
blade.subnets.update_subnets(names=subnet_new,
subnet=Subnet(vlan=module.params['vlan']))
changed = True
except:
module.fail_json(msg='Failed to change subnet {0} VLAN to {1}'.format(module.params['name'],
module.params['vlan']))
if module.params['gateway']:
if module.params['gateway'] != subnet.gateway:
try:
blade.subnets.update_subnets(names=subnet_new,
subnet=Subnet(gateway=module.params['gateway']))
changed = True
except:
module.fail_json(msg='Failed to change subnet {0} gateway to {1}'.format(module.params['name'],
module.params['gateway']))
if module.params['mtu']:
if module.params['mtu'] != subnet.mtu:
try:
blade.subnets.update_subnets(names=subnet_new,
subnet=Subnet(mtu=module.params['mtu']))
changed = True
except:
module.fail_json(msg='Failed to change subnet {0} MTU to {1}'.format(module.params['name'],
module.params['mtu']))
module.exit_json(changed=changed)
def delete_subnet(module, blade):
""" Delete Subnet"""
subnet = []
subnet.append(module.params['name'])
try:
blade.subnets.delete_subnets(names=subnet)
changed = True
except:
changed = False
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(
dict(
name=dict(required=True),
state=dict(default='present', choices=['present', 'absent']),
gateway=dict(),
mtu=dict(type='int', default=1500),
prefix=dict(),
vlan=dict(type='int', default=0),
)
)
required_if = [["state", "present", ["gateway", 'prefix']]]
module = AnsibleModule(argument_spec,
required_if=required_if,
supports_check_mode=False)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
if not HAS_NETADDR:
module.fail_json(msg='netaddr module is required')
state = module.params['state']
blade = get_blade(module)
api_version = blade.api_version.list_versions().versions
if MINIMUM_API_VERSION not in api_version:
module.fail_json(msg='Upgrade Purity//FB to enable this module')
subnet = get_subnet(module, blade)
if state == 'present':
if not (1280 <= module.params['mtu'] <= 9216):
module.fail_json(msg='MTU {0} is out of range (1280 to 9216)'.format(module.params['mtu']))
if not (0 <= module.params['vlan'] <= 4094):
module.fail_json(msg='VLAN ID {0} is out of range (0 to 4094)'.format(module.params['vlan']))
if netaddr.IPAddress(module.params['gateway']) not in netaddr.IPNetwork(module.params['prefix']):
module.fail_json(msg='Gateway and subnet are not compatible.')
subnets = blade.subnets.list_subnets()
nrange = netaddr.IPSet([module.params['prefix']])
for sub in range(0, len(subnets.items)):
if subnets.items[sub].vlan == module.params['vlan'] and subnets.items[sub].name != module.params['name']:
module.fail_json(msg='VLAN ID {0} is already in use.'.format(module.params['vlan']))
if nrange & netaddr.IPSet([subnets.items[sub].prefix]) and subnets.items[sub].name != module.params['name']:
module.fail_json(msg='Prefix CIDR overlaps with existing subnet.')
if state == 'present' and not subnet:
create_subnet(module, blade)
elif state == 'present' and subnet:
modify_subnet(module, blade)
elif state == 'absent' and subnet:
delete_subnet(module, blade)
elif state == 'absent' and not subnet:
module.exit_json(changed=False)
if __name__ == '__main__':
main()