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:
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
@@ -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 ###
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user