Merge "Implementation of the BP services-insertion-wrapper inside the Cisco Plugin"
This commit is contained in:
commit
47767d4f52
@ -94,6 +94,17 @@ def network_list(tenant_id):
|
||||
all()
|
||||
|
||||
|
||||
def network_id(net_name):
|
||||
session = get_session()
|
||||
try:
|
||||
return session.query(models.Network).\
|
||||
options(joinedload(models.Network.ports)). \
|
||||
filter_by(name=net_name).\
|
||||
all()
|
||||
except exc.NoResultFound, e:
|
||||
raise q_exc.NetworkNotFound(net_name=net_name)
|
||||
|
||||
|
||||
def network_get(net_id):
|
||||
session = get_session()
|
||||
try:
|
||||
|
@ -26,6 +26,7 @@ import logging as LOG
|
||||
import quantum.plugins.cisco.db.api as db
|
||||
import quantum.plugins.cisco.db.nexus_db as ndb
|
||||
import quantum.plugins.cisco.db.ucs_db as udb
|
||||
import quantum.plugins.cisco.db.services_db as sdb
|
||||
|
||||
|
||||
def initialize():
|
||||
|
78
quantum/plugins/cisco/db/services_db.py
Normal file
78
quantum/plugins/cisco/db/services_db.py
Normal file
@ -0,0 +1,78 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011, Cisco Systems, 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.
|
||||
#
|
||||
# @author: Edgar Magana, Cisco Systems, Inc.
|
||||
|
||||
import logging as LOG
|
||||
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
import quantum.plugins.cisco.db.api as db
|
||||
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as c_exc
|
||||
from quantum.plugins.cisco.db import services_models
|
||||
|
||||
|
||||
def get_all_services_bindings():
|
||||
"""Lists all the services bindings"""
|
||||
LOG.debug("get_all_services_bindings() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
bindings = session.query(services_models.ServicesBinding).\
|
||||
all()
|
||||
return bindings
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def get_service_bindings(service_id):
|
||||
"""Lists services bindings for a service_id"""
|
||||
LOG.debug("get_service_bindings() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
bindings = session.query(services_models.ServicesBinding).\
|
||||
filter_by(service_id=service_id).\
|
||||
one()
|
||||
return bindings
|
||||
except exc.NoResultFound:
|
||||
return []
|
||||
|
||||
|
||||
def add_services_binding(service_id, mngnet_id, nbnet_id, sbnet_id):
|
||||
"""Adds a services binding"""
|
||||
LOG.debug("add_services_binding() called")
|
||||
session = db.get_session()
|
||||
binding = services_models.ServicesBinding(service_id, mngnet_id, \
|
||||
nbnet_id, sbnet_id)
|
||||
session.add(binding)
|
||||
session.flush()
|
||||
return binding
|
||||
|
||||
|
||||
def remove_services_binding(service_id):
|
||||
"""Removes a services binding"""
|
||||
LOG.debug("remove_services_binding() called")
|
||||
session = db.get_session()
|
||||
try:
|
||||
binding = session.query(services_models.ServicesBinding).\
|
||||
filter_by(service_id=service_id).\
|
||||
all()
|
||||
for bind in binding:
|
||||
session.delete(bind)
|
||||
session.flush()
|
||||
return binding
|
||||
except exc.NoResultFound:
|
||||
pass
|
42
quantum/plugins/cisco/db/services_models.py
Normal file
42
quantum/plugins/cisco/db/services_models.py
Normal file
@ -0,0 +1,42 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2011, Cisco Systems, 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.
|
||||
#
|
||||
# @author: Edgar Magana, Cisco Systems, Inc.
|
||||
|
||||
from sqlalchemy import Column, Integer, String
|
||||
|
||||
from quantum.plugins.cisco.db.l2network_models import L2NetworkBase
|
||||
from quantum.plugins.cisco.db.models import BASE
|
||||
|
||||
|
||||
class ServicesBinding(BASE, L2NetworkBase):
|
||||
"""Represents a binding of L2 services to networks"""
|
||||
__tablename__ = 'services_bindings'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
service_id = Column(String(255))
|
||||
mngnet_id = Column(String(255))
|
||||
nbnet_id = Column(String(255))
|
||||
sbnet_id = Column(String(255))
|
||||
|
||||
def __init__(self, service_id, mngnet_id, nbnet_id, sbnet_id):
|
||||
self.service_id = service_id
|
||||
self.mngnet_id = mngnet_id
|
||||
self.nbnet_id = nbnet_id
|
||||
self.sbnet_id = sbnet_id
|
||||
|
||||
def __repr__(self):
|
||||
return "<ServicesBinding (%s,%d)>" % \
|
||||
(self.service_id, self.mngnet_id, self.nbnet_id, self.sbnet_id)
|
70
quantum/plugins/cisco/services/README
Normal file
70
quantum/plugins/cisco/services/README
Normal file
@ -0,0 +1,70 @@
|
||||
=========================================================================================
|
||||
README: L2 Network Services Insertion Utility
|
||||
=========================================================================================
|
||||
:Authors: Edgar Magana, Mani Ramasamy, Ram Durairaj
|
||||
:Collaborators: Deepak Khanorkar, Sumit Naiksatam, Nat Chidambaram, Dan Wendlandt
|
||||
:Contact: netstack@lists.launchpad.net
|
||||
:Web site: https://blueprints.launchpad.net/quantum/+spec/services-insertion-wrapper
|
||||
|
||||
Introduction
|
||||
------------
|
||||
This utility offers a simplify way to insert and remove network services
|
||||
in the path of the traffic to the server VMs, by splitting the network into two,
|
||||
and having the service bridge between the two, in the process applying the service.
|
||||
This model is called In-Path (Bump in the Wire)
|
||||
|
||||
Pre-requisites
|
||||
--------------
|
||||
This integration uses Quantum APIs offered on diablo realease and Nova compute
|
||||
functionality, basically to create new service instances.
|
||||
|
||||
Instructions
|
||||
------------------------------------------------------
|
||||
This utility offer four functionalities:
|
||||
|
||||
1. insert_inpath_service <tenant_id> <service_image_id>
|
||||
<management_net_name> <northbound_net_name> <southbound_net_name>
|
||||
Creates two networks and insert a service vm between them bridging the traffic
|
||||
path. It also creates a management network to access the service configuration.
|
||||
|
||||
2. delete_service <tenant_id> <service_instance_id>
|
||||
Deletes the service prevopusly inserted as well as the network dependencies.
|
||||
|
||||
connect_vm <tenant_id> <vm_image_id> <service_instance_id>
|
||||
Instanciate a VM which is connected to the southbound network created by
|
||||
insert_inpath_service. Facilitates the connections of server vms into the
|
||||
tenant's network.
|
||||
|
||||
4. disconnect_vm <vm_instance_id>
|
||||
Disconnect from the southbound network and terminates the server vm.
|
||||
|
||||
Example
|
||||
------------------------------------------------------
|
||||
Let's insert a Firewall service between northbound and southbound networks,
|
||||
the management network will be called mng_net:
|
||||
|
||||
#PYTHONPATH=. python quantum/services/service_insertion.py insert_inpath_service
|
||||
naas ami-00000029 mng_net northnet southnet
|
||||
|
||||
"ami-00000029" is the reference id provided by Glance for the Firewall image
|
||||
service instance id: i-00000091
|
||||
|
||||
Now, we can connect a fresh web server in to the southbound network with:
|
||||
#PYTHONPATH=. python quantum/services/service_insertion.py connect_vm
|
||||
naas ami-0000002b i-00000091
|
||||
|
||||
"ami-0000002b" is the reference id provided by Glace for the Web Server image
|
||||
and "i-00000091" is the instance id provided by Nova for the FW service instance
|
||||
previously created.
|
||||
server instance id: i-00000092
|
||||
|
||||
If we want to disconnect and shutdown the vm instance server:
|
||||
#PYTHONPATH=. python quantum/plugins/cisco/services/service_insertion.py disconnect_vm i-00000092
|
||||
|
||||
We can delete the service instance and the network configuration with:
|
||||
#PYTHONPATH=. python quantum/plugins/cisco/services/service_insertion.py delete_service naas i-00000091
|
||||
|
||||
Caveats
|
||||
------------------------------------------------------
|
||||
nova-compute service should be running in the same server that Quantum.
|
||||
Nova API calls will be implemented in the next release (essex-3)
|
19
quantum/plugins/cisco/services/__init__.py
Normal file
19
quantum/plugins/cisco/services/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2011 OpenStack LLC
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# @author: Edgar Magana, Cisco Systems
|
||||
"""
|
||||
L2 Network Services Insertion Utility
|
||||
"""
|
318
quantum/plugins/cisco/services/service_insertion.py
Normal file
318
quantum/plugins/cisco/services/service_insertion.py
Normal file
@ -0,0 +1,318 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, 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.
|
||||
#
|
||||
# @author: Edgar Magana, Cisco Systems
|
||||
#
|
||||
"""
|
||||
Network Library to insert services using Quantum APIs
|
||||
Currently has four functionalities:
|
||||
1. insert_inpath_service <tenant_id> <service_image_id>
|
||||
<management_net_name> <northbound_net_name> <southbound_net_name>
|
||||
2. delete_service <tenant_id> <service_instance_id>
|
||||
3. connect_vm <tenant_id> <vm_image_id> <service_instance_id>
|
||||
4. disconnect_vm <vm_instance_id>
|
||||
"""
|
||||
|
||||
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
import subprocess
|
||||
import re
|
||||
import sys
|
||||
|
||||
from optparse import OptionParser
|
||||
from quantum.client import Client
|
||||
from quantum.plugins.cisco.db import api as db
|
||||
from quantum.plugins.cisco.db import l2network_db as l2db
|
||||
from quantum.plugins.cisco.db import services_db as sdb
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.services import services_constants as servconts
|
||||
from quantum.plugins.cisco.services import services_logistics as servlogcs
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def insert_inpath_service(tenant_id, service_image_id,
|
||||
management_net_name, northbound_net_name,
|
||||
southbound_net_name, *args):
|
||||
"""Inserting a network service between two networks"""
|
||||
print ("Creating Network for Services and Servers")
|
||||
service_logic = servlogcs.ServicesLogistics()
|
||||
net_list = {}
|
||||
multiport_net_list = []
|
||||
networks_name_list = [management_net_name, northbound_net_name, \
|
||||
southbound_net_name]
|
||||
client = Client(HOST, PORT, USE_SSL, format='json', tenant=tenant_id)
|
||||
for net in networks_name_list:
|
||||
data = {servconts.NETWORK: {servconts.NAME: net}}
|
||||
net_list[net] = client.create_network(data)
|
||||
net_list[net][servconts.PORTS] = []
|
||||
LOG.debug("Network %s Created with ID: %s " % (net, \
|
||||
net_list[net][servconts.NETWORK][servconts.ID]))
|
||||
print "Completed"
|
||||
print ("Creating Ports on Services and Server Networks")
|
||||
LOG.debug("Operation 'create_port' executed.")
|
||||
if not service_logic.verify_plugin(const.UCS_PLUGIN):
|
||||
for net in networks_name_list:
|
||||
net_list[net][servconts.PORTS].append
|
||||
(client.create_port
|
||||
(net_list[net][servconts.NETWORK][servconts.ID]))
|
||||
LOG.debug("Operation 'create_port' executed.")
|
||||
else:
|
||||
for net in networks_name_list:
|
||||
nets = net_list[net][servconts.NETWORK][servconts.ID]
|
||||
multiport_net_list.append(nets)
|
||||
data = create_multiport(tenant_id, multiport_net_list)
|
||||
net_idx = 0
|
||||
for net in networks_name_list:
|
||||
port_id = data[servconts.PORTS][net_idx][servconts.ID]
|
||||
net_list[net][servconts.PORTS].append(port_id)
|
||||
LOG.debug("Port UUID: %s on network: %s" % \
|
||||
(data[servconts.PORTS][net_idx][servconts.ID], net))
|
||||
net_idx = net_idx + 1
|
||||
print "Completed"
|
||||
try:
|
||||
create_vm_args = []
|
||||
create_vm_args.append(servconts.CREATE_VM_CMD)
|
||||
create_vm_args.append(service_image_id)
|
||||
print ("Creating VM with image: %s" % (service_image_id))
|
||||
process = subprocess.Popen(create_vm_args, stdout=subprocess.PIPE)
|
||||
result = process.stdout.readlines()
|
||||
tokens = re.search("i-[a-f0-9]*", str(result[1]))
|
||||
service_vm_name = tokens.group(0)
|
||||
print ("Image: %s instantiated successfully" % (service_vm_name))
|
||||
|
||||
except Exception as exc:
|
||||
print exc
|
||||
|
||||
service_logic.image_status(service_vm_name)
|
||||
print "Completed"
|
||||
print "Attaching Ports To VM Service interfaces"
|
||||
try:
|
||||
idx = 0
|
||||
for net in networks_name_list:
|
||||
network_id = net_list[net][servconts.NETWORK][servconts.ID]
|
||||
port_id = net_list[net][servconts.PORTS][idx]
|
||||
attachment = client.show_port_attachment(network_id, port_id)
|
||||
attachment = attachment[servconts.ATTACHMENT][servconts.ID][:36]
|
||||
LOG.debug("Plugging virtual interface: %s of VM %s \
|
||||
into port: %s on network: %s" %
|
||||
(attachment, service_vm_name, port_id, net))
|
||||
attach_data = {servconts.ATTACHMENT: {servconts.ID: '%s' %
|
||||
attachment}}
|
||||
client.attach_resource(network_id, port_id, attach_data)
|
||||
except Exception as exc:
|
||||
print exc
|
||||
print "Completed"
|
||||
try:
|
||||
LOG.debug("Registering Service in DB")
|
||||
l2db.initialize()
|
||||
for uuid_net in db.network_id(networks_name_list[0]):
|
||||
mngnet_id = str(uuid_net.uuid)
|
||||
for uuid_net in db.network_id(networks_name_list[1]):
|
||||
nbnet_id = str(uuid_net.uuid)
|
||||
for uuid_net in db.network_id(networks_name_list[2]):
|
||||
sbnet_id = str(uuid_net.uuid)
|
||||
sdb.add_services_binding(service_vm_name, mngnet_id, nbnet_id,
|
||||
sbnet_id)
|
||||
except Exception as exc:
|
||||
print exc
|
||||
|
||||
|
||||
def delete_service(tenant_id, service_instance_id, *args):
|
||||
"""
|
||||
Removes a service and all the network configuration
|
||||
"""
|
||||
l2db.initialize()
|
||||
print ("Terminating Service VM")
|
||||
service_logic = servlogcs.ServicesLogistics()
|
||||
vms_list = []
|
||||
vms_list.append(servconts.DELETE_VM_CMD)
|
||||
vms_list.append(service_instance_id)
|
||||
|
||||
if not service_logic.image_exist(service_instance_id):
|
||||
print ("Service VM does not exist")
|
||||
sys.exit()
|
||||
|
||||
result = subprocess.call(vms_list)
|
||||
service_logic.image_shutdown_verification(service_instance_id)
|
||||
|
||||
client = Client(HOST, PORT, USE_SSL, format='json', tenant=tenant_id)
|
||||
service_nets = sdb.get_service_bindings(service_instance_id)
|
||||
print ("Terminating Ports and Networks")
|
||||
network_name = db.network_get(service_nets.mngnet_id)
|
||||
port_id_net = db.port_list(service_nets.mngnet_id)
|
||||
for ports_uuid in port_id_net:
|
||||
client.delete_port(service_nets.mngnet_id, ports_uuid.uuid)
|
||||
client.delete_network(service_nets.mngnet_id)
|
||||
network_name = db.network_get(service_nets.nbnet_id)
|
||||
port_id_net = db.port_list(service_nets.nbnet_id)
|
||||
for ports_uuid in port_id_net:
|
||||
client.delete_port(service_nets.nbnet_id, ports_uuid.uuid)
|
||||
client.delete_network(service_nets.nbnet_id)
|
||||
network_name = db.network_get(service_nets.sbnet_id)
|
||||
port_id_net = db.port_list(service_nets.sbnet_id)
|
||||
for ports_uuid in port_id_net:
|
||||
client.delete_port(service_nets.sbnet_id, ports_uuid.uuid)
|
||||
client.delete_network(service_nets.sbnet_id)
|
||||
service_list = sdb.remove_services_binding(service_instance_id)
|
||||
print ("Configuration Removed Successfully")
|
||||
|
||||
|
||||
def disconnect_vm(vm_instance_id, *args):
|
||||
"""
|
||||
Deletes VMs and Port connection
|
||||
"""
|
||||
l2db.initialize()
|
||||
print ("Terminating Service VM")
|
||||
service_logic = servlogcs.ServicesLogistics()
|
||||
vms_list = []
|
||||
vms_list.append(servconts.DELETE_VM_CMD)
|
||||
vms_list.append(vm_instance_id)
|
||||
result = subprocess.call(vms_list)
|
||||
service_logic.image_shutdown_verification(vm_instance_id)
|
||||
print ("VM Server Off")
|
||||
|
||||
|
||||
def connect_vm(tenant_id, vm_image_id, service_instance_id, *args):
|
||||
"""
|
||||
Starts a VMs and is connected to southbound network
|
||||
"""
|
||||
l2db.initialize()
|
||||
client = Client(HOST, PORT, USE_SSL, format='json', tenant=tenant_id)
|
||||
print ("Connecting %s to Service %s " % (vm_image_id, service_instance_id))
|
||||
service_logic = servlogcs.ServicesLogistics()
|
||||
service_nets = sdb.get_service_bindings(service_instance_id)
|
||||
client.create_port(service_nets.mngnet_id)
|
||||
client.create_port(service_nets.nbnet_id)
|
||||
sb_port_id = client.create_port(service_nets.sbnet_id)
|
||||
LOG.debug("Operation 'create_port' executed.")
|
||||
new_port_id = sb_port_id[servconts.PORT][servconts.ID]
|
||||
try:
|
||||
create_vm_args = []
|
||||
create_vm_args.append(servconts.CREATE_VM_CMD)
|
||||
create_vm_args.append(vm_image_id)
|
||||
print ("Creating VM with image: %s" % (vm_image_id))
|
||||
process = subprocess.Popen(create_vm_args, stdout=subprocess.PIPE)
|
||||
result = process.stdout.readlines()
|
||||
tokens = re.search("i-[a-f0-9]*", str(result[1]))
|
||||
vm_name = tokens.group(0)
|
||||
print ("Image: %s instantiated successfully" % (vm_name))
|
||||
except Exception as exc:
|
||||
print exc
|
||||
|
||||
service_logic.image_status(vm_name)
|
||||
print "Completed"
|
||||
print "Attaching Ports To VM Service interfaces"
|
||||
south_net = service_nets.sbnet_id
|
||||
attachment = client.show_port_attachment(south_net, new_port_id)
|
||||
attachment = attachment[servconts.ATTACHMENT][servconts.ID][:36]
|
||||
LOG.debug("Plugging virtual interface: %s of VM %s \
|
||||
into port: %s on network: %s" %
|
||||
(attachment, vm_name, new_port_id, service_nets.sbnet_id))
|
||||
attach_data = {servconts.ATTACHMENT: {servconts.ID: '%s' % attachment}}
|
||||
client.attach_resource(service_nets.sbnet_id, new_port_id, attach_data)
|
||||
print ("Connect VM Ended")
|
||||
|
||||
|
||||
def create_multiport(tenant_id, networks_list, *args):
|
||||
"""Creates ports on a single host"""
|
||||
ports_info = {'multiport': \
|
||||
{'status': 'ACTIVE',
|
||||
'net_id_list': networks_list,
|
||||
'ports_desc': {'key': 'value'}}}
|
||||
request_url = "/multiport"
|
||||
client = Client(HOST, PORT, USE_SSL, format='json', tenant=tenant_id,
|
||||
action_prefix=servconts.ACTION_PREFIX_CSCO)
|
||||
data = client.do_request('POST', request_url, body=ports_info)
|
||||
return data
|
||||
|
||||
|
||||
def build_args(cmd, cmdargs, arglist):
|
||||
"""Building the list of args for a particular CLI"""
|
||||
args = []
|
||||
orig_arglist = arglist[:]
|
||||
try:
|
||||
for cmdarg in cmdargs:
|
||||
args.append(arglist[0])
|
||||
del arglist[0]
|
||||
except:
|
||||
LOG.debug("Not enough arguments for \"%s\" (expected: %d, got: %d)"
|
||||
% (cmd, len(cmdargs), len(orig_arglist)))
|
||||
print "Service Insertion Usage:\n %s %s" % (cmd,
|
||||
" ".join(["<%s>" % y for y in SERVICE_COMMANDS[cmd]["args"]]))
|
||||
sys.exit()
|
||||
if len(arglist) > 0:
|
||||
LOG.debug("Too many arguments for \"%s\" (expected: %d, got: %d)" \
|
||||
% (cmd, len(cmdargs), len(orig_arglist)))
|
||||
print "Service Insertion Usage:\n %s %s" % (cmd,
|
||||
" ".join(["<%s>" % y for y in SERVICE_COMMANDS[cmd]["args"]]))
|
||||
sys.exit()
|
||||
return args
|
||||
|
||||
|
||||
SERVICE_COMMANDS = {
|
||||
"insert_inpath_service": {
|
||||
"func": insert_inpath_service,
|
||||
"args": ["tenant_id", "service_image_id",
|
||||
"management_net_name", "northbound_net_name",
|
||||
"southbound_net_name"]},
|
||||
"delete_service": {
|
||||
"func": delete_service,
|
||||
"args": ["tenant_id", "service_instance_id"]},
|
||||
"connect_vm": {
|
||||
"func": connect_vm,
|
||||
"args": ["tenant_id", "vm_image_id",
|
||||
"service_instance_id"]},
|
||||
"disconnect_vm": {
|
||||
"func": disconnect_vm,
|
||||
"args": ["vm_instance_id"]}}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.system("clear")
|
||||
usagestr = "Usage: %prog [OPTIONS] <command> [args]"
|
||||
PARSER = OptionParser(usage=usagestr)
|
||||
PARSER.add_option("-H", "--host", dest="host",
|
||||
type="string", default="127.0.0.1", help="ip address of api host")
|
||||
PARSER.add_option("-p", "--port", dest="port",
|
||||
type="int", default=9696, help="api port")
|
||||
PARSER.add_option("-s", "--ssl", dest="ssl",
|
||||
action="store_true", default=False, help="use ssl")
|
||||
PARSER.add_option("-v", "--verbose", dest="verbose",
|
||||
action="store_true", default=False, help="turn on verbose logging")
|
||||
PARSER.add_option("-f", "--logfile", dest="logfile",
|
||||
type="string", default="syslog", help="log file path")
|
||||
options, args = PARSER.parse_args()
|
||||
if options.verbose:
|
||||
LOG.setLevel(logging.DEBUG)
|
||||
else:
|
||||
LOG.setLevel(logging.WARN)
|
||||
if options.logfile == "syslog":
|
||||
LOG.addHandler(logging.handlers.SysLogHandler(address='/dev/log'))
|
||||
else:
|
||||
LOG.addHandler(logging.handlers.WatchedFileHandler(options.logfile))
|
||||
os.chmod(options.logfile, 0644)
|
||||
service_logic = servlogcs.ServicesLogistics()
|
||||
HOST = options.host
|
||||
PORT = options.port
|
||||
USE_SSL = options.ssl
|
||||
CMD = args[0]
|
||||
args = build_args(CMD, SERVICE_COMMANDS[CMD]["args"], args[1:])
|
||||
SERVICE_COMMANDS[CMD]["func"](*args)
|
||||
sys.exit(0)
|
35
quantum/plugins/cisco/services/services_constants.py
Normal file
35
quantum/plugins/cisco/services/services_constants.py
Normal file
@ -0,0 +1,35 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2011 OpenStack LLC
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# @author: Edgar Magana, Cisco Systems
|
||||
#
|
||||
"""
|
||||
Services Constants for the Services insertion Library
|
||||
"""
|
||||
|
||||
|
||||
FORMAT = 'json'
|
||||
ACTION_PREFIX_EXT = '/v1.0'
|
||||
ACTION_PREFIX_CSCO = ACTION_PREFIX_EXT + \
|
||||
'/extensions/csco/tenants/{tenant_id}'
|
||||
NETWORK = 'network'
|
||||
ID = 'id'
|
||||
PORTS = 'ports'
|
||||
PORT = 'port'
|
||||
NAME = 'name'
|
||||
ATTACHMENT = 'attachment'
|
||||
CREATE_VM_CMD = '/usr/bin/euca-run-instances'
|
||||
DELETE_VM_CMD = '/usr/bin/euca-terminate-instances'
|
||||
DESCRIBE_VM_CMD = '/usr/bin/euca-describe-instances'
|
122
quantum/plugins/cisco/services/services_logistics.py
Normal file
122
quantum/plugins/cisco/services/services_logistics.py
Normal file
@ -0,0 +1,122 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, 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.
|
||||
#
|
||||
# @author: Edgar Magana, Cisco Systems
|
||||
"""
|
||||
Logistic components for Service Insertion utility
|
||||
"""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
import re
|
||||
import time
|
||||
|
||||
from quantum.common import utils
|
||||
from quantum.plugins.cisco import l2network_plugin_configuration as conf
|
||||
from quantum.plugins.cisco.db import services_db as sdb
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.services import services_constants as servconts
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ServicesLogistics():
|
||||
"""
|
||||
Services Logistics Modules
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def image_shutdown_verification(self, image_name):
|
||||
"""
|
||||
Verifies that the VM has been properly shutdown
|
||||
"""
|
||||
try:
|
||||
service_args = []
|
||||
service_args.append(servconts.DESCRIBE_VM_CMD)
|
||||
service_args.append(image_name)
|
||||
counter = 0
|
||||
flag = False
|
||||
while flag == False and counter <= 5:
|
||||
counter = counter + 1
|
||||
time.sleep(2.5)
|
||||
process = subprocess.Popen(service_args, \
|
||||
stdout=subprocess.PIPE)
|
||||
result = process.stdout.readlines()
|
||||
if not result:
|
||||
flag = True
|
||||
except Exception, exc:
|
||||
print exc
|
||||
|
||||
def image_status(self, image_name):
|
||||
"""
|
||||
Checks the status of the image
|
||||
"""
|
||||
try:
|
||||
service_args = []
|
||||
service_args.append(servconts.DESCRIBE_VM_CMD)
|
||||
service_args.append(image_name)
|
||||
counter = 0
|
||||
flag = False
|
||||
while flag == False and counter <= 10:
|
||||
counter = counter + 1
|
||||
time.sleep(2.5)
|
||||
process = subprocess.Popen(service_args, \
|
||||
stdout=subprocess.PIPE)
|
||||
result = process.stdout.readlines()
|
||||
if result:
|
||||
tokens = re.search("running", str(result[1]))
|
||||
if tokens:
|
||||
service_status = tokens.group(0)
|
||||
if service_status == "running":
|
||||
flag = True
|
||||
except Exception as exc:
|
||||
print exc
|
||||
|
||||
def image_exist(self, image_name):
|
||||
"""
|
||||
Verifies that the image id is available
|
||||
"""
|
||||
try:
|
||||
service_vm = sdb.get_service_bindings(image_name)
|
||||
if service_vm:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Exception as exc:
|
||||
print exc
|
||||
|
||||
def verify_plugin(self, plugin_key):
|
||||
"""
|
||||
Verifies the PlugIn available
|
||||
"""
|
||||
_plugins = {}
|
||||
for key in conf.PLUGINS[const.PLUGINS].keys():
|
||||
_plugins[key] = \
|
||||
utils.import_object(conf.PLUGINS[const.PLUGINS][key])
|
||||
if not plugin_key in _plugins.keys():
|
||||
LOG.debug("No %s Plugin loaded" % plugin_key)
|
||||
return False
|
||||
else:
|
||||
LOG.debug("Plugin %s founded" % const.UCS_PLUGIN)
|
||||
return True
|
||||
|
||||
def press_key(self):
|
||||
"""
|
||||
Waits for en external input
|
||||
"""
|
||||
key = raw_input("Press any key to continue")
|
||||
return key
|
@ -27,6 +27,7 @@ from quantum.plugins.cisco.common import cisco_constants as const
|
||||
import quantum.plugins.cisco.db.api as db
|
||||
import quantum.plugins.cisco.db.l2network_db as l2network_db
|
||||
import quantum.plugins.cisco.db.nexus_db as nexus_db
|
||||
import quantum.plugins.cisco.db.services_db as services_db
|
||||
import quantum.plugins.cisco.db.ucs_db as ucs_db
|
||||
|
||||
|
||||
@ -191,6 +192,59 @@ class NexusDB(object):
|
||||
% str(exc))
|
||||
|
||||
|
||||
class ServicesDB(object):
|
||||
"""Class consisting of methods to call services db methods"""
|
||||
def get_all_servicesbindings(self):
|
||||
"""get all services port bindings"""
|
||||
bindings = []
|
||||
try:
|
||||
for bind in services_db.get_all_services_bindings():
|
||||
LOG.debug("Getting services bindings : %s" % bind.service_id)
|
||||
bind_dict = {}
|
||||
bind_dict["service_id"] = str(bind.service_id)
|
||||
bind_dict["mngnet_id"] = str(bind.mngnet_id)
|
||||
bind_dict["nbnet_id"] = str(bind.nbnet_id)
|
||||
bind_dict["sbnet_id"] = str(bind.sbnet_id)
|
||||
bindings.append(bind_dict)
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get all bindings: %s" % str(exc))
|
||||
return bindings
|
||||
|
||||
def get_servicebindings(self, service_id):
|
||||
"""get service binding"""
|
||||
try:
|
||||
bind = services_db.get_service_bindings(service_id)
|
||||
LOG.debug("Getting service binding : %s" % bind.service_id)
|
||||
return bind
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to get service binding: %s" % str(exc))
|
||||
|
||||
def create_servicebinding(self, service_id, mngnet_id, nbnet_id, sbnet_id):
|
||||
"""create service binding"""
|
||||
bind_dict = {}
|
||||
try:
|
||||
res = services_db.add_services_binding(service_id, mngnet_id, \
|
||||
nbnet_id, sbnet_id)
|
||||
LOG.debug("Created service binding : %s" % res.service_id)
|
||||
bind_dict["service_id"] = str(res.service_id)
|
||||
bind_dict["mngnet_id"] = str(res.mngnet_id)
|
||||
bind_dict["nbnet_id"] = str(res.nbnet_id)
|
||||
bind_dict["sbnet_id"] = str(res.sbnet_id)
|
||||
return bind_dict
|
||||
except Exception, exc:
|
||||
LOG.error("Failed to create service binding: %s" % str(exc))
|
||||
|
||||
def delete_servicebinding(self, service_id):
|
||||
"""delete service binding"""
|
||||
try:
|
||||
bind = services_db.remove_services_binding(service_id)
|
||||
for res in bind:
|
||||
LOG.debug("Deleted service binding: %s" % res.service_id)
|
||||
except Exception, exc:
|
||||
raise Exception("Failed to delete service binding: %s"
|
||||
% str(exc))
|
||||
|
||||
|
||||
class L2networkDB(object):
|
||||
"""Class conisting of methods to call L2network db methods"""
|
||||
def get_all_vlan_bindings(self):
|
||||
@ -741,6 +795,72 @@ class NexusDBTest(unittest.TestCase):
|
||||
self.dbtest.delete_nexusportbinding(vlan_id)
|
||||
|
||||
|
||||
class ServicesDBTest(unittest.TestCase):
|
||||
"""Class conisting of services DB unit tests"""
|
||||
def setUp(self):
|
||||
"""Setup for services db tests"""
|
||||
l2network_db.initialize()
|
||||
self.dbtest = ServicesDB()
|
||||
LOG.debug("Setup")
|
||||
|
||||
def tearDown(self):
|
||||
"""Tear Down"""
|
||||
db.clear_db()
|
||||
|
||||
def testa_create_servicebinding(self):
|
||||
"""create service binding"""
|
||||
service_id = self.dbtest.create_servicebinding("i-00001", \
|
||||
"mng_net", "northb_net", "northb_net")
|
||||
self.assertTrue(service_id["service_id"] == "i-00001")
|
||||
self.tearDown_servicebinding()
|
||||
|
||||
def testb_get_servicesbindings(self):
|
||||
"""get all services binding"""
|
||||
service_id = self.dbtest.create_servicebinding("i-00001", \
|
||||
"mng_net", "northb_net", "northb_net")
|
||||
bindings = self.dbtest.get_servicebindings("i-00001")
|
||||
count = 0
|
||||
if bindings:
|
||||
count += 1
|
||||
self.assertTrue(count == 1)
|
||||
self.tearDown_servicebinding()
|
||||
|
||||
def testb_getall_servicesbindings(self):
|
||||
"""get all services binding"""
|
||||
service_id = self.dbtest.create_servicebinding("i-00001", \
|
||||
"mng_net", "northb_net", "northb_net")
|
||||
service_id = self.dbtest.create_servicebinding("i-00002", \
|
||||
"mng_net", "northb_net", "northb_net")
|
||||
bindings = self.dbtest.get_all_servicesbindings()
|
||||
count = 0
|
||||
for bind in bindings:
|
||||
if "mng_net" in bind["mngnet_id"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 2)
|
||||
self.tearDown_servicebinding()
|
||||
|
||||
def testc_delete_servicesbinding(self):
|
||||
"""delete services binding"""
|
||||
binding_serv = self.dbtest.create_servicebinding("i-00001", \
|
||||
"mng_net", "northb_net", "northb_net")
|
||||
self.dbtest.delete_servicebinding("i-00001")
|
||||
bindings = self.dbtest.get_all_servicesbindings()
|
||||
count = 0
|
||||
for bind in bindings:
|
||||
if "mng_net" in bind["mngnet_id"]:
|
||||
count += 1
|
||||
self.assertTrue(count == 0)
|
||||
self.tearDown_servicebinding()
|
||||
|
||||
def tearDown_servicebinding(self):
|
||||
"""tear down nexusport binding table"""
|
||||
LOG.debug("Tearing Down Nexus port Bindings")
|
||||
binds = self.dbtest.get_all_servicesbindings()
|
||||
for bind in binds:
|
||||
service_id = bind["service_id"]
|
||||
self.dbtest.delete_servicebinding(service_id)
|
||||
|
||||
|
||||
class L2networkDBTest(unittest.TestCase):
|
||||
"""Class conisting of L2network DB unit tests"""
|
||||
def setUp(self):
|
||||
|
Loading…
Reference in New Issue
Block a user