diff --git a/README.rst b/README.rst index b67aeff..e93829e 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,6 @@ -=============================== -namos -=============================== - -OpenStack Service, Device manager +========================= +namos - OpenStack manager +========================= * Free software: Apache license * Documentation: http://docs.openstack.org/developer/namos diff --git a/etc/namos.conf b/etc/namos.conf new file mode 100644 index 0000000..f9bfabb --- /dev/null +++ b/etc/namos.conf @@ -0,0 +1,2 @@ +[database] +connection = mysql+pymysql://root:password@172.241.0.101/namos?charset=utf8 \ No newline at end of file diff --git a/namos/cmd/__init__.py b/namos/cmd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/namos/cmd/manage.py b/namos/cmd/manage.py new file mode 100644 index 0000000..f745f6d --- /dev/null +++ b/namos/cmd/manage.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- + +# 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 sys + +from oslo_config import cfg + +from namos.common import config +from namos.db import sample +from namos.db.sqlalchemy import migration + + +CONF = cfg.CONF +MANAGE_COMMAND_NAME = 'namos-manage' + + +class DBCommand(object): + + def upgrade(self): + migration.upgrade(CONF.command.revision) + + def downgrade(self): + migration.downgrade(CONF.command.revision) + + def revision(self): + migration.revision(CONF.command.message, CONF.command.autogenerate) + + def stamp(self): + migration.stamp(CONF.command.revision) + + def version(self): + print(migration.version()) + + def create_schema(self): + migration.create_schema() + + def history(self): + migration.history() + + def demo_data(self): + if CONF.command.purge: + sample.purge_demo_data() + else: + sample.populate_demo_data() + + +def add_command_parsers(subparsers): + command_object = DBCommand() + + parser = subparsers.add_parser('upgrade') + parser.set_defaults(func=command_object.upgrade) + parser.add_argument('--revision', nargs='?') + + parser = subparsers.add_parser('downgrade') + parser.set_defaults(func=command_object.downgrade) + parser.add_argument('--revision', nargs='?') + + parser = subparsers.add_parser('stamp') + parser.add_argument('--revision', nargs='?') + parser.set_defaults(func=command_object.stamp) + + parser = subparsers.add_parser('revision') + parser.add_argument('-m', '--message') + parser.add_argument('--autogenerate', action='store_true') + parser.set_defaults(func=command_object.revision) + + parser = subparsers.add_parser('version') + parser.set_defaults(func=command_object.version) + + parser = subparsers.add_parser('history') + parser.set_defaults(func=command_object.history) + + parser = subparsers.add_parser('create_schema') + parser.set_defaults(func=command_object.create_schema) + + parser = subparsers.add_parser('demo_data') + parser.add_argument('-p', '--purge', action='store_true') + parser.set_defaults(func=command_object.demo_data) + + +command_opt = cfg.SubCommandOpt('command', + title='Command', + help='Available commands', + handler=add_command_parsers) + +CONF.register_cli_opt(command_opt) +# olso mandates to initialize the config after cli opt registration +config.init_conf(prog=MANAGE_COMMAND_NAME) + + +def main(): + try: + CONF.command.func() + except Exception as e: + sys.exit("ERROR: %s" % e) + + +if __name__ == '__main__': + main() diff --git a/namos/common/__init__.py b/namos/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/namos/common/config.py b/namos/common/config.py new file mode 100644 index 0000000..22f0610 --- /dev/null +++ b/namos/common/config.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +# 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 oslo_config import cfg +from oslo_log import log as logging + +import namos + +PROJECT_NAME = 'namos' +VERSION = namos.__version__ + +CONF = cfg.CONF + + +def init_conf(prog): + CONF(project=PROJECT_NAME, + version=VERSION, + prog=prog) + + +def setup_log(prog=PROJECT_NAME): + logging.register_options(cfg.CONF) + logging.setup(cfg.CONF, + prog, + version=VERSION) diff --git a/namos/common/exception.py b/namos/common/exception.py new file mode 100644 index 0000000..d9da06f --- /dev/null +++ b/namos/common/exception.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- + +# 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 logging +import six + + +LOG = logging.getLogger(__name__) + + +class NamosException(Exception): + msg_fmt = ("An unknown exception occurred.") + message = None + error_code = None + http_status_code = None + data = {} + + def __init__(self, **kwargs): + self.kwargs = kwargs + + try: + if kwargs.get('message') is not None: + self.message = kwargs['message'] + else: + self.message = json.dumps( + {'error_code': self.error_code, + 'message': self.msg_fmt % kwargs, + 'http_code': self.http_status_code, + 'data': kwargs}) + if kwargs.get('data') is not None: + self.data = kwargs['data'] + except KeyError: + self.message = self.msg_fmt + LOG.exception(('Exception in string format operation')) + for name, value in six.iteritems(kwargs): + LOG.error("%s: %s" % (name, value)) # noqa + + def __str__(self): + return unicode(self.message).encode('UTF-8') + + def __unicode__(self): + return unicode(self.message) + + def __deepcopy__(self, memo): + return self.__class__(**self.kwargs) + + +class NotFound(NamosException): + msg_fmt = ("Not Found") + error_code = -1 + http_status_code = 404 + + +class RegionNotFound(NotFound): + msg_fmt = ("Region %(region_id)s does not found") + error_code = 0x01001 + + +class RegionAlreadyExist(NamosException): + msg_fmt = ("Region %(region_id)s already exists") + error_code = 0x01002 + http_status_code = 403 + + +class DeviceNotFound(NotFound): + msg_fmt = ("Device %(device_id)s does not found") + error_code = 0x02001 + + +class DeviceEndpointNotFound(NotFound): + msg_fmt = ("Device Endpoint %(device_endpoint_id)s does not found") + error_code = 0x03001 + + +class DeviceDriverNotFound(NotFound): + msg_fmt = ("Device Driver %(device_driver_id)s does not found") + error_code = 0x04001 + + +class DeviceDriverClassNotFound(NotFound): + msg_fmt = ("Device Driver Class %(device_driver_class_id)s " + "does not found") + error_code = 0x05001 + + +class ServiceNotFound(NotFound): + msg_fmt = ("Service %(service_id)s does not found") + error_code = 0x06001 + + +class ServiceNodeNotFound(NotFound): + msg_fmt = ("Service Node %(service_node_id)s does not found") + error_code = 0x07001 + + +class ServiceComponentNotFound(NotFound): + msg_fmt = ("Service Component %(service_component_id)s does not found") + error_code = 0x08001 + + +class ServiceWorkerNotFound(NotFound): + msg_fmt = ("Service Worker %(service_worker_id)s " + "does not found") + error_code = 0x09001 + + +class ConfigNotFound(NotFound): + msg_fmt = ("Config %(config_id)s does not found") + error_code = 0x0a001 diff --git a/namos/db/__init__.py b/namos/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/namos/db/api.py b/namos/db/api.py new file mode 100644 index 0000000..cb81564 --- /dev/null +++ b/namos/db/api.py @@ -0,0 +1,367 @@ +# -*- coding: utf-8 -*- + +# 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 oslo_config import cfg +from oslo_db import api + +CONF = cfg.CONF + +_BACKEND_MAPPING = {'sqlalchemy': 'namos.db.sqlalchemy.api'} + +IMPL = api.DBAPI.from_config(CONF, backend_mapping=_BACKEND_MAPPING) + + +def get_engine(): + return IMPL.get_engine() + + +def get_session(): + return IMPL.get_session() + + +# TODO(kanagaraj-manickam): Add db wrapper function to capture the db +# exception in each of the below methods and log it + +# Region + +def region_create(context, values): + return IMPL.region_create(context, values) + + +def region_update(context, _id, values): + return IMPL.region_update(context, _id, values) + + +def region_get(context, _id): + return IMPL.region_get(context, _id) + + +def region_get_by_name(context, name): + return IMPL.region_get_by_name(context, name) + + +def region_get_all(context): + return IMPL.region_get_all(context) + + +def region_delete(context, _id): + return IMPL.region_delete(context, _id) + + +# Device + +def device_create(context, values): + return IMPL.device_create(context, values) + + +def device_update(context, _id, values): + return IMPL.device_update(context, _id, values) + + +def device_get(context, _id): + return IMPL.device_get(context, _id) + + +def device_get_by_name(context, name): + return IMPL.device_get_by_name(context, name) + + +def device_get_all(context): + return IMPL.device_get_all(context) + + +def device_delete(context, _id): + return IMPL.device_delete(context, _id) + + +# Device Endpoint + +def device_endpoint_create(context, values): + return IMPL.device_endpoint_create(context, values) + + +def device_endpoint_update(context, _id, values): + return IMPL.device_endpoint_update(context, _id, values) + + +def device_endpoint_get(context, _id): + return IMPL.device_endpoint_get(context, _id) + + +def device_endpoint_get_by_name(context, name): + return IMPL.device_endpoint_get_by_name(context, name) + + +def device_endpoint_get_by_device_type(context, + device_id, + type=None, + name=None): + return IMPL.device_endpoint_get_by_device_type(context, device_id, + type, name) + + +def device_endpoint_get_all(context): + return IMPL.device_endpoint_get_all(context) + + +def device_endpoint_delete(context, _id): + return IMPL.device_endpoint_delete(context, _id) + + +# Device Driver + +def device_driver_create(context, values): + return IMPL.device_driver_create(context, values) + + +def device_driver_update(context, _id, values): + return IMPL.device_driver_update(context, _id, values) + + +def device_driver_get(context, _id): + return IMPL.device_driver_get(context, _id) + + +def device_driver_get_by_name(context, name): + return IMPL.device_driver_get_by_name(context, name) + + +def device_driver_get_by_device_endpoint_service_worker( + context, + device_id=None, + endpoint_id=None, + device_driver_class_id=None, + service_worker_id=None): + return IMPL.device_driver_get_by_device_endpoint_service_worker( + context, + device_id, + endpoint_id, + device_driver_class_id, + service_worker_id) + + +def device_driver_get_all(context): + return IMPL.device_driver_get_all(context) + + +def device_driver_delete(context, _id): + return IMPL.device_driver_delete(context, _id) + + +# Device Driver Class + +def device_driver_class_create(context, values): + return IMPL.device_driver_class_create(context, values) + + +def device_driver_class_update(context, _id, values): + return IMPL.device_driver_class_update(context, _id, values) + + +def device_driver_class_get(context, _id): + return IMPL.device_driver_class_get(context, _id) + + +def device_driver_class_get_by_name(context, name): + return IMPL.device_driver_class_get_by_name(context, name) + + +def device_driver_class_get_all(context): + return IMPL.device_driver_class_get_all(context) + + +def device_driver_class_delete(context, _id): + return IMPL.device_driver_class_delete(context, _id) + + +# Service + +def service_create(context, values): + return IMPL.service_create(context, values) + + +def service_update(context, _id, values): + return IMPL.service_update(context, _id, values) + + +def service_get(context, _id): + return IMPL.service_get(context, _id) + + +def service_get_by_name(context, name): + return IMPL.service_get_by_name(context, name) + + +def service_get_all(context): + return IMPL.service_get_all(context) + + +def service_delete(context, _id): + return IMPL.service_delete(context, _id) + + +# Service Node + +def service_node_create(context, values): + return IMPL.service_node_create(context, values) + + +def service_node_update(context, _id, values): + return IMPL.service_node_update(context, _id, values) + + +def service_node_get(context, _id): + return IMPL.service_node_get(context, _id) + + +def service_node_get_by_name(context, name): + return IMPL.service_node_get_by_name(context, name) + + +def service_node_get_all(context): + return IMPL.service_node_get_all(context) + + +def service_node_delete(context, _id): + return IMPL.service_node_delete(context, _id) + + +# Service Component + +def service_component_create(context, values): + return IMPL.service_component_create(context, values) + + +def service_component_update(context, _id, values): + return IMPL.service_component_update(context, _id, values) + + +def service_component_get(context, _id): + return IMPL.service_component_get(context, _id) + + +def service_component_get_by_name(context, name): + return IMPL.service_component_get_by_name(context, name) + + +def service_component_get_all_by_node_for_service(context, + node_id, + service_id=None, + name=None): + return IMPL.service_component_get_all_by_node_for_service(context, + node_id, + service_id, + name) + + +def service_component_get_all(context): + return IMPL.service_component_get_all(context) + + +def service_component_delete(context, _id): + return IMPL.service_component_delete(context, _id) + + +# Service Worker +def service_worker_create(context, values): + return IMPL.service_worker_create(context, values) + + +def service_worker_update(context, _id, values): + return IMPL.service_worker_update(context, _id, values) + + +def service_worker_get(context, _id): + return IMPL.service_worker_get(context, _id) + + +def service_worker_get_by_name(context, name): + return IMPL.service_worker_get_by_name(context, name) + + +def service_worker_get_by_host_for_service_component(context, + service_component_id, + host=None): + return IMPL.service_worker_get_by_host_for_service_component( + context, + service_component_id, + host) + + +def service_worker_get_all(context): + return IMPL.service_worker_get_all(context) + + +def service_worker_delete(context, _id): + return IMPL.service_worker_delete(context, _id) + + +# Config + +def config_create(context, values): + return IMPL.config_create(context, values) + + +def config_update(context, _id, values): + return IMPL.config_update(context, _id, values) + + +def config_get(context, _id): + return IMPL.config_get(context, _id) + + +def config_get_by_name(context, name): + return IMPL.config_get_by_name(context, name) + + +def config_get_by_name_for_service_worker(context, + service_worker_id, + name=None): + return IMPL.config_get_by_name_for_service_worker(context, + service_worker_id, + name) + + +def config_get_all(context): + return IMPL.config_get_all(context) + + +def config_delete(context, _id): + return IMPL.config_delete(context, _id) + + +def service_perspective_get(context, service_id, + include_details=False): + return IMPL.service_perspective_get(context, + service_id, + include_details) + + +def device_perspective_get(context, device_id, + include_details=False): + return IMPL.device_perspective_get(context, + device_id, + include_details) + + +def region_perspective_get(context, region_id, + include_details=False): + return IMPL.region_perspective_get(context, + region_id, + include_details) + + +def infra_perspective_get(context): + return IMPL.infra_perspective_get(context) diff --git a/namos/db/migration.py b/namos/db/migration.py new file mode 100644 index 0000000..33848db --- /dev/null +++ b/namos/db/migration.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +# 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. + +"""Database setup and migration commands.""" + +# TODO(kanagaraj-manickam) Introduce the abstraction here and consume it +# in db_sync to make the db backend as portable diff --git a/namos/db/openstack_drivers.py b/namos/db/openstack_drivers.py new file mode 100644 index 0000000..ea1c997 --- /dev/null +++ b/namos/db/openstack_drivers.py @@ -0,0 +1,1435 @@ +# -*- coding: utf-8 -*- + +# 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 urlparse + +__all__ = ['get_drivers_config', + 'get_drivers_def'] + + +def _get_db_name(*args, **kwargs): + result = urlparse.urlparse(args[0]) + return '%s' % result.path.replace('/', '') + + +def _get_rpc_name(*args, **kwargs): + return '%s' % args[0] + + +_DRIVERS_CONFIG = { + # db + 'db_backend':{ + 'sqlalchemy': { #driver_class + # alias should be always end with driver class name. + 'alias':'database.backend:sqlalchemy', + } + }, + # TODO(mrkanag) sql_connectio is used in trove for db_backends + # just check it + 'database.backend': { + 'sqlalchemy': { #driver_class + 'endpoint': { + 'name': 'database.connection', + 'connection': { + # mysql://root:password@127.0.0.1/neutron?charset=utf8 + 'database.connection': 'database.connection' + } + }, + 'device': { + 'name': ['DB_%s', (_get_db_name, 'database.connection')] + } + } + }, + # rpc + 'rpc_backend':{ + 'rabbit': { + 'endpoint': { + 'name': 'rabbit_hosts', + 'connection': { + 'rabbit_hosts': 'rabbit_hosts', + 'rabbit_port': 'rabbit_port', + 'rabbit_userid': 'rabbit_userid', + 'rabbit_password': 'rabbit_password', + 'control_exchange': 'control_exchange' + } + }, + 'device': { + 'name': ['RPC_%s', (_get_rpc_name, 'control_exchange')] + } + }, + 'nova.openstack.common.rpc.impl_kombu': { + 'alias': 'rpc_backend:rabbit' + }, + 'cinder.openstack.common.rpc.impl_kombu': { + 'alias': 'rpc_backend:rabbit' + }, + 'neutron.openstack.common.rpc.impl_kombu': { + 'alias': 'rpc_backend:rabbit' + }, + 'glance.openstack.common.rpc.impl_kombu': { + 'alias': 'rpc_backend:rabbit' + }, + 'heat.openstack.common.rpc.impl_kombu': { + 'alias': 'rpc_backend:rabbit' + }, + 'namos.openstack.common.rpc.impl_kombu': { + 'alias': 'rpc_backend:rabbit' + } + }, + # nova + 'compute_driver' : { + 'libvirt.LibvirtDriver': { + 'endpoint': { + 'type': 'libvirt.virt_type', + 'kvm': { + 'name': 'host', + 'connection': { + 'libvirt.virt_type': 'libvirt.virt_type' + } + }, + 'qemu' : { + 'name': 'host', + 'connection': { + 'libvirt.virt_type': 'libvirt.virt_type' + } + }, + 'xen': { + 'name': 'xenapi_connection_url', + 'connection': { + 'xenapi_connection_url': 'xenapi_connection_url', + 'xenapi_connection_username': + 'xenapi_connection_username', + 'xenapi_connection_password': + 'xenapi_connection_password' + }, + 'device': { + 'name': ['%s %s', 'libvirt.virt_type', + 'xenapi_connection_url'] + } + }, + 'lxc': { + 'name': 'host', + 'connection': { + 'libvirt.virt_type': 'libvirt.virt_type' + } + }, + }, + 'device': { + 'name': ['%s host %s', 'libvirt.virt_type', 'host'] + } + }, + 'vmwareapi.VMwareVCDriver':{ + 'endpoint': { + 'name': 'vmware.host_ip', + 'connection': { + 'vmware.host_ip': 'vmware.host_ip', + 'vmware.host_username': 'vmware.host_username', + 'vmware.host_password': 'vmware.host_password', + 'vmware.cluster_name': 'vmware.cluster_name', + 'vmware.datastore_regex': 'vmware.datastore_regex' + }, + # When one driver supports mutiple devices, parent-child + # relation will be formed and parent usually has the + # endpoint associated with it, which is used by children + # devices + 'child_device': { + # TODO(mrkanag) key should be comma separated or list, + # just check !! + 'key': 'vmware.cluster_name', + 'base_name': ['VMWare Cluster %s', 'vmware.host_ip'] + # This name will be postfixed with device name got from key + } + }, + 'device': { + 'name': 'vmware.host_ip' + } + }, + 'nova.virt.hyperv.driver.HyperVDriver': { + 'endpoint': { + 'name': 'host', + 'connection': { + 'libvirt.type': 'libvirt.type' + } + }, + 'device':{ + 'name': ['Hyper-V host %s', 'host'] + } + } + }, + # cinder + 'volume_driver': { + 'cinder.volume.drivers.lvm.LVMISCSIDriver': { + 'endpoint': { + 'name': 'volume_group', + 'connection': { + 'volume_group': 'volume_group', + 'lvm_mirrors': 'lvm_mirrors', + 'lvm_type': 'lvm_type' + } + }, + 'device': { + 'name': ['%s@%s', 'volume_group', 'host'] + } + }, + 'cinder.volume.drivers.lvm.LVMISERDriver': { + 'alias': 'volume_driver:cinder.volume.drivers.lvm.LVMISCSIDriver' + }, + 'cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver': { + 'endpoint': { + 'name': 'hp3par_api_url', + 'connection': { + 'hp3par_api_url': 'hp3par_api_url', + 'hp3par_username': 'hp3par_username', + 'hp3par_password' : 'hp3par_password', + 'hp3par_cpg': 'hp3par_cpg', + 'san_ip': 'san_ip', + 'san_login':'san_login', + 'san_password': 'san_password', + 'hp3par_iscsi_ips': 'hp3par_iscsi_ips', + 'iscsi_ip_address': 'iscsi_ip_address' + }, + 'device': { + 'name': ['%s@%s', 'hp3par_cpg', 'san_ip'] + } + } + }, + 'cinder.volume.drivers.san.hp.hp_3par_fc.HP3PARFCDriver': { + 'alias': 'volume_driver:cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver' + }, + 'cinder.volume.drivers.san.hp.hp_lefthand_iscsi.HPLeftHandISCSIDriver': + { + 'endpoint': { + # TODO(mrkanag) type is not config param. what to do? + 'type': '#REST', + '#CLIQ': { + 'name': 'san_ip', + 'connection': { + 'san_ip': 'san_ip', + 'san_login': 'san_login', + 'san_password': 'san_password', + 'san_ssh_port': 'san_ssh_port', + 'san_clustername': 'san_clustername' + }, + 'device': { + 'name': ['%s@%s', 'san_clustername', 'san_ip'] + } + }, + '#REST': { + 'name': 'hplefthand_api_url', + 'connection': { + 'hplefthand_api_url': 'hplefthand_api_url', + 'hplefthand_username': 'hplefthand_username', + 'hplefthand_password': 'hplefthand_password', + 'hplefthand_clustername': 'hplefthand_clustername' + }, + 'device': { + 'name': ['%s@%s', 'hplefthand_clustername', + 'hplefthand_api_url'] + } + } + } + }, + 'cinder.volume.drivers.coraid.CoraidDriver': { + 'endpoint': { + 'name': 'coraid_esm_address', + 'connection': { + 'coraid_esm_address': 'coraid_esm_address', + 'coraid_user': 'coraid_user', + 'coraid_group': 'coraid_group', + 'coraid_password': 'coraid_password', + 'coraid_repository_key': 'coraid_repository_key' + } + }, + 'device': { + 'name': ['coraid %s', 'coraid_esm_address'] + } + }, + 'cinder.volume.drivers.eqlx.DellEQLSanISCSIDriver': { + 'endpoint': { + 'name': 'san_ip', + 'connection': { + 'san_ip': 'san_ip', + 'san_login': 'san_login', + 'san_password': 'san_password', + 'eqlx_group_name': 'eqlx_group_name', + 'eqlx_pool': 'eqlx_pool' + } + }, + 'device': { + 'name': ['%s@%s', 'eqlx_group_name', 'san_ip'] + } + }, + 'cinder.volume.drivers.emc.emc_vmax_iscsi.EMCVMAXISCSIDriver': { + 'endpoint': { + 'name': 'iscsi_ip_address', + 'connection': { + 'iscsi_ip_address': 'iscsi_ip_address', + # TODO(mrkanag) not sure what to do with config file + 'cinder_emc_config_file': 'cinder_emc_config_file' + } + }, + 'device': { + 'name': ['EMCVMAX %s', 'iscsi_ip_address'] + } + }, + 'cinder.volume.drivers.emc.emc_vmax_fc.EMCVMAXFCDriver': { + 'endpoint': { + 'name': '', + 'connection': { + 'cinder_emc_config_file': 'cinder_emc_config_file' + } + }, + 'device': { + # TODO(mrkanag) fill it + 'name': '' + } + }, + 'cinder.volume.drivers.emc.emc_cli_iscsi.EMCCLIISCSIDriver': { + 'endpoint': { + 'name': 'iscsi_ip_address', + 'connection': { + 'iscsi_ip_address': 'iscsi_ip_address', + 'san_ip': 'iscsi_ip_address', + 'san_login': 'san_login', + 'san_password': 'san_password', + 'naviseccli_path': 'naviseccli_path', + 'storage_vnx_pool_name': 'storage_vnx_pool_name', + 'default_timeout': 'default_timeout', + 'max_luns_per_storage_group': 'max_luns_per_storage_group' + } + }, + 'device': { + 'name': ['EMC %s@%s', 'storage_vnx_pool_name', 'san_ip'] + } + }, + 'cinder.volume.drivers.glusterfs.GlusterfsDriver': { + 'endpoint': { + 'name': 'glusterfs_mount_point_base', + 'connection': { + 'glusterfs_mount_point_base': 'glusterfs_mount_point_base', + 'glusterfs_shares_config': 'glusterfs_shares_config' + } + }, + 'device': { + 'name': ['Gfs %s', 'glusterfs_mount_point_base'] + } + }, + 'cinder.volume.drivers.hds.iscsi.HDSISCSIDriver': { + 'endpoint': { + 'name': 'HDS', + 'connection': { + 'hds_hnas_iscsi_config_file': 'hds_hnas_iscsi_config_file' + } + }, + 'device': { + 'name': 'HDS' + } + }, + 'cinder.volume.drivers.hds.nfs.HDSNFSDriver': { + 'endpoint': { + 'name': '', + 'connection': { + 'hds_hnas_nfs_config_file': 'hds_hnas_nfs_config_file' + } + }, + 'device': { + 'name': 'HDS' + } + }, + 'cinder.volume.drivers.hds.hds.HUSDriver': { + 'endpoint': { + 'name': '', + 'connection': { + 'hds_cinder_config_file': 'hds_cinder_config_file' + } + }, + 'device': { + 'name': 'HUS' + } + }, + 'cinder.volume.drivers.hitachi.hbsd_fc.HBSDFCDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.hitachi.hbsd_iscsi.HBSDISCSIDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.san.hp.hp_msa_fc.HPMSAFCDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.huawei.HuaweiVolumeDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.ibm.gpfs.GPFSDriver': { + 'endpoint': { + 'name': '', + 'connection': { + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.ibm.storwize_svc.StorwizeSVCDriver': { + 'endpoint': { + 'name': '', + 'connection': { + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.xiv_ds8k.XIVDS8KDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.netapp.common.NetAppDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.netapp.iscsi.NetAppDirectCmodeISCSIDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.netapp.nfs.NetAppDirectCmodeNfsDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.netapp.iscsi.NetAppDirect7modeISCSIDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.netapp.nfs.NetAppDirect7modeNfsDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.nexenta.iscsi.NexentaISCSIDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.nexenta.nfs.NexentaNfsDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.nfs.NfsDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.prophetstor.dpl_fc.DPLFCDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.prophetstor.dpl_iscsi.DPLISCSIDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.pure.PureISCSIDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.sheepdog.SheepdogDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.solidfire.SolidFireDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.windows.WindowsDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.xenapi.sm.XenAPINFSDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.zadara.ZadaraVPSAISCSIDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.volume.drivers.zfssa.zfssaiscsi.ZFSSAISCSIDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + } + }, + 'backup_driver': { + 'cinder.backup.drivers.ceph': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.backup.drivers.swift': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.backup.drivers.tsm': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + } + }, + 'zone_driver': { + 'cinder.zonemanager.drivers.brocade.brcd_fc_zone_driver.BrcdFCZoneDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + }, + 'cinder.zonemanager.drivers.cisco.cisco_fc_zone_driver.CiscoFCZoneDriver': { + 'endpoint': { + 'name': '', + 'connection': { + + } + }, + 'device': { + 'name': '' + } + } + }, + # neutron + # 'core_plugin': { + # 'neutron.plugins.ml2.plugin.Ml2Plugin': { + # + # } + # }, + # 'service_plugins': { + # 'neutron.services.l3_router.l3_router_plugin.L3RouterPlugin': { + # + # } + # }, + # 'service_providers.service_provider': { + # + # }, + 'dhcp_driver': { + 'neutron.agent.linux.dhcp.Dnsmasq': { + 'endpoint': { + 'name': 'dhcp_domain', + 'connection': { + 'dhcp_domain': 'dhcp_domain' + } + }, + 'device': { + 'name': ['DHCP %s', 'dhcp_domain'] + } + } + }, + 'interface_driver': { + 'neutron.agent.linux.interface.OVSInterfaceDriver': { + 'endpoint': { + 'name': 'ovs_integration_bridge', + 'connection': { + 'ovs_integration_bridge': 'ovs_integration_bridge' + } + }, + 'device': { + 'name': ['OVS bridge %s', 'ovs_integration_bridge'] + } + } + }, + # 'extension_drivers': { + # + # }, + 'ml2.mechanism_drivers': { + 'linuxbridge' : { + 'alias': 'ml2.mechanism_drivers:neutron.plugins.ml2.drivers.mech_linuxbridge.LinuxbridgeMechanismDriver' + }, + 'neutron.plugins.ml2.drivers.mech_linuxbridge.LinuxbridgeMechanismDriver': { + 'endpoint': { + 'name': '#Linux Bride', + 'connection': { + } + }, + 'device': { + 'name': '#Linux Bride' + } + }, + 'openvswitch': { + 'alias': 'ml2.mechanism_drivers:neutron.plugins.ml2.drivers.mech_openvswitch.OpenvswitchMechanismDriver' + }, + 'neutron.plugins.ml2.drivers.mech_openvswitch.OpenvswitchMechanismDriver': { + 'endpoint': { + 'name': '#OVS', + 'connection': { + } + }, + 'device': { + 'name': '#OVS' + } + } + }, + 'ml2.type_drivers': { + 'local': { + 'alias': 'ml2.type_drivers:neutron.plugins.ml2.drivers.type_local.LocalTypeDriver' + }, + 'neutron.plugins.ml2.drivers.type_local.LocalTypeDriver': { + 'endpoint': { + 'name': '#Local Type', + 'connection': { + } + }, + 'device': { + 'name': '#Local Type' + } + }, + 'flat': { + 'alias': 'ml2.type_drivers:neutron.plugins.ml2.drivers.type_flat.FlatTypeDriver' + }, + 'neutron.plugins.ml2.drivers.type_flat.FlatTypeDriver': { + 'endpoint': { + 'name': '#FLAT Type', + 'connection': { + } + }, + 'device': { + 'name': '#FLAT type' + } + }, + 'vlan': { + 'alias': 'ml2.type_drivers:neutron.plugins.ml2.drivers.type_vlan.VlanTypeDriver' + }, + 'neutron.plugins.ml2.drivers.type_vlan.VlanTypeDriver': { + 'endpoint': { + 'name': '#VLAN Type', + 'connection': { + } + }, + 'device': { + 'name': '#VLAN Type' + } + }, + 'gre': { + 'alias': 'ml2.type_drivers:neutron.plugins.ml2.drivers.type_gre.GreTypeDriver' + }, + 'neutron.plugins.ml2.drivers.type_gre.GreTypeDriver': { + 'endpoint': { + 'name': '#GRE Type', + 'connection': { + } + }, + 'device': { + 'name': '#GRE Type' + } + }, + 'vxlan': { + 'alias': 'ml2.type_drivers:neutron.plugins.ml2.drivers.type_vxlan.VxlanTypeDriver' + }, + 'neutron.plugins.ml2.drivers.type_vxlan.VxlanTypeDriver': { + 'endpoint': { + 'name': '#VxLAN Type', + 'connection': { + } + }, + 'device': { + 'name': '#VxLAN Type' + } + }, + }, + 'firewall_driver': { + 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver': { + 'endpoint': { + 'name': '#Firewall', + 'connection': { + } + }, + 'device': { + 'name': '#Firewall' + } + }, + 'nova.virt.firewall.NoopFirewallDriver' : { + 'endpoint': { + 'name': '#NoopFirewall', + 'connection': { + } + }, + 'device': { + 'name': '#Firewall' + } + } + }, + 'SECURITY_GROUP.firewall_driver': { + 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver': { + 'alias': 'firewall_driver:neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver' + } + }, + + # 'dhcp_agent_manager': { + # + # }, + # 'l3_agent_manager': { + # + # }, + # Glance + 'glance_store.stores': { + 'file': { + 'alias': 'glance_store.stores:glance_store._drivers.filesystem.Store' + }, + 'filesystem': { + 'alias': 'glance_store.stores:glance_store._drivers.filesystem.Store' + }, + 'glance_store._drivers.filesystem.Store': { + 'endpoint': { + 'name': 'glance_store.filesystem_store_datadir', + 'connection': { + 'glance_store.filesystem_store_datadir': 'glance_store.filesystem_store_datadir', + 'glance_store.filesystem_store_datadirs': 'glance_store.filesystem_store_datadirs', + 'glance_store.filesystem_store_file_perm': 'glance_store.filesystem_store_file_perm', + 'glance_store.filesystem_store_metadata_file': + 'glance_store.filesystem_store_metadata_file' + } + }, + 'device': { + 'name': ['File System Store %s', 'glance_store.filesystem_store_datadir'] + } + }, + 'http': { + 'alias': 'glance_store.stores:glance_store._drivers.http.Store' + }, + 'https': { + 'alias': 'glance_store.stores:glance_store._drivers.http.Store' + }, + 'glance_store._drivers.http.Store': { + 'endpoint': { + 'name': '#http', + 'connection': { + } + }, + 'device': { + 'name': '#http Image beackend' + } + }, + 'cinder': { + 'alias': 'glance_store.stores:glance_store._drivers.cinder.Store' + }, + 'glance_store._drivers.cinder.Store': { + 'endpoint': { + 'name': '#Cinder Image Backend', + 'connection': { + 'glance_store.cinder_endpoint_template': 'glance_store.cinder_endpoint_template', + 'glance_store.cinder_api_insecure': 'glance_store.cinder_api_insecure', + 'glance_store.cinder_ca_certificates_file': + 'glance_store.cinder_ca_certificates_file', + 'glance_store.cinder_catalog_info': 'glance_store.cinder_catalog_info', + 'glance_store.cinder_http_retries': 'glance_store.cinder_http_retries' + } + }, + 'device': { + 'name': '#Cinder Image Backend' + } + }, + 'swift': { + 'alias': 'glance_store.stores:glance_store._drivers.swift.Store' + }, + 'glance_store._drivers.swift.Store': { + 'endpoint': { + 'name': 'glance_store.default_swift_reference', + 'connection': { + 'glance_store.default_swift_reference': 'glance_store.default_swift_reference', + 'glance_store.swift_enable_snet': 'glance_store.swift_enable_snet', + 'glance_store.swift_store_admin_tenants': 'glance_store.swift_store_admin_tenants', + 'glance_store.swift_store_auth_address': 'glance_store.swift_store_auth_address', + 'glance_store.swift_store_auth_insecure': 'glance_store.swift_store_auth_insecure', + 'glance_store.swift_store_auth_version': 'glance_store.swift_store_auth_version', + 'glance_store.swift_store_config_file': 'glance_store.swift_store_config_file', + 'glance_store.swift_store_container': 'glance_store.swift_store_container', + 'glance_store.swift_store_create_container_on_put': 'glance_store.swift_store_create_container_on_put', + 'glance_store.swift_store_endpoint_type': 'glance_store.swift_store_endpoint_type', + 'glance_store.swift_store_key': 'glance_store.swift_store_key', + 'glance_store.swift_store_large_object_chunk_size': 'glance_store.swift_store_large_object_chunk_size', + 'glance_store.swift_store_large_object_size': 'glance_store.swift_store_large_object_size', + 'glance_store.swift_store_multi_tenant': 'glance_store.swift_store_multi_tenant', + 'glance_store.swift_store_region': 'glance_store.swift_store_region', + 'glance_store.swift_store_retry_get_count': 'glance_store.swift_store_retry_get_count', + 'glance_store.swift_store_service_type': 'glance_store.swift_store_service_type', + 'glance_store.swift_store_ssl_compression': 'glance_store.swift_store_ssl_compression', + 'glance_store.swift_store_user': 'glance_store.swift_store_user' + } + }, + 'device': { + 'name': ['Swift Image backend %s', 'glance_store.default_swift_reference'] + } + }, + 'rbd': { + 'alias': 'glance_store.stores:glance_store._drivers.rbd.Store' + }, + 'glance_store._drivers.rbd.Store': { + 'endpoint': { + 'name': 'glance_store.rbd_store_pool', + 'connection': { + 'glance_store.rbd_store_ceph_conf': 'glance_store.rbd_store_ceph_conf', + 'glance_store.rbd_store_chunk_size': 'glance_store.rbd_store_chunk_size', + 'glance_store.rbd_store_pool': 'glance_store.rbd_store_pool', + 'glance_store.rbd_store_user': 'glance_store.rbd_store_user' + } + }, + 'device': { + 'name': ['RBD Image backend %s', 'glance_store.rbd_store_pool'] + } + }, + 'sheepdog': { + 'alias': 'glance_store.stores:glance_store._drivers.sheepdog.Store' + }, + 'glance_store._drivers.sheepdog.Store': { + 'endpoint': { + 'name': 'glance_store.sheepdog_store_address', + 'connection': { + 'glance_store.sheepdog_store_address': 'glance_store.sheepdog_store_address', + 'glance_store.sheepdog_store_chunk_size': 'glance_store.sheepdog_store_chunk_size', + 'glance_store.sheepdog_store_port': 'glance_store.sheepdog_store_port' + } + }, + 'device': { + 'name': ['Sheepdog Image backend %s', 'glance_store.sheepdog_store_address'] + } + }, + 'gridfs': { + 'alias': 'glance_store.stores:glance_store._drivers.gridfs.Store' + }, + 'glance_store._drivers.gridfs.Store': { + 'endpoint': { + 'name': 'glance_store.mongodb_store_uri', + 'connection': { + 'glance_store.mongodb_store_db': 'glance_store.mongodb_store_db', + 'glance_store.mongodb_store_uri': 'glance_store.mongodb_store_uri' + } + }, + 'device': { + 'name': ['Gird FS Image backend %s', 'glance_store.mongodb_store_db'] + } + }, + 's3': { + 'alias': 'glance_store.stores:glance_store._drivers.s3.Store' + }, + 's3+http': { + 'alias': 'glance_store.stores:glance_store._drivers.s3.Store' + }, + 's3': { + 'alias': 'glance_store.stores:glance_store._drivers.s3.Store' + }, + 'glance_store._drivers.s3.Store': { + 'endpoint': { + 'name': ['%s/%s', 'glance_store.s3_store_host', 'glance_store.s3_store_bucket'], + 'connection': { + 'glance_store.s3_store_host': 'glance_store.s3_store_host', + 'glance_store.s3_store_bucket': 'glance_store.s3_store_bucket', + 'glance_store.s3_store_object_buffer_dir': 'glance_store.s3_store_object_buffer_dir', + 'glance_store.s3_store_secret_key': 'glance_store.s3_store_secret_key', + 'glance_store.s3_store_create_bucket_on_put': 'glance_store.s3_store_create_bucket_on_put', + 'glance_store.s3_store_bucket_url_format': 'glance_store.s3_store_bucket_url_format', + 'glance_store.s3_store_access_key': 'glance_store.s3_store_access_key' + } + }, + 'device': { + 'name': ['S3 Image Backend %s/%s', + 'glance_store.s3_store_host', + 'glance_store.s3_store_bucket'] + } + }, + 'vsphere': { + 'alias': 'glance_store.stores:glance_store._drivers.vmware_datastore.Store' + }, + 'glance_store._drivers.vmware_datastore.Store': { + 'endpoint': { + 'name': ['%s/%s', + 'glance_store.vmware_server_host', + 'glance_store.vmware_datastore_name' + ], + 'connection': { + 'glance_store.vmware_api_insecure': 'glance_store.vmware_api_insecure', + 'glance_store.vmware_api_retry_count': 'glance_store.vmware_api_retry_count', + 'glance_store.vmware_datacenter_path': 'glance_store.vmware_datacenter_path', + 'glance_store.vmware_datastore_name': 'glance_store.vmware_datastore_name', + 'glance_store.vmware_server_host': 'glance_store.vmware_server_host', + 'glance_store.vmware_server_password': 'glance_store.vmware_server_password', + 'glance_store.vmware_server_username': 'glance_store.vmware_server_username', + 'glance_store.vmware_store_image_dir': 'glance_store.vmware_store_image_dir', + 'glance_store.vmware_task_poll_interval': 'glance_store.vmware_task_poll_interval' + } + }, + 'device': { + 'name': ['VMWare Image backend %s/%s', + 'glance_store.vmware_server_host', + 'glance_store.vmware_datastore_name' + ] + } + } + } +} + +_DRIVERS = { + 'sqlalchemy': { + 'type': 'database', + 'extra': { + 'url': 'https://pypi.python.org/pypi/SQLAlchemy', + 'python_class': 'sqlalchemy', + 'version': '0.9.8', + 'device_support': [ + { + 'vendor': 'MYSQL', + 'model': 'MYSQL', + 'version': ['5.6','5.7'] + } + ], + 'configuration_guide':'', + 'metadata': { + 'wiki': '' + } + } + }, + 'rabbit': { + 'type': 'message', + 'extra': { + 'url': 'https://github.com/openstack/oslo.messaging', + 'python_class': '%{service_type}s.openstack.common.rpc.impl_kombu', + 'version': '0.9.8', + 'device_support': [ + { + 'vendor': 'RabbitMQ', + 'model': 'RabbitMQ Server', + 'version': ['3.4','3.5'] + } + ], + 'configuration_guide':'', + 'metadata': { + 'wiki': '' + } + } + }, + 'vmwareapi.VMwareVCDriver': { + 'type': 'nova', + 'class': 'hypervisor', + 'extra': { + 'url': 'https://github.com/openstack/nova', + 'python_class': 'nova.virt.vmwareapi.VMwareVCDriver', + 'version': '2014.5', + 'device_support': [ + { + 'vendor': 'VMWare', + 'model': 'vSphere', + 'version': ['5.0','5.1'] + } + ], + 'configuration_guide':'', + 'metadata': { + 'wiki': '' + } + } + }, + 'libvirt.LibvirtDriver': { + 'type': 'nova', + 'class': ['hypervisor', 'container'], + 'extra' : { + 'url': 'https://github.com/openstack/nova', + 'python_class': 'nova.virt.libvirt.LibvirtDriver', + 'version': '2014.5', + 'device_support': [ + { + 'vendor': 'KVM, LXC, QEMU, UML, and XEN', + 'model': 'KVM', + 'version': ['5.0','5.1'] + } + ], + 'configuration_guide':'', + 'metadata': { + 'libvirt_supports': 'https://wiki.openstack.org/wiki/LibvirtDistroSupportMatrix' + } + } + }, + 'nova.virt.hyperv.driver.HyperVDriver': { + 'type': 'nova', + 'extra' : { + 'url': 'https://github.com/openstack/nova', + 'python_class': 'nova.virt.hyperv.driver.HyperVDriver', + 'version': '2014.5', + 'device_support': [ + { + 'vendor': 'Microsoft', + 'model': 'Hyper-V', + 'version': ['2014'] + } + ], + 'configuration_guide':'', + 'metadata': { + } + } + }, + 'cinder.volume.drivers.lvm.LVMISCSIDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.lvm.LVMISERDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.san.hp.hp_3par_fc.HP3PARFCDriver': { + 'type': 'cinder', + 'class': 'volume', + 'requirements_txt': { + # TODO(mrkanag) Add installer reqs here, pip pkg or apt pkg or + # any other OS packages + }, + 'apt_get_list': { + + }, + 'deprecation': { + 'alternate': '', + 'since': '2012.1' + } + }, + 'cinder.volume.drivers.san.hp.hp_lefthand_iscsi.HPLeftHandISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.coraid.CoraidDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.eqlx.DellEQLSanISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.emc.emc_vmax_iscsi.EMCVMAXISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.emc.emc_vmax_fc.EMCVMAXFCDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.emc.emc_cli_iscsi.EMCCLIISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.glusterfs.GlusterfsDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.hds.iscsi.HDSISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.hds.nfs.HDSNFSDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.hds.hds.HUSDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.hitachi.hbsd_fc.HBSDFCDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.hitachi.hbsd_iscsi.HBSDISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.san.hp.hp_msa_fc.HPMSAFCDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.huawei.HuaweiVolumeDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.ibm.gpfs.GPFSDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.ibm.storwize_svc.StorwizeSVCDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.xiv_ds8k.XIVDS8KDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.netapp.common.NetAppDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.netapp.iscsi.NetAppDirectCmodeISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.netapp.nfs.NetAppDirectCmodeNfsDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.netapp.iscsi.NetAppDirect7modeISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.netapp.nfs.NetAppDirect7modeNfsDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.nexenta.iscsi.NexentaISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.nexenta.nfs.NexentaNfsDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.nfs.NfsDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.prophetstor.dpl_fc.DPLFCDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.prophetstor.dpl_iscsi.DPLISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.pure.PureISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.sheepdog.SheepdogDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.solidfire.SolidFireDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver': { + 'type': 'cinder', + 'class': 'volume', + 'compute_driver': 'vmwareapi.VMwareVCDriver' + }, + 'cinder.volume.drivers.windows.WindowsDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.xenapi.sm.XenAPINFSDriver': { + 'type': 'cinder', + 'class': 'volume' + }, + 'cinder.volume.drivers.zadara.ZadaraVPSAISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.volume.drivers.zfssa.zfssaiscsi.ZFSSAISCSIDriver': { + 'type': 'cinder', + 'class': 'volume', + 'protocol': 'iSCSI' + }, + 'cinder.backup.drivers.ceph': { + 'type': 'cinder', + 'class': 'backup' + }, + 'cinder.backup.drivers.tsm': { + 'type': 'cinder', + 'class': 'backup' + }, + 'cinder.backup.drivers.swift': { + 'type': 'cinder', + 'class': 'backup' + }, + 'cinder.zonemanager.drivers.brocade.brcd_fc_zone_driver.BrcdFCZoneDriver': + { + 'type': 'cinder', + 'class': 'zone_manager' + }, + 'cinder.zonemanager.drivers.cisco.cisco_fc_zone_driver.CiscoFCZoneDriver': + { + 'type': 'cinder', + 'class': 'zone_manager' + }, + 'glance_store._drivers.filesystem.Store': { + 'type': 'glance' + }, + 'glance_store._drivers.http.Store': { + 'type': 'glance' + }, + 'glance_store._drivers.cinder.Store': { + 'type': 'glance' + }, + 'glance_store._drivers.swift.Store': { + 'type': 'glance' + }, + 'glance_store._drivers.rbd.Store': { + 'type': 'glance' + }, + 'glance_store._drivers.gridfs.Store': { + 'type': 'glance' + }, + 'glance_store._drivers.vmware_datstore.Store': { + 'type': 'glance' + }, + 'glance_store._drivers.filesystem.Store': { + 'type': 'glance' + }, + 'neutron.agent.linux.interface.OVSInterfaceDriver': { + 'type': 'neutron' + }, + 'neutron.agent.linux.dhcp.Dnsmasq': { + 'type': 'neutron' + }, + 'neutron.agent.linux.interface.OVSInterfaceDriver': { + 'type': 'neutron' + }, + 'neutron.plugins.ml2.drivers.mech_linuxbridge.LinuxbridgeMechanismDriver': { + 'type': 'neutron' + }, + 'neutron.plugins.ml2.drivers.mech_openvswitch.OpenvswitchMechanismDriver': { + 'type': 'neutron' + }, + 'neutron.plugins.ml2.drivers.type_local.LocalTypeDriver': { + 'type': 'neutron' + }, + 'neutron.plugins.ml2.drivers.type_flat.FlatTypeDriver': { + 'type': 'neutron' + }, + 'neutron.plugins.ml2.drivers.type_vlan.VlanTypeDriver': { + 'type': 'neutron' + }, + 'neutron.plugins.ml2.drivers.type_gre.GreTypeDriver': { + 'type': 'neutron' + }, + 'neutron.plugins.ml2.drivers.type_vxlan.VxlanTypeDriver': { + 'type': 'neutron' + }, + 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver': { + 'type': 'neutron' + }, + 'nova.virt.firewall.NoopFirewallDriver' : { + 'type': 'neutron' + }, + 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver': { + 'type': 'neutron' + } +} + + +def get_drivers_config(): + return _DRIVERS_CONFIG + + +def get_drivers_def(): + return _DRIVERS diff --git a/namos/db/sample.py b/namos/db/sample.py new file mode 100644 index 0000000..9c20b18 --- /dev/null +++ b/namos/db/sample.py @@ -0,0 +1,444 @@ +# -*- coding: utf-8 -*- + +# 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 namos.db import api + +REGION_LIST = [ + {'f7dcd175-27ef-46b5-997f-e6e572f320af': + {'name': 'RegionOne', + 'keystone_region_id': 'region_one', + 'extra': {'location': 'bangalore'}} + }, + {'f7dcd175-27ef-46b5-997f-e6e572f320b0': + {'name': 'RegionTwo', + 'keystone_region_id': 'region_two', + 'extra': {'location': 'chennai'}} + } +] + +DEVICE_LIST = [ + # vCenter + {'91007d3c-9c95-40c5-8f94-c7b071f9b577': + { + 'name': 'Vmware_vCenter_1', + 'display_name': 'VMWare vCenter 1', + 'description': 'vCenter 5.0', + 'status': 'active', + 'extra': {'owner': 'mkr1481@namos.com'}, + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'} + }, + # Clusters + {'d468ea2e-74f6-4a55-a7f4-a56d18e91c66': + { + 'name': 'vmware_vc_Cluster_1', + 'display_name': 'VMWare vCenter 1 Cluster 1', + 'description': 'Cluster 1 having 3 hosts', + 'status': 'active', + 'extra': {'owner': 'mkr1481@namos.com', + 'vcpus': 1000, + 'ram_in_gb': 1024}, + 'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'} + }, + {'6c97f476-8e27-4e21-8528-a5ec236306f3': + {'name': 'vmware_vc_Cluster_2', + 'display_name': 'VMWare vCenter 1 Cluster 2', + 'description': 'Cluster 2 having 5 hosts', + 'status': 'active', + 'extra': {'owner': 'mkr1481@namos.com'}, + 'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'} + }, + # Datastores + {'fdab6c51-38fb-4fb1-a76f-9c243a8b8296': + {'name': 'Vmware_vCenter_1_datastore_1', + 'display_name': 'VMWare vCenter 1 datastore 1', + 'description': 'vCenter 5.0 Datastore created from FC', + 'status': 'active', + 'extra': {'owner': 'mkr1481@namos.com', + 'size_in_gb': '102400'}, + 'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'} + }, + {'05b935b3-942c-439c-a6a4-9c3c73285430': + {'name': 'Vmware_vCenter_1_datastore_2', + 'display_name': 'VMWare vCenter 1 datastore 2', + 'description': 'vCenter 5.0 Datastore created from FC', + 'status': 'active', + 'extra': {'owner': 'mkr1481@namos.com', + 'size_in_gb': '10240'}, + 'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'} + }, + # Switch + {'f062556b-45c4-417d-80fa-4283b9c58da3': + {'name': 'Vmware_vCenter_1_switch_1', + 'display_name': 'VMWare vCenter 1 Dist. vSwitch 1', + 'description': 'vCenter 5.0 distributed virtual switch', + 'status': 'active', + 'extra': {'owner': 'mkr1481@namos.com'}, + 'parent_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af'} + } +] + +ENDPOINT_LIST = [ + {'7403bf80-9376-4081-89ee-d2501661ca84':{ + 'name': 'vcenter1_connection', + 'connection': {'host_ip': '10.1.1.3', + 'host_port': 443, + 'host_username': 'adminstrator', + 'host_password': 'password'}, + 'device_id': '91007d3c-9c95-40c5-8f94-c7b071f9b577' + }} +] + + +DEVICE_DRIVER_CLASS_LIST = [ + {'0664e8c0-ff02-427e-8fa3-8788c017ad84': { + 'python_class': 'nova...vcdriver', + 'type': 'compute', + 'vendor': 'vmware-community' + }}, + {'11caf99c-f820-4266-a461-5a15437a8144': { + 'python_class': 'cinder...vmdkdriver', + 'type': 'volume', + 'vendor': 'vmware-community' + }}, + {'bb99ea96-fe6b-49e6-a761-faea92b79f75': { + 'python_class': 'neutron...nsxdriver', + 'type': 'network', + 'vendor': 'vmware-community' + }} +] + +DEVICE_DRIVER_LIST = [ + # nova + {'3c089cdb-e1d5-4182-9a8e-cef9899fd7e5':{ + 'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84', + 'device_driver_class_id':'0664e8c0-ff02-427e-8fa3-8788c017ad84', + 'device_id': 'd468ea2e-74f6-4a55-a7f4-a56d18e91c66' + }}, + # nova + {'4e0360ae-0728-4bfd-a557-3ad867231787':{ + 'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84', + 'device_driver_class_id':'0664e8c0-ff02-427e-8fa3-8788c017ad84', + 'device_id': '6c97f476-8e27-4e21-8528-a5ec236306f3' + }}, + # cinder + {'92d5e2c1-511b-4837-a57d-5e6ee723060c':{ + 'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84', + 'device_driver_class_id':'11caf99c-f820-4266-a461-5a15437a8144', + 'device_id': 'fdab6c51-38fb-4fb1-a76f-9c243a8b8296' + }}, + # cinder + {'f3d807a0-eff0-4473-8ae5-594967136e05':{ + 'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84', + 'python_class_id':'11caf99c-f820-4266-a461-5a15437a8144', + 'device_id': '05b935b3-942c-439c-a6a4-9c3c73285430' + }}, + # neutron + {'f27eb548-929c-45e2-a2a7-dc123e2a1bc7':{ + 'endpoint_id': '7403bf80-9376-4081-89ee-d2501661ca84', + 'python_class_id':'bb99ea96-fe6b-49e6-a761-faea92b79f75', + 'device_id': 'f062556b-45c4-417d-80fa-4283b9c58da3' + }} +] + + +SERVICE_LIST =[ + {'11367a37-976f-468a-b8dd-77b28ee63cf4': { + 'name': 'nova_service', + 'keystone_service_id': 'b9c2549f-f685-4bc2-92e9-ba8af9c18599' + }}, + {'809e04c1-2f3b-43af-9677-3428a0154216': { + 'name': 'cinder_service', + 'keystone_service_id': '9cc4c374-abb5-4bdc-9129-f0fa4bba0e0b' + }}, + {'3495fa07-39d9-4d87-9f97-0a582a3e25c3': { + 'name': 'neutron_service', + 'keystone_service_id': 'b24e2884-75bc-4876-81d1-5b4fb6e92afc' + }} +] + +SERVICE_NODE_LIST = [ + { + 'a5073d58-2dbb-4146-b47c-4e5f7dc11fbe': { + 'name': 'd_network_node_1', + 'fqdn': 'network_node_1.devstack1.abc.com', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af' + } + }, + { + '4e99a641-dbe9-416e-8c0a-78015dc55a2a': { + 'name': 'd_compute_node_1', + 'fqdn': 'compute_node_1.devstack.abc.com', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af' + } + }, + { + 'b92f4811-7970-421b-a611-d51c62972388': { + 'name': 'd_cloud-controller-1', + 'fqdn': 'cloud_controller_1.devstack1.abc.com', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af' + } + }, + { + 'e5913cd3-a416-40e1-889f-1a1b1c53001c': { + 'name': 'd_storage_node_1', + 'fqdn': 'storage_node_1.devstack.abc.com', + 'region_id': 'f7dcd175-27ef-46b5-997f-e6e572f320af' + } + } +] + + +SERVICE_COMPONENT_LIST = [ + # nova + { + '7259a9ff-2e6f-4e8d-b2fb-a529188825dd': { + 'name': 'd_nova-compute', + 'node_id': '4e99a641-dbe9-416e-8c0a-78015dc55a2a', + 'service_id': '11367a37-976f-468a-b8dd-77b28ee63cf4' + } + }, + { + 'e5e366ea-9029-4ba0-8bbc-f658e642aa54': { + 'name': 'd_nova-scheduler', + 'node_id': 'b92f4811-7970-421b-a611-d51c62972388', + 'service_id': '11367a37-976f-468a-b8dd-77b28ee63cf4' + } + }, + { + 'f7813622-85ee-4588-871d-42c3128fa14f': { + 'name': 'd_nova-api', + 'node_id': 'b92f4811-7970-421b-a611-d51c62972388', + 'service_id': '11367a37-976f-468a-b8dd-77b28ee63cf4' + } + }, + # cinder + { + 'b0e9ac3f-5600-406c-95e4-f698b1eecfc6': { + 'name': 'd_cinder-volume', + 'node_id': 'e5913cd3-a416-40e1-889f-1a1b1c53001c', + 'service_id': '809e04c1-2f3b-43af-9677-3428a0154216' + } + }, + # neutron + { + '54f608bd-fb01-4614-9653-acbb803aeaf7':{ + 'name': 'd_neutron-agent', + 'node_id': 'a5073d58-2dbb-4146-b47c-4e5f7dc11fbe', + 'service_id': '3495fa07-39d9-4d87-9f97-0a582a3e25c3' + } + } +] + +SERVICE_WORKER_LIST = [ + # cluster-1 + { + '65dbd695-fa92-4950-b8b4-d46aa0408f6a': { + 'name': 'd_nova-compute-esx-cluster1', + 'pid': '1233454343', + 'host': 'd_nova-compute-esx-cluster1', + 'service_component_id': '7259a9ff-2e6f-4e8d-b2fb-a529188825dd', + 'device_driver_id': '3c089cdb-e1d5-4182-9a8e-cef9899fd7e5' + } + }, + # cluster-2 + { + '50d2c0c6-741d-4108-a3a2-2090eaa0be37': { + 'name': 'd_nova-compute-esx-cluster2', + 'pid': '1233454344', + 'host': 'd_nova-compute-esx-cluster2', + 'service_component_id': '7259a9ff-2e6f-4e8d-b2fb-a529188825dd', + 'device_driver_id': '4e0360ae-0728-4bfd-a557-3ad867231787' + } + }, + # datastore-1 + { + '77e3ee16-fa2b-4e12-ad1c-226971d1a482': { + 'name': 'd_cinder-volume-vmdk-1', + 'pid': '09878654', + 'host': 'd_cinder-volume-vmdk-1', + 'service_component_id': 'b0e9ac3f-5600-406c-95e4-f698b1eecfc6', + 'device_driver_id': '92d5e2c1-511b-4837-a57d-5e6ee723060c' + } + }, + # datastore-2 + { + '8633ce68-2b02-4efd-983c-49a460f6d7ef': { + 'name': 'd_cinder-volume-vmdk-2', + 'pid': '4353453', + 'host': 'd_cinder-volume-vmdk-2', + 'service_component_id': 'b0e9ac3f-5600-406c-95e4-f698b1eecfc6', + 'device_driver_id': 'f3d807a0-eff0-4473-8ae5-594967136e05' + } + }, + # vswitch + { + '5a3ac5b9-9186-45d8-928c-9e702368dfb4': { + 'name': 'd_neutron-agent', + 'pid': '2359234', + 'host': 'd_neutron-agent', + 'service_component_id': '54f608bd-fb01-4614-9653-acbb803aeaf7', + 'device_driver_id': 'f27eb548-929c-45e2-a2a7-dc123e2a1bc7' + } + }, +] + +CONFIG_LIST = [ + { + 'dc6aa02f-ba70-4410-a59c-5e113e629fe5': { + 'name':'vmware.host_ip', + 'value':'10.1.0.1', + 'help': 'VMWare vcenter IP address', + 'default':'', + 'type':'String', + 'required':True, + 'secret': False, + 'config_file':'/etc/nova/nova.conf', + 'service_worker_id': '65dbd695-fa92-4950-b8b4-d46aa0408f6a' + } + }, + { + 'dc6aa02f-ba70-4410-a59c-5e113e629f10': { + 'name':'vmware.host_username', + 'value':'Administraotr', + 'help': 'VMWare vcenter Username', + 'default':'Administrator', + 'type':'String', + 'required':True, + 'secret': False, + 'file':'/etc/nova/nova.conf', + 'service_worker_id': '65dbd695-fa92-4950-b8b4-d46aa0408f6a' + } + }, + { + 'dc6aa02f-ba70-4410-a59c-5e113e629f11': { + 'name':'vmware.host_password', + 'value':'password', + 'help': 'VMWare vcenter password', + 'default':'', + 'type':'String', + 'required':True, + 'secret': True, + 'file':'/etc/nova/nova.conf', + 'service_worker_id': '65dbd695-fa92-4950-b8b4-d46aa0408f6a' + }, + } +] + + +def inject_id(value): + if isinstance(value, dict): + _id = value.keys()[0] + value1 = value[_id].copy() + value1['id'] = _id + + return value1 + return value + + +def _device_populate_demo_data(): + for region in REGION_LIST: + region = inject_id(region) + api.region_create(None, region) + + for device in DEVICE_LIST: + device = inject_id(device) + api.device_create(None, device) + + for device_endpoint in ENDPOINT_LIST: + device_endpoint = inject_id(device_endpoint) + api.device_endpoint_create(None, device_endpoint) + + # TODO(kanagaraj-manickam) Move this to alembic upgrade + for device_driver_class in DEVICE_DRIVER_CLASS_LIST: + device_driver_class = inject_id(device_driver_class) + api.device_driver_class_create(None, device_driver_class) + + for device_driver in DEVICE_DRIVER_LIST: + device_driver = inject_id(device_driver) + api.device_driver_create(None, device_driver) + + +def _service_populate_demo_data(): + for service in SERVICE_LIST: + service = inject_id(service) + api.service_create(None, service) + + for service_node in SERVICE_NODE_LIST: + service_node = inject_id(service_node) + api.service_node_create(None, service_node) + + for service_component in SERVICE_COMPONENT_LIST: + service_component = inject_id(service_component) + api.service_component_create(None, service_component) + + for service_worker in SERVICE_WORKER_LIST: + service_worker = inject_id(service_worker) + api.service_worker_create(None, service_worker) + + for config in CONFIG_LIST: + config = inject_id(config) + api.config_create(None, config) + + +def populate_demo_data(): + _device_populate_demo_data() + _service_populate_demo_data() + + +def _device_purge_demo_data(): + for device_driver in DEVICE_DRIVER_LIST: + api.device_driver_delete(None, device_driver.keys()[0]) + + for device_endpoint in ENDPOINT_LIST: + api.device_endpoint_delete(None, device_endpoint.keys()[0]) + + # Reverse the order of delete from child to parent device + for device in DEVICE_LIST[::-1]: + api.device_delete(None, device.keys()[0]) + + # TODO(kanagaraj-manickam) Move this to alembic downgrade + for device_driver_class in DEVICE_DRIVER_CLASS_LIST: + api.device_driver_class_delete(None, device_driver_class.keys()[0]) + + +def _service_purge_demo_data(): + for config in CONFIG_LIST: + api.config_delete(None, config.keys()[0]) + for service_worker in SERVICE_WORKER_LIST: + api.service_worker_delete(None, service_worker.keys()[0]) + + for service_component in SERVICE_COMPONENT_LIST: + api.service_component_delete(None, service_component.keys()[0]) + + for service_node in SERVICE_NODE_LIST: + api.service_node_delete(None, service_node.keys()[0]) + + for service in SERVICE_LIST: + api.service_delete(None, service.keys()[0]) + + +def _region_purge_demo_data(): + for region in REGION_LIST: + api.region_delete(None, region.keys()[0]) + + +def purge_demo_data(): + _service_purge_demo_data() + _device_purge_demo_data() + _region_purge_demo_data() diff --git a/namos/db/sqlalchemy/__init__.py b/namos/db/sqlalchemy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/namos/db/sqlalchemy/alembic.ini b/namos/db/sqlalchemy/alembic.ini new file mode 100644 index 0000000..4bc5b83 --- /dev/null +++ b/namos/db/sqlalchemy/alembic.ini @@ -0,0 +1,59 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = %(here)s/alembic + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# max length of characters to apply to the +# "slug" field +#truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +#sqlalchemy.url = driver://user:pass@localhost/dbname +#sqlalchemy.url = mysql+mysqldb://root:password@localhost/namos + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/namos/db/sqlalchemy/alembic/env.py b/namos/db/sqlalchemy/alembic/env.py new file mode 100644 index 0000000..6858339 --- /dev/null +++ b/namos/db/sqlalchemy/alembic/env.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +# 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 __future__ import with_statement +from alembic import context +from sqlalchemy import engine_from_config, pool +from logging.config import fileConfig + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata + +from namos.db.sqlalchemy.models import BASE +target_metadata = BASE.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure(url=url, target_metadata=target_metadata) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + engine = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool) + + connection = engine.connect() + context.configure( + connection=connection, + target_metadata=target_metadata + ) + + try: + with context.begin_transaction(): + context.run_migrations() + finally: + connection.close() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/namos/db/sqlalchemy/alembic/script.py.mako b/namos/db/sqlalchemy/alembic/script.py.mako new file mode 100644 index 0000000..9570201 --- /dev/null +++ b/namos/db/sqlalchemy/alembic/script.py.mako @@ -0,0 +1,22 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision} +Create Date: ${create_date} + +""" + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} + +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/namos/db/sqlalchemy/alembic/versions/48ebec3cd6f6_initial_version.py b/namos/db/sqlalchemy/alembic/versions/48ebec3cd6f6_initial_version.py new file mode 100644 index 0000000..507dd85 --- /dev/null +++ b/namos/db/sqlalchemy/alembic/versions/48ebec3cd6f6_initial_version.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- + +# 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. + +"""Initial version + +Revision ID: 48ebec3cd6f6 +Revises: None +Create Date: 2014-10-31 10:57:41.695077 + +""" + +# revision identifiers, used by Alembic. +revision = '48ebec3cd6f6' +down_revision = None + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.create_table( + 'service', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('keystone_service_id', sa.Uuid(length=36), nullable=False), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + op.create_table( + 'device_driver_class', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('python_class', sa.String(length=64), nullable=False), + sa.Column('version', sa.String(length=64), nullable=True), + sa.Column('type', sa.String(length=64), nullable=False), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + op.create_table( + 'region', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('keystone_region_id', sa.String(length=255), nullable=False), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + op.create_table( + 'device', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('status', sa.String(length=64), nullable=False), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('display_name', sa.String(length=255), nullable=True), + sa.Column('parent_id', sa.Uuid(length=36), nullable=True), + sa.Column('region_id', sa.Uuid(length=36), nullable=False), + sa.ForeignKeyConstraint(['parent_id'], ['device.id'], ), + sa.ForeignKeyConstraint(['region_id'], ['region.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + op.create_table( + 'service_node', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('fqdn', sa.String(length=128), nullable=False), + sa.Column('region_id', sa.Uuid(length=36), nullable=True), + sa.ForeignKeyConstraint(['region_id'], ['region.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + op.create_table( + 'device_endpoint', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('device_id', sa.Uuid(length=36), nullable=True), + sa.Column('connection', sa.Json(), nullable=False), + sa.ForeignKeyConstraint(['device_id'], ['device.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + op.create_table( + 'service_component', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('node_id', sa.Uuid(length=36), nullable=False), + sa.Column('service_id', sa.Uuid(length=36), nullable=False), + sa.ForeignKeyConstraint(['node_id'], ['service_node.id'], ), + sa.ForeignKeyConstraint(['service_id'], ['service.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + op.create_table( + 'device_driver', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('endpoint_id', sa.Uuid(length=36), nullable=True), + sa.Column('device_id', sa.Uuid(length=36), nullable=True), + sa.Column('python_class_id', sa.Uuid(length=36), nullable=True), + sa.ForeignKeyConstraint(['device_id'], ['device.id'], ), + sa.ForeignKeyConstraint(['endpoint_id'], ['device_endpoint.id'], ), + sa.ForeignKeyConstraint(['python_class_id'], + ['device_driver_class.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + op.create_table( + 'service_worker', + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('id', sa.Uuid(length=36), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('deleted_at', sa.DateTime(), nullable=True), + sa.Column('extra', sa.Json(), nullable=True), + sa.Column('pid', sa.String(length=32), nullable=False), + sa.Column('host', sa.String(length=248), nullable=False), + sa.Column('service_component_id', sa.Uuid(length=36), nullable=False), + sa.Column('device_driver_id', sa.Uuid(length=36), nullable=False), + sa.ForeignKeyConstraint(['device_driver_id'], ['device_driver.id'], ), + sa.ForeignKeyConstraint(['service_component_id'], + ['service_component.id'], ), + sa.PrimaryKeyConstraint('id'), + mysql_engine='InnoDB' + ) + + +def downgrade(): + op.drop_table('oslo_config') + op.drop_table('device_driver') + op.drop_table('service_worker') + op.drop_table('service_component') + op.drop_table('device_endpoint') + op.drop_table('service_node') + op.drop_table('device') + op.drop_table('region') + op.drop_table('device_driver_class') + op.drop_table('service') diff --git a/namos/db/sqlalchemy/api.py b/namos/db/sqlalchemy/api.py new file mode 100644 index 0000000..a36de55 --- /dev/null +++ b/namos/db/sqlalchemy/api.py @@ -0,0 +1,794 @@ +# -*- coding: utf-8 -*- + +# 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 sys + +from oslo_config import cfg +from oslo_db.sqlalchemy import session as db_session + +from namos.common import exception +from namos.db.sqlalchemy import models + + +CONF = cfg.CONF + +_facade = None + + +def get_facade(): + global _facade + + if not _facade: + _facade = db_session.EngineFacade.from_config(CONF) + return _facade + + +get_engine = lambda: get_facade().get_engine() +get_session = lambda: get_facade().get_session() + + +def get_backend(): + """The backend is this module itself.""" + return sys.modules[__name__] + + +def _model_query(context, *args): + session = _session(context) + query = session.query(*args) + return query + + +def _session(context): + return (context and hasattr(context, 'session') and context.session) \ + or get_session() + + +def _create(context, resource_ref, values): + resource_ref.update(values) + resource_ref.save(_session(context)) + return resource_ref + + +def _update(context, cls, _id, values): + resource_ref = _get(context, cls, _id) + resource_ref.update_and_save(values, _session(context)) + return resource_ref + + +def _get(context, cls, _id): + result = _model_query(context, cls).get(_id) + return result + + +def _get_by_name(context, cls, name): + result = _model_query(context, cls). \ + filter_by(name=name).first() + return result + + +# TODO(kanagaraj-manickam): Add pagination +def _get_all(context, cls): + results = _model_query(context, cls).all() + + if results is None: + results = [] + + return results + + +def _get_all_by(context, cls, **kwargs): + results = _model_query(context, cls).filter_by(**kwargs).all() + return results + + +def _delete(context, cls, _id): + result = _get(context, cls, _id) + if result is not None: + result.delete(_session(context)) + + +# Region + +def region_create(context, values): + return _create(context, models.Region(), values) + + +def region_update(context, _id, values): + return _update(context, models.Region, _id, values) + + +def region_get(context, _id): + region = _get(context, models.Region, _id) + if region is None: + raise exception.RegionNotFound(region_id=_id) + + return region + + +def region_get_by_name(context, name): + region = _get_by_name(context, models.Region, name) + if region is None: + raise exception.RegionNotFound(region_id=name) + + return region + + +def region_get_all(context): + return _get_all(context, models.Region) + + +def region_delete(context, _id): + return _delete(context, models.Region, _id) + + +# Device + +def device_create(context, values): + return _create(context, models.Device(), values) + + +def device_update(context, _id, values): + return _update(context, models.Device, _id, values) + + +def device_get(context, _id): + region = _get(context, models.Device, _id) + if region is None: + raise exception.DeviceNotFound(device_id=_id) + + return region + + +def device_get_by_name(context, name): + region = _get_by_name(context, models.Device, name) + if region is None: + raise exception.DeviceNotFound(device_id=name) + + return region + + +def device_get_all(context): + return _get_all(context, models.Device) + + +def _device_get_all_by(context, **kwargs): + return _get_all_by(context, models.Device, **kwargs) + + +def device_delete(context, _id): + return _delete(context, models.Device, _id) + + +# Device Endpoint + +def device_endpoint_create(context, values): + return _create(context, models.DeviceEndpoint(), values) + + +def device_endpoint_update(context, _id, values): + return _update(context, models.DeviceEndpoint, _id, values) + + +def device_endpoint_get(context, _id): + region = _get(context, models.DeviceEndpoint, _id) + if region is None: + raise exception.DeviceEndpointNotFound(device_endpoint_id=_id) + + return region + + +def device_endpoint_get_by_name(context, name): + region = _get_by_name(context, models.DeviceEndpoint, name) + if region is None: + raise exception.DeviceEndpointNotFound(device_endpoint_id=name) + + return region + + +def device_endpoint_get_by_device_type(context, + device_id, + type=None, + name=None): + query = _model_query(context, models.DeviceEndpoint) + if device_id is not None: + query = query.filter_by(device_id=device_id) + if type is not None: + query = query.filter_by(type=type) + if name is not None: + query = query.filter_by(name=name) + return query.all() + + +def device_endpoint_get_all(context): + return _get_all(context, models.DeviceEndpoint) + + +def _device_endpoint_get_all_by(context, **kwargs): + return _get_all_by(context, models.DeviceEndpoint, **kwargs) + + +def device_endpoint_delete(context, _id): + return _delete(context, models.DeviceEndpoint, _id) + + +# Device Driver +def device_driver_create(context, values): + return _create(context, models.DeviceDriver(), values) + + +def device_driver_update(context, _id, values): + return _update(context, models.DeviceDriver, _id, values) + + +def device_driver_get(context, _id): + region = _get(context, models.DeviceDriver, _id) + if region is None: + raise exception.DeviceDriverNotFound(device_driver_id=_id) + + return region + + +def device_driver_get_by_name(context, name): + region = _get_by_name(context, models.DeviceDriver, name) + if region is None: + raise exception.DeviceDriverNotFound(device_driver_id=name) + + return region + + +def device_driver_get_by_device_endpoint_service_worker( + context, + device_id=None, + endpoint_id=None, + device_driver_class_id=None, + service_worker_id=None): + query = _model_query(context, models.DeviceDriver) + if device_id is not None: + query = query.filter_by(device_id=device_id) + if endpoint_id is not None: + query = query.filter_by(endpoint_id=endpoint_id) + if device_driver_class_id is not None: + query = query.filter_by(device_driver_class_id=device_driver_class_id) + if service_worker_id is not None: + query = query.filter_by(service_worker_id=service_worker_id) + return query.all() + + +def device_driver_get_all(context): + return _get_all(context, models.DeviceDriver) + + +def _device_driver_get_all_by(context, **kwargs): + return _get_all_by(context, models.DeviceDriver, **kwargs) + + +def device_driver_delete(context, _id): + return _delete(context, models.DeviceDriver, _id) + + +# Device Driver Class + +def device_driver_class_create(context, values): + return _create(context, models.DeviceDriverClass(), values) + + +def device_driver_class_update(context, _id, values): + return _update(context, models.DeviceDriverClass, _id, values) + + +def device_driver_class_get(context, _id): + region = _get(context, models.DeviceDriverClass, _id) + if region is None: + raise exception.DeviceDriverClassNotFound(device_driver_id=_id) + + return region + + +def device_driver_class_get_by_name(context, name): + region = _get_by_name(context, models.DeviceDriverClass, name) + if region is None: + raise exception.DeviceDriverClassNotFound(device_driver_class_id=name) + + return region + + +def device_driver_class_get_all(context): + return _get_all(context, models.DeviceDriverClass) + + +def _device_driver_classget_all_by(context, **kwargs): + return _get_all_by(context, models.DeviceDriverClass, **kwargs) + + +def device_driver_class_delete(context, _id): + return _delete(context, models.DeviceDriverClass, _id) + + +# Service + +def service_create(context, values): + return _create(context, models.Service(), values) + + +def service_update(context, _id, values): + return _update(context, models.Service, _id, values) + + +def service_get(context, _id): + region = _get(context, models.Service, _id) + if region is None: + raise exception.ServiceNotFound(service_id=_id) + + return region + + +def service_get_by_name(context, name): + region = _get_by_name(context, models.Service, name) + if region is None: + raise exception.ServiceNotFound(service_id=name) + + return region + + +def service_get_all(context): + return _get_all(context, models.Service) + + +def _service_get_all_by(context, **kwargs): + return _get_all_by(context, models.Service, **kwargs) + + +def service_delete(context, _id): + return _delete(context, models.Service, _id) + + +# ServiceNode + +def service_node_create(context, values): + return _create(context, models.ServiceNode(), values) + + +def service_node_update(context, _id, values): + return _update(context, models.ServiceNode, _id, values) + + +def service_node_get(context, _id): + region = _get(context, models.ServiceNode, _id) + if region is None: + raise exception.ServiceNodeNotFound(service_node_id=_id) + + return region + + +def service_node_get_by_name(context, name): + region = _get_by_name(context, models.ServiceNode, name) + if region is None: + raise exception.ServiceNodeNotFound(service_node_id=name) + + return region + + +def service_node_get_all(context): + return _get_all(context, models.ServiceNode) + + +def _service_node_get_all_by(context, **kwargs): + return _get_all_by(context, models.ServiceNode, **kwargs) + + +def service_node_delete(context, _id): + return _delete(context, models.ServiceNode, _id) + + +# ServiceComponent + +def service_component_create(context, values): + return _create(context, models.ServiceComponent(), values) + + +def service_component_update(context, _id, values): + return _update(context, models.ServiceComponent, _id, values) + + +def service_component_get(context, _id): + region = _get(context, models.ServiceComponent, _id) + if region is None: + raise exception.ServiceComponentNotFound(service_component_id=_id) + + return region + + +def service_component_get_by_name(context, name): + region = _get_by_name(context, models.ServiceComponent, name) + if region is None: + raise exception.ServiceComponentNotFound(service_component_id=name) + + return region + + +def service_component_get_all_by_node_for_service(context, + node_id, + service_id=None, + name=None): + query = _model_query(context, models.ServiceComponent). \ + filter_by(node_id=node_id) + if service_id is not None: + query = query.filter_by(service_id=service_id) + if name is not None: + query = query.filter_by(name=name) + return query.all() + + +def service_component_get_all(context): + return _get_all(context, models.ServiceComponent) + + +def _service_component_get_all_by(context, **kwargs): + return _get_all_by(context, models.ServiceComponent, **kwargs) + + +def service_component_delete(context, _id): + return _delete(context, models.ServiceComponent, _id) + + +# ServiceWorker + +def service_worker_create(context, values): + return _create(context, models.ServiceWorker(), values) + + +def service_worker_update(context, _id, values): + return _update(context, models.ServiceWorker, _id, values) + + +def service_worker_get(context, _id): + service_worker = _get(context, models.ServiceWorker, _id) + if service_worker is None: + raise exception.ServiceWorkerNotFound(service_worker_id=_id) + + return service_worker + + +def service_worker_get_by_name(context, name): + service_worker = _get_by_name(context, models.ServiceWorker, name) + if service_worker is None: + raise exception.ServiceWorkerNotFound(service_worker_id=name) + + return service_worker + + +def service_worker_get_by_host_for_service_component(context, + service_component_id, + host=None): + query = _model_query(context, models.ServiceWorker). \ + filter_by(service_component_id=service_component_id) + if host is not None: + query = query.filter_by(host=host) + return query.all() + + +def service_worker_get_all(context): + return _get_all(context, models.ServiceWorker) + + +def _service_worker_get_all_by(context, **kwargs): + return _get_all_by(context, models.ServiceWorker, **kwargs) + + +def service_worker_delete(context, _id): + return _delete(context, models.ServiceWorker, _id) + + +# Config + +def config_create(context, values): + return _create(context, models.OsloConfig(), values) + + +def config_update(context, _id, values): + return _update(context, models.OsloConfig, _id, values) + + +def config_get(context, _id): + config = _get(context, models.OsloConfig, _id) + if config is None: + raise exception.ConfigNotFound(config_id=_id) + + return config + + +def config_get_by_name(context, name): + config = _get_by_name(context, models.OsloConfig, name) + if config is None: + raise exception.ConfigNotFound(config_id=name) + + return config + + +def config_get_by_name_for_service_worker(context, + service_worker_id, + name=None): + query = _model_query(context, models.OsloConfig). \ + filter_by(service_worker_id=service_worker_id) + if name is not None: + query = query.filter_by(name=name) + return query.all() + + +def config_get_all(context): + return _get_all(context, models.OsloConfig) + + +def _config_get_all_by(context, **kwargs): + return _get_all_by(context, models.OsloConfig, **kwargs) + + +def config_delete(context, _id): + return _delete(context, models.OsloConfig, _id) + + +# REST-API +def service_perspective_get(context, service_id, include_details=False): + # 1. itr over Service Components and find name vs set of components + # (for example, nova-compute vs set of nova-compute deployment) + # Mention the service_node + # 2. For each components, itr over Service Workers + # 3. For each workers, itr over device_drivers + # 4. For each device_driver, Mention + # device_driver_class + # device_endpoint<->device + + # on include_details, for each of the entity, include complete details + service_perspective = dict() + service_perspective['service'] = service_get(context, service_id).to_dict() + service_components = _service_component_get_all_by(context, + service_id=service_id) + service_perspective['service_components'] = dict() + # service_perspective['service_components']['size'] = + # len(service_components) + + for sc in service_components: + service_perspective['service_components'][sc.id] = dict() + service_perspective['service_components'][sc.id]['service_component']\ + = sc.to_dict() + service_perspective['service_components'][sc.id]['service_node']\ + = service_node_get(context, sc.node_id).to_dict() + service_workers = _service_worker_get_all_by( + context, + service_component_id=sc.id) + service_perspective['service_components'][sc.id]['service_workers'] \ + = dict() + # service_perspective['service_components'][sc.id]\ + # ['service_workers']['size'] = len(service_workers) + + for sw in service_workers: + service_perspective['service_components'][ + sc.id]['service_workers'][sw.id] = dict() + service_perspective['service_components'][ + sc.id]['service_workers'][sw.id][ + 'service_worker'] = sw.to_dict() + + device_drivers = _device_driver_get_all_by( + context, + service_worker_id=sw.id) + service_perspective['service_components'][ + sc.id]['service_workers'][sw.id]['device_drivers'] = dict() + + # service_perspective['service_components'][sc.id]\ + # ['service_workers'][sw.id]['device_drivers']['size'] \ + # = len(device_drivers) + for driver in device_drivers: + service_perspective['service_components'][ + sc.id]['service_workers'][sw.id]['device_drivers'][ + driver.id] = dict() + service_perspective['service_components'][ + sc.id]['service_workers'][sw.id]['device_drivers'][ + driver.id]['driver'] = driver.to_dict() + service_perspective['service_components'][ + sc.id]['service_workers'][sw.id]['device_drivers'][ + driver.id]['device_endpoint'] = device_endpoint_get( + context, + driver.endpoint_id).to_dict() + service_perspective['service_components'][ + sc.id]['service_workers'][sw.id]['device_drivers'][ + driver.id]['device'] = device_get( + context, + driver.device_id).to_dict() + service_perspective['service_components'][ + sc.id]['service_workers'][sw.id]['device_drivers'][ + driver.id][ + 'device_driver_class'] = device_driver_class_get( + context, + driver.device_driver_class_id + ).to_dict() + + return service_perspective + + +# REST-API +def device_perspective_get(context, device_id, include_details=False): + # 1. list endpoints + # 2. For each endpoint, itr over device_drivers and + # find device_driver_class vs set of device_driver (for example, + # nova-compute-vc-driver vs set of nova-compute's device-driver deployment) + # 3. For each drivers, mention service_worker, + # service_component<->service_node<->service + + # on include_details, for each of the entity, include complete details + device_perspective = dict() + device_perspective['device'] = device_get(context, device_id).to_dict() + endpoints = _device_endpoint_get_all_by(context, + device_id=device_id) + device_perspective['device_endpoints'] = dict() + # device_perspective['device_endpoints']['size'] = len(endpoints) + + for ep in endpoints: + device_perspective['device_endpoints'][ep.id] = dict() + device_perspective['device_endpoints'][ + ep.id]['device_endpoint'] = ep.to_dict() + + device_drivers = _device_driver_get_all_by(context, + endpoint_id=ep.id) + device_perspective['device_endpoints'][ + ep.id]['device_drivers'] = dict() + # device_perspective['device_endpoints'][ep.id] \ + # ['device_drivers']['size'] = len(device_drivers) + + for driver in device_drivers: + device_perspective['device_endpoints'][ + ep.id]['device_drivers'][driver.id] = dict() + device_perspective['device_endpoints'][ + ep.id]['device_drivers'][driver.id][ + 'device_driver'] = driver.to_dict() + + service_worker = service_worker_get( + context, + driver.service_worker_id) + service_component = service_component_get( + context, + service_worker.service_component_id) + device_perspective['device_endpoints'][ + ep.id]['device_drivers'][ + driver.id]['service_worker'] = service_worker.to_dict() + service = service_get(context, service_component.service_id) + + device_perspective['device_endpoints'][ + ep.id]['device_drivers'][ + driver.id]['service_component'] = service_component.to_dict() + + device_perspective['device_endpoints'][ + ep.id]['device_drivers'][ + driver.id]['service'] = service.to_dict() + device_perspective['device_endpoints'][ + ep.id]['device_drivers'][driver.id][ + 'device_driver_class'] = device_driver_class_get( + context, + driver.device_driver_class_id + ).to_dict() + + return device_perspective + + +# REST-API +def region_perspective_get(context, region_id, include_details=False): + # itr over service_nodes + # For each service_nodes, itr over service_id + # itr over devices. + + # on include_details, for each of the entity, include complete details + + region_perspective = dict() + region_perspective['region'] = region_get(context, region_id).to_dict() + s_nodes = _service_node_get_all_by(context, + region_id=region_id) + # region_perspective['service_nodes'] = dict() + # region_perspective['service_nodes']['size'] = len(s_nodes) + # for s_node in s_nodes: + # region_perspective['service_nodes'][s_node.id] = dict() + # region_perspective['service_nodes'][s_node.id]['service_node']\ + # = s_node + # s_components = _service_component_get_all_by(context, + # node_id=s_node.id) + # srvs = list() + # for s_component in s_components: + # srvs.append(s_component.service_id) + # srvs = set(srvs) + # + # region_perspective['service_nodes'][s_node.id]['services'] = dict() + # region_perspective['service_nodes'][s_node.id]['services']['size']\ + # = len(srvs) + # for s_id in srvs: + # s = service_get(context, s_id) + # region_perspective['service_nodes'][s_node.id]['services'][s_id]\ + # = s + + region_perspective['services'] = dict() + for s_node in s_nodes: + s_components = _service_component_get_all_by( + context, + node_id=s_node.id) + srvs = list() + for s_component in s_components: + srvs.append(s_component.service_id) + srvs = set(srvs) + + # region_perspective['services']['size']\ + # = len(srvs) + for s_id in srvs: + s = service_get(context, s_id) + region_perspective['services'][s_id] = s.to_dict() + + devices = _device_get_all_by(context, region_id=region_id) + region_perspective['devices'] = dict() + # region_perspective['devices']['size'] = len(devices) + for d in devices: + region_perspective['devices'][d.id] = d.to_dict() + + return region_perspective + + +def infra_perspective_get(context): + infra_perspective = dict() + + regions = region_get_all(context) + infra_perspective['regions'] = dict() + # infra_perspective['regions']['size'] = len(regions) + + for region in regions: + infra_perspective['regions'][region.id] = dict() + infra_perspective['regions'][region.id]['region'] = region.to_dict() + region_perspective = region_perspective_get(context, + region.id) + + infra_perspective['regions'][region.id]['services'] = dict() + for s_id in region_perspective['services']: + infra_perspective['regions'][ + region.id]['services'][s_id] = service_perspective_get( + context, + s_id) + + infra_perspective['regions'][region.id]['devices'] = dict() + for d_id in region_perspective['devices']: + infra_perspective['regions'][region.id]['devices'][ + d_id] = device_perspective_get( + context, + d_id) + + return infra_perspective + +if __name__ == '__main__': + from namos.common import config + + config.init_conf(prog='test-run') + # print config_get_by_name_for_service_worker( + # None, + # 'f46983a4-6b42-48b0-8b66-66175fa07bc8', + # 'database.use_db_reconnect' + # ) + + # print region_perspective_get(None, + # region_id='f7dcd175-27ef-46b5-997f-e6e572f320b0') + # + # print service_perspective_get(None, + # service_id='11367a37-976f-468a-b8dd-77b28ee63cf4') + # + # print device_perspective_get( + # None, + # device_id='05b935b3-942c-439c-a6a4-9c3c73285430') + + # persp = infra_perspective_get(None) + # import json + # perp_json = json.dumps(persp, indent=4) + # print perp_json diff --git a/namos/db/sqlalchemy/migration.py b/namos/db/sqlalchemy/migration.py new file mode 100644 index 0000000..d994d3f --- /dev/null +++ b/namos/db/sqlalchemy/migration.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- + +# 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 os + +import alembic +from alembic import config as alembic_config +import alembic.migration as alembic_migration + +from oslo_config import cfg +from oslo_db import exception as db_exc + +from namos.db.sqlalchemy import api as sqla_api +from namos.db.sqlalchemy import models + + +# Following commands are based on sqlalchemy +def version(config=None, engine=None): + """Current database version. + + :returns: Database version + :rtype: string + """ + if engine is None: + engine = sqla_api.get_engine() + with engine.connect() as conn: + context = alembic_migration.MigrationContext.configure(conn) + return context.get_current_revision() + + +def create_schema(config=None, engine=None): + """Create database schema from models description. + + Can be used for initial installation instead of upgrade('head'). + """ + if engine is None: + engine = sqla_api.get_engine() + + if version(engine=engine) is not None: + raise db_exc.DbMigrationError("DB schema is already under version" + " control. Use upgrade instead") + + models.BASE.metadata.create_all(engine) + stamp('head', config=config) + + +# Following commands are alembic commands + +def _alembic_config(): + # TODO(kanagaraj-manickam): It is an hack to use database.connection + # for all alembic related commands + + path = os.path.join(os.path.dirname(__file__), 'alembic.ini') + config = alembic_config.Config(path) + config.set_main_option('sqlalchemy.url', cfg.CONF.database.connection) + return config + + +def upgrade(revision, config=None): + """Used for upgrading database. + + :param version: Desired database version + :type version: string + """ + revision = revision or 'head' + config = config or _alembic_config() + + alembic.command.upgrade(config, revision) + + +def downgrade(revision, config=None): + """Used for downgrading database. + + :param version: Desired database version + :type version: string + """ + revision = revision or 'base' + config = config or _alembic_config() + return alembic.command.downgrade(config, revision) + + +def stamp(revision, config=None): + """Stamps database with provided revision. + + Don't run any migrations. + + :param revision: Should match one from repository or head - to stamp + database with most recent revision + :type revision: string + """ + config = config or _alembic_config() + return alembic.command.stamp(config, revision=revision) + + +def revision(message=None, autogenerate=False, config=None): + """Creates template for migration. + + :param message: Text that will be used for migration title + :type message: string + :param autogenerate: If True - generates diff based on current database + state + :type autogenerate: bool + """ + config = config or _alembic_config() + return alembic.command.revision(config, message=message, + autogenerate=autogenerate) + + +def history(config=None): + """List the available versions.""" + config = config or _alembic_config() + return alembic.command.history(config) diff --git a/namos/db/sqlalchemy/models.py b/namos/db/sqlalchemy/models.py new file mode 100644 index 0000000..00b9b48 --- /dev/null +++ b/namos/db/sqlalchemy/models.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- + +# 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. + +""" +SQLAlchemy models for namos database +""" + +import sqlalchemy +from sqlalchemy.ext.declarative import declarative_base +import uuid + +from namos.db.sqlalchemy.types import Json +from namos.db.sqlalchemy.types import Uuid +from oslo_db.sqlalchemy import models +from oslo_utils import timeutils + + +BASE = declarative_base() + + +class NamosBase(models.ModelBase, + models.TimestampMixin): + # TODO(kanagaraj-manickam) Make this as db independent + __table_args__ = {'mysql_engine': 'InnoDB'} + + id = sqlalchemy.Column(Uuid, primary_key=True, + default=lambda: str(uuid.uuid4())) + name = sqlalchemy.Column(sqlalchemy.String(255), + # unique=True, + nullable=False, + default=lambda: str(uuid.uuid4())) + + def expire(self, session, attrs=None): + session.expire(self, attrs) + + def refresh(self, session, attrs=None): + session.refresh(self, attrs) + + def delete(self, session): + session.delete(self) + session.flush() + + def update_and_save(self, values, session): + self.update(values) + self.save(session) + + def __str__(self): + return "{id:%s, name:%s}" % (self.id, self.name) + + def __repr__(self): + return str(self.to_dict()) + + def to_dict(self): + result = dict() + for k, v in self.iteritems(): + if not str(k).endswith('_at'): + result[k] = v + return result + + +class SoftDelete(object): + deleted_at = sqlalchemy.Column(sqlalchemy.DateTime) + + def soft_delete(self, session): + self.update_and_save({'deleted_at': timeutils.utcnow()}, + session=session) + + +class StateAware(object): + status = sqlalchemy.Column( + 'status', + sqlalchemy.String(64), + nullable=False) + + +class Description(object): + description = sqlalchemy.Column(sqlalchemy.Text) + + +class Extra(object): + extra = sqlalchemy.Column(Json) + + +class Region(BASE, + NamosBase, + SoftDelete, + Extra): + __tablename__ = 'region' + + # Its of type String to match with keystone region id + keystone_region_id = sqlalchemy.Column( + sqlalchemy.String(255), + nullable=False) + + +class Device(BASE, + NamosBase, + SoftDelete, + StateAware, + Description, + Extra): + __tablename__ = 'device' + + display_name = sqlalchemy.Column(sqlalchemy.String(255)) + parent_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('device.id')) + region_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('region.id'), + nullable=False) + # TODO(kanagaraj-manickam) owner with keystone user id as one field?? + + +class DeviceEndpoint(BASE, + NamosBase, + Extra): + __tablename__ = 'device_endpoint' + + device_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('device.id'), + nullable=False) + type = sqlalchemy.Column( + sqlalchemy.String(32) + ) + connection = sqlalchemy.Column( + Json, + nullable=False) + + +class DeviceDriver(BASE, + NamosBase, + SoftDelete, + Extra): + __tablename__ = 'device_driver' + + endpoint_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('device_endpoint.id') + ) + + device_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('device.id')) + + device_driver_class_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('device_driver_class.id') + ) + service_worker_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('service_worker.id') + ) + +# List of supported drivers in a given openstack release. so when +# openstack is released, migration script could be updated to pre-populate +# drivers in this table, which helps to track the drivers being released +# in the given openstack version. + + +class DeviceDriverClass(BASE, + NamosBase, + SoftDelete, + Extra): + __tablename__ = 'device_driver_class' + + # TODO(kanagaraj-manickam) Correct the max python class path here + python_class = sqlalchemy.Column( + sqlalchemy.String(64), + nullable=False + ) + # service type like compute, network, volume, etc + type = sqlalchemy.Column( + sqlalchemy.String(64), + nullable=False + ) + + # TODO(kanagaraj-manickam) add vendor, + # additional details like protocol, etc, + # Capture all related driver details + + +class Service(BASE, + NamosBase, + SoftDelete, + Extra): + __tablename__ = 'service' + + keystone_service_id = sqlalchemy.Column( + Uuid, + nullable=False) + + +class ServiceNode(BASE, + NamosBase, + SoftDelete, + Description, + Extra): + __tablename__ = 'service_node' + + fqdn = sqlalchemy.Column( + sqlalchemy.String(128), + nullable=False) + region_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('region.id')) + + +class ServiceComponent(BASE, + NamosBase, + SoftDelete, + Description, + Extra): + __tablename__ = 'service_component' + + node_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('service_node.id'), + nullable=False) + service_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('service.id'), + nullable=False) + + +class ServiceWorker(BASE, + NamosBase, + SoftDelete, + Extra): + __tablename__ = 'service_worker' + + pid = sqlalchemy.Column( + sqlalchemy.String(32), + nullable=False + ) + host = sqlalchemy.Column( + sqlalchemy.String(248), + nullable=False + ) + service_component_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('service_component.id'), + nullable=False) + + +class OsloConfig(BASE, + NamosBase, + SoftDelete, + Extra): + __tablename__ = 'oslo_config' + + default_value = sqlalchemy.Column( + sqlalchemy.Text + ) + help = sqlalchemy.Column( + sqlalchemy.Text, + nullable=False, + default='' + ) + type = sqlalchemy.Column( + sqlalchemy.String(16), + nullable=False + ) + value = sqlalchemy.Column( + sqlalchemy.Text + ) + required = sqlalchemy.Column( + sqlalchemy.Boolean, + default=False + ) + secret = sqlalchemy.Column( + sqlalchemy.Boolean, + default=False + ) + file = sqlalchemy.Column( + sqlalchemy.String(512) + ) + service_worker_id = sqlalchemy.Column( + Uuid, + sqlalchemy.ForeignKey('service_worker.id'), + nullable=False + ) diff --git a/namos/db/sqlalchemy/types.py b/namos/db/sqlalchemy/types.py new file mode 100644 index 0000000..756ff57 --- /dev/null +++ b/namos/db/sqlalchemy/types.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# 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 uuid + +from sqlalchemy.dialects import mysql +from sqlalchemy.types import String +from sqlalchemy.types import Text +from sqlalchemy.types import TypeDecorator + + +class Json(TypeDecorator): + impl = Text + + def load_dialect_impl(self, dialect): + if dialect.name == 'mysql': + return dialect.type_descriptor(mysql.LONGTEXT()) + else: + return self.impl + + def process_bind_param(self, value, dialect): + return json.dumps(value) + + def process_result_value(self, value, dialect): + return json.loads(value) + + +class Uuid(TypeDecorator): + impl = String(36) + + def process_bind_param(self, value, dialect): + if value is not None: + try: + uuid.UUID(value, version=4) + except ValueError: + raise ValueError( + "Invalid format. It should be in UUID v4 format") + + return value + + def process_result_value(self, value, dialect): + return value diff --git a/requirements.txt b/requirements.txt index 30806d5..fbfc5d4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,14 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr>=1.6 +#common +pbr>=1.6 # Apache-2.0 +oslo.config>=3.7.0 # Apache-2.0 +oslo.i18n>=2.1.0 # Apache-2.0 +oslo.log>=1.14.0 # Apache-2.0 +#db layer +oslo.db>=4.1.0 # Apache-2.0 +SQLAlchemy<1.1.0,>=1.0.10 # MIT +sqlalchemy-migrate>=0.9.6 # Apache-2.0 +PyMySQL +#rpc service layer diff --git a/setup.cfg b/setup.cfg index 4cd859c..c6c9315 100644 --- a/setup.cfg +++ b/setup.cfg @@ -43,3 +43,7 @@ input_file = namos/locale/namos.pot keywords = _ gettext ngettext l_ lazy_gettext mapping_file = babel.cfg output_file = namos/locale/namos.pot + +[entry_points] +console_scripts = + namos-manage = namos.cmd.manage:main \ No newline at end of file