187d0a8558
When using mysql, we need to make sure that the name column is long enough to accomodate the package name. 'io.murano.lib.networks.Neutron' is more than 20 chars. Modify the schema to make it 80 chars Change-Id: I6f7154141ad4b728d98f436b2eaa839239ee302a Closes-Bug: #1314389
363 lines
12 KiB
Python
363 lines
12 KiB
Python
# Copyright (c) 2013 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""
|
|
SQLAlchemy models for muranoapi data
|
|
"""
|
|
import anyjson
|
|
|
|
import sqlalchemy as sa
|
|
from sqlalchemy.ext import compiler as sa_compiler
|
|
from sqlalchemy.ext import declarative as sa_decl
|
|
from sqlalchemy import orm as sa_orm
|
|
|
|
from muranoapi.common import uuidutils
|
|
from muranoapi.db import session as db_session
|
|
from muranoapi.openstack.common import timeutils
|
|
|
|
|
|
BASE = sa_decl.declarative_base()
|
|
|
|
|
|
@sa_compiler.compiles(sa.BigInteger, 'sqlite')
|
|
def compile_big_int_sqlite(type_, compiler, **kw):
|
|
return 'INTEGER'
|
|
|
|
|
|
class ModelBase(object):
|
|
def save(self, session=None):
|
|
"""Save this object"""
|
|
session = session or db_session.get_session()
|
|
session.add(self)
|
|
session.flush()
|
|
|
|
def update(self, values):
|
|
"""dict.update() behaviour."""
|
|
for k, v in values.iteritems():
|
|
self[k] = v
|
|
|
|
def __setitem__(self, key, value):
|
|
setattr(self, key, value)
|
|
|
|
def __getitem__(self, key):
|
|
return getattr(self, key)
|
|
|
|
def __iter__(self):
|
|
self._i = iter(sa_orm.object_mapper(self).columns)
|
|
return self
|
|
|
|
def next(self):
|
|
n = self._i.next().name
|
|
return n, getattr(self, n)
|
|
|
|
def keys(self):
|
|
return self.__dict__.keys()
|
|
|
|
def values(self):
|
|
return self.__dict__.values()
|
|
|
|
def items(self):
|
|
return self.__dict__.items()
|
|
|
|
def to_dict(self):
|
|
dictionary = self.__dict__.copy()
|
|
return dict((k, v) for k, v in dictionary.iteritems()
|
|
if k != '_sa_instance_state')
|
|
|
|
|
|
class ModificationsTrackedObject(ModelBase):
|
|
__protected_attributes__ = set(["created", "updated"])
|
|
|
|
created = sa.Column(sa.DateTime, default=timeutils.utcnow,
|
|
nullable=False)
|
|
updated = sa.Column(sa.DateTime, default=timeutils.utcnow,
|
|
nullable=False, onupdate=timeutils.utcnow)
|
|
|
|
def update(self, values):
|
|
"""dict.update() behaviour."""
|
|
self.updated = timeutils.utcnow()
|
|
super(ModificationsTrackedObject, self).update(values)
|
|
|
|
def __setitem__(self, key, value):
|
|
self.updated = timeutils.utcnow()
|
|
super(ModificationsTrackedObject, self).__setitem__(key, value)
|
|
|
|
|
|
class JsonBlob(sa.TypeDecorator):
|
|
impl = sa.Text
|
|
|
|
def process_bind_param(self, value, dialect):
|
|
return anyjson.serialize(value)
|
|
|
|
def process_result_value(self, value, dialect):
|
|
return anyjson.deserialize(value)
|
|
|
|
|
|
class Environment(BASE, ModificationsTrackedObject):
|
|
"""Represents a Environment in the metadata-store"""
|
|
__tablename__ = 'environment'
|
|
|
|
id = sa.Column(sa.String(32),
|
|
primary_key=True,
|
|
default=uuidutils.generate_uuid)
|
|
name = sa.Column(sa.String(255), nullable=False)
|
|
tenant_id = sa.Column(sa.String(32), nullable=False)
|
|
version = sa.Column(sa.BigInteger, nullable=False, default=0)
|
|
description = sa.Column(JsonBlob(), nullable=False, default={})
|
|
networking = sa.Column(JsonBlob(), nullable=True, default={})
|
|
|
|
sessions = sa_orm.relationship("Session", backref='environment',
|
|
cascade='save-update, merge, delete')
|
|
deployments = sa_orm.relationship("Deployment", backref='environment',
|
|
cascade='save-update, merge, delete')
|
|
|
|
def to_dict(self):
|
|
dictionary = super(Environment, self).to_dict()
|
|
del dictionary['description']
|
|
return dictionary
|
|
|
|
|
|
class Session(BASE, ModificationsTrackedObject):
|
|
__tablename__ = 'session'
|
|
|
|
id = sa.Column(sa.String(32),
|
|
primary_key=True,
|
|
default=uuidutils.generate_uuid)
|
|
environment_id = sa.Column(sa.String(32), sa.ForeignKey('environment.id'))
|
|
|
|
user_id = sa.Column(sa.String(36), nullable=False)
|
|
state = sa.Column(sa.String(36), nullable=False)
|
|
description = sa.Column(JsonBlob(), nullable=False)
|
|
version = sa.Column(sa.BigInteger, nullable=False, default=0)
|
|
|
|
def to_dict(self):
|
|
dictionary = super(Session, self).to_dict()
|
|
del dictionary['description']
|
|
#object relations may be not loaded yet
|
|
if 'environment' in dictionary:
|
|
del dictionary['environment']
|
|
return dictionary
|
|
|
|
|
|
class Deployment(BASE, ModificationsTrackedObject):
|
|
__tablename__ = 'deployment'
|
|
|
|
id = sa.Column(sa.String(32),
|
|
primary_key=True,
|
|
default=uuidutils.generate_uuid)
|
|
started = sa.Column(sa.DateTime, default=timeutils.utcnow, nullable=False)
|
|
finished = sa.Column(sa.DateTime, default=None, nullable=True)
|
|
description = sa.Column(JsonBlob(), nullable=False)
|
|
environment_id = sa.Column(sa.String(32), sa.ForeignKey('environment.id'))
|
|
|
|
statuses = sa_orm.relationship("Status", backref='deployment',
|
|
cascade='save-update, merge, delete')
|
|
|
|
def to_dict(self):
|
|
dictionary = super(Deployment, self).to_dict()
|
|
# del dictionary["description"]
|
|
if 'statuses' in dictionary:
|
|
del dictionary['statuses']
|
|
if 'environment' in dictionary:
|
|
del dictionary['environment']
|
|
return dictionary
|
|
|
|
|
|
class Status(BASE, ModificationsTrackedObject):
|
|
__tablename__ = 'status'
|
|
|
|
id = sa.Column(sa.String(32),
|
|
primary_key=True,
|
|
default=uuidutils.generate_uuid)
|
|
entity_id = sa.Column(sa.String(32), nullable=True)
|
|
entity = sa.Column(sa.String(10), nullable=True)
|
|
deployment_id = sa.Column(sa.String(32), sa.ForeignKey('deployment.id'))
|
|
text = sa.Column(sa.String(), nullable=False)
|
|
level = sa.Column(sa.String(32), nullable=False)
|
|
details = sa.Column(sa.Text(), nullable=True)
|
|
|
|
def to_dict(self):
|
|
dictionary = super(Status, self).to_dict()
|
|
#object relations may be not loaded yet
|
|
if 'deployment' in dictionary:
|
|
del dictionary['deployment']
|
|
return dictionary
|
|
|
|
|
|
class ApiStats(BASE, ModificationsTrackedObject):
|
|
__tablename__ = 'apistats'
|
|
|
|
id = sa.Column(sa.Integer(), primary_key=True)
|
|
host = sa.Column(sa.String(80))
|
|
request_count = sa.Column(sa.BigInteger())
|
|
error_count = sa.Column(sa.BigInteger())
|
|
average_response_time = sa.Column(sa.Float())
|
|
requests_per_tenant = sa.Column(sa.Text())
|
|
requests_per_second = sa.Column(sa.Float())
|
|
errors_per_second = sa.Column(sa.Float())
|
|
cpu_count = sa.Column(sa.Integer())
|
|
cpu_percent = sa.Column(sa.Float())
|
|
|
|
def to_dict(self):
|
|
dictionary = super(ApiStats, self).to_dict()
|
|
return dictionary
|
|
|
|
package_to_category = sa.Table('package_to_category',
|
|
BASE.metadata,
|
|
sa.Column('package_id',
|
|
sa.String(32),
|
|
sa.ForeignKey('package.id')),
|
|
sa.Column('category_id',
|
|
sa.String(32),
|
|
sa.ForeignKey('category.id',
|
|
ondelete="RESTRICT")))
|
|
|
|
package_to_tag = sa.Table('package_to_tag',
|
|
BASE.metadata,
|
|
sa.Column('package_id',
|
|
sa.String(32),
|
|
sa.ForeignKey('package.id')),
|
|
sa.Column('tag_id',
|
|
sa.String(32),
|
|
sa.ForeignKey('tag.id',
|
|
ondelete="CASCADE")))
|
|
|
|
|
|
class Instance(BASE, ModelBase):
|
|
__tablename__ = 'instance_stats'
|
|
|
|
environment_id = sa.Column(
|
|
sa.String(100), primary_key=True, nullable=False)
|
|
instance_id = sa.Column(
|
|
sa.String(100), primary_key=True, nullable=False)
|
|
instance_type = sa.Column(sa.Integer, default=0, nullable=False)
|
|
created = sa.Column(sa.Integer, nullable=False)
|
|
destroyed = sa.Column(sa.Integer, nullable=True)
|
|
type_name = sa.Column('type_name', sa.String(512), nullable=False)
|
|
type_title = sa.Column('type_title', sa.String(512))
|
|
unit_count = sa.Column('unit_count', sa.Integer())
|
|
tenant_id = sa.Column('tenant_id', sa.String(32), nullable=False)
|
|
|
|
def to_dict(self):
|
|
dictionary = super(Instance, self).to_dict()
|
|
return dictionary
|
|
|
|
|
|
class Package(BASE, ModificationsTrackedObject):
|
|
"""
|
|
Represents a meta information about application package.
|
|
"""
|
|
__tablename__ = 'package'
|
|
|
|
id = sa.Column(sa.String(36),
|
|
primary_key=True,
|
|
default=uuidutils.generate_uuid)
|
|
archive = sa.Column(sa.LargeBinary)
|
|
fully_qualified_name = sa.Column(sa.String(512),
|
|
nullable=False,
|
|
index=True,
|
|
unique=True)
|
|
type = sa.Column(sa.String(20), nullable=False, default='class')
|
|
author = sa.Column(sa.String(80), default='Openstack')
|
|
name = sa.Column(sa.String(80), nullable=False)
|
|
enabled = sa.Column(sa.Boolean, default=True)
|
|
description = sa.Column(sa.String(512),
|
|
nullable=False,
|
|
default='The description is not provided')
|
|
is_public = sa.Column(sa.Boolean, default=True)
|
|
tags = sa_orm.relationship("Tag",
|
|
secondary=package_to_tag,
|
|
cascade='save-update, merge',
|
|
lazy='joined')
|
|
logo = sa.Column(sa.LargeBinary, nullable=True)
|
|
owner_id = sa.Column(sa.String(36), nullable=False)
|
|
ui_definition = sa.Column(sa.Text)
|
|
categories = sa_orm.relationship("Category",
|
|
secondary=package_to_category,
|
|
cascade='save-update, merge',
|
|
lazy='joined')
|
|
class_definitions = sa_orm.relationship(
|
|
"Class", cascade='save-update, merge, delete', lazy='joined')
|
|
|
|
def to_dict(self):
|
|
d = self.__dict__.copy()
|
|
not_serializable = ['_sa_instance_state',
|
|
'archive',
|
|
'logo',
|
|
'ui_definition']
|
|
nested_objects = ['categories', 'tags', 'class_definitions']
|
|
for key in not_serializable:
|
|
if key in d.keys():
|
|
del d[key]
|
|
for key in nested_objects:
|
|
d[key] = [a.name for a in d.get(key, [])]
|
|
return d
|
|
|
|
|
|
class Category(BASE, ModificationsTrackedObject):
|
|
"""
|
|
Represents an application categories in the datastore.
|
|
"""
|
|
__tablename__ = 'category'
|
|
|
|
id = sa.Column(sa.String(32),
|
|
primary_key=True,
|
|
default=uuidutils.generate_uuid)
|
|
name = sa.Column(sa.String(80), nullable=False, index=True, unique=True)
|
|
|
|
|
|
class Tag(BASE, ModificationsTrackedObject):
|
|
"""
|
|
Represents tags in the datastore.
|
|
"""
|
|
__tablename__ = 'tag'
|
|
|
|
id = sa.Column(sa.String(32),
|
|
primary_key=True,
|
|
default=uuidutils.generate_uuid)
|
|
name = sa.Column(sa.String(80), nullable=False, unique=True)
|
|
|
|
|
|
class Class(BASE, ModificationsTrackedObject):
|
|
"""
|
|
Represents a class definition in the datastore.
|
|
"""
|
|
__tablename__ = 'class_definition'
|
|
|
|
id = sa.Column(sa.String(32),
|
|
primary_key=True,
|
|
default=uuidutils.generate_uuid)
|
|
name = sa.Column(sa.String(80), nullable=False, index=True)
|
|
package_id = sa.Column(sa.String(32), sa.ForeignKey('package.id'))
|
|
|
|
|
|
def register_models(engine):
|
|
"""
|
|
Creates database tables for all models with the given engine
|
|
"""
|
|
models = (Environment, Status, Session, Deployment,
|
|
ApiStats, Package, Category, Class, Instance)
|
|
for model in models:
|
|
model.metadata.create_all(engine)
|
|
|
|
|
|
def unregister_models(engine):
|
|
"""
|
|
Drops database tables for all models with the given engine
|
|
"""
|
|
models = (Environment, Status, Session, Deployment,
|
|
ApiStats, Package, Category, Class)
|
|
for model in models:
|
|
model.metadata.drop_all(engine)
|