Added Plexxi Driver
Change-Id: Iee629b199ce8c4251d7c2aea27877fc88b46990d
This commit is contained in:
parent
58d10be4d6
commit
046516109b
540
congress/datasources/plexxi_driver.py
Normal file
540
congress/datasources/plexxi_driver.py
Normal file
@ -0,0 +1,540 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2014 Marist SDN Innovation lab Joint with Plexxi Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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 json
|
||||
import requests
|
||||
|
||||
try:
|
||||
from plexxi.core.api.binding import AffinityGroup
|
||||
from plexxi.core.api.binding import Job
|
||||
from plexxi.core.api.binding import PhysicalPort
|
||||
from plexxi.core.api.binding import PlexxiSwitch
|
||||
from plexxi.core.api.binding import VirtualizationHost
|
||||
from plexxi.core.api.binding import VirtualMachine
|
||||
from plexxi.core.api.binding import VirtualSwitch
|
||||
from plexxi.core.api.binding import VmwareVirtualMachine
|
||||
from plexxi.core.api.session import CoreSession
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from congress.datasources.datasource_driver import DataSourceDriver
|
||||
from congress.datasources import datasource_utils
|
||||
from congress.openstack.common import log as logging
|
||||
from oslo.config import cfg
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def d6service(name, keys, inbox, datapath, args):
|
||||
"""This method is called by d6cage to create a dataservice instance.
|
||||
"""
|
||||
|
||||
return PlexxiDriver(name, keys, inbox, datapath, args)
|
||||
|
||||
|
||||
class PlexxiDriver(DataSourceDriver):
|
||||
HOSTS = "hosts"
|
||||
HOST_MACS = HOSTS + '.macs'
|
||||
HOST_GUESTS = HOSTS + '.guests'
|
||||
VMS = "vms"
|
||||
VM_MACS = VMS + '.macs'
|
||||
AFFINITIES = "affinities"
|
||||
VSWITCHES = "vswitches"
|
||||
PLEXXISWITCHES = "plexxiswitches"
|
||||
PORTS = "ports"
|
||||
PORT_LINKS = PORTS + '.links'
|
||||
NETWORKLINKS = "networklinks"
|
||||
|
||||
def __init__(self, name='', keys='', inbox=None, datapath=None, args=None,
|
||||
session=None):
|
||||
args['tenant_name'] = None
|
||||
super(PlexxiDriver, self).__init__(name, keys, inbox, datapath, args)
|
||||
self.exchange = session
|
||||
self.creds = datasource_utils.get_credentials(name, args)
|
||||
self.raw_state = {}
|
||||
self.key_index = self.create_index()
|
||||
self.name_rule = False
|
||||
self.cooldown = 0
|
||||
try:
|
||||
self.unique_names = self.string_to_bool(args['unique_names'])
|
||||
except KeyError:
|
||||
LOG.warning("unique_names has not been configured in "
|
||||
"datasources.conf, defaulting to False.")
|
||||
self.unique_names = False
|
||||
port = str(cfg.CONF.bind_port)
|
||||
host = str(cfg.CONF.bind_host)
|
||||
self.api_address = "http://" + host + ":" + port + "/v1"
|
||||
|
||||
def update_from_datasource(self):
|
||||
"""Called when it is time to pull new data from this datasource.
|
||||
|
||||
Pulls lists of objects from PlexxiCore, if the data does not match
|
||||
the correspondig table in the driver's raw state or has not yet been
|
||||
added to the state, the driver calls methods to parse this data.
|
||||
|
||||
Once all data has been updated,sets
|
||||
self.state[tablename] = <list of tuples of strings/numbers>
|
||||
for every tablename exported by PlexxiCore.
|
||||
"""
|
||||
|
||||
# Initialize instance variables that get set during update
|
||||
self.hosts = []
|
||||
self.mac_list = []
|
||||
self.guest_list = []
|
||||
self.plexxi_switches = []
|
||||
self.affinities = []
|
||||
self.vswitches = []
|
||||
self.vms = []
|
||||
self.vm_macs = []
|
||||
self.ports = []
|
||||
self.network_links = []
|
||||
|
||||
if self.exchange is None:
|
||||
self.connect_to_plexxi(self.creds)
|
||||
|
||||
# Get host data from PlexxiCore
|
||||
hosts = VirtualizationHost.getAll(session=self.exchange)
|
||||
if (self.HOSTS not in self.state or
|
||||
hosts != self.raw_state[self.HOSTS]):
|
||||
self._translate_hosts(hosts)
|
||||
self.raw_state[self.HOSTS] = hosts
|
||||
else:
|
||||
self.hosts = self.state[self.HOSTS]
|
||||
self.mac_list = self.state[self.HOST_MACS]
|
||||
self.guest_list = self.state[self.HOST_GUESTS]
|
||||
|
||||
# Get PlexxiSwitch Data from PlexxiCore
|
||||
plexxiswitches = PlexxiSwitch.getAll(session=self.exchange)
|
||||
if (self.PLEXXISWITCHES not in self.state or
|
||||
plexxiswitches != self.raw_state[self.PLEXXISWITCHES]):
|
||||
self._translate_pswitches(plexxiswitches)
|
||||
self.raw_state[self.PLEXXISWITCHES] = plexxiswitches
|
||||
else:
|
||||
self.plexxi_switches = self.state[self.PLEXXISWITCHES]
|
||||
|
||||
# Get affinity data from PlexxiCore
|
||||
affinities = AffinityGroup.getAll(session=self.exchange)
|
||||
if (self.AFFINITIES not in self.state or
|
||||
affinities != self.raw_state[self.AFFINITIES]):
|
||||
if AffinityGroup.getCount(session=self.exchange) == 0:
|
||||
self.state[self.AFFINITIES] = ['No Affinities found']
|
||||
else:
|
||||
self._translate_affinites(affinities)
|
||||
self.raw_state[self.AFFINITIES] = affinities
|
||||
else:
|
||||
self.affinties = self.state[self.AFFINITIES]
|
||||
|
||||
# Get vswitch data from PlexxiCore
|
||||
vswitches = VirtualSwitch.getAll(session=self.exchange)
|
||||
if (self.VSWITCHES not in self.state or
|
||||
vswitches != self.raw_state[self.VSWITCHES]):
|
||||
self._translate_vswitches(vswitches)
|
||||
self.raw_state[self.VSWITCHES] = vswitches
|
||||
else:
|
||||
self.vswitches = self.state[self.VSWITCHES]
|
||||
|
||||
# Get virtual machine data from PlexxiCore
|
||||
vms = VirtualMachine.getAll(session=self.exchange)
|
||||
if (self.VMS not in self.state or
|
||||
vms != self.raw_state[self.VMS]):
|
||||
self._translate_vms(vms)
|
||||
self.raw_state[self.VMS] = set(vms)
|
||||
else:
|
||||
self.vms = self.state[self.VMS]
|
||||
self.vm_macs = self.state[self.VMS_MACS]
|
||||
# Get port data from PlexxiCore
|
||||
ports = PhysicalPort.getAll(session=self.exchange)
|
||||
if(self.PORTS not in self.state or
|
||||
ports != self.raw_state[self.PORTS]):
|
||||
self._translate_ports(ports)
|
||||
self.raw_state[self.PORTS] = set(ports)
|
||||
else:
|
||||
self.ports = self.state[self.PORTS]
|
||||
self.network_links = self.state[self.PORT_LINKS]
|
||||
|
||||
LOG.debug("Setting Plexxi State")
|
||||
self.state = {}
|
||||
self.state['key_index'] = self.key_index
|
||||
self.state[self.HOSTS] = set(self.hosts)
|
||||
self.state[self.HOST_MACS] = set(self.mac_list)
|
||||
self.state[self.HOST_GUESTS] = set(self.guest_list)
|
||||
self.state[self.PLEXXISWITCHES] = set(self.plexxi_switches)
|
||||
self.state[self.PLEXXISWITCHES + '.macs'] = set(self.ps_macs)
|
||||
self.state[self.AFFINITIES] = set(self.affinities)
|
||||
self.state[self.VSWITCHES] = set(self.vswitches)
|
||||
self.state[self.VMS] = set(self.vms)
|
||||
self.state[self.VM_MACS] = set(self.vm_macs)
|
||||
self.state[self.PORTS] = set(self.ports)
|
||||
self.state[self.PORT_LINKS] = set(self.network_links)
|
||||
# Create Rules
|
||||
if self.name_rule is False:
|
||||
self.create_rule_table()
|
||||
# Act on Policy
|
||||
if self.unique_names is True:
|
||||
if self.cooldown == 0:
|
||||
self.name_response()
|
||||
else:
|
||||
self.cooldown -= 1
|
||||
|
||||
@classmethod
|
||||
def get_schema(cls):
|
||||
"""Creates a table schema for incoming data from PlexxiCore.
|
||||
|
||||
Returns a dictionary map of tablenames corresponding to column names
|
||||
for that table. Both tableNames and columnnames are strings.
|
||||
"""
|
||||
|
||||
d = {}
|
||||
d[cls.HOSTS] = ("uuid", "name", "mac_count", "vmcount")
|
||||
d[cls.VMS] = ("uuid", "name", "host_uuid", "ip", "mac_count")
|
||||
d[cls.AFFINITIES] = ("uuid", "name")
|
||||
d[cls.VSWITCHES] = ("uuid", "host_count", "vnic_count")
|
||||
d[cls.PLEXXISWITCHES] = ("uuid", "ip", "status")
|
||||
d[cls.PORTS] = ("uuid", "name")
|
||||
d[cls.NETWORKLINKS] = ("uuid", "name", "port_uuid", "start_uuid",
|
||||
"start_name", "stop_uuid", "stop_name")
|
||||
return d
|
||||
|
||||
def _translate_hosts(self, hosts):
|
||||
"""Translates data about Hosts from PlexxiCore for Congress.
|
||||
|
||||
Responsible for the states 'hosts','hosts.macs' and 'hosts.guests'
|
||||
"""
|
||||
|
||||
row_keys = self.get_column_map(self.HOSTS)
|
||||
hostlist = []
|
||||
maclist = []
|
||||
vm_uuids = []
|
||||
for host in hosts:
|
||||
row = ['None'] * (max(row_keys.values()) + 1)
|
||||
hostID = host.getForeignUuid()
|
||||
row[row_keys['uuid']] = hostID
|
||||
row[row_keys['name']] = host.getName()
|
||||
pnics = host.getPhysicalNetworkInterfaces()
|
||||
if pnics:
|
||||
for pnic in pnics:
|
||||
mac = str(pnic.getMacAddress())
|
||||
tuple_mac = (hostID, mac)
|
||||
maclist.append(tuple_mac)
|
||||
mac_count = len(maclist)
|
||||
if (mac_count > 0):
|
||||
row[row_keys['mac_count']] = mac_count
|
||||
vmCount = host.getVirtualMachineCount()
|
||||
row[row_keys['vmcount']] = vmCount
|
||||
if vmCount != 0:
|
||||
vms = host.getVirtualMachines()
|
||||
for vm in vms:
|
||||
tuple_vmid = (hostID, vm.getForeignUuid())
|
||||
vm_uuids.append(tuple_vmid)
|
||||
hostlist.append(tuple(row))
|
||||
self.hosts = hostlist
|
||||
self.mac_list = maclist
|
||||
self.guest_list = vm_uuids
|
||||
|
||||
def _translate_pswitches(self, plexxi_switches):
|
||||
"""Translates data on Plexxi Switches from PlexxiCore for Congress.
|
||||
|
||||
Responsible for state 'Plexxi_swtiches' and 'Plexxi_switches.macs'
|
||||
"""
|
||||
|
||||
row_keys = self.get_column_map(self.PLEXXISWITCHES)
|
||||
pslist = []
|
||||
maclist = []
|
||||
for switch in plexxi_switches:
|
||||
row = ['None'] * (max(row_keys.values()) + 1)
|
||||
psuuid = str(switch.getUuid())
|
||||
row[row_keys['uuid']] = psuuid
|
||||
psip = str(switch.getIpAddress())
|
||||
row[row_keys['ip']] = psip
|
||||
psstatus = str(switch.getStatus())
|
||||
row[row_keys['status']] = psstatus
|
||||
pnics = switch.getPhysicalNetworkInterfaces()
|
||||
for pnic in pnics:
|
||||
mac = str(pnic.getMacAddress())
|
||||
macrow = [psuuid, mac]
|
||||
maclist.append(tuple(macrow))
|
||||
pslist.append(tuple(row))
|
||||
self.plexxi_switches = pslist
|
||||
self.ps_macs = maclist
|
||||
|
||||
def _translate_affinites(self, affinites):
|
||||
"""Translates data about affinites from PlexxiCore for Congress.
|
||||
|
||||
Responsible for state 'affinities'
|
||||
"""
|
||||
|
||||
row_keys = self.get_column_map(self.AFFINITIES)
|
||||
affinitylist = []
|
||||
for affinity in affinites:
|
||||
row = ['None'] * (max(row_keys.values()) + 1)
|
||||
uuid = str(affinity.getUuid())
|
||||
row[row_keys['uuid']] = uuid
|
||||
row[row_keys['name']] = affinity.getName()
|
||||
affinitylist.append(tuple(row))
|
||||
self.affinities = affinitylist
|
||||
|
||||
def _translate_vswitches(self, vswitches):
|
||||
"""Translates data about vswitches from PlexxiCore for Congress.
|
||||
|
||||
Responsible for states vswitchlist,vswitch_macs,vswitch_hosts
|
||||
"""
|
||||
|
||||
# untested
|
||||
row_keys = self.get_column_map(self.VSWITCHES)
|
||||
vswitchlist = []
|
||||
tuple_macs = []
|
||||
vswitch_host_list = []
|
||||
for vswitch in vswitches:
|
||||
row = ['None'] * (max(row_keys.values()) + 1)
|
||||
vswitchID = vswitch.getForeignUuid()
|
||||
row[row_keys['uuid']] = vswitchID
|
||||
vSwitchHosts = vswitch.getVirtualizationHosts()
|
||||
try:
|
||||
host_count = len(vSwitchHosts)
|
||||
except TypeError:
|
||||
host_count = 0
|
||||
row[row_keys['host_count']] = host_count
|
||||
if host_count != 0:
|
||||
for host in vSwitchHosts:
|
||||
hostuuid = host.getForeignUuid()
|
||||
hostrow = [vswitchID, hostuuid]
|
||||
vswitch_host_list.append(tuple(hostrow))
|
||||
vswitch_vnics = vswitch.getVirtualNetworkInterfaces()
|
||||
try:
|
||||
vnic_count = len(vswitch_vnics)
|
||||
except TypeError:
|
||||
vnic_count = 0
|
||||
row[row_keys['vnic_count']] = vnic_count
|
||||
if vnic_count != 0:
|
||||
for vnic in vswitch_vnics:
|
||||
mac = vnic.getMacAddress()
|
||||
macrow = [vswitchID, str(mac)]
|
||||
tuple_macs.append(tuple(macrow))
|
||||
vswitchlist.append(tuple(row))
|
||||
self.vswitches = vswitchlist
|
||||
self.vswitch_macs = tuple_macs
|
||||
self.vswitch_hosts = vswitch_host_list
|
||||
|
||||
def _translate_vms(self, vms):
|
||||
"""Translate data on VMs from PlexxiCore for Congress.
|
||||
|
||||
Responsible for states 'vms' and 'vms.macs'
|
||||
"""
|
||||
|
||||
row_keys = self.get_column_map(self.VMS)
|
||||
vmlist = []
|
||||
maclist = []
|
||||
for vm in vms:
|
||||
row = ['None'] * (max(row_keys.values()) + 1)
|
||||
vmID = vm.getForeignUuid()
|
||||
row[row_keys['uuid']] = vmID
|
||||
vmName = vm.getName()
|
||||
row[row_keys['name']] = vmName
|
||||
try:
|
||||
vmhost = vm.getVirtualizationHost()
|
||||
vmhostuuid = vmhost.getForeignUuid()
|
||||
row[row_keys['host_uuid']] = vmhostuuid
|
||||
except AttributeError:
|
||||
LOG.debug("The host for " + vmName + " could not be found")
|
||||
vmIP = vm.getIpAddress()
|
||||
if vmIP:
|
||||
row[row_keys['ip']] = vmIP
|
||||
vmVnics = vm.getVirtualNetworkInterfaces()
|
||||
mac_count = 0
|
||||
for vnic in vmVnics:
|
||||
mac = str(vnic.getMacAddress())
|
||||
tuple_mac = (vmID, mac)
|
||||
maclist.append(tuple_mac)
|
||||
mac_count += 1
|
||||
row[row_keys['mac_count']] = mac_count
|
||||
vmlist.append(tuple(row))
|
||||
self.vms = vmlist
|
||||
self.vm_macs = maclist
|
||||
|
||||
def _translate_ports(self, ports):
|
||||
"""Translate data about ports from PlexxiCore for Congress.
|
||||
|
||||
Responsible for states 'ports' and 'ports.links'
|
||||
"""
|
||||
|
||||
row_keys = self.get_column_map(self.PORTS)
|
||||
link_keys = self.get_column_map(self.NETWORKLINKS)
|
||||
port_list = []
|
||||
link_list = []
|
||||
for port in ports:
|
||||
row = ['None'] * (max(row_keys.values()) + 1)
|
||||
portID = str(port.getUuid())
|
||||
row[row_keys['uuid']] = portID
|
||||
portName = str(port.getName())
|
||||
row[row_keys['name']] = portName
|
||||
links = port.getNetworkLinks()
|
||||
if links:
|
||||
link_keys = self.get_column_map(self.NETWORKLINKS)
|
||||
for link in links:
|
||||
link_row = self._translate_network_link(link, link_keys,
|
||||
portID)
|
||||
link_list.append(tuple(link_row))
|
||||
port_list.append(tuple(row))
|
||||
self.ports = port_list
|
||||
self.network_links = link_list
|
||||
|
||||
def _translate_network_link(self, link, row_keys, sourcePortUuid):
|
||||
"""Translates data about network links from PlexxiCore for Congress.
|
||||
|
||||
Subfunction of translate_ports,each handles a set of network links
|
||||
attached to a port. Directly responsible for the state of
|
||||
'ports.links'
|
||||
"""
|
||||
|
||||
row = ['None'] * (max(row_keys.values()) + 1)
|
||||
linkID = str(link.getUuid())
|
||||
row[row_keys['uuid']] = linkID
|
||||
row[row_keys['port_uuid']] = sourcePortUuid
|
||||
linkName = str(link.getName())
|
||||
row[row_keys['name']] = linkName
|
||||
linkStartObj = link.getStartNetworkInterface()
|
||||
linkStartName = str(linkStartObj.getName())
|
||||
row[row_keys['start_name']] = linkStartName
|
||||
linkStartUuid = str(linkStartObj.getUuid())
|
||||
row[row_keys['start_uuid']] = linkStartUuid
|
||||
linkStopObj = link.getStopNetworkInterface()
|
||||
linkStopUuid = str(linkStopObj.getUuid())
|
||||
row[row_keys['stop_uuid']] = linkStopUuid
|
||||
linkStopName = str(linkStopObj.getName())
|
||||
row[row_keys['stop_name']] = linkStopName
|
||||
return row
|
||||
|
||||
def string_to_bool(self, string):
|
||||
"""Used for parsing boolean variables stated in datasources.conf.
|
||||
"""
|
||||
|
||||
string = string.strip()
|
||||
s = string.lower()
|
||||
if s in['true', 'yes', 'on']:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def create_index(self):
|
||||
"""Creates key_index table
|
||||
|
||||
The key_index table is used expose the table schema through the API.
|
||||
The CONGRESS_INDEX_ID field contains the name of the table the rest
|
||||
of the data is pertaining to.The other values give the names
|
||||
columns paired with their position in the table.
|
||||
"""
|
||||
|
||||
key_index = []
|
||||
row_keys = self.get_schema()
|
||||
for key in row_keys.keys():
|
||||
key_map = self.get_column_map(key)
|
||||
key_map['CONGRESS_INDEX_ID'] = key
|
||||
key_index.append(key_map)
|
||||
return key_index
|
||||
|
||||
def connect_to_plexxi(self, creds):
|
||||
"""Create a CoreSession connecting congress to PlexxiCore using
|
||||
credentials provided in datasources.conf
|
||||
"""
|
||||
|
||||
if 'auth_url' not in creds:
|
||||
LOG.error("Plexxi url not supplied. Could not start Plexxi" +
|
||||
"connection driver")
|
||||
if 'username' not in creds:
|
||||
LOG.error("Plexxi username not supplied. Could not start " +
|
||||
"Plexxi connection driver")
|
||||
if 'password' not in creds:
|
||||
LOG.error("Plexxi password not supplied. Could not start " +
|
||||
"Plexxi connection driver")
|
||||
try:
|
||||
self.exchange = CoreSession.connect(
|
||||
baseUrl=creds['auth_url'],
|
||||
allowUntrusted=True,
|
||||
username=creds['username'],
|
||||
password=creds['password'])
|
||||
except requests.exceptions.HTTPError as error:
|
||||
if int(error.response.status_code) == 401 or\
|
||||
int(error.response.status_code) == 403:
|
||||
msg = "Incorrect username/password combination. Passed" + \
|
||||
"in username was " + creds['username'] + ", " + \
|
||||
"password was " + creds['password']
|
||||
|
||||
raise Exception(requests.exceptions.HTTPErrror(msg))
|
||||
else:
|
||||
raise Exception(requests.exceptions.HTTPError(error))
|
||||
|
||||
except requests.exceptions.ConnectionError:
|
||||
msg = "Cannot connect to PlexxiCore at " + creds['auth_url'] + \
|
||||
" with the username " + creds['username'] + " and the " + \
|
||||
"password " + creds['password']
|
||||
|
||||
raise Exception(requests.exceptions.ConnectionError(msg))
|
||||
|
||||
def create_rule_table(self):
|
||||
"""Creates RepeatedName table for unique names policy.
|
||||
|
||||
The RepeatedName table contains the name and plexxiUuid of
|
||||
VMs that have the same name in the Plexxi table and the Nova Table.
|
||||
"""
|
||||
|
||||
repeated_name_rule = '{"rule": "RepeatedName(vname,pvuuid)' +\
|
||||
':- plexxi:vms(pvuuid,vname,phuuid,pvip,pvmaccount,pvaffin),' +\
|
||||
'nova:servers(nvuuid,vname,a,nstatus,b,c,d,num)"}'
|
||||
try:
|
||||
requests.post(self.api_address + '/policies/classification/rules',
|
||||
data=repeated_name_rule)
|
||||
self.name_rule = False
|
||||
except Exception:
|
||||
LOG.exception("Could not create Repeated Name table")
|
||||
|
||||
def name_response(self):
|
||||
"""Checks for any entries in the RepeatedName table.
|
||||
|
||||
For all entries found in the RepeatedName table, the corresponding
|
||||
VM will be then prefixed with 'conflict-' in PlexxiCore.
|
||||
"""
|
||||
|
||||
vmname = False
|
||||
vmuuid = False
|
||||
json_response = []
|
||||
self.cooldown += 1
|
||||
try:
|
||||
plexxivms = VmwareVirtualMachine.getAll(session=self.exchange)
|
||||
table = requests.get(self.api_address + "/policies/" +
|
||||
"classification/tables/RepeatedName/rows")
|
||||
json_response = json.loads(table.text)
|
||||
|
||||
for row in json_response['results']:
|
||||
vmname = row['data'][0]
|
||||
vmuuid = row['data'][1]
|
||||
if vmname and vmuuid:
|
||||
for plexxivm in plexxivms:
|
||||
if (plexxivm.getForeignUuid() == vmuuid):
|
||||
new_vm_name = "Conflict-" + vmname
|
||||
desc = "Congress has found a VM with the same " +\
|
||||
"name on the nova network. This vm " +\
|
||||
"will now be renamed to " + new_vm_name
|
||||
job_name = " Congress Driver:Changing virtual" +\
|
||||
"machine, " + vmname + "\'s name"
|
||||
changenamejob = Job.create(name=job_name,
|
||||
description=desc + ".",
|
||||
session=self.exchange)
|
||||
changenamejob.begin()
|
||||
plexxivm.setName(new_vm_name)
|
||||
changenamejob.commit()
|
||||
LOG.info(desc + " in PlexxiCore.")
|
||||
except Exception:
|
||||
LOG.exception("error in name_response")
|
174
congress/datasources/tests/unit/plexxi_fakes.py
Normal file
174
congress/datasources/tests/unit/plexxi_fakes.py
Normal file
@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2014 Marist SDN Innovation lab Joint with Plexxi Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
class MockAffinity(object):
|
||||
def __init__(self, uuid, name):
|
||||
self.uuid = uuid
|
||||
self.name = name
|
||||
|
||||
def getUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class MockCoreSession(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def disconnect():
|
||||
pass
|
||||
|
||||
|
||||
class MockHost(object):
|
||||
def __init__(self, uuid, name, mac_count, pnics):
|
||||
self.uuid = uuid
|
||||
self.name = name
|
||||
self.mac_count = mac_count
|
||||
self.pnics = pnics
|
||||
self.vms = []
|
||||
|
||||
def addvm(self, vm):
|
||||
self.vms.append(vm)
|
||||
|
||||
def getForeignUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getPhysicalNetworkInterfaces(self):
|
||||
return self.pnics
|
||||
|
||||
def getVirtualMachineCount(self):
|
||||
return len(self.vms)
|
||||
|
||||
def getVirtualMachines(self):
|
||||
return self.vms
|
||||
|
||||
|
||||
class MockNetworkLink(object):
|
||||
def __init__(self, uuid, name, stopint, startint):
|
||||
self.uuid = uuid
|
||||
self.name = name
|
||||
self.startint = startint
|
||||
self.stopint = stopint
|
||||
|
||||
def getUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getStartNetworkInterface(self):
|
||||
return self.startint
|
||||
|
||||
def getStopNetworkInterface(self):
|
||||
return self.stopint
|
||||
|
||||
|
||||
class MockNIC(object):
|
||||
def __init__(self, uuid, mac):
|
||||
self.uuid = uuid
|
||||
self.mac = mac
|
||||
|
||||
def getMacAddress(self):
|
||||
return self.mac
|
||||
|
||||
|
||||
class MockPort(object):
|
||||
def __init__(self, uuid, name, networklinks):
|
||||
self.uuid = uuid
|
||||
self.name = name
|
||||
self.networklinks = networklinks
|
||||
|
||||
def getUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getNetworkLinks(self):
|
||||
return self.networklinks
|
||||
|
||||
|
||||
class MockSwitch(object):
|
||||
def __init__(self, uuid, ip, name, status, pnics):
|
||||
self.uuid = uuid
|
||||
self.ip = ip
|
||||
self.status = status
|
||||
self.pnics = pnics
|
||||
self.name = name
|
||||
|
||||
def getUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getIpAddress(self):
|
||||
return self.ip
|
||||
|
||||
def getStatus(self):
|
||||
return self.status
|
||||
|
||||
def getPhysicalNetworkInterfaces(self):
|
||||
return self.pnics
|
||||
|
||||
|
||||
class MockVM(object):
|
||||
def __init__(self, uuid, ip, name, host, vnics):
|
||||
self.uuid = uuid
|
||||
self.ip = ip
|
||||
self.host = host
|
||||
self.name = name
|
||||
self.vnics = vnics
|
||||
|
||||
def getForeignUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getVirtualizationHost(self):
|
||||
return self.host
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getIpAddress(self):
|
||||
return self.ip
|
||||
|
||||
def getVirtualNetworkInterfaces(self):
|
||||
return self.vnics
|
||||
|
||||
|
||||
class MockVSwitch(object):
|
||||
def __init__(self, uuid, hosts, vnics):
|
||||
self.uuid = uuid
|
||||
self.hosts = hosts
|
||||
self.vnics = vnics
|
||||
|
||||
def getForeignUuid(self):
|
||||
return self.uuid
|
||||
|
||||
def getVirtualizationHosts(self):
|
||||
return self.hosts
|
||||
|
||||
def getVirtualNetworkInterfaces(self):
|
||||
return self.vnics
|
158
congress/datasources/tests/unit/test_plexxi_driver.py
Normal file
158
congress/datasources/tests/unit/test_plexxi_driver.py
Normal file
@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
from congress.datasources import plexxi_driver
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockAffinity
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockCoreSession
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockHost
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockNetworkLink
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockNIC
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockPort
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockSwitch
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockVM
|
||||
from congress.datasources.tests.unit.plexxi_fakes import MockVSwitch
|
||||
from congress.tests import base
|
||||
from congress.tests import helper
|
||||
|
||||
|
||||
class TestPlexxiDriver(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestPlexxiDriver, self).setUp()
|
||||
args = helper.datasource_openstack_args()
|
||||
args['unique_names'] = 'False'
|
||||
session = MockCoreSession()
|
||||
self.driver = plexxi_driver.PlexxiDriver(args=args, session=session)
|
||||
self.driver.exchange = True
|
||||
vnic1 = MockNIC(uuid='f318ac0a-9255-4af0-8a41-6f3fbc06c8aa',
|
||||
mac='B8:ED:0A:4D:82:91')
|
||||
vnic2 = MockNIC(uuid='f318ac0a-9255-4af0-8a41-6f3fbc06c8a2',
|
||||
mac='B8:ED:0A:4D:82:99')
|
||||
pnic1 = MockNIC(uuid='f318ac0a-9255-4af0-8a41-6f3fbc06c8ab',
|
||||
mac='B8:ED:0A:4D:82:92')
|
||||
pnic2 = MockNIC(uuid='f318ac0a-9255-4af0-8a41-6f3fbc06c8ac',
|
||||
mac='B8:ED:0A:4D:82:93')
|
||||
host1 = MockHost('eed4ebfc-25e5-4a65-9f37-b70b8e8219d3',
|
||||
'mock1',
|
||||
1,
|
||||
[pnic1])
|
||||
vm1 = MockVM('2ca924f6-90aa-4ce8-a986-f62f8f64d14b',
|
||||
'192.168.90.2',
|
||||
'namevm',
|
||||
host1,
|
||||
[vnic1])
|
||||
host1.addvm(vm1)
|
||||
switch1 = MockSwitch('12da13e3-ecb2-4c26-98a0-26cb07f9c33d',
|
||||
'192.168.90.3',
|
||||
'switch1',
|
||||
'HEALTHY',
|
||||
[pnic2])
|
||||
affinity = MockAffinity('fd487ecf-5279-4d3c-9378-7fb214f5dd5a',
|
||||
'Testfinnity')
|
||||
affinity2 = MockAffinity('fd487ecf-5279-4d3c-9378-7fb214f5dd5b',
|
||||
'Testfinnity2')
|
||||
vswitch = MockVSwitch('fd487ecf-5279-4d3c-9378-7fb214f5dd5c',
|
||||
[host1],
|
||||
[vnic2])
|
||||
link1 = MockNetworkLink('fd487ecf-5279-4d3c-9378-7fb214f5dd5f',
|
||||
'Link1',
|
||||
host1,
|
||||
switch1)
|
||||
port = MockPort('fd487ecf-5279-4d3c-9378-7fb214f5dd5d',
|
||||
'Port1',
|
||||
[link1])
|
||||
port2 = MockPort('fd487ecf-5279-4d3c-9378-7fb214f5dd5e',
|
||||
'Port2',
|
||||
None)
|
||||
|
||||
self.hosts = [host1]
|
||||
self.pswitches = [switch1]
|
||||
self.affinites = [affinity, affinity2]
|
||||
self.vswitches = [vswitch]
|
||||
self.vms = [vm1]
|
||||
self.ports = [port, port2]
|
||||
|
||||
def test_translate_hosts(self):
|
||||
self.driver._translate_hosts(self.hosts)
|
||||
ExpectedHosts = [('eed4ebfc-25e5-4a65-9f37-b70b8e8219d3',
|
||||
'mock1',
|
||||
1,
|
||||
1)]
|
||||
self.assertEqual(self.driver.hosts, ExpectedHosts)
|
||||
ExpectedHost_Macs = [('eed4ebfc-25e5-4a65-9f37-b70b8e8219d3',
|
||||
'B8:ED:0A:4D:82:92')]
|
||||
self.assertEqual(self.driver.mac_list, ExpectedHost_Macs)
|
||||
ExpectedGuests = [('eed4ebfc-25e5-4a65-9f37-b70b8e8219d3',
|
||||
'2ca924f6-90aa-4ce8-a986-f62f8f64d14b')]
|
||||
self.assertEqual(self.driver.guest_list, ExpectedGuests)
|
||||
|
||||
def test_translate_pswitches(self):
|
||||
self.driver._translate_pswitches(self.pswitches)
|
||||
ExpectedpSwitches = [('12da13e3-ecb2-4c26-98a0-26cb07f9c33d',
|
||||
'192.168.90.3',
|
||||
'HEALTHY')]
|
||||
self.assertEqual(self.driver.plexxi_switches, ExpectedpSwitches)
|
||||
ExpectedPSmacs = [('12da13e3-ecb2-4c26-98a0-26cb07f9c33d',
|
||||
'B8:ED:0A:4D:82:93')]
|
||||
self.assertEqual(self.driver.ps_macs, ExpectedPSmacs)
|
||||
|
||||
def test_translate_affinites(self):
|
||||
self.driver._translate_affinites(self.affinites)
|
||||
ExpectedAffinities = [('fd487ecf-5279-4d3c-9378-7fb214f5dd5a',
|
||||
'Testfinnity'),
|
||||
('fd487ecf-5279-4d3c-9378-7fb214f5dd5b',
|
||||
'Testfinnity2')]
|
||||
|
||||
self.assertEqual(self.driver.affinities, ExpectedAffinities)
|
||||
|
||||
def test_translate_vswitches(self):
|
||||
self.driver._translate_vswitches(self.vswitches)
|
||||
ExpectedvSwitches = [('fd487ecf-5279-4d3c-9378-7fb214f5dd5c',
|
||||
1,
|
||||
1)]
|
||||
self.assertEqual(self.driver.vswitches, ExpectedvSwitches)
|
||||
ExpectedvSwitch_macs = [('fd487ecf-5279-4d3c-9378-7fb214f5dd5c',
|
||||
'B8:ED:0A:4D:82:99')]
|
||||
self.assertEqual(self.driver.vswitch_macs, ExpectedvSwitch_macs)
|
||||
ExpectedvSwitch_hosts = [('fd487ecf-5279-4d3c-9378-7fb214f5dd5c',
|
||||
'eed4ebfc-25e5-4a65-9f37-b70b8e8219d3')]
|
||||
|
||||
self.assertEqual(self.driver.vswitch_hosts, ExpectedvSwitch_hosts)
|
||||
|
||||
def test_translate_vms(self):
|
||||
self.driver._translate_vms(self.vms)
|
||||
ExpectedVMs = [('2ca924f6-90aa-4ce8-a986-f62f8f64d14b',
|
||||
'namevm',
|
||||
'eed4ebfc-25e5-4a65-9f37-b70b8e8219d3',
|
||||
'192.168.90.2',
|
||||
1)]
|
||||
|
||||
self.assertEqual(self.driver.vms, ExpectedVMs)
|
||||
Expectedvm_macs = [('2ca924f6-90aa-4ce8-a986-f62f8f64d14b',
|
||||
'B8:ED:0A:4D:82:91')]
|
||||
self.assertEqual(self.driver.vm_macs, Expectedvm_macs)
|
||||
|
||||
def test_translate_ports(self):
|
||||
self.driver._translate_ports(self.ports)
|
||||
ExpectedPorts = [('fd487ecf-5279-4d3c-9378-7fb214f5dd5d',
|
||||
'Port1'),
|
||||
('fd487ecf-5279-4d3c-9378-7fb214f5dd5e',
|
||||
'Port2')]
|
||||
self.assertEqual(self.driver.ports, ExpectedPorts)
|
||||
ExpectedLinks = [('fd487ecf-5279-4d3c-9378-7fb214f5dd5f',
|
||||
'Link1',
|
||||
'fd487ecf-5279-4d3c-9378-7fb214f5dd5d',
|
||||
'12da13e3-ecb2-4c26-98a0-26cb07f9c33d',
|
||||
'switch1',
|
||||
'eed4ebfc-25e5-4a65-9f37-b70b8e8219d3',
|
||||
'mock1')]
|
||||
self.assertEqual(self.driver.network_links, ExpectedLinks)
|
@ -46,3 +46,11 @@ username: admin
|
||||
password: password
|
||||
auth_url: http://127.0.0.1:5000/v2.0
|
||||
tenant_name: admin
|
||||
|
||||
#[plexxi]
|
||||
#module:datasources/plexxi_driver.py
|
||||
#username: plexxiCore_username
|
||||
#password: plexxiCore_password
|
||||
#auth_url: http://PlexxiCoreURL/PlexxiCore/api
|
||||
#unique_names: False
|
||||
|
||||
|
4
thirdparty/plexxi_setup.sh
vendored
Normal file
4
thirdparty/plexxi_setup.sh
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
# Replace 2.0.2-sp2 with your repective plexxicore verison
|
||||
# This can be checked at http://PlexxiCoreURL:8080/PlexxiCore/
|
||||
pip install -v --index-url http://pypi.plexxi.com plexxi==2.0.2-sp2
|
Loading…
Reference in New Issue
Block a user