Extend contrail fromula
This patch extends contrail states/modules and client to
be able of:
* Create physical_routers
* Create tor switches
* Create ports
* Create logical_interfaces
* Create Virtual Machine Interfaces
Related-Prod: PROD-14409
Change-Id: Ia4b8390c077e4590bb9ecc53e44d15f53d8a7c95
diff --git a/README.rst b/README.rst
index 54e9502..f76fb4c 100644
--- a/README.rst
+++ b/README.rst
@@ -590,11 +590,32 @@
compute:
gateway_mode: server
+TSN nodes
+---------
+
+Configure TSN nodes
+
+.. code-block:: yaml
+
+ opencontrail:
+ compute:
+ enabled: true
+ tor:
+ enabled: true
+ bind:
+ port: 8086
+ agent:
+ tor01:
+ id: 0
+ port: 6632
+ host: 127.0.0.1
+ address: 127.0.0.1
+
Set up metadata secret for the Vrouter
-------------------------------------
-In order to get cloud-init within the instance to properly fetch
+In order to get cloud-init within the instance to properly fetch
instance metadata, metadata_proxy_secret in the Vrouter agent config
should match the value in nova.conf. The administrator should define
it in the pillar:
@@ -740,7 +761,7 @@
--------------------------
.. code-block:: yaml
-
+
database:
....
bind:
@@ -953,6 +974,51 @@
- 10.10.10.10
ipf_port: 80
+Enforcing physical routers
+
+.. code-block:: yaml
+
+ opencontrail:
+ client:
+ ...
+ physical_router:
+ router1:
+ name: router1
+ dataplane_ip: 1.2.3.4
+ management_ip: 1.2.3.4
+ vendor_name: ovs
+ product_name: ovs
+ agents:
+ - tsn0-0
+ - tsn0
+
+Enforcing physical/logical interfaces for routers
+
+
+.. code-block:: yaml
+
+ opencontrail
+ client:
+ ...
+ physical_router:
+ router1:
+ ...
+ interface:
+ port1:
+ name: port1
+ logical_interface:
+ port1_l:
+ name: 'port1.0'
+ vlan_tag: 0
+ interface_type: L2
+ virtual_machine_interface:
+ port1_port:
+ name: port1_port
+ ip_address: 192.168.90.107
+ mac_address: '2e:92:a8:af:c2:21'
+ security_group: 'default'
+ virtual_network: 'virtual-network'
+
Usage
=====
@@ -1001,7 +1067,7 @@
Display IF MAP table
-Look for neighbours, if VM has 2, it's ok
+Look for neighbours, if VM has 2, it's ok
http://<control-node>:8083/Snh_IFMapTableShowReq?table_name=
diff --git a/_modules/contrail.py b/_modules/contrail.py
index f03ee33..8818922 100644
--- a/_modules/contrail.py
+++ b/_modules/contrail.py
@@ -16,6 +16,7 @@
from netaddr import IPNetwork
from vnc_api.vnc_api import PhysicalRouter, PhysicalInterface, LogicalInterface
from vnc_api.vnc_api import EncapsulationPrioritiesType
+from vnc_api.vnc_api import VirtualMachineInterface, MacAddressesType
try:
from vnc_api import vnc_api
@@ -81,6 +82,17 @@
return rt_inst_obj
+def _get_fq_name(vnc_client, resource_name, project_name, domain='default-domain'):
+ res = [domain]
+ if project_name:
+ res.append(project_name)
+ if resource_name:
+ res.append(resource_name)
+ return res
+
+def _get_project_obj(vnc_client, name, domain='default-domain'):
+ return vnc_client.project_read(fq_name=[domain, name])
+
def _get_ip(ip_w_pfx):
return str(IPNetwork(ip_w_pfx).ip)
@@ -501,7 +513,7 @@
def logical_interface_create(name, parent_names, parent_type='physical-interface', vlan_tag=None, interface_type="l2",
- **kwargs):
+ vmis=None, **kwargs):
'''
Create specific Contrail logical interface
@@ -514,6 +526,7 @@
ret = {}
vnc_client = _auth(**kwargs)
gsc_obj = _get_config(vnc_client)
+
liface_obj = logical_interface_get(name, parent_names, parent_type, **kwargs)
if 'Error' not in liface_obj:
return {'OK': 'Logical interface ' + name + ' already exists'}
@@ -538,7 +551,14 @@
return {'Error': "Virtual Network have to be defined for L3 interface type"}
liface_obj = LogicalInterface(name, parent_obj, vlan_tag, interface_type.lower())
+
+ for vmi_name, vmi in vmis.iteritems():
+ vmi = vnc_client.virtual_machine_interface_read(
+ fq_name=_get_fq_name(vnc_client, resource_name=vmi_name,
+ project_name=kwargs.get('tenant', 'admin')))
+ liface_obj.add_virtual_machine_interface(vmi)
vnc_client.logical_interface_create(liface_obj)
+
return "Created"
@@ -1193,12 +1213,76 @@
salt '*' contrail.virtual_machine_interfaces
'''
+ ret = []
+ vnc_client = _auth(**kwargs)
+ project = _get_project_obj(vnc_client, name=kwargs.get('tenant', 'admin'))
+ project_uuid = project.get_uuid()
+
+ vm_ifaces = vnc_client.virtual_machine_interfaces_list(
+ detail=True, parent_id=project_uuid)
+
+ for vm_iface in vm_ifaces:
+ ret.append(vm_iface.__dict__)
+
+ return ret
+
+
+def virtual_machine_interface_create(name,
+ virtual_network,
+ mac_address=None,
+ ip_address=None,
+ security_group=None,
+ **kwargs):
+ '''
+ Create specific Contrail virtual machine interface (Port)
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt '*' contrail.virtual_machine_interface_create port01 net01 mac_address='01:02:03:04:05:06'
+ router_types:
+ - tor-agent
+ - tor-service-node
+ - embedded
+ '''
ret = {}
vnc_client = _auth(**kwargs)
- vm_ifaces = vnc_client._objects_list('virtual-machine-interface', detail=True)
- for vm_iface in vm_ifaces:
- ret[vm_iface.name] = vm_iface.__dict__
- return ret
+ project = _get_project_obj(vnc_client, name=kwargs.get('tenant', 'admin'))
+
+ vm_int = VirtualMachineInterface(name, parent_obj=project)
+
+ if mac_address:
+ mac_address_obj = MacAddressesType([mac_address])
+ vm_int.set_virtual_machine_interface_mac_addresses(mac_address_obj)
+
+ if security_group:
+ sgo = vnc_client.security_group_read(fq_name=_get_fq_name(
+ vnc_client, security_group, kwargs.get('tenant', 'admin')))
+ vm_int.set_security_group(sgo)
+
+ vnet_uuid = virtual_network_get(virtual_network, **kwargs)[virtual_network]['_uuid']
+ vnet_obj = vnc_client.virtual_network_read(id=vnet_uuid)
+ vm_int.set_virtual_network(vnet_obj)
+
+ vmi_uuid = vnc_client.virtual_machine_interface_create(vm_int)
+ vmi = vnc_client.virtual_machine_interface_read(id=vmi_uuid)
+
+ vm_int.set_port_security_enabled(False)
+ vnc_client.virtual_machine_interface_update(vm_int)
+
+ #Allocate IP to VMI
+ ip = vnc_api.InstanceIp(name + '.ip')
+ ip.set_virtual_machine_interface(vmi)
+ ip.set_virtual_network(vnet_obj)
+
+ ip_uuid = vnc_client.instance_ip_create(ip)
+
+ if ip_address:
+ ip.set_instance_ip_address(ip_address)
+ vnc_client.instance_ip_update(ip)
+
+ return vmi.__dict__
def virtual_network_list(**kwargs):
@@ -1218,3 +1302,23 @@
for virtual_network in virtual_networks:
ret[virtual_network.name] = virtual_network.__dict__
return ret
+
+
+def virtual_network_get(name, **kwargs):
+ '''
+ Return a specific Contrail virtual network
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt '*' contrail.virtual_network_get net01
+ '''
+ ret = {}
+ vnet_objs = virtual_network_list(**kwargs)
+ if name in vnet_objs:
+ ret[name] = vnet_objs.get(name)
+ if len(ret) != 1 :
+ return {'result': False,
+ 'Error': 'Error in retrieving virtual networks.'}
+ return ret
diff --git a/_states/contrail.py b/_states/contrail.py
index e64948e..c66333f 100644
--- a/_states/contrail.py
+++ b/_states/contrail.py
@@ -375,7 +375,8 @@
return ret
-def logical_interface_present(name, parent_names, parent_type, vlan_tag=None, interface_type="L2", **kwargs):
+def logical_interface_present(name, parent_names, parent_type, vlan_tag=None, interface_type="L2",
+ vmis=None, **kwargs):
'''
Ensures that the Contrail logical interface exists.
@@ -383,7 +384,8 @@
:param parent_names: List of parents
:param parent_type Parent resource type. Any of ['physical-router', 'physical-interface']
:param vlan_tag: VLAN tag (.1Q) classifier for this logical interface.
- :param interface_type Logical interface type can be L2 or L3.
+ :param interface_type: Logical interface type can be L2 or L3.
+ :param vmis: Virtual machine interface name associate with
'''
ret = {'name': name,
'changes': {},
@@ -394,7 +396,7 @@
pass
else:
result = __salt__['contrail.logical_interface_create'](name, parent_names, parent_type, vlan_tag,
- interface_type, **kwargs)
+ interface_type, vmis=vmis, **kwargs)
if 'Error' in result:
return False
@@ -593,3 +595,42 @@
ret['comment'] = 'Database node {0} has been created'.format(name)
ret['changes']['DatabaseNode'] = result
return ret
+
+
+def virtual_machine_interface_present(name,
+ virtual_network,
+ mac_address=None,
+ ip_address=None,
+ security_group=None,
+ **kwargs):
+ '''
+ Ensures that the Contrail virtual machine interface exists.
+
+ :param name: Virtual machine interface name
+ :param virtual_network: Network name
+ :param mac_address: Mac address of vmi interface
+ :param ip_address: Virtual machine interface ip address
+ '''
+ ret = {'name': name,
+ 'changes': {},
+ 'result': True,
+ 'comment': 'Virtual machine interface "{0}" already exists'.format(name)}
+
+ vmis = __salt__['contrail.virtual_machine_interface_list'](**kwargs)
+
+ for vmi in vmis:
+ if vmi['name'] == name:
+ return ret
+
+ vmi = __salt__['contrail.virtual_machine_interface_create'](name, virtual_network,
+ mac_address=mac_address,
+ ip_address=ip_address,
+ security_group=security_group,
+ **kwargs)
+ if vmi['name'] == name:
+ ret['comment'] = 'Virtual machine interface {0} has been created'.format(name)
+ ret['result'] = True
+ else:
+ ret['comment'] = 'Virtual machine interface {0} creation failed'.format(name)
+ ret['result'] = False
+ return ret
diff --git a/opencontrail/client.sls b/opencontrail/client.sls
index 99b5bee..e467c27 100644
--- a/opencontrail/client.sls
+++ b/opencontrail/client.sls
@@ -134,4 +134,82 @@
{%- endfor %}
+{%- for physical_router_name, physical_router in client.get('physical_router', {}).items() %}
+
+opencontrail_client_physical_router_{{ physical_router_name }}:
+ contrail.physical_router_present:
+ - name: {{ physical_router.name }}
+ - dataplane_ip: {{ physical_router.dataplane_ip }}
+ - management_ip: {{ physical_router.get('management_ip') }}
+ - vendor_name: {{ physical_router.get('vendor_name') }}
+ - product_name: {{ physical_router.get('product_name') }}
+ - vnc_managed: {{ physical_router.get('vnc_managed', True) }}
+ - agents: {{ physical_router.get('agents') }}
+ - user: {{ client.identity.user }}
+ - password: {{ client.identity.password }}
+ - project: {{ client.identity.tenant }}
+ - auth_host_ip: {{ client.identity.host }}
+ - api_server_ip: {{ client.api.host }}
+ - api_server_port: {{ client.api.port }}
+ - api_base_url: '/'
+
+{%- for physical_interface_name, physical_interface in physical_router.get('interface', {}).items() %}
+
+opencontrail_client_physical_interface_{{ physical_interface_name }}:
+ contrail.physical_interface_present:
+ - name: {{ physical_interface_name }}
+ - physical_router: {{ physical_router_name }}
+ - requires:
+ - opencontrail_client_physical_router_{{ physical_router_name }}
+
+
+{%- for logical_interface_name, logical_interface in physical_interface.get('logical_interface', {}).items() %}
+
+{%- for virtual_machine_interface_name, virtual_machine_interface in logical_interface.get('virtual_machine_interface', {}).items() %}
+
+opencontrail_client_virtual_machine_interface_{{ virtual_machine_interface_name }}:
+ contrail.virtual_machine_interface_present:
+ - name: {{ virtual_machine_interface.name }}
+ - virtual_network: {{ virtual_machine_interface.virtual_network }}
+ - ip_address: {{ virtual_machine_interface.get('ip_address') }}
+ - mac_address: {{ virtual_machine_interface.get('mac_address') }}
+ - security_group: {{ virtual_machine_interface.get('security_group') }}
+ - user: {{ client.identity.user }}
+ - password: {{ client.identity.password }}
+ - project: {{ client.identity.tenant }}
+ - auth_host_ip: {{ client.identity.host }}
+ - api_server_ip: {{ client.api.host }}
+ - api_server_port: {{ client.api.port }}
+ - api_base_url: '/'
+ - requires_in:
+ - opencontrail_client_logical_interface_{{ logical_interface_name }}
+
+{%- endfor %} # end for virtual_machine_interface
+
+opencontrail_client_logical_interface_{{ logical_interface_name }}:
+ contrail.logical_interface_present:
+ - name: {{ logical_interface.name }}
+ - parent_names:
+ - {{ physical_interface.name }}
+ - {{ physical_router.name }}
+ - parent_type: 'physical-interface'
+ - vlan_tag: {{ logical_interface.get('vlan_tag') }}
+ - interface_type: {{ logical_interface.get('interface_type', 'L2') }}
+ - vmis: {{ logical_interface.get('virtual_machine_interface', {}) }}
+ - user: {{ client.identity.user }}
+ - password: {{ client.identity.password }}
+ - project: {{ client.identity.tenant }}
+ - auth_host_ip: {{ client.identity.host }}
+ - api_server_ip: {{ client.api.host }}
+ - api_server_port: {{ client.api.port }}
+ - api_base_url: '/'
+ - requires:
+ - opencontrail_client_physical_interface_{{ physical_interface_name }}
+
+{%- endfor %} # end for logical_interaface
+
+{%- endfor %} # end for physical_interface
+
+{%- endfor %} # end for physical_router
+
{%- endif %}