Connecting REST API to DB, part I

* Implemented Clusters POST URI functionality which creates a
      new cluster
    * Added new create_cluster function in DB API
    * Added new get_clusters_nodes function in DB API
    * Updated DB scema
    ** Removed endpoint_types table and merged content in endpoints
       table
    ** Added volume_size column in clusters and nodes tables
    ** Added deleted (boolean) column in clusteers, nodes and endpoints
       tables
    * Added 'add' class method in DB Cluster, Node and Endpoint classes

Change-Id: Ie7f03dc0a0d9d143a212b56be179d4f2a162c75b
This commit is contained in:
dagnello
2014-12-02 11:05:45 -08:00
parent fcbf581712
commit 24cffca99e
5 changed files with 122 additions and 35 deletions

View File

@@ -18,7 +18,10 @@
"""Version 1 of the Cue API
"""
from cue.db import api as dbapi
import datetime
import uuid
import pecan
from pecan import rest
@@ -128,6 +131,24 @@ class ClustersController(rest.RestController):
if cluster_flavor != node.flavor:
pecan.abort(400)
# TODO(dagnello): project_id will have to be extracted from HTTP header
db_cluster = dbapi.create_cluster(str(uuid.uuid1()), data.name,
data.nic, data.volume_size,
cluster_flavor, len(data.nodes))
db_cluster_nodes = dbapi.get_cluster_nodes(db_cluster.id)
data.cluster_id = db_cluster.id
data.status = db_cluster.status
data.created = db_cluster.created_at
data.updated = db_cluster.updated_at
for node in data.nodes:
db_node = db_cluster_nodes.pop()
node.node_id = db_node.id
node.status = db_node.status
node.created = db_node.created_at
node.updated = db_node.updated_at
return data
@pecan.expose()

View File

@@ -1,5 +1,5 @@
# Copyright 2011 VMware, Inc.
# All Rights Reserved.
# Copyright 2011 VMware, Inc.
# All Rights Reserved.
#
# 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
@@ -14,6 +14,7 @@
# under the License.
#
# Copied from Neutron
from cue.db import models
from oslo.config import cfg
from oslo.db import options as db_options
@@ -49,3 +50,20 @@ def get_session(autocommit=True, expire_on_commit=False):
facade = _create_facade_lazily()
return facade.get_session(autocommit=autocommit,
expire_on_commit=expire_on_commit)
def create_cluster(project_id, name, nic, vol_size, flavor, num_of_nodes):
session = get_session()
cluster_ref = models.Cluster.add(session, project_id, name, nic, vol_size)
for i in range(num_of_nodes):
models.Node.add(session, cluster_ref.id, flavor, vol_size)
return cluster_ref
def get_cluster_nodes(cluster_id):
session = get_session()
return models.Node.get_all(session, cluster_id=cluster_id)

View File

@@ -43,13 +43,10 @@ def upgrade():
sa.Column('nic', sa.String(length=36), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('status', sa.String(length=50), nullable=True),
sa.Column('volume_size', sa.Integer(), nullable=False),
sa.Column('deleted', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('endpoint_types',
sa.Column('type', sa.SmallInteger(), autoincrement=False, nullable=False),
sa.Column('description', sa.String(length=255), nullable=False),
sa.PrimaryKeyConstraint('type')
)
op.create_table('nodes',
sa.Column('id', types.UUID(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
@@ -59,13 +56,18 @@ def upgrade():
sa.Column('flavor', sa.String(length=36), nullable=False),
sa.Column('instance_id', sa.String(length=36), nullable=True),
sa.Column('status', sa.String(length=50), nullable=True),
sa.Column('volume_size', sa.Integer(), nullable=False),
sa.Column('deleted', sa.Boolean(), nullable=False),
sa.ForeignKeyConstraint(['cluster_id'], ['clusters.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('endpoints',
sa.Column('id', types.UUID(), nullable=False),
sa.Column('node_id', types.UUID(), nullable=False),
sa.Column('type', sa.String(length=255), nullable=False),
sa.Column('uri', sa.String(length=255), nullable=False),
sa.ForeignKeyConstraint(['id'], ['nodes.id'], ),
sa.Column('deleted', sa.Boolean(), nullable=False),
sa.ForeignKeyConstraint(['node_id'], ['nodes.id'], ),
sa.PrimaryKeyConstraint('id')
)
### end Alembic commands ###
@@ -75,6 +77,5 @@ def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_table('endpoints')
op.drop_table('nodes')
op.drop_table('endpoint_types')
op.drop_table('clusters')
### end Alembic commands ###

View File

@@ -6,7 +6,7 @@
# 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
# 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
@@ -20,7 +20,6 @@ import sqlalchemy as sa
from cue.db import base
from cue.db import types
CLUSTER_STATUSES = (
'BUILDING',
'ACTIVE',
@@ -30,13 +29,27 @@ CLUSTER_STATUSES = (
NODE_STATUSES = CLUSTER_STATUSES
class Cluster(base.BASE, base.IdMixin, base.ProjectMixin, base.TimeMixin):
__tablename__ = 'clusters'
class Endpoint(base.BASE):
__tablename__ = 'endpoints'
nic = sa.Column(sa.String(36), nullable=False)
name = sa.Column(sa.String(255), nullable=False)
status = sa.Column(sa.String(50), sa.Enum(*CLUSTER_STATUSES))
sa.Index("clusters_cluster_id_idx", "cluster_id", unique=True)
node_id = sa.Column(types.UUID(), sa.ForeignKey('nodes.id'),
primary_key=True)
uri = sa.Column(sa.String(255), nullable=False)
type = sa.Column(sa.String(length=255), nullable=False)
deleted = sa.Column(sa.Boolean(), nullable=False)
sa.Index("endpoints_id_idx", "id", unique=True)
sa.Index("endpoints_nodes_id_idx", "node_id", unique=False)
@classmethod
def add(cls, session, node_id, endpoint_type, uri):
endpoint = {
"node_id": node_id,
"uri": uri,
"type": endpoint_type,
"deleted": False
}
return super(Endpoint, cls).create(session, **endpoint)
class Node(base.BASE, base.IdMixin, base.TimeMixin):
@@ -48,22 +61,44 @@ class Node(base.BASE, base.IdMixin, base.TimeMixin):
flavor = sa.Column(sa.String(36), nullable=False)
instance_id = sa.Column(sa.String(36), nullable=True)
status = sa.Column(sa.String(50), sa.Enum(*NODE_STATUSES))
volume_size = sa.Column(sa.Integer(), nullable=False)
deleted = sa.Column(sa.Boolean(), nullable=False)
sa.Index("nodes_id_idx", "id", unique=True)
sa.Index("nodes_cluster_id_idx", "cluster_id", unique=False)
@classmethod
def add(cls, session, cluster_id, flavor, vol_size):
node = {
"cluster_id": cluster_id,
"flavor": flavor,
"volume_size": vol_size,
"deleted": False,
"status": CLUSTER_STATUSES[CLUSTER_STATUSES.index('BUILDING')]
}
class EndpointTypes(base.BASE):
__tablename__ = 'endpoint_types'
type = sa.Column(sa.SmallInteger(), primary_key=True, autoincrement=False)
description = sa.Column(sa.String(255), nullable=False)
return super(Node, cls).create(session, **node)
class Endpoint(base.BASE):
__tablename__ = 'endpoints'
class Cluster(base.BASE, base.IdMixin, base.TimeMixin):
__tablename__ = 'clusters'
id = sa.Column(types.UUID(), sa.ForeignKey('nodes.id'), primary_key=True)
uri = sa.Column(sa.String(255), nullable=False)
type = sa.Column(sa.SmallInteger(),
sa.ForeignKey('endpoint_types.endpoint_type')),
sa.Index("endpoints_id_idx", "id", unique=True)
project_id = sa.Column(sa.String(36), nullable=False)
nic = sa.Column(sa.String(36), nullable=False)
name = sa.Column(sa.String(255), nullable=False)
status = sa.Column(sa.String(50), sa.Enum(*CLUSTER_STATUSES))
volume_size = sa.Column(sa.Integer(), nullable=False)
deleted = sa.Column(sa.Boolean(), nullable=False)
sa.Index("clusters_cluster_id_idx", "cluster_id", unique=True)
@classmethod
def add(cls, session, project_id, name, nic, vol_size):
cluster = {
"project_id": project_id,
"name": name,
"nic": nic,
"volume_size": vol_size,
"deleted": False,
"status": CLUSTER_STATUSES[CLUSTER_STATUSES.index('BUILDING')]
}
return super(Cluster, cls).create(session, **cluster)

View File

@@ -31,7 +31,9 @@ class ClusterTests(base.TestCase):
data = {
"project_id": UUID1,
"name": "test",
"nic": UUID2
"nic": UUID2,
"volume_size": 0,
"deleted": False
}
ref = models.Cluster.create(self.session, **data)
self.assertIsInstance(ref, models.Cluster)
@@ -48,7 +50,9 @@ class ClusterTests(base.TestCase):
"project_id": UUID1,
"name": "test",
"status": "BUILDING",
"nic": UUID2
"nic": UUID2,
"volume_size": 0,
"deleted": False
}
ref = models.Cluster.create(self.session, **data)
self.assertIsInstance(ref, models.Cluster)
@@ -89,7 +93,9 @@ class ClusterTests(base.TestCase):
data = {
"project_id": UUID1,
"name": "test",
"nic": UUID2
"nic": UUID2,
"volume_size": 0,
"deleted": False
}
ref = models.Cluster.create(self.session, **data)
self.assertIsInstance(ref, models.Cluster)
@@ -112,7 +118,9 @@ class ClusterTests(base.TestCase):
"project_id": UUID1,
"name": "test1",
"status": "BUILDING",
"nic": UUID2
"nic": UUID2,
"volume_size": 0,
"deleted": False
}
ref1 = models.Cluster.create(self.session, **data)
self.assertIsInstance(ref1, models.Cluster)
@@ -153,7 +161,9 @@ class NodeRepositoryTests(base.TestCase):
cluster = {
"project_id": UUID1,
"name": "test",
"nic": UUID2
"nic": UUID2,
"volume_size": 0,
"deleted": False
}
cluster_ref = models.Cluster.create(self.session, **cluster)
@@ -161,7 +171,9 @@ class NodeRepositoryTests(base.TestCase):
node = {
"flavor": 'foo',
"instance_id": 'bar',
"cluster_id": cluster_ref.id
"cluster_id": cluster_ref.id,
"volume_size": 0,
"deleted": False
}
node_ref = models.Node.create(self.session, **node)