Refactor neutrong state and module (part 1)
_authenticate decorator automatically merges dictionaries in array if
they have 'name' or 'id' key [0]. This poses a problem since OpenStack
resource names (networks/subnets/routers/instances etc)
are generally not required to be unique.
Thus trying to get list of any resource from neutronng module will
lead to merging of resources with the same name.
For example if tenant has two networks with the same name calling
`salt '*' neutronng.list_networks profile=admin` will show only one.
This patch updates the following functions in neutronng:
* list_subnets
* list_networks
to return a dictionary as it is returned from Neutron API
as it is done in the upstream salt network module [1].
Also fix passing profile with connection_args in _auth() method.
TODO: refactor other functions.
[0] https://github.com/salt-formulas/salt-formula-neutron/blob/master/_modules/neutronng.py#L60
[1] https://github.com/saltstack/salt/blob/c3579e9284d76c79df42974a322954c208cc7cb1/salt/modules/neutron.py#L354
Change-Id: If9f666ef397386746f3cce51f220c3d75d7fef72
diff --git a/_modules/neutronng.py b/_modules/neutronng.py
index 652e612..6a3eaf8 100644
--- a/_modules/neutronng.py
+++ b/_modules/neutronng.py
@@ -34,7 +34,7 @@
'''
Authenticate request and format return data
'''
- connection_args = {'profile': kwargs.get('profile', None)}
+ connection_args = {'profile': kwargs.pop('profile', None)}
nkwargs = {}
for kwarg in kwargs:
if 'connection_' in kwarg:
@@ -55,6 +55,8 @@
neutron_interface = client.Client(
endpoint_url=endpoint, token=token)
return_data = func_name(neutron_interface, *args, **nkwargs)
+ # TODO(vsaienko) drop this formatting when all commands are updated
+ # to return dictionary
if isinstance(return_data, list):
# format list as a dict for rendering
return {data.get('name', None) or data['id']: data
@@ -69,7 +71,7 @@
list all floatingips
CLI Example:
.. code-block:: bash
- salt '*' neutron.list_floatingips
+ salt '*' neutronng.list_floatingips
'''
return neutron_interface.list_floatingips(**kwargs)['floatingips']
@@ -80,7 +82,7 @@
list all security_groups
CLI Example:
.. code-block:: bash
- salt '*' neutron.list_security_groups
+ salt '*' neutronng.list_security_groups
'''
return neutron_interface.list_security_groups(**kwargs)['security_groups']
@@ -91,9 +93,9 @@
list all subnets
CLI Example:
.. code-block:: bash
- salt '*' neutron.list_subnets
+ salt '*' neutronng.list_subnets
'''
- return neutron_interface.list_subnets(**kwargs)['subnets']
+ return neutron_interface.list_subnets(**kwargs)
@_autheticate
@@ -102,9 +104,9 @@
list all networks
CLI Example:
.. code-block:: bash
- salt '*' neutron.list_networks
+ salt '*' neutronng.list_networks
'''
- return neutron_interface.list_networks(**kwargs)['networks']
+ return neutron_interface.list_networks(**kwargs)
@_autheticate
@@ -113,7 +115,7 @@
list all ports
CLI Example:
.. code-block:: bash
- salt '*' neutron.list_ports
+ salt '*' neutronng.list_ports
'''
return neutron_interface.list_ports(**kwargs)['ports']
@@ -124,7 +126,7 @@
list all routers
CLI Example:
.. code-block:: bash
- salt '*' neutron.list_routers
+ salt '*' neutronng.list_routers
'''
return neutron_interface.list_routers(**kwargs)['routers']
@@ -136,9 +138,9 @@
CLI Example:
.. code-block:: bash
to associate with an instance's port
- salt '*' neutron.update_floatingip openstack-floatingip-id port-id
+ salt '*' neutronng.update_floatingip openstack-floatingip-id port-id
to disassociate from an instance's port
- salt '*' neutron.update_floatingip openstack-floatingip-id
+ salt '*' neutronng.update_floatingip openstack-floatingip-id
'''
neutron_interface.update_floatingip(fip, {"floatingip":
{"port_id": port_id}})
@@ -150,9 +152,9 @@
update given subnet
CLI Example:
.. code-block:: bash
- salt '*' neutron.update_subnet openstack-subnet-id name='new_name'
+ salt '*' neutronng.update_subnet openstack-subnet-id name='new_name'
'''
- neutron_interface.update_subnet(subnet_id, {'subnet': subnet_params})
+ return neutron_interface.update_subnet(subnet_id, {'subnet': subnet_params})
@_autheticate
@@ -161,7 +163,7 @@
Update give network
CLI Example:
.. code-block:: bash
- salt '*' neutron.update_network openstack-net-id admin_state_up=false
+ salt '*' neutronng.update_network openstack-net-id admin_state_up=false
'''
network_params = {}
for param in net_params:
@@ -170,7 +172,7 @@
else:
network_params[param] = net_params[param]
LOG.info('ATTRIBUTES ' + str(network_params))
- neutron_interface.update_network(network_id, {'network': network_params})
+ return neutron_interface.update_network(network_id, {'network': network_params})
@_autheticate
@@ -179,7 +181,7 @@
update given router
CLI Example:
.. code-block:: bash
- salt '*' neutron.update_router openstack-router-id name='new_name'
+ salt '*' neutronng.update_router openstack-router-id name='new_name'
external_gateway='openstack-network-id' administrative_state=true
'''
neutron_interface.update_router(router_id, {'router': router_params})
@@ -191,7 +193,7 @@
Set external gateway for a router
CLI Example:
.. code-block:: bash
- salt '*' neutron.update_router openstack-router-id openstack-network-id
+ salt '*' neutronng.update_router openstack-router-id openstack-network-id
'''
neutron_interface.update_router(
router_id, {'router': {'external_gateway_info':
@@ -204,7 +206,7 @@
Clear external gateway for a router
CLI Example:
.. code-block:: bash
- salt '*' neutron.update_router openstack-router-id
+ salt '*' neutronng.update_router openstack-router-id
'''
neutron_interface.update_router(
router_id, {'router': {'external_gateway_info': None}})
@@ -216,7 +218,7 @@
Create OpenStack Neutron router
CLI Example:
.. code-block:: bash
- salt '*' neutron.create_router name=R1
+ salt '*' neutronng.create_router name=R1
'''
response = neutron_interface.create_router({'router': router_params})
if 'router' in response and 'id' in response['router']:
@@ -229,7 +231,7 @@
Attach router to a subnet
CLI Example:
.. code-block:: bash
- salt '*' neutron.router_add_interface openstack-router-id subnet-id
+ salt '*' neutronng.router_add_interface openstack-router-id subnet-id
'''
neutron_interface.add_interface_router(router_id, {'subnet_id': subnet_id})
@@ -240,7 +242,7 @@
Dettach router from a subnet
CLI Example:
.. code-block:: bash
- salt '*' neutron.router_rem_interface openstack-router-id subnet-id
+ salt '*' neutronng.router_rem_interface openstack-router-id subnet-id
'''
neutron_interface.remove_interface_router(
router_id, {'subnet_id': subnet_id})
@@ -252,7 +254,7 @@
Create a new security group
CLI Example:
.. code-block:: bash
- salt '*' neutron.create_security_group name='new_rule'
+ salt '*' neutronng.create_security_group name='new_rule'
description='test rule'
'''
response = neutron_interface.create_security_group(
@@ -267,7 +269,7 @@
Create a rule entry for a security group
CLI Example:
.. code-block:: bash
- salt '*' neutron.create_security_group_rule
+ salt '*' neutronng.create_security_group_rule
'''
neutron_interface.create_security_group_rule(
{'security_group_rule': rule_params})
@@ -279,7 +281,7 @@
Create a new floating IP
CLI Example:
.. code-block:: bash
- salt '*' neutron.create_floatingip floating_network_id=ext-net-id
+ salt '*' neutronng.create_floatingip floating_network_id=ext-net-id
'''
response = neutron_interface.create_floatingip(
{'floatingip': floatingip_params})
@@ -293,18 +295,11 @@
Create a new subnet in OpenStack
CLI Example:
.. code-block:: bash
- salt '*' neutron.create_subnet name='subnet name'
+ salt '*' neutronng.create_subnet name='subnet name'
network_id='openstack-network-id' cidr='192.168.10.0/24' \\
- gateway_ip='192.168.10.1' ip_version='4' enable_dhcp=false \\
- start_ip='192.168.10.10' end_ip='192.168.10.20'
+ gateway_ip='192.168.10.1' ip_version='4' enable_dhcp=false
'''
- if 'start_ip' in subnet_params:
- subnet_params.update(
- {'allocation_pools': [{'start': subnet_params.pop('start_ip'),
- 'end': subnet_params.pop('end_ip', None)}]})
- response = neutron_interface.create_subnet({'subnet': subnet_params})
- if 'subnet' in response and 'id' in response['subnet']:
- return response['subnet']['id']
+ return neutron_interface.create_subnet({'subnet': subnet_params})
@_autheticate
@@ -313,7 +308,7 @@
Create a new network segment in OpenStack
CLI Example:
.. code-block:: bash
- salt '*' neutron.create_network name=External
+ salt '*' neutronng.create_network name=External
provider_network_type=flat provider_physical_network=ext
'''
network_params = {}
@@ -322,9 +317,7 @@
network_params[param.replace('_', ':', 1)] = net_params[param]
else:
network_params[param] = net_params[param]
- response = neutron_interface.create_network({'network': network_params})
- if 'network' in response and 'id' in response['network']:
- return response['network']['id']
+ return neutron_interface.create_network({'network': network_params})
@_autheticate
@@ -333,7 +326,7 @@
Create a new port in OpenStack
CLI Example:
.. code-block:: bash
- salt '*' neutron.create_port network_id='openstack-network-id'
+ salt '*' neutronng.create_port network_id='openstack-network-id'
'''
response = neutron_interface.create_port({'port': port_params})
if 'port' in response and 'id' in response['port']:
@@ -346,7 +339,7 @@
Create a new port in OpenStack
CLI Example:
.. code-block:: bash
- salt '*' neutron.update_port name='new_port_name'
+ salt '*' neutronng.update_port name='new_port_name'
'''
neutron_interface.update_port(port_id, {'port': port_params})
@@ -357,7 +350,7 @@
delete a floating IP
CLI Example:
.. code-block:: bash
- salt '*' neutron.delete_floatingip openstack-floating-ip-id
+ salt '*' neutronng.delete_floatingip openstack-floating-ip-id
'''
neutron_interface.delete_floatingip(floating_ip_id)
@@ -368,7 +361,7 @@
delete a security group
CLI Example:
.. code-block:: bash
- salt '*' neutron.delete_security_group openstack-security-group-id
+ salt '*' neutronng.delete_security_group openstack-security-group-id
'''
neutron_interface.delete_security_group(sg_id)
@@ -380,7 +373,7 @@
to be deleted
CLI Example:
.. code-block:: bash
- salt '*' neutron.delete_security_group_rule direction='ingress'
+ salt '*' neutronng.delete_security_group_rule direction='ingress'
ethertype='ipv4' security_group_id='openstack-security-group-id'
port_range_min=100 port_range_max=4096 protocol='tcp'
remote_group_id='default'
@@ -399,7 +392,7 @@
delete given subnet
CLI Example:
.. code-block:: bash
- salt '*' neutron.delete_subnet openstack-subnet-id
+ salt '*' neutronng.delete_subnet openstack-subnet-id
'''
neutron_interface.delete_subnet(subnet_id)
@@ -410,7 +403,7 @@
delete given network
CLI Example:
.. code-block:: bash
- salt '*' neutron.delete_network openstack-network-id
+ salt '*' neutronng.delete_network openstack-network-id
'''
neutron_interface.delete_network(network_id)
@@ -421,6 +414,7 @@
delete given router
CLI Example:
.. code-block:: bash
- salt '*' neutron.delete_router openstack-router-id
+ salt '*' neutronng.delete_router openstack-router-id
'''
- neutron_interface.delete_router(router_id)
\ No newline at end of file
+ neutron_interface.delete_router(router_id)
+
diff --git a/_states/neutronng.py b/_states/neutronng.py
index 67a088c..89e0011 100644
--- a/_states/neutronng.py
+++ b/_states/neutronng.py
@@ -5,8 +5,8 @@
:depends: - neutronclient Python module
:configuration: See :py:mod:`salt.modules.neutron` for setup instructions.
.. code-block:: yaml
- neutron network present:
- neutron.network_present:
+ neutronng network present:
+ neutronng.network_present:
- name: Netone
- provider_physical_network: PHysnet1
- provider_network_type: vlan
@@ -41,6 +41,15 @@
def _neutron_module_call(method, *args, **kwargs):
return __salt__['neutronng.{0}'.format(method)](*args, **kwargs)
+def _get_tenant_id(tenant_name, *args, **kwargs):
+ try:
+ tenant_id = __salt__['keystone.tenant_get'](
+ name=tenant_name, **kwargs)[tenant_name]['id']
+ except:
+ tenant_id = None
+ LOG.debug('Cannot get the tenant id. User {0} is not an admin.'.format(
+ kwargs.get('connection_user')))
+ return tenant_id
def _auth(profile=None, endpoint_type=None):
'''
@@ -57,13 +66,15 @@
'connection_password': password,
'connection_tenant': tenant,
'connection_auth_url': auth_url,
- 'connection_endpoint_type': endpoint_type
+ 'connection_endpoint_type': endpoint_type,
+ 'profile': profile
}
return kwargs
@_test_call
def network_present(name=None,
+ network_id=None,
tenant=None,
provider_network_type=None,
provider_physical_network=None,
@@ -78,17 +89,12 @@
name
The name of the network to manage
'''
- tenant_name = tenant
connection_args = _auth(profile, endpoint_type)
- try:
- tenant_id = __salt__['keystone.tenant_get'](
- name=tenant_name, **connection_args)[tenant_name]['id']
- except:
- tenant_id = None
- LOG.debug('Cannot get the tenant id. User {0} is not an admin.'.format(
- connection_args['connection_user']))
- existing_network = _neutron_module_call(
- 'list_networks', name=name, **connection_args)
+ tenant_id = _get_tenant_id(tenant_name=tenant, **connection_args)
+
+ existing_networks = _neutron_module_call(
+ 'list_networks', name=name, tenant_id=tenant_id,
+ **connection_args)['networks']
network_arguments = _get_non_null_args(
name=name,
provider_network_type=provider_network_type,
@@ -99,64 +105,63 @@
tenant_id=tenant_id,
provider_segmentation_id=provider_segmentation_id)
- if not existing_network:
+ if len(existing_networks) == 0:
network_arguments.update(connection_args)
- _neutron_module_call('create_network', **network_arguments)
- existing_networks = _neutron_module_call(
- 'list_networks',name=name, **connection_args)
- for network in existing_networks:
- if network.get(name) == name:
- existing_network = network
- if existing_network:
- return _created(name, 'network', existing_network[name])
- return _update_failed(name, 'network')
+ res = _neutron_module_call(
+ 'create_network', **network_arguments)['network']
- LOG.info('CONNECTION STRINGS' + str(connection_args))
- LOG.info('existing ' + str(existing_network))
- LOG.info('new ' + str(network_arguments))
- existing_network = dict((key.replace(':', '_', 1), value)
- for key, value in
- existing_network[name].iteritems())
- # generate differential
- diff = dict((key, value) for key, value in network_arguments.iteritems()
- if existing_network.get(key, None) != value)
- if diff:
- # update the changes
- network_arguments = diff.copy()
- network_arguments.update(connection_args)
- try:
- LOG.debug('updating network {0} with changes {1}'.format(
- name, str(diff)))
- _neutron_module_call('update_network',
- existing_network['id'],
- **network_arguments)
- changes_dict = _created(name, 'network', diff)
- changes_dict['comment'] = '{1} {0} updated'.format(name, 'network')
- return changes_dict
- except:
- LOG.exception('Could not update network {0}'.format(name))
- return _update_failed(name, 'network')
- return _no_change(name, 'network')
+ if res.get('name') == name:
+ return _created(name, 'network', res['name'])
+
+ elif len(existing_networks) > 1:
+ LOG.error("More than one network found with the name: {0}".format(
+ name))
+
+ elif len(existing_networks) == 1:
+ existing_network = existing_networks[0]
+ LOG.info('CONNECTION STRINGS' + str(connection_args))
+ LOG.info('existing ' + str(existing_network))
+ LOG.info('new ' + str(network_arguments))
+ existing_network = dict((key.replace(':', '_', 1), value)
+ for key, value in
+ existing_network.iteritems())
+ # generate differential
+ diff = dict((key, value) for key, value in network_arguments.iteritems()
+ if existing_network.get(key, None) != value)
+ if diff:
+ # update the changes
+ network_arguments = diff.copy()
+ network_arguments.update(connection_args)
+ try:
+ LOG.debug('updating network {0} with changes {1}'.format(
+ name, str(diff)))
+ _neutron_module_call('update_network',
+ existing_network['id'],
+ **network_arguments)
+ changes_dict = _created(name, 'network', diff)
+ changes_dict['comment'] = '{1} {0} updated'.format(name, 'network')
+ return changes_dict
+ except:
+ LOG.error('Could not update network {0}'.format(name))
+ return _update_failed(name, 'network')
+ return _no_change(name, 'network')
+ return _create_failed(name, 'network')
@_test_call
-def network_absent(name, profile=None,endpoint_type=None):
+def network_absent(name, network_id=None, profile=None, endpoint_type=None):
connection_args = _auth(profile, endpoint_type)
- existing_network = _neutron_module_call(
- 'list_networks', name=name, **connection_args)
- if existing_network:
- _neutron_module_call(
- 'delete_network', existing_network[name]['id'], **connection_args)
- if _neutron_module_call('list_networks', name=name, **connection_args):
- return _delete_failed(name, 'network')
- return _deleted(name, 'network', existing_network[name])
- return _absent(name, 'network')
+ identifier = network_id or name
+ _neutron_module_call(
+ 'delete_network', identifier, **connection_args)
+ return _absent(identifier, 'network')
@_test_call
-def subnet_present(name=None,
+def subnet_present(name,
+ network_name=None,
+ network_id=None,
tenant=None,
- network=None,
cidr=None,
ip_version=4,
enable_dhcp=True,
@@ -171,20 +176,19 @@
name
The name of the subnet to manage
'''
+ if network_name is None and network_id is None:
+ LOG.error("Network identificator name or uuid should be provided.")
+ return _create_failed(name, 'subnet')
+
connection_args = _auth(profile, endpoint_type)
- tenant_name = tenant
- try:
- tenant_id = __salt__['keystone.tenant_get'](
- name=tenant_name, **connection_args)[tenant_name]['id']
- except:
- tenant_id = None
- LOG.debug('Cannot get the tenant id. User {0} is not an admin.'.format(
- connection_args['connection_user']))
- existing_subnet = _neutron_module_call(
- 'list_subnets', tenant_id=tenant_id, name=name, **connection_args)
+ tenant_id = _get_tenant_id(tenant_name=tenant, **connection_args)
+
+ existing_subnets = _neutron_module_call(
+ 'list_subnets', tenant_id=tenant_id, name=name,
+ **connection_args)['subnets']
+
subnet_arguments = _get_non_null_args(
name=name,
- network=network,
cidr=cidr,
ip_version=ip_version,
enable_dhcp=enable_dhcp,
@@ -192,29 +196,43 @@
gateway_ip=gateway_ip,
dns_nameservers=dns_nameservers,
host_routes=host_routes)
- # replace network with network_id
- if 'network' in subnet_arguments:
- network = subnet_arguments.pop('network', None)
- existing_network = _neutron_module_call(
- 'list_networks', tenant_id=tenant_id, name=network, **connection_args)
- if existing_network:
- subnet_arguments['network_id'] = existing_network[network]['id']
- if not existing_subnet:
+
+ if network_id is None and network_name:
+ existing_networks = _neutron_module_call(
+ 'list_networks', tenant_id=tenant_id, name=network_name,
+ **connection_args)['networks']
+ if len(existing_networks) == 0:
+ LOG.error("Can't find network with name: {0}".format(network_name))
+ elif len(existing_networks) == 1:
+ network_id = existing_networks[0]['id']
+ elif len(existing_networks) > 1:
+ LOG.error("Multiple networks with name: {0} found.".format(
+ network_name))
+
+ if network_id is None:
+ return _create_failed(name, 'subnet')
+
+ subnet_arguments['network_id'] = network_id
+
+ if len(existing_subnets) == 0:
subnet_arguments.update(connection_args)
- _neutron_module_call('create_subnet', tenant_id=tenant_id, **subnet_arguments)
- existing_subnet = _neutron_module_call(
- 'list_subnets', tenant_id=tenant_id, name=name, **connection_args)
- if existing_subnet:
- return _created(name, 'subnet', existing_subnet[name])
- return _update_failed(name, 'subnet')
- # change from internal representation
- existing_subnet = existing_subnet[name]
- # create differential
- LOG.error('existing ' + str(existing_subnet))
- LOG.error('new ' + str(subnet_arguments))
- diff = dict((key, value) for key, value in subnet_arguments.iteritems()
- if existing_subnet.get(key, None) != value)
- if diff:
+ res = _neutron_module_call('create_subnet', tenant_id=tenant_id,
+ **subnet_arguments)['subnet']
+ if res.get('name') == name:
+ return _created(name, 'subnet', res)
+ return _create_failed(name, 'subnet')
+
+ elif len(existing_subnets) == 1:
+ existing_subnet = existing_subnets[0]
+
+ # create differential
+ LOG.error('existing ' + str(existing_subnet))
+ LOG.error('new ' + str(subnet_arguments))
+ diff = dict((key, value) for key, value in subnet_arguments.iteritems()
+ if existing_subnet.get(key, None) != value)
+ if not diff:
+ return _no_change(name, 'subnet')
+
# update the changes
subnet_arguments = diff.copy()
subnet_arguments.update(connection_args)
@@ -228,24 +246,22 @@
changes_dict['comment'] = '{1} {0} updated'.format(name, 'subnet')
return changes_dict
except:
- LOG.exception('Could not update subnet {0}'.format(name))
+ LOG.error('Could not update subnet {0}'.format(name))
return _update_failed(name, 'subnet')
- return _no_change(name, 'subnet')
+
+ elif len(existing_subnets) > 1:
+ LOG.error("Multiple subnets with name: {0} found".format(
+ name))
+ return _create_failed(name, 'network')
@_test_call
-def subnet_absent(name, profile=None, endpoint_type=None):
+def subnet_absent(name, subnet_id=None, profile=None, endpoint_type=None):
connection_args = _auth(profile, endpoint_type)
- existing_subnet = _neutron_module_call(
- 'list_subnets', tenant_id=tenant_id, name=name, **connection_args)
- if existing_subnet:
- _neutron_module_call(
- 'delete_subnet', existing_subnet[name]['id'], **connection_args)
- if _neutron_module_call('list_subnets', name=name, **connection_args):
- return _delete_failed(name, 'subnet')
- return _deleted(name, 'subnet', existing_subnet[name])
+ identifier = subnet_id or name
+ _neutron_module_call(
+ 'delete_subnet', identifier, **connection_args)
return _absent(name, 'subnet')
- return _absent(name, 'network')
@_test_call
@@ -390,6 +406,7 @@
else:
return _no_change('for instance {0}'.format(name), 'floatingip')
+
def security_group_present(name=None,
tenant=None,
description=None,
@@ -583,4 +600,4 @@
Return those kwargs which are not null
'''
return dict((key, value,) for key, value in kwargs.iteritems()
- if value is not None)
\ No newline at end of file
+ if value is not None)
diff --git a/neutron/client.sls b/neutron/client.sls
index 91f81e8..e31e969 100644
--- a/neutron/client.sls
+++ b/neutron/client.sls
@@ -45,7 +45,7 @@
neutron_openstack_subnet_{{ subnet_name }}:
neutronng.subnet_present:
- name: {{ subnet_name }}
- - network: {{ network_name }}
+ - network_name: {{ network_name }}
- profile: {{ identity_name }}
- tenant: {{ network.tenant }}
{%- if identity.endpoint_type is defined %}