1) Added a bare-bones framework for quantum plugins.
2) Created demo quantum plugin that conforms to QuantumPluginBase Abstract class specification. 3) Demonstrated plugin registration and invocation using the demo plugin called "QuantumEchoPlugin" 4) Created the initial file structure for a quantum CLI 5) Seeded the utils module that will contain frequently used Quantum utilities. 6) Modified the manager module to initialize and register the quantum plugin defined in a configuration file. I have hard-coded the path to plugin for now but this will move to a quantum.conf file. TODO: 1) Finish up the Quantum CLI 2) Write Quantum unit tests that can be run against any plug-in for certification. 3) Create a working quantum plugin.
This commit is contained in:
parent
5626c2fedd
commit
9a82d8a9e3
@ -14,8 +14,50 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
# @author: Somik Behera, Nicira Networks, Inc.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Manager is responsible for parsing a config file and instantiating the correct
|
Quantum's Manager class is responsible for parsing a config file and instantiating the correct
|
||||||
set of plugins that concretely implement quantum_plugin_base class
|
plugin that concretely implement quantum_plugin_base class
|
||||||
|
|
||||||
|
The caller should make sure that QuantumManager is a singleton.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import utils
|
||||||
|
from quantum_plugin_base import QuantumPluginBase
|
||||||
|
|
||||||
|
CONFIG_FILE = "quantum_plugin.conf"
|
||||||
|
|
||||||
|
class QuantumManager(object):
|
||||||
|
|
||||||
|
def __init__(self,config=CONFIG_FILE):
|
||||||
|
self.configuration_file = CONFIG_FILE
|
||||||
|
#TODO(somik): plugin location should be grabbed from a
|
||||||
|
# configuration file as opposed to hard-coding the location
|
||||||
|
#
|
||||||
|
#plugin_location = get_plugin_location(configuration_file)
|
||||||
|
plugin_location = "plugins.SamplePlugin.QuantumEchoPlugin"
|
||||||
|
plugin_klass = utils.import_class(plugin_location)
|
||||||
|
if not issubclass(plugin_klass, QuantumPluginBase):
|
||||||
|
raise Exception("Imported plugin didn't pass compatibility test")
|
||||||
|
else:
|
||||||
|
print("Imported plugin passed compatibility test\n")
|
||||||
|
self.plugin = plugin_klass()
|
||||||
|
|
||||||
|
def get_manager(self):
|
||||||
|
return self.plugin
|
||||||
|
|
||||||
|
# TODO(somik): rmove the main class
|
||||||
|
# Added for temporary testing purposes
|
||||||
|
def main():
|
||||||
|
manager = QuantumManager()
|
||||||
|
myManager = manager.get_manager()
|
||||||
|
myManager.get_all_networks("tesst")
|
||||||
|
#print("is a plugin")
|
||||||
|
|
||||||
|
# Standard boilerplate to call the main() function.
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
131
quantum/plugins/SamplePlugin.py
Normal file
131
quantum/plugins/SamplePlugin.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2011, Nicira Networks, 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: Somik Behera, Nicira Networks, Inc.
|
||||||
|
|
||||||
|
class QuantumEchoPlugin(object):
|
||||||
|
|
||||||
|
"""
|
||||||
|
QuantumEchoPlugin is a demo plugin that doesn't
|
||||||
|
do anything but demonstrated the concept of a
|
||||||
|
concrete Quantum Plugin. Any call to this plugin
|
||||||
|
will result in just a "print" to std. out with
|
||||||
|
the name of the method that was called.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_all_networks(self, tenant_id):
|
||||||
|
"""
|
||||||
|
Returns a dictionary containing all
|
||||||
|
<network_uuid, network_name> for
|
||||||
|
the specified tenant.
|
||||||
|
"""
|
||||||
|
print("get_all_networks() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def create_network(self, tenant_id, net_name):
|
||||||
|
"""
|
||||||
|
Creates a new Virtual Network, and assigns it
|
||||||
|
a symbolic name.
|
||||||
|
"""
|
||||||
|
print("create_network() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def delete_network(self, tenant_id, net_id):
|
||||||
|
"""
|
||||||
|
Deletes the network with the specified network identifier
|
||||||
|
belonging to the specified tenant.
|
||||||
|
"""
|
||||||
|
print("delete_network() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_network_details(self, tenant_id, net_id):
|
||||||
|
"""
|
||||||
|
Deletes the Virtual Network belonging to a the
|
||||||
|
spec
|
||||||
|
"""
|
||||||
|
print("get_network_details() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def rename_network(self, tenant_id, net_id, new_name):
|
||||||
|
"""
|
||||||
|
Updates the symbolic name belonging to a particular
|
||||||
|
Virtual Network.
|
||||||
|
"""
|
||||||
|
print("rename_network() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_ports(self, tenant_id, net_id):
|
||||||
|
"""
|
||||||
|
Retrieves all port identifiers belonging to the
|
||||||
|
specified Virtual Network.
|
||||||
|
"""
|
||||||
|
print("get_all_ports() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def create_port(self, tenant_id, net_id):
|
||||||
|
"""
|
||||||
|
Creates a port on the specified Virtual Network.
|
||||||
|
"""
|
||||||
|
print("create_port() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def delete_port(self, tenant_id, net_id, port_id):
|
||||||
|
"""
|
||||||
|
Deletes a port on a specified Virtual Network,
|
||||||
|
if the port contains a remote interface attachment,
|
||||||
|
the remote interface is first un-plugged and then the port
|
||||||
|
is deleted.
|
||||||
|
"""
|
||||||
|
print("delete_port() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_port_details(self, tenant_id, net_id, port_id):
|
||||||
|
"""
|
||||||
|
This method allows the user to retrieve a remote interface
|
||||||
|
that is attached to this particular port.
|
||||||
|
"""
|
||||||
|
print("get_port_details() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
|
||||||
|
"""
|
||||||
|
Attaches a remote interface to the specified port on the
|
||||||
|
specified Virtual Network.
|
||||||
|
"""
|
||||||
|
print("plug_interface() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def unplug_interface(self, tenant_id, net_id, port_id):
|
||||||
|
"""
|
||||||
|
Detaches a remote interface from the specified port on the
|
||||||
|
specified Virtual Network.
|
||||||
|
"""
|
||||||
|
print("unplug_interface() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_interface_details(self, tenant_id, net_id, port_id):
|
||||||
|
"""
|
||||||
|
Retrieves the remote interface that is attached at this
|
||||||
|
particular port.
|
||||||
|
"""
|
||||||
|
print("get_interface_details() called\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_attached_interfaces(self, tenant_id, net_id):
|
||||||
|
"""
|
||||||
|
Retrieves all remote interfaces that are attached to
|
||||||
|
a particular Virtual Network.
|
||||||
|
"""
|
||||||
|
print("get_all_attached_interfaces() called\n")
|
16
quantum/plugins/__init__.py
Normal file
16
quantum/plugins/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
# Copyright 2011 Nicira Networks, 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: Somik Behera, Nicira Networks, Inc.
|
33
quantum/quantumCLI.py
Normal file
33
quantum/quantumCLI.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2011, Nicira Networks, 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: Somik Behera, Nicira Networks, Inc.
|
||||||
|
|
||||||
|
from manager import QuantumManager
|
||||||
|
|
||||||
|
class CLI():
|
||||||
|
|
||||||
|
def index(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def main():
|
||||||
|
quantum = QuantumManager()
|
||||||
|
manager = quantum.get_manager()
|
||||||
|
manager.get_all_networks("tesst")
|
||||||
|
#print("is a plugin")
|
||||||
|
|
||||||
|
# Standard boilerplate to call the main() function.
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -133,3 +133,21 @@ class QuantumPluginBase(object):
|
|||||||
a particular Virtual Network.
|
a particular Virtual Network.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __subclasshook__(cls, klass):
|
||||||
|
"""
|
||||||
|
The __subclasshook__ method is a class method
|
||||||
|
that will be called everytime a class is tested
|
||||||
|
using issubclass(klass, Plugin).
|
||||||
|
In that case, it will check that every method
|
||||||
|
marked with the abstractmethod decorator is
|
||||||
|
provided by the plugin class.
|
||||||
|
"""
|
||||||
|
if cls is QuantumPluginBase:
|
||||||
|
for method in cls.__abstractmethods__:
|
||||||
|
if any(method in base.__dict__ for base in klass.__mro__):
|
||||||
|
continue
|
||||||
|
return NotImplemented
|
||||||
|
return True
|
||||||
|
return NotImplemented
|
57
quantum/utils.py
Normal file
57
quantum/utils.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2011, Nicira Networks, 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.
|
||||||
|
#
|
||||||
|
# Borrowed from nova code base, more utilities will be added/borrowed as and
|
||||||
|
# when needed.
|
||||||
|
# @author: Somik Behera, Nicira Networks, Inc.
|
||||||
|
|
||||||
|
"""Utilities and helper functions."""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import datetime
|
||||||
|
import functools
|
||||||
|
import inspect
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
|
import string
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import types
|
||||||
|
|
||||||
|
|
||||||
|
def import_class(import_str):
|
||||||
|
"""Returns a class from a string including module and class."""
|
||||||
|
mod_str, _sep, class_str = import_str.rpartition('.')
|
||||||
|
try:
|
||||||
|
__import__(mod_str)
|
||||||
|
return getattr(sys.modules[mod_str], class_str)
|
||||||
|
except (ImportError, ValueError, AttributeError), exc:
|
||||||
|
print(('Inner Exception: %s'), exc)
|
||||||
|
raise exception.ClassNotFound(class_name=class_str)
|
||||||
|
|
||||||
|
|
||||||
|
def import_object(import_str):
|
||||||
|
"""Returns an object including a module or module and class."""
|
||||||
|
try:
|
||||||
|
__import__(import_str)
|
||||||
|
return sys.modules[import_str]
|
||||||
|
except ImportError:
|
||||||
|
cls = import_class(import_str)
|
||||||
|
return cls()
|
Loading…
Reference in New Issue
Block a user