namos/namos/db/sqlalchemy/models.py

395 lines
10 KiB
Python

# -*- 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
from sqlalchemy import UniqueConstraint
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'
__table_args__ = (
UniqueConstraint("device_id", "type"),
)
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'
__table_args__ = (
UniqueConstraint("device_id",
"endpoint_id",
"device_driver_class_id",
"service_worker_id"),
)
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(256),
nullable=False,
unique=True
)
# 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'
__table_args__ = (
UniqueConstraint("name", "node_id", "service_id"),
)
name = sqlalchemy.Column(sqlalchemy.String(255),
# unique=True,
nullable=False,
default=lambda: str(uuid.uuid4()))
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'
__table_args__ = (
UniqueConstraint("host", "service_component_id"),
)
name = sqlalchemy.Column(sqlalchemy.String(255),
# unique=True,
nullable=False,
default=lambda: str(uuid.uuid4()))
pid = sqlalchemy.Column(
sqlalchemy.String(64),
nullable=False,
unique=True
)
host = sqlalchemy.Column(
sqlalchemy.String(248),
nullable=False
)
service_component_id = sqlalchemy.Column(
Uuid,
sqlalchemy.ForeignKey('service_component.id'),
nullable=False)
class OsloConfigSchema(BASE,
NamosBase,
Extra):
__tablename__ = 'oslo_config_schema'
# TODO(mrkanag) Check whether conf is unique across all services or only
# sepcific to namespace, otherwise uniqueconstraint is name, group_name
__table_args__ = (
UniqueConstraint("group_name", "name", "namespace"),
)
name = sqlalchemy.Column(sqlalchemy.String(255),
# unique=True,
nullable=False,
default=lambda: str(uuid.uuid4()))
help = sqlalchemy.Column(
sqlalchemy.Text,
nullable=False,
default=''
)
type = sqlalchemy.Column(
sqlalchemy.String(128),
nullable=False
)
group_name = sqlalchemy.Column(
sqlalchemy.String(128),
nullable=False
)
namespace = sqlalchemy.Column(
sqlalchemy.String(128),
nullable=False
)
# TODO(mrkanag) default value is some time overriden by services, which
# osloconfig allows, so this column should have values per given service
default_value = sqlalchemy.Column(
sqlalchemy.Text
)
required = sqlalchemy.Column(
sqlalchemy.Boolean,
default=False
)
secret = sqlalchemy.Column(
sqlalchemy.Boolean,
default=False
)
mutable = sqlalchemy.Column(
sqlalchemy.Boolean,
default=False
)
class OsloConfig(BASE,
NamosBase,
SoftDelete,
Extra):
__tablename__ = 'oslo_config'
__table_args__ = (
UniqueConstraint("oslo_config_schema_id", "service_worker_id"),
)
name = sqlalchemy.Column(sqlalchemy.String(255),
# unique=True,
nullable=False,
default=lambda: str(uuid.uuid4()))
value = sqlalchemy.Column(
sqlalchemy.Text
)
file = sqlalchemy.Column(
sqlalchemy.String(512)
)
oslo_config_schema_id = sqlalchemy.Column(
Uuid,
sqlalchemy.ForeignKey('oslo_config_schema.id'),
nullable=False
)
service_worker_id = sqlalchemy.Column(
Uuid,
sqlalchemy.ForeignKey('service_worker.id'),
nullable=False
)
class OsloConfigFile(BASE,
NamosBase,
SoftDelete,
Extra):
__tablename__ = 'oslo_config_file'
__table_args__ = (
UniqueConstraint("name", "service_component_id"),
)
name = sqlalchemy.Column(sqlalchemy.String(255),
# unique=True,
nullable=False,
default=lambda: str(uuid.uuid4()))
file = sqlalchemy.Column(
sqlalchemy.Text
)
service_component_id = sqlalchemy.Column(
Uuid,
sqlalchemy.ForeignKey('service_component.id'),
nullable=False
)