Add the Object Capsule and database table

Part of blueprint introduce-compose

Change-Id: I8ed3711d14e8cda92b5bb5cf2874980cbd66cad0
Signed-off-by: Kevin Zhao <kevin.zhao@arm.com>
This commit is contained in:
Kevin Zhao 2017-07-17 22:40:45 +08:00
parent 080f4fb00f
commit 0b4c53e363
8 changed files with 266 additions and 2 deletions

View File

@ -177,3 +177,26 @@ class ResourceClass(Base):
@classmethod
def fields(cls):
return cls._fields
class Capsule(Base):
"""Represents a capsule."""
_path = '/capsules'
_fields = objects.Capsule.fields.keys()
def __init__(self, capsule_data):
self.path = Capsule.path()
for f in Capsule.fields():
setattr(self, f, None)
self.id = 1
self.update(capsule_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
return cls._fields

View File

@ -0,0 +1,58 @@
# Copyright 2017 ARM Holdings
#
# 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.
"""create capsule table
Revision ID: a251f1f61217
Revises: 75315e219cfb
Create Date: 2017-06-20 17:12:56.105277
"""
# revision identifiers, used by Alembic.
revision = 'a251f1f61217'
down_revision = '75315e219cfb'
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
from zun.db.sqlalchemy import models
def upgrade():
op.create_table(
'capsule',
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('capsule_version', sa.String(length=255), nullable=True),
sa.Column('kind', sa.String(length=36), nullable=True),
sa.Column('project_id', sa.String(length=255), nullable=True),
sa.Column('user_id', sa.String(length=255), nullable=True),
sa.Column('restart_policy', sa.String(length=255), nullable=True),
sa.Column('host_selector', sa.String(length=255), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('uuid', sa.String(length=36), nullable=False),
sa.Column('status', sa.String(length=255), nullable=True),
sa.Column('status_reason', sa.Text(), nullable=True),
sa.Column('message', models.JSONEncodedDict(), nullable=True),
sa.Column('spec', models.JSONEncodedDict(), nullable=True),
sa.Column('cpu', sa.Float(), nullable=True),
sa.Column('memory', sa.String(length=255), nullable=True),
sa.Column('meta_name', sa.String(length=255), nullable=True),
sa.Column('meta_labels', models.JSONEncodedList(), nullable=True),
sa.Column('containers_uuids', models.JSONEncodedList(), nullable=True),
sa.PrimaryKeyConstraint('id'),
)

View File

@ -288,3 +288,30 @@ class ComputeNode(Base):
os = Column(String(64), nullable=True)
kernel_version = Column(String(128), nullable=True)
labels = Column(JSONEncodedDict)
class Capsule(Base):
"""Represents a capsule."""
__tablename__ = 'capsule'
__table_args__ = (
schema.UniqueConstraint('uuid', name='uniq_capsule0uuid'),
table_args()
)
uuid = Column(String(36), nullable=False)
id = Column(Integer, primary_key=True, nullable=False)
host_selector = Column(String(255))
capsule_version = Column(String(255))
kind = Column(String(255))
restart_policy = Column(JSONEncodedDict)
project_id = Column(String(255))
user_id = Column(String(255))
status = Column(String(20))
status_reason = Column(Text, nullable=True)
meta_labels = Column(JSONEncodedList)
meta_name = Column(String(255))
spec = Column(JSONEncodedDict)
containers_uuids = Column(JSONEncodedList)
cpu = Column(Float)
memory = Column(String(255))

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from zun.objects import capsule
from zun.objects import compute_node
from zun.objects import container
from zun.objects import image
@ -26,6 +27,7 @@ NUMATopology = numa.NUMATopology
ResourceProvider = resource_provider.ResourceProvider
ResourceClass = resource_class.ResourceClass
ComputeNode = compute_node.ComputeNode
Capsule = capsule.Capsule
__all__ = (
Container,
@ -36,4 +38,5 @@ __all__ = (
NUMANode,
NUMATopology,
ComputeNode,
Capsule,
)

152
zun/objects/capsule.py Normal file
View File

@ -0,0 +1,152 @@
# Copyright 2017 ARM Holdings.
#
# 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_versionedobjects import fields
from zun.db import api as dbapi
from zun.objects import base
from zun.objects import fields as z_fields
@base.ZunObjectRegistry.register
class Capsule(base.ZunPersistentObject, base.ZunObject):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'capsule_version': fields.StringField(nullable=True),
'kind': fields.StringField(nullable=True),
'restart_policy': fields.DictOfStringsField(nullable=True),
'host_selector': fields.StringField(nullable=True),
# uuid is the infra-container id
'id': fields.IntegerField(),
'uuid': fields.UUIDField(nullable=True),
'project_id': fields.StringField(nullable=True),
'user_id': fields.StringField(nullable=True),
'status': z_fields.ContainerStatusField(nullable=True),
'status_reason': fields.StringField(nullable=True),
'cpu': fields.FloatField(nullable=True),
'memory': fields.StringField(nullable=True),
# conclude the readable message
# 'key': 'value'--> 'time':'message'
# wait until zun notify is finished
# 'message': fields.DictOfStringsField(nullable=True),
'spec': z_fields.JsonField(nullable=True),
'meta_name': fields.StringField(nullable=True),
'meta_labels': z_fields.JsonField(nullable=True),
'containers': fields.ListOfObjectsField('Container', nullable=True),
'containers_uuids': fields.ListOfStringsField(nullable=True),
# add volumes after Cinder integration is ready
# 'volumes': fields.ListOfObjectsField(nullable=True),
}
@staticmethod
def _from_db_object(capsule, db_capsule):
"""Converts a database entity to a formal object."""
for field in capsule.fields:
if field != 'containers':
setattr(capsule, field, db_capsule[field])
capsule.obj_reset_changes()
return capsule
@staticmethod
def _from_db_object_list(db_objects, cls, context):
"""Converts a list of database entities to a list of formal objects."""
return [Capsule._from_db_object(cls(context), obj)
for obj in db_objects]
@base.remotable_classmethod
def get_by_uuid(cls, context, uuid):
"""Find a container based on uuid and return a :class:`Container` object.
:param uuid: the uuid of a container.
:param context: Security context
:returns: a :class:`Container` object.
"""
db_capsule = dbapi.get_capsule_by_uuid(context, uuid)
capsule = Capsule._from_db_object(cls(context), db_capsule)
return capsule
@base.remotable_classmethod
def list(cls, context, limit=None, marker=None,
sort_key=None, sort_dir=None, filters=None):
"""Return a list of Container objects.
:param context: Security context.
:param limit: maximum number of resources to return in a single result.
:param marker: pagination marker for large data sets.
:param sort_key: column to sort results by.
:param sort_dir: direction to sort. "asc" or "desc".
:param filters: filters when list containers, the filter name could be
'name', 'image', 'project_id', 'user_id', 'memory'.
For example, filters={'image': 'nginx'}
:returns: a list of :class:`Container` object.
"""
db_capsules = dbapi.list_capsules(
context, limit=limit, marker=marker, sort_key=sort_key,
sort_dir=sort_dir, filters=filters)
return Capsule._from_db_object_list(db_capsules, cls, context)
@base.remotable
def create(self, context):
"""Create a Container record in the DB.
:param context: Security context. NOTE: This should only
be used internally by the indirection_api.
Unfortunately, RPC requires context as the first
argument, even though we don't use it.
A context should be set when instantiating the
object, e.g.: Container(context)
"""
values = self.obj_get_changes()
db_capsule = dbapi.create_capsule(context, values)
self._from_db_object(self, db_capsule)
@base.remotable
def destroy(self, context=None):
"""Delete the Container from the DB.
:param context: Security context. NOTE: This should only
be used internally by the indirection_api.
Unfortunately, RPC requires context as the first
argument, even though we don't use it.
A context should be set when instantiating the
object, e.g.: Container(context)
"""
dbapi.destroy_capsule(context, self.uuid)
self.obj_reset_changes()
@base.remotable
def save(self, context=None):
"""Save updates to this Container.
Updates will be made column by column based on the result
of self.what_changed().
:param context: Security context. NOTE: This should only
be used internally by the indirection_api.
Unfortunately, RPC requires context as the first
argument, even though we don't use it.
A context should be set when instantiating the
object, e.g.: Container(context)
"""
updates = self.obj_get_changes()
dbapi.update_capsule(context, self.uuid, updates)
self.obj_reset_changes()

View File

@ -353,6 +353,7 @@ object_data = {
'ResourceProvider': '1.0-92b427359d5a4cf9ec6c72cbe630ee24',
'ZunService': '1.1-b1549134bfd5271daec417ca8cabc77e',
'ComputeNode': '1.6-33a173b969781644a95ea2925eb5cca2',
'Capsule': '1.0-0dce1bd569773c35193d75c285226e75',
}

View File

@ -1,4 +1,4 @@
# Copyright 2017 Linaro Limited
# Copyright 2017 ARM Holdings.
#
# 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

View File

@ -1,4 +1,4 @@
# Copyright (c) 2017 Linaro Limited
# Copyright 2017 ARM Holdings.
#
# 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