from . import glance as gl_drv
from . import ceilometer as ce_drv
from . import cinder as ci_drv
-from . import portchain as port_drv
from . import utils as drv_utils
# Exceptions
region_name = region,
logger = self.log)
- self.portchain_drv = port_drv.L2PortChainDriver(self.sess_drv,
- self.neutron_drv,
- logger = self.log)
self.utils = DriverUtilities(self)
self._mgmt_network = mgmt_network
def ceilo_alarm_delete(self, alarm_id):
self.ceilo_drv.client.alarms.delete(alarm_id)
- def create_port_chain(self,name,port_lists):
- "Create port chain"
- #Create port pair
- ppgrp_list = list()
- for index,port_pair in enumerate(port_lists):
- ppair_list = list()
- ingress_port,egress_port = port_pair
- #Disable security group and port security for the port
- self.neutron_drv.port_update(ingress_port,no_security_groups=True,port_security_enabled=False)
- if ingress_port != egress_port:
- self.neutron_drv.port_update(egress_port,no_security_groups=True,port_security_enabled=False)
-
- ppair_id = self.portchain_drv.create_port_pair(name+'ppair'+str(index),ingress_port,egress_port)
- ppair_list.append(ppair_id)
- # Create port pair group
- ppgrp_id = self.portchain_drv.create_port_pair_group(name+'_ppgrp_'+str(index),ppair_list)
- ppgrp_list.append(ppgrp_id)
- #Create port chain
- port_chain_id = self.portchain_drv.create_port_chain(name,ppgrp_list)
- return port_chain_id
-
- def delete_port_chain(self,port_chain_id):
- "Delete port chain"
- try:
- result = self.portchain_drv.get_port_chain(port_chain_id)
- port_chain = result.json()
- self.log.debug("Port chain result is %s", port_chain)
- port_pair_groups = port_chain["port_chain"]["port_pair_groups"]
- self.portchain_drv.delete_port_chain(port_chain_id)
-
- # Get port pairs and delete port pair groups
- port_pairs = list()
- self.log.debug("Port pair groups during delete is %s", port_pair_groups)
- for port_pair_group_id in port_pair_groups:
- result = self.portchain_drv.get_port_pair_group(port_pair_group_id)
- port_pair_group = result.json()
- self.log.debug("Port pair group result is %s", port_pair_group)
- port_pairs.extend(port_pair_group["port_pair_group"]["port_pairs"])
- self.portchain_drv.delete_port_pair_group(port_pair_group_id)
-
- self.log.debug("Port pairs during delete is %s",port_pairs)
-
- for port_pair_id in port_pairs:
- self.portchain_drv.delete_port_pair(port_pair_id)
- pass
- except Exception as e:
- self.log.error("Error while delete port chain with id %s, exception %s", port_chain_id,str(e))
-
- def update_port_chain(self,port_chain_id,flow_classifier_list):
- result = self.portchain_drv.get_port_chain(port_chain_id)
- result.raise_for_status()
- port_chain = result.json()['port_chain']
- new_flow_classifier_list = list()
- if port_chain and port_chain['flow_classifiers']:
- new_flow_classifier_list.extend(port_chain['flow_classifiers'])
- new_flow_classifier_list.extend(flow_classifier_list)
- port_chain_id = self.portchain_drv.update_port_chain(port_chain['id'],flow_classifiers=new_flow_classifier_list)
- return port_chain_id
-
- def create_flow_classifer(self,classifier_name,classifier_dict):
- "Create flow classifier"
- flow_classifier_id = self.portchain_drv.create_flow_classifier(classifier_name,classifier_dict)
- return flow_classifier_id
-
- def delete_flow_classifier(self,classifier_id):
- "Create flow classifier"
- try:
- self.portchain_drv.delete_flow_classifier(classifier_id)
- except Exception as e:
- self.log.error("Error while deleting flow classifier with id %s, exception %s", classifier_id,str(e))
-
- def get_port_chain_list(self):
- result = self.portchain_drv.get_port_chain_list()
- port_chain_list = result.json()
- if 'port_chains' in port_chain_list:
- return port_chain_list['port_chains']
-
def cinder_volume_list(self):
return self.cinder_drv.volume_list()
PORT_CHAINS_URL='/sfc/port_chains'
FLOW_CLASSIFIERS_URL='/sfc/flow_classifiers'
- def __init__(self, sess_handle, neutron_drv, logger = None):
+ def __init__(self, sess_handle, neutron_base_url, logger = None):
"""
Constructor for L2PortChainDriver class
Arguments:
sess_handle (instance of class SessionDriver)
- neutron_drv
+ neutron_base_url Neutron service endpoint
logger (instance of logging.Logger)
"""
if logger is None:
self.log = logger
self._sess = sess_handle
- self.neutron_drv = neutron_drv
- self._neutron_base_url = neutron_drv.neutron_endpoint
+ self._neutron_base_url = neutron_base_url
@property
def neutron_base_url(self):
%(volume.name))
kwargs['boot_index'] = volume.boot_priority
- if "image" in volume:
+ if volume.has_field("image"):
# Support image->volume
- if volume.image is not None:
- kwargs['source_type'] = "image"
- kwargs['uuid'] = self.resolve_image_n_validate(volume.image, volume.image_checksum)
- else:
- # Support blank->volume
- kwargs['source_type'] = "blank"
+ kwargs['source_type'] = "image"
+ kwargs['uuid'] = self.resolve_image_n_validate(volume.image, volume.image_checksum)
+ else:
+ # Support blank->volume
+ kwargs['source_type'] = "blank"
kwargs['device_name'] = volume.name
kwargs['destination_type'] = "volume"
kwargs['volume_size'] = volume.size
kwargs['delete_on_termination'] = True
if volume.has_field('device_type'):
- if volume.device_type == 'cdrom':
- kwargs['device_type'] = 'cdrom'
- elif volume.device_bus == 'ide':
- kwargs['disk_bus'] = 'ide'
+ if volume.device_type in ['cdrom', 'disk']:
+ kwargs['device_type'] = volume.device_type
else:
self.log.error("Unsupported device_type <%s> found for volume: %s",
volume.device_type, volume.name)
volume.name)
raise VolumeValidateError("Mandatory field <device_type> not specified for volume: %s"
%(volume.name))
+
+ if volume.has_field('device_bus'):
+ if volume.device_bus in ['ide', 'virtio', 'scsi']:
+ kwargs['disk_bus'] = volume.device_bus
+ else:
+ self.log.error("Unsupported device_bus <%s> found for volume: %s",
+ volume.device_bus, volume.name)
+ raise VolumeValidateError("Unsupported device_bus <%s> found for volume: %s"
+ %(volume.device_bus, volume.name))
+ else:
+ self.log.error("Mandatory field <device_bus> not specified for volume: %s",
+ volume.name)
+ raise VolumeValidateError("Mandatory field <device_bus> not specified for volume: %s"
+ %(volume.name))
+
return kwargs
def make_vdu_storage_args(self, vdu_params):
kwargs = dict()
if vdu_params.has_field('volumes'):
kwargs['block_device_mapping_v2'] = list()
+ # Ignore top-level image
+ kwargs['image_id'] = ""
for volume in vdu_params.volumes:
kwargs['block_device_mapping_v2'].append(self.make_vdu_volume_args(volume, vdu_params))
return kwargs
console_url = None
if self._parse_vdu_state_info(vm_info) == 'active':
try:
- console_url = self.driver.nova_server_console(vm_info['id'])
serv_console_url = self.driver.nova_server_console(vm_info['id'])
if 'console' in serv_console_url:
console_url = serv_console_url['console']['url']
#!/usr/bin/python
-#
+#
# Copyright 2017 RIFT.IO Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
network_ids.append(self.driver._mgmt_network_id)
### Create ports and collect port ids
- port_ids = self.driver.neutron_multi_port_create(port_args)
+ if port_args:
+ port_ids = self.driver.neutron_multi_port_create(port_args)
+ else:
+ port_ids = list()
+
return port_ids, network_ids
import yaml
import gi
-gi.require_version('RwSdn', '1.0')
gi.require_version('RwCal', '1.0')
gi.require_version('RwcalYang', '1.0')
from gi.repository import (
GObject,
RwCal,
- RwSdn, # Vala package
- RwsdnYang,
RwTypes,
RwcalYang)
def __init__(self):
GObject.Object.__init__(self)
- self._driver_class = openstack_drv.OpenstackDriver
self.log = logging.getLogger('rwcal.openstack.%s' % RwcalOpenstackPlugin.instance_num)
self.log.setLevel(logging.DEBUG)
self._rwlog_handler = None
self._account_drivers = dict()
RwcalOpenstackPlugin.instance_num += 1
+ def _get_account_key(self, account):
+ key = str()
+ for f in account.openstack.fields:
+ try:
+ key+= str(getattr(account.openstack, f))
+ except:
+ pass
+ key += account.name
+ return key
+
def _use_driver(self, account):
if self._rwlog_handler is None:
raise UninitializedPluginError("Must call init() in CAL plugin before use.")
- if account.name not in self._account_drivers:
+ acct_key = self._get_account_key(account)
+
+ if acct_key not in self._account_drivers:
self.log.debug("Creating OpenstackDriver")
kwargs = dict(username = account.openstack.key,
password = account.openstack.secret,
self._account_drivers[account.name] = drv
return drv.driver
else:
- return self._account_drivers[account.name].driver
+ return self._account_drivers[acct_key].driver
@rwstatus
flavor id
"""
drv = self._use_driver(account)
- return drv.nova_flavor_create(name = flavor.name,
- ram = flavor.vm_flavor.memory_mb,
- vcpus = flavor.vm_flavor.vcpu_count,
- disk = flavor.vm_flavor.storage_gb,
- epa_specs = drv.utils.flavor.get_extra_specs(flavor))
-
+ try:
+ flavor_id = drv.nova_flavor_create(name = flavor.name,
+ ram = flavor.vm_flavor.memory_mb,
+ vcpus = flavor.vm_flavor.vcpu_count,
+ disk = flavor.vm_flavor.storage_gb,
+ epa_specs = drv.utils.flavor.get_extra_specs(flavor))
+ except Exception as e:
+ self.log.error("Encountered exceptions during Flavor creation. Exception: %s", str(e))
+ raise
+
+ return flavor_id
@rwstatus
def do_delete_flavor(self, account, flavor_id):
flavor_id - id flavor of the VM
"""
drv = self._use_driver(account)
- drv.nova_flavor_delete(flavor_id)
+ try:
+ drv.nova_flavor_delete(flavor_id)
+ except Exception as e:
+ self.log.error("Encountered exceptions during Flavor deletion. Exception: %s", str(e))
+ raise
@rwstatus(ret_on_failure=[[]])
"""
response = RwcalYang.VimResources()
drv = self._use_driver(account)
- flavors = drv.nova_flavor_list()
- for flv in flavors:
- response.flavorinfo_list.append(drv.utils.flavor.parse_flavor_info(flv))
+ try:
+ flavors = drv.nova_flavor_list()
+ for flv in flavors:
+ response.flavorinfo_list.append(drv.utils.flavor.parse_flavor_info(flv))
+ except Exception as e:
+ self.log.error("Encountered exceptions during get-flavor-list. Exception: %s", str(e))
+ raise
+
return response
@rwstatus(ret_on_failure=[None])
Flavor info item
"""
drv = self._use_driver(account)
- flavor = drv.nova_flavor_get(id)
- return drv.utils.flavor.parse_flavor_info(flavor)
+ try:
+ flavor = drv.nova_flavor_get(id)
+ response = drv.utils.flavor.parse_flavor_info(flavor)
+ except Exception as e:
+ self.log.error("Encountered exceptions during get-flavor. Exception: %s", str(e))
+ raise
+
+ return response
def _fill_network_info(self, network_info, account):
try:
kwargs = drv.utils.network.make_virtual_link_args(link_params)
network_id = drv.neutron_network_create(**kwargs)
+ kwargs = drv.utils.network.make_subnet_args(link_params, network_id)
+ drv.neutron_subnet_create(**kwargs)
except Exception as e:
self.log.error("Encountered exceptions during network creation. Exception: %s", str(e))
raise
- kwargs = drv.utils.network.make_subnet_args(link_params, network_id)
- drv.neutron_subnet_create(**kwargs)
return network_id
return vnf_resources
-class SdnOpenstackPlugin(GObject.Object, RwSdn.Topology):
- instance_num = 1
- def __init__(self):
- GObject.Object.__init__(self)
- self._driver_class = openstack_drv.OpenstackDriver
- self.log = logging.getLogger('rwsdn.openstack.%s' % SdnOpenstackPlugin.instance_num)
- self.log.setLevel(logging.DEBUG)
-
- self._rwlog_handler = None
- SdnOpenstackPlugin.instance_num += 1
-
- @contextlib.contextmanager
- def _use_driver(self, account):
- if self._rwlog_handler is None:
- raise UninitializedPluginError("Must call init() in CAL plugin before use.")
-
- with rwlogger.rwlog_root_handler(self._rwlog_handler):
- try:
- drv = self._driver_class(username = account.openstack.key,
- password = account.openstack.secret,
- auth_url = account.openstack.auth_url,
- tenant_name = account.openstack.tenant,
- mgmt_network = account.openstack.mgmt_network,
- cert_validate = account.openstack.cert_validate )
- except Exception as e:
- self.log.error("SdnOpenstackPlugin: OpenstackDriver init failed. Exception: %s" %(str(e)))
- raise
-
- yield drv
-
- @rwstatus
- def do_init(self, rwlog_ctx):
- self._rwlog_handler = rwlogger.RwLogger(
- category="rw-cal-log",
- subcategory="openstack",
- log_hdl=rwlog_ctx,
- )
- self.log.addHandler(self._rwlog_handler)
- self.log.propagate = False
-
- @rwstatus(ret_on_failure=[None])
- def do_validate_sdn_creds(self, account):
- """
- Validates the sdn account credentials for the specified account.
- Performs an access to the resources using Keystone API. If creds
- are not valid, returns an error code & reason string
-
- @param account - a SDN account
-
- Returns:
- Validation Code and Details String
- """
- status = RwsdnYang.SdnConnectionStatus()
- try:
- with self._use_driver(account) as drv:
- drv.validate_account_creds()
-
- except openstack_drv.ValidationError as e:
- self.log.error("SdnOpenstackPlugin: OpenstackDriver credential validation failed. Exception: %s", str(e))
- status.status = "failure"
- status.details = "Invalid Credentials: %s" % str(e)
-
- except Exception as e:
- msg = "SdnOpenstackPlugin: OpenstackDriver connection failed. Exception: %s" %(str(e))
- self.log.error(msg)
- status.status = "failure"
- status.details = msg
-
- else:
- status.status = "success"
- status.details = "Connection was successful"
-
- return status
-
- @rwstatus(ret_on_failure=[""])
- def do_create_vnffg_chain(self, account,vnffg):
- """
- Creates Service Function chain in ODL
-
- @param account - a SDN account
-
- """
- self.log.debug('Received Create VNFFG chain for account {}, chain {}'.format(account,vnffg))
- with self._use_driver(account) as drv:
- port_list = list()
- vnf_chain_list = sorted(vnffg.vnf_chain_path, key = lambda x: x.order)
- prev_vm_id = None
- for path in vnf_chain_list:
- if prev_vm_id and path.vnfr_ids[0].vdu_list[0].vm_id == prev_vm_id:
- prev_entry = port_list.pop()
- port_list.append((prev_entry[0],path.vnfr_ids[0].vdu_list[0].port_id))
- prev_vm_id = None
- else:
- prev_vm_id = path.vnfr_ids[0].vdu_list[0].vm_id
- port_list.append((path.vnfr_ids[0].vdu_list[0].port_id,path.vnfr_ids[0].vdu_list[0].port_id))
- vnffg_id = drv.create_port_chain(vnffg.name,port_list)
- return vnffg_id
-
- @rwstatus
- def do_terminate_vnffg_chain(self, account,vnffg_id):
- """
- Terminate Service Function chain in ODL
-
- @param account - a SDN account
- """
- self.log.debug('Received terminate VNFFG chain for id %s ', vnffg_id)
- with self._use_driver(account) as drv:
- drv.delete_port_chain(vnffg_id)
-
- @rwstatus(ret_on_failure=[None])
- def do_create_vnffg_classifier(self, account, vnffg_classifier):
- """
- Add VNFFG Classifier
-
- @param account - a SDN account
- """
- self.log.debug('Received Create VNFFG classifier for account {}, classifier {}'.format(account,vnffg_classifier))
- protocol_map = {1:'ICMP',6:'TCP',17:'UDP'}
- flow_classifier_list = list()
- with self._use_driver(account) as drv:
- for rule in vnffg_classifier.match_attributes:
- classifier_name = vnffg_classifier.name + '_' + rule.name
- flow_dict = {}
- for field, value in rule.as_dict().items():
- if field == 'ip_proto':
- flow_dict['protocol'] = protocol_map.get(value,None)
- elif field == 'source_ip_address':
- flow_dict['source_ip_prefix'] = value
- elif field == 'destination_ip_address':
- flow_dict['destination_ip_prefix'] = value
- elif field == 'source_port':
- flow_dict['source_port_range_min'] = value
- flow_dict['source_port_range_max'] = value
- elif field == 'destination_port':
- flow_dict['destination_port_range_min'] = value
- flow_dict['destination_port_range_max'] = value
- if vnffg_classifier.has_field('port_id'):
- flow_dict['logical_source_port'] = vnffg_classifier.port_id
- flow_classifier_id = drv.create_flow_classifer(classifier_name, flow_dict)
- flow_classifier_list.append(flow_classifier_id)
- drv.update_port_chain(vnffg_classifier.rsp_id,flow_classifier_list)
- return flow_classifier_list
-
- @rwstatus(ret_on_failure=[None])
- def do_terminate_vnffg_classifier(self, account, vnffg_classifier_list):
- """
- Add VNFFG Classifier
-
- @param account - a SDN account
- """
- self.log.debug('Received terminate VNFFG classifier for id %s ', vnffg_classifier_list)
- with self._use_driver(account) as drv:
- for classifier_id in vnffg_classifier_list:
- drv.delete_flow_classifier(classifier_id)
-
- @rwstatus(ret_on_failure=[None])
- def do_get_vnffg_rendered_paths(self, account):
- """
- Get ODL Rendered Service Path List (SFC)
-
- @param account - a SDN account
- """
- self.log.debug('Received get VNFFG rendered path for account %s ', account)
- vnffg_rsps = RwsdnYang.VNFFGRenderedPaths()
- with self._use_driver(account) as drv:
- port_chain_list = drv.get_port_chain_list()
- for port_chain in port_chain_list:
- #rsp = vnffg_rsps.vnffg_rendered_path.add()
- #rsp.name = port_chain['name']
- pass
- return vnffg_rsps
-
-
rwsdn_mock
rwsdn_sim
rwsdn_odl
+ rwsdn_openstack
rwsdn-python
)
rift_add_subdirs(SUBDIR_LIST ${subdirs})
--- /dev/null
+
+#
+# Copyright 2017 RIFT.IO Inc
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include(rift_plugin)
+
+rift_install_python_plugin(rwsdn_openstack rwsdn_openstack.py)
--- /dev/null
+
+#
+# Copyright 2016 RIFT.IO Inc
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import contextlib
+import logging
+
+import gi
+gi.require_version('RwSdn', '1.0')
+gi.require_version('RwCal', '1.0')
+gi.require_version('RwcalYang', '1.0')
+
+from rift.rwcal.openstack import session as sess_drv
+from rift.rwcal.openstack import keystone as ks_drv
+from rift.rwcal.openstack import neutron as nt_drv
+from rift.rwcal.openstack import portchain as port_drv
+
+
+
+import rw_status
+import rift.cal.rwcal_status as rwcal_status
+import rwlogger
+import neutronclient.common.exceptions as NeutronException
+import keystoneclient.exceptions as KeystoneExceptions
+
+
+from gi.repository import (
+ GObject,
+ RwCal,
+ RwSdn, # Vala package
+ RwsdnYang,
+ RwTypes,
+ RwcalYang)
+
+rwstatus_exception_map = { IndexError: RwTypes.RwStatus.NOTFOUND,
+ KeyError: RwTypes.RwStatus.NOTFOUND,
+ NotImplementedError: RwTypes.RwStatus.NOT_IMPLEMENTED,}
+
+rwstatus = rw_status.rwstatus_from_exc_map(rwstatus_exception_map)
+rwcalstatus = rwcal_status.rwcalstatus_from_exc_map(rwstatus_exception_map)
+
+
+class OpenstackSdnOperationFailure(Exception):
+ pass
+
+class UninitializedPluginError(Exception):
+ pass
+
+class OpenstackL2PortChainingDriver(object):
+ """
+ Driver for openstack keystone and neutron
+ """
+ def __init__(self, logger = None, **kwargs):
+ """
+ OpenstackDriver Driver constructor
+ Arguments:
+ logger: (instance of logging.Logger)
+ kwargs: A dictionary of
+ {
+ username (string) : Username for project/tenant.
+ password (string) : Password
+ auth_url (string) : Keystone Authentication URL.
+ project (string) : Openstack project name
+ cert_validate (boolean, optional) : In case of SSL/TLS connection if certificate validation is required or not.
+ user_domain : Domain name for user
+ project_domain : Domain name for project
+ region : Region name
+ }
+ """
+
+ if logger is None:
+ self.log = logging.getLogger('rwsdn.openstack.driver')
+ self.log.setLevel(logging.DEBUG)
+ else:
+ self.log = logger
+
+ args = dict(auth_url = kwargs['auth_url'],
+ username = kwargs['username'],
+ password = kwargs['password'],
+ project_name = kwargs['project'],
+ project_domain_name = kwargs['project_domain'] if 'project_domain' in kwargs else None,
+ user_domain_name = kwargs['user_domain'] if 'user_domain' in kwargs else None,)
+
+ cert_validate = kwargs['cert_validate'] if 'cert_validate' in kwargs else False
+ region = kwargs['region_name'] if 'region_name' in kwargs else False
+
+ discover = ks_drv.KeystoneVersionDiscover(kwargs['auth_url'], logger = self.log)
+ (major, minor) = discover.get_version()
+
+ self.sess_drv = sess_drv.SessionDriver(auth_method = 'password',
+ version = str(major),
+ cert_validate = cert_validate,
+ logger = self.log,
+ **args)
+
+ self.neutron_drv = nt_drv.NeutronDriver(self.sess_drv,
+ region_name = region,
+ logger = self.log)
+
+ self.portchain_drv = port_drv.L2PortChainDriver(self.sess_drv,
+ self.neutron_drv.neutron_endpoint,
+ logger = self.log)
+
+ def validate_account_creds(self):
+ try:
+ self.sess_drv.invalidate_auth_token()
+ self.sess_drv.auth_token
+ except KeystoneExceptions.AuthorizationFailure as e:
+ self.log.error("Unable to authenticate or validate the existing credentials. Exception: %s", str(e))
+ raise ValidationError("Invalid Credentials: "+ str(e))
+ except Exception as e:
+ self.log.error("Could not connect to Openstack. Exception: %s", str(e))
+ raise ValidationError("Connection Error: "+ str(e))
+
+ def delete_port_chain(self,port_chain_id):
+ "Delete port chain"
+ try:
+ result = self.portchain_drv.get_port_chain(port_chain_id)
+ port_chain = result.json()
+ self.log.debug("Port chain result is %s", port_chain)
+ port_pair_groups = port_chain["port_chain"]["port_pair_groups"]
+ self.portchain_drv.delete_port_chain(port_chain_id)
+
+ # Get port pairs and delete port pair groups
+ port_pairs = list()
+ self.log.debug("Port pair groups during delete is %s", port_pair_groups)
+ for port_pair_group_id in port_pair_groups:
+ result = self.portchain_drv.get_port_pair_group(port_pair_group_id)
+ port_pair_group = result.json()
+ self.log.debug("Port pair group result is %s", port_pair_group)
+ port_pairs.extend(port_pair_group["port_pair_group"]["port_pairs"])
+ self.portchain_drv.delete_port_pair_group(port_pair_group_id)
+
+ self.log.debug("Port pairs during delete is %s",port_pairs)
+
+ for port_pair_id in port_pairs:
+ self.portchain_drv.delete_port_pair(port_pair_id)
+ pass
+ except Exception as e:
+ self.log.error("Error while delete port chain with id %s, exception %s", port_chain_id,str(e))
+
+ def update_port_chain(self,port_chain_id,flow_classifier_list):
+ result = self.portchain_drv.get_port_chain(port_chain_id)
+ result.raise_for_status()
+ port_chain = result.json()['port_chain']
+ new_flow_classifier_list = list()
+ if port_chain and port_chain['flow_classifiers']:
+ new_flow_classifier_list.extend(port_chain['flow_classifiers'])
+ new_flow_classifier_list.extend(flow_classifier_list)
+ port_chain_id = self.portchain_drv.update_port_chain(port_chain['id'],flow_classifiers=new_flow_classifier_list)
+ return port_chain_id
+
+ def create_flow_classifer(self,classifier_name,classifier_dict):
+ "Create flow classifier"
+ flow_classifier_id = self.portchain_drv.create_flow_classifier(classifier_name,classifier_dict)
+ return flow_classifier_id
+
+ def delete_flow_classifier(self,classifier_id):
+ "Create flow classifier"
+ try:
+ self.portchain_drv.delete_flow_classifier(classifier_id)
+ except Exception as e:
+ self.log.error("Error while deleting flow classifier with id %s, exception %s", classifier_id,str(e))
+
+ def get_port_chain_list(self):
+ result = self.portchain_drv.get_port_chain_list()
+ port_chain_list = result.json()
+ if 'port_chains' in port_chain_list:
+ return port_chain_list['port_chains']
+
+
+class RwsdnAccountDriver(object):
+ """
+ Container class per sdn account
+ """
+ def __init__(self, logger, **kwargs):
+ self.log = logger
+ try:
+ self._driver = OpenstackL2PortChainingDriver(logger = self.log, **kwargs)
+ except (KeystoneExceptions.Unauthorized, KeystoneExceptions.AuthorizationFailure,
+ NeutronException.NotFound) as e:
+ raise
+ except Exception as e:
+ self.log.error("RwsdnOpenstackPlugin: OpenstackL2PortChainingDriver init failed. Exception: %s" %(str(e)))
+ raise
+
+ @property
+ def driver(self):
+ return self._driver
+
+
+class SdnOpenstackPlugin(GObject.Object, RwSdn.Topology):
+ instance_num = 1
+ def __init__(self):
+ GObject.Object.__init__(self)
+ self.log = logging.getLogger('rwsdn.openstack.%s' % SdnOpenstackPlugin.instance_num)
+ self.log.setLevel(logging.DEBUG)
+
+ self._rwlog_handler = None
+ self._account_drivers = dict()
+ SdnOpenstackPlugin.instance_num += 1
+
+ def _use_driver(self, account):
+ if self._rwlog_handler is None:
+ raise UninitializedPluginError("Must call init() in SDN plugin before use.")
+
+ if account.name not in self._account_drivers:
+ self.log.debug("Creating SDN OpenstackDriver")
+ kwargs = dict(username = account.openstack.key,
+ password = account.openstack.secret,
+ auth_url = account.openstack.auth_url,
+ project = account.openstack.tenant,
+ cert_validate = account.openstack.cert_validate,
+ user_domain = account.openstack.user_domain,
+ project_domain = account.openstack.project_domain,
+ region = account.openstack.region)
+ drv = RwsdnAccountDriver(self.log, **kwargs)
+ self._account_drivers[account.name] = drv
+ return drv.driver
+ else:
+ return self._account_drivers[account.name].driver
+
+ @rwstatus
+ def do_init(self, rwlog_ctx):
+ self._rwlog_handler = rwlogger.RwLogger(
+ category="rw-cal-log",
+ subcategory="openstack",
+ log_hdl=rwlog_ctx,
+ )
+ self.log.addHandler(self._rwlog_handler)
+ self.log.propagate = False
+
+ @rwstatus(ret_on_failure=[None])
+ def do_validate_sdn_creds(self, account):
+ """
+ Validates the sdn account credentials for the specified account.
+ Performs an access to the resources using Keystone API. If creds
+ are not valid, returns an error code & reason string
+
+ @param account - a SDN account
+
+ Returns:
+ Validation Code and Details String
+ """
+ status = RwsdnYang.SdnConnectionStatus()
+ drv = self._use_driver(account)
+ try:
+ drv.validate_account_creds()
+
+ except openstack_drv.ValidationError as e:
+ self.log.error("SdnOpenstackPlugin: OpenstackDriver credential validation failed. Exception: %s", str(e))
+ status.status = "failure"
+ status.details = "Invalid Credentials: %s" % str(e)
+
+ except Exception as e:
+ msg = "SdnOpenstackPlugin: OpenstackDriver connection failed. Exception: %s" %(str(e))
+ self.log.error(msg)
+ status.status = "failure"
+ status.details = msg
+
+ else:
+ status.status = "success"
+ status.details = "Connection was successful"
+
+ return status
+
+ @rwstatus(ret_on_failure=[""])
+ def do_create_vnffg_chain(self, account,vnffg):
+ """
+ Creates Service Function chain in ODL
+
+ @param account - a SDN account
+
+ """
+ self.log.debug('Received Create VNFFG chain for account {}, chain {}'.format(account,vnffg))
+ drv = self._use_driver(account)
+ port_list = list()
+ vnf_chain_list = sorted(vnffg.vnf_chain_path, key = lambda x: x.order)
+ prev_vm_id = None
+ for path in vnf_chain_list:
+ if prev_vm_id and path.vnfr_ids[0].vdu_list[0].vm_id == prev_vm_id:
+ prev_entry = port_list.pop()
+ port_list.append((prev_entry[0],path.vnfr_ids[0].vdu_list[0].port_id))
+ prev_vm_id = None
+ else:
+ prev_vm_id = path.vnfr_ids[0].vdu_list[0].vm_id
+ port_list.append((path.vnfr_ids[0].vdu_list[0].port_id,path.vnfr_ids[0].vdu_list[0].port_id))
+ vnffg_id = drv.create_port_chain(vnffg.name,port_list)
+ return vnffg_id
+
+ @rwstatus
+ def do_terminate_vnffg_chain(self, account,vnffg_id):
+ """
+ Terminate Service Function chain in ODL
+
+ @param account - a SDN account
+ """
+ self.log.debug('Received terminate VNFFG chain for id %s ', vnffg_id)
+ drv = self._use_driver(account)
+ drv.delete_port_chain(vnffg_id)
+
+ @rwstatus(ret_on_failure=[None])
+ def do_create_vnffg_classifier(self, account, vnffg_classifier):
+ """
+ Add VNFFG Classifier
+
+ @param account - a SDN account
+ """
+ self.log.debug('Received Create VNFFG classifier for account {}, classifier {}'.format(account,vnffg_classifier))
+ protocol_map = {1:'ICMP',6:'TCP',17:'UDP'}
+ flow_classifier_list = list()
+ drv = self._use_driver(account)
+ for rule in vnffg_classifier.match_attributes:
+ classifier_name = vnffg_classifier.name + '_' + rule.name
+ flow_dict = {}
+ for field, value in rule.as_dict().items():
+ if field == 'ip_proto':
+ flow_dict['protocol'] = protocol_map.get(value,None)
+ elif field == 'source_ip_address':
+ flow_dict['source_ip_prefix'] = value
+ elif field == 'destination_ip_address':
+ flow_dict['destination_ip_prefix'] = value
+ elif field == 'source_port':
+ flow_dict['source_port_range_min'] = value
+ flow_dict['source_port_range_max'] = value
+ elif field == 'destination_port':
+ flow_dict['destination_port_range_min'] = value
+ flow_dict['destination_port_range_max'] = value
+ if vnffg_classifier.has_field('port_id'):
+ flow_dict['logical_source_port'] = vnffg_classifier.port_id
+ flow_classifier_id = drv.create_flow_classifer(classifier_name, flow_dict)
+ flow_classifier_list.append(flow_classifier_id)
+ drv.update_port_chain(vnffg_classifier.rsp_id,flow_classifier_list)
+ return flow_classifier_list
+
+ @rwstatus(ret_on_failure=[None])
+ def do_terminate_vnffg_classifier(self, account, vnffg_classifier_list):
+ """
+ Add VNFFG Classifier
+
+ @param account - a SDN account
+ """
+ self.log.debug('Received terminate VNFFG classifier for id %s ', vnffg_classifier_list)
+ drv = self._use_driver(account)
+ for classifier_id in vnffg_classifier_list:
+ drv.delete_flow_classifier(classifier_id)
+
+ @rwstatus(ret_on_failure=[None])
+ def do_get_vnffg_rendered_paths(self, account):
+ """
+ Get Rendered Service Path List (SFC)
+
+ @param account - a SDN account
+ """
+ self.log.debug('Received get VNFFG rendered path for account %s ', account)
+ vnffg_rsps = RwsdnYang.VNFFGRenderedPaths()
+ drv = self._use_driver(account)
+ port_chain_list = drv.get_port_chain_list()
+ for port_chain in port_chain_list:
+ #rsp = vnffg_rsps.vnffg_rendered_path.add()
+ #rsp.name = port_chain['name']
+ pass
+ return vnffg_rsps
+
+
enum odl;
enum mock;
enum sdnsim;
+ enum openstack;
}
}
default "rwsdn_sim";
}
}
+
+ container openstack {
+ leaf key {
+ type string;
+ mandatory true;
+ }
+
+ leaf secret {
+ type string;
+ mandatory true;
+ }
+
+ leaf auth_url {
+ type string;
+ mandatory true;
+ }
+
+ leaf tenant {
+ type string;
+ mandatory true;
+ }
+
+ leaf admin {
+ type boolean;
+ default false;
+ }
+
+ leaf user-domain {
+ type string;
+ default "Default";
+ description "Domain of the OpenStack user";
+ }
+
+ leaf project-domain {
+ type string;
+ default "Default";
+ description "Domain of the OpenStack project";
+ }
+
+ leaf region {
+ type string;
+ default "RegionOne";
+ }
+
+ leaf plugin-name {
+ type string;
+ default "rwsdn_openstack";
+ }
+
+ leaf cert-validate {
+ type boolean;
+ default false;
+ description "Certificate validatation policy in case of SSL/TLS connection";
+ }
+ }
+
}
}
leaf rsp-name {
type string;
}
+ leaf rsp-id {
+ type yang:uuid;
+ }
leaf port-id {
rwpb:field-inline "true";
rwpb:field-string-max 64;