database layer

Change-Id: I6ff5e8773e8eb158e61f5eead8b1c76f7e4df834
This commit is contained in:
Kanagaraj Manickam 2016-03-17 19:59:10 +05:30
parent 40b32e8273
commit 363a76281d
23 changed files with 4175 additions and 6 deletions

View File

@ -1,8 +1,6 @@
===============================
namos
===============================
OpenStack Service, Device manager
=========================
namos - OpenStack manager
=========================
* Free software: Apache license
* Documentation: http://docs.openstack.org/developer/namos

2
etc/namos.conf Normal file
View File

@ -0,0 +1,2 @@
[database]
connection = mysql+pymysql://root:password@172.241.0.101/namos?charset=utf8

0
namos/cmd/__init__.py Normal file
View File

110
namos/cmd/manage.py Normal file
View File

@ -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()

0
namos/common/__init__.py Normal file
View File

36
namos/common/config.py Normal file
View File

@ -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)

121
namos/common/exception.py Normal file
View File

@ -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

0
namos/db/__init__.py Normal file
View File

367
namos/db/api.py Normal file
View File

@ -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)

18
namos/db/migration.py Normal file
View File

@ -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

File diff suppressed because it is too large Load Diff

444
namos/db/sample.py Normal file
View File

@ -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()

View File

View File

@ -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

View File

@ -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()

View File

@ -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"}

View File

@ -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')

794
namos/db/sqlalchemy/api.py Normal file
View File

@ -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

View File

@ -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)

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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