# Copyright 2013 Hewlett-Packard Development Company, L.P. # # 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 container service """ from oslo_db.sqlalchemy import models from oslo_db.sqlalchemy.types import String from oslo_serialization import jsonutils import six.moves.urllib.parse as urlparse from sqlalchemy import Boolean from sqlalchemy import Column from sqlalchemy import DateTime from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Integer from sqlalchemy import schema from sqlalchemy import Text from sqlalchemy.types import TypeDecorator, TEXT from sqlalchemy.dialects.mysql import TEXT as mysql_TEXT from sqlalchemy.dialects.mysql import TINYTEXT import magnum.conf CONF = magnum.conf.CONF def table_args(): engine_name = urlparse.urlparse(CONF.database.connection).scheme if engine_name == 'mysql': return {'mysql_engine': CONF.database.mysql_engine, 'mysql_charset': "utf8"} return None class JsonEncodedType(TypeDecorator): """Abstract base type serialized as json-encoded string in db.""" type = None impl = TEXT def process_bind_param(self, value, dialect): if value is None: # Save default value according to current type to keep the # interface the consistent. value = self.type() elif not isinstance(value, self.type): raise TypeError("%(class)s supposes to store " "%(type)s objects, but %(value)s " "given" % {'class': self.__class__.__name__, 'type': self.type.__name__, 'value': type(value).__name__}) serialized_value = jsonutils.dumps(value) return serialized_value def process_result_value(self, value, dialect): if value is not None: value = jsonutils.loads(value) return value class JSONEncodedDict(JsonEncodedType): """Represents dict serialized as json-encoded string in db.""" type = dict class JSONEncodedList(JsonEncodedType): """Represents list serialized as json-encoded string in db.""" type = list class MagnumBase(models.TimestampMixin, models.ModelBase): metadata = None def as_dict(self): d = {} for c in self.__table__.columns: d[c.name] = self[c.name] return d def save(self, session=None): import magnum.db.sqlalchemy.api as db_api if session is None: session = db_api.get_session() super(MagnumBase, self).save(session) Base = declarative_base(cls=MagnumBase) class Cluster(Base): """Represents a Cluster.""" __tablename__ = 'cluster' __table_args__ = ( schema.UniqueConstraint('uuid', name='uniq_bay0uuid'), table_args() ) id = Column(Integer, primary_key=True) project_id = Column(String(255)) user_id = Column(String(255)) uuid = Column(String(36)) name = Column(String(255)) cluster_template_id = Column(String(255)) keypair = Column(String(255)) docker_volume_size = Column(Integer()) labels = Column(JSONEncodedDict) master_flavor_id = Column(String(255)) flavor_id = Column(String(255)) stack_id = Column(String(255)) api_address = Column(String(255)) status = Column(String(20)) status_reason = Column(Text) health_status = Column(String(20)) health_status_reason = Column(JSONEncodedDict) create_timeout = Column(Integer()) discovery_url = Column(String(255, mysql_ndb_type=TINYTEXT)) # TODO(wanghua): encrypt trust_id in db trust_id = Column(String(255)) trustee_username = Column(String(255, mysql_ndb_type=TINYTEXT)) trustee_user_id = Column(String(255)) # TODO(wanghua): encrypt trustee_password in db trustee_password = Column(String(255, mysql_ndb_type=TINYTEXT)) coe_version = Column(String(255, mysql_ndb_type=TINYTEXT)) container_version = Column(String(255, mysql_ndb_type=TINYTEXT)) # (yuanying) if we use barbican, # cert_ref size is determined by below format # * http(s)://${DOMAIN_NAME}/v1/containers/${UUID} # as a result, cert_ref length is estimated to 312 chars. # but we can use another backend to store certs. # so, we use 512 chars to get some buffer. ca_cert_ref = Column(String(512, mysql_ndb_type=mysql_TEXT)) magnum_cert_ref = Column(String(512, mysql_ndb_type=mysql_TEXT)) etcd_ca_cert_ref = Column(String(512, mysql_ndb_type=mysql_TEXT)) front_proxy_ca_cert_ref = Column(String(512, mysql_ndb_type=mysql_TEXT)) fixed_network = Column(String(255, mysql_ndb_type=TINYTEXT)) fixed_subnet = Column(String(255, mysql_ndb_type=TINYTEXT)) floating_ip_enabled = Column(Boolean, default=True) master_lb_enabled = Column(Boolean, default=False) class ClusterTemplate(Base): """Represents a ClusterTemplate.""" __tablename__ = 'cluster_template' __table_args__ = ( schema.UniqueConstraint('uuid', name='uniq_baymodel0uuid'), table_args() ) id = Column(Integer, primary_key=True) uuid = Column(String(36)) project_id = Column(String(255)) user_id = Column(String(255)) name = Column(String(255)) image_id = Column(String(255)) flavor_id = Column(String(255)) master_flavor_id = Column(String(255)) keypair_id = Column(String(255)) external_network_id = Column(String(255)) fixed_network = Column(String(255, mysql_ndb_type=TINYTEXT)) fixed_subnet = Column(String(255, mysql_ndb_type=TINYTEXT)) network_driver = Column(String(255, mysql_ndb_type=TINYTEXT)) volume_driver = Column(String(255, mysql_ndb_type=TINYTEXT)) dns_nameserver = Column(String(255, mysql_ndb_type=TINYTEXT)) apiserver_port = Column(Integer()) docker_volume_size = Column(Integer()) docker_storage_driver = Column(String(255)) cluster_distro = Column(String(255, mysql_ndb_type=TINYTEXT)) coe = Column(String(255, mysql_ndb_type=TINYTEXT)) http_proxy = Column(String(255, mysql_ndb_type=TINYTEXT)) https_proxy = Column(String(255, mysql_ndb_type=TINYTEXT)) no_proxy = Column(String(255, mysql_ndb_type=TINYTEXT)) registry_enabled = Column(Boolean, default=False) labels = Column(JSONEncodedDict) tls_disabled = Column(Boolean, default=False) public = Column(Boolean, default=False) server_type = Column(String(255)) insecure_registry = Column(String(255, mysql_ndb_type=TINYTEXT)) master_lb_enabled = Column(Boolean, default=False) floating_ip_enabled = Column(Boolean, default=True) hidden = Column(Boolean, default=False) tags = Column(String(255)) class X509KeyPair(Base): """X509KeyPair""" __tablename__ = 'x509keypair' __table_args__ = ( schema.UniqueConstraint('uuid', name='uniq_x509keypair0uuid'), table_args() ) id = Column(Integer, primary_key=True) uuid = Column(String(36)) certificate = Column(Text()) private_key = Column(Text()) private_key_passphrase = Column(Text()) intermediates = Column(Text()) project_id = Column(String(255)) user_id = Column(String(255)) class MagnumService(Base): """Represents health status of various magnum services""" __tablename__ = 'magnum_service' __table_args__ = ( schema.UniqueConstraint("host", "binary", name="uniq_magnum_service0host0binary"), table_args() ) id = Column(Integer, primary_key=True) host = Column(String(255)) binary = Column(String(255)) disabled = Column(Boolean, default=False) disabled_reason = Column(String(255)) last_seen_up = Column(DateTime, nullable=True) forced_down = Column(Boolean, default=False) report_count = Column(Integer, nullable=False, default=0) class Quota(Base): """Represents Quota for a resource within a project""" __tablename__ = 'quotas' __table_args__ = ( schema.UniqueConstraint( "project_id", "resource", name='uniq_quotas0project_id0resource'), table_args() ) id = Column(Integer, primary_key=True) project_id = Column(String(255)) resource = Column(String(255)) hard_limit = Column(Integer()) class Federation(Base): """Represents a Federation.""" __tablename__ = 'federation' __table_args__ = ( schema.UniqueConstraint("uuid", name="uniq_federation0uuid"), table_args() ) id = Column(Integer, primary_key=True) project_id = Column(String(255)) uuid = Column(String(36)) name = Column(String(255)) hostcluster_id = Column(String(255)) member_ids = Column(JSONEncodedList) status = Column(String(20)) status_reason = Column(Text) properties = Column(JSONEncodedDict) class NodeGroup(Base): """Represents a NodeGroup.""" __tablename__ = 'nodegroup' __table_args__ = ( schema.UniqueConstraint('uuid', name='uniq_nodegroup0uuid'), schema.UniqueConstraint( 'cluster_id', 'name', name='uniq_nodegroup0cluster_id0name'), table_args() ) id = Column(Integer, primary_key=True) uuid = Column(String(36)) name = Column(String(255)) cluster_id = Column(String(255)) project_id = Column(String(255)) docker_volume_size = Column(Integer(), nullable=True) labels = Column(JSONEncodedDict, nullable=True) flavor_id = Column(String(255), nullable=True) image_id = Column(String(255), nullable=True) node_addresses = Column(JSONEncodedList, nullable=True) node_count = Column(Integer()) role = Column(String(255)) # NOTE(ttsiouts) We have to define the min and # max number of nodes for each nodegroup max_node_count = Column(Integer()) min_node_count = Column(Integer()) is_default = Column(Boolean, default=False) stack_id = Column(String(255)) status = Column(String(20)) status_reason = Column(Text) version = Column(String(20))