summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--development/development_enviroment.sh59
-rw-r--r--reddwarf/common/utils.py7
-rw-r--r--reddwarf/database/models.py19
-rw-r--r--reddwarf/database/service.py33
-rw-r--r--reddwarf/database/views.py14
-rw-r--r--reddwarf/tests/unit/test_database_models.py20
-rw-r--r--reddwarf/tests/unit/test_database_service.py102
8 files changed, 233 insertions, 23 deletions
diff --git a/.gitignore b/.gitignore
index ce9b613f..4fe11bc5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@ guest-agent-files.txt
reddwarf.egg*
reddwarf/vcsversion.py
*py*.egg
+.coverage
+covhtml/
diff --git a/development/development_enviroment.sh b/development/development_enviroment.sh
index 7f69d25f..cb08a988 100644
--- a/development/development_enviroment.sh
+++ b/development/development_enviroment.sh
@@ -35,22 +35,52 @@ keystone --endpoint http://localhost:35357/v2.0 --token be19c524ddc92109a224 use
# These are the values
REDDWARF_TENANT=reddwarf
echo $REDDWARF_TENANT
+REDDWARF_USER=$(mysql keystone -e "select id from user where name='reddwarf';" | awk 'NR==2')
echo $REDDWARF_USER
+REDDWARF_ROLE=$(mysql keystone -e "select id from role where name='reddwarf';" | awk 'NR==2')
echo $REDDWARF_ROLE
# These all need to be set tenant did not work with the id but the name did match in the auth shim.
-# REDDWARF_TOKEN=
+REDDWARF_TOKEN=$(curl -d '{"auth":{"passwordCredentials":{"username": "reddwarf", "password": "REDDWARF-PASS"},"tenantName":"reddwarf"}}' -H "Content-type: application/json" http://localhost:35357/v2.0/tokens | python -mjson.tool | grep id | tr -s ' ' | cut -d ' ' -f 3 | sed s/\"/''/g | awk 'NR==2' | cut -d ',' -f 1)
+echo $REDDWARF_TOKEN
+
# Now attempt a login
-curl -d '{"auth":{"passwordCredentials":{"username": "reddwarf", "password": "REDDWARF-PASS"},"tenantName":"reddwarf"}}' \
- -H "Content-type: application/json" http://localhost:35357/v2.0/tokens | python -mjson.tool
+#curl -d '{"auth":{"passwordCredentials":{"username": "reddwarf", "password": "REDDWARF-PASS"},"tenantName":"reddwarf"}}' \
+# -H "Content-type: application/json" http://localhost:35357/v2.0/tokens | python -mjson.tool
# now get a list of instances, which connects over python-novaclient to nova
# NOTE THIS AUTH TOKEN NEEDS TO BE CHANGED
# Also note that keystone uses the tenant id now and _not_ the name
-# curl -H"X-Auth-Token:$REDDWARF_TOKEN" http://0.0.0.0:8779/v0.1/$REDDWARF_TENANT/instances
-# curl -H"Content-type:application/json" -H"X-Auth-Token:$REDDWARF_TOKEN" \
-# http://0.0.0.0:8779/v0.1/$REDDWARF_TENANT/instances -d '{"name":"my_test","flavor":"1"}'
+# list instances
+# curl -H"X-Auth-Token:$REDDWARF_TOKEN" http://0.0.0.0:8779/v0.1/$REDDWARF_TENANT/instances | python -mjson.tool
+# old create instance:
+# curl -H"Content-type:application/json" -H"X-Auth-Token:$REDDWARF_TOKEN" http://0.0.0.0:8779/v0.1/$REDDWARF_TENANT/instances -d '{"name":"my_test","flavor":"1"}' | python -mjson.tool
+# create instance:
+# curl -H"Content-type:application/json" -H"X-Auth-Token:$REDDWARF_TOKEN" http://0.0.0.0:8779/v0.1/$REDDWARF_TENANT/instances -d '{"instance": {"databases": [{"character_set": "utf8", "collate": "utf8_general_ci", "name": "sampledb"}, {"name": "nextround"}], "flavorRef": "http://0.0.0.0:8779/v0.1/$REDDWARF_TENANT/flavors/1", "name": "json_rack_instance", "volume": {"size": "2"}}}'| python -mjson.tool
+# {
+# "instance": {
+# "databases": [
+# {
+# "character_set": "utf8",
+# "collate": "utf8_general_ci",
+# "name": "sampledb"
+# },
+# {
+# "name": "nextround"
+# }
+# ],
+# "flavorRef": "http://0.0.0.0:8779/v0.1/$REDDWARF_TENANT/flavors/1",
+# "name": "json_rack_instance",
+# "volume": {
+# "size": "2"
+# }
+# }
+# }
+
+# DELETE INSTANCE
+# curl -H"X-Auth-Token:$REDDWARF_TOKEN" http://0.0.0.0:8779/v0.1/$REDDWARF_TENANT/instances/id -X DELETE | python -mjson.tool
+
# update the etc/reddwarf/reddwarf.conf.sample
# add this config setting
@@ -67,9 +97,24 @@ curl -d '{"auth":{"passwordCredentials":{"username": "reddwarf", "password": "RE
# ssh-keygen
-# build the image for reddwarf
+# first time build the image for reddwarf
# ./bootstrap/bootstrap.sh
+##### re-add image manually #####
+VM_PATH=~/oneiric_mysql_image
+UBUNTU_DISTRO="ubuntu 11.10"
+UBUNTU_DISTRO_NAME=oneiric
+QCOW_IMAGE=`find $VM_PATH -name '*.qcow2'`
+function get_glance_id () {
+ echo `$@ | awk '{print $6}'`
+}
+glance add name="oneiric_mysql_image" is_public=true container_format=ovf disk_format=qcow2 distro='"ubuntu 11.10"' -A $REDDWARF_TOKEN < $QCOW_IMAGE
+# GLANCE_IMAGEID=
+echo "updating your database - $GLANCE_IMAGEID"
+sqlite3 /src/reddwarf_test.sqlite "INSERT INTO service_images VALUES('1', 'database', '$GLANCE_IMAGEID');"
+#sqlite3 /src/reddwarf_test.sqlite "UPDATE service_images set image_id='$GLANCE_IMAGEID';"
+echo "done GLANCE IMAGE ID = $GLANCE_IMAGEID"
+
# add the image to the reddwarf database
# get the image id from glance
# glance index -A $REDDWARF_TOKEN
diff --git a/reddwarf/common/utils.py b/reddwarf/common/utils.py
index b3412d18..8f04053f 100644
--- a/reddwarf/common/utils.py
+++ b/reddwarf/common/utils.py
@@ -42,6 +42,13 @@ def stringify_keys(dictionary):
return dict((str(key), value) for key, value in dictionary.iteritems())
+def exclude(key_values, *exclude_keys):
+ if key_values is None:
+ return None
+ return dict((key, value) for key, value in key_values.iteritems()
+ if key not in exclude_keys)
+
+
def generate_uuid():
return str(uuid.uuid4())
diff --git a/reddwarf/database/models.py b/reddwarf/database/models.py
index 614ee728..085d1840 100644
--- a/reddwarf/database/models.py
+++ b/reddwarf/database/models.py
@@ -116,7 +116,8 @@ class RemoteModelBase(ModelBase):
class Instance(RemoteModelBase):
- _data_fields = ['name', 'status', 'updated', 'id', 'flavor']
+ _data_fields = ['name', 'status', 'id', 'created', 'updated',
+ 'flavor', 'links', 'addresses']
def __init__(self, server=None, context=None, uuid=None):
if server is None and context is None and uuid is None:
@@ -124,7 +125,12 @@ class Instance(RemoteModelBase):
msg = "server, content, and uuid are not defined"
raise InvalidModelError(msg)
elif server is None:
- self._data_object = self.get_client(context).servers.get(uuid)
+ try:
+ self._data_object = self.get_client(context).servers.get(uuid)
+ except nova_exceptions.NotFound, e:
+ raise rd_exceptions.NotFound(uuid=uuid)
+ except nova_exceptions.ClientException, e:
+ raise rd_exceptions.ReddwarfError()
else:
self._data_object = server
@@ -138,10 +144,13 @@ class Instance(RemoteModelBase):
raise rd_exceptions.ReddwarfError()
@classmethod
- def create(cls, context, name, image_id, flavor):
- srv = cls.get_client(context).servers.create(name,
+ def create(cls, context, image_id, body):
+ # self.is_valid()
+ LOG.info("instance body : '%s'\n\n" % body)
+ flavorRef = body['instance']['flavorRef']
+ srv = cls.get_client(context).servers.create(body['instance']['name'],
image_id,
- flavor)
+ flavorRef)
return Instance(server=srv)
diff --git a/reddwarf/database/service.py b/reddwarf/database/service.py
index a72527c0..22d92c53 100644
--- a/reddwarf/database/service.py
+++ b/reddwarf/database/service.py
@@ -23,20 +23,42 @@ from reddwarf import rpc
from reddwarf.common import config
from reddwarf.common import context as rd_context
from reddwarf.common import exception
+from reddwarf.common import utils
from reddwarf.common import wsgi
from reddwarf.database import models
from reddwarf.database import views
CONFIG = config.Config
-LOG = logging.getLogger('reddwarf.database.service')
+LOG = logging.getLogger(__name__)
class BaseController(wsgi.Controller):
"""Base controller class."""
+ exclude_attr = []
+ exception_map = {
+ webob.exc.HTTPUnprocessableEntity: [
+ ],
+ webob.exc.HTTPBadRequest: [
+ models.InvalidModelError,
+ ],
+ webob.exc.HTTPNotFound: [
+ exception.NotFound,
+ models.ModelNotFoundError,
+ ],
+ webob.exc.HTTPConflict: [
+ ],
+ }
+
def __init__(self):
pass
+ def _extract_required_params(self, params, model_name):
+ params = params or {}
+ model_params = params.get(model_name, {})
+ return utils.stringify_keys(utils.exclude(model_params,
+ *self.exclude_attr))
+
class InstanceController(BaseController):
"""Controller for instance functionality"""
@@ -67,10 +89,11 @@ class InstanceController(BaseController):
context = rd_context.ReddwarfContext(
auth_tok=req.headers["X-Auth-Token"],
tenant=tenant_id)
+ # TODO(cp16net) : need to handle exceptions here if the delete fails
models.Instance.delete(context=context, uuid=id)
# TODO(hub-cap): fixgure out why the result is coming back as None
- LOG.info("result of delete %s" % result)
+ # LOG.info("result of delete %s" % result)
# TODO(cp16net): need to set the return code correctly
return wsgi.Result(202)
@@ -87,15 +110,17 @@ class InstanceController(BaseController):
# code. Or maybe we shouldnt due to the nature of changing images.
# This needs discussion.
# TODO(hub-cap): turn this into middleware
+ LOG.info("Creating a database instance for tenant '%s'" % tenant_id)
+ LOG.info("req : '%s'\n\n" % req)
+ LOG.info("body : '%s'\n\n" % body)
context = rd_context.ReddwarfContext(
auth_tok=req.headers["X-Auth-Token"],
tenant=tenant_id)
database = models.ServiceImage.find_by(service_name="database")
image_id = database['image_id']
server = models.Instance.create(context,
- body['name'],
image_id,
- body['flavor']).data()
+ body).data()
# Now wait for the response from the create to do additional work
#TODO(cp16net): need to set the return code correctly
diff --git a/reddwarf/database/views.py b/reddwarf/database/views.py
index edb0befb..a99e5582 100644
--- a/reddwarf/database/views.py
+++ b/reddwarf/database/views.py
@@ -21,16 +21,26 @@ class InstanceView(object):
def __init__(self, instance):
self.instance = instance
- #TODO(hub-cap): fix the link generation
def data(self):
return {"instance": {
"id": self.instance['id'],
"name": self.instance['name'],
"status": self.instance['status'],
- "links": "Links will be coming in the future"
+ "created": self.instance['created'],
+ "updated": self.instance['updated'],
+ "flavor": self.instance['flavor'],
+ "links": self._build_links(self.instance['links']),
+ "addresses": self.instance['addresses'],
},
}
+ @staticmethod
+ def _build_links(links):
+ """Build the links for the instance"""
+ for link in links:
+ link['href'] = link['href'].replace('servers', 'instances')
+ return links
+
class InstancesView(object):
diff --git a/reddwarf/tests/unit/test_database_models.py b/reddwarf/tests/unit/test_database_models.py
index 67c88f0c..6117a94c 100644
--- a/reddwarf/tests/unit/test_database_models.py
+++ b/reddwarf/tests/unit/test_database_models.py
@@ -41,9 +41,26 @@ class TestInstance(tests.BaseTest):
self.FAKE_SERVER.name = 'my_name'
self.FAKE_SERVER.status = 'ACTIVE'
self.FAKE_SERVER.updated = utils.utcnow()
+ self.FAKE_SERVER.created = utils.utcnow()
self.FAKE_SERVER.id = utils.generate_uuid()
self.FAKE_SERVER.flavor = ('http://localhost/1234/flavors/',
'52415800-8b69-11e0-9b19-734f1195ff37')
+ self.FAKE_SERVER.links = [{
+ "href": "http://localhost/1234/instances/123",
+ "rel": "self"
+ },
+ {
+ "href": "http://localhost/1234/instances/123",
+ "rel": "bookmark"
+ }]
+ self.FAKE_SERVER.addresses = {
+ "private": [
+ {
+ "addr": "10.0.0.4",
+ "version": 4
+ }
+ ]
+ }
client = self.mock.CreateMock(novaclient.v1_1.Client)
servers = self.mock.CreateMock(novaclient.v1_1.servers.ServerManager)
@@ -64,5 +81,8 @@ class TestInstance(tests.BaseTest):
self.assertEqual(instance['name'], self.FAKE_SERVER.name)
self.assertEqual(instance['status'], self.FAKE_SERVER.status)
self.assertEqual(instance['updated'], self.FAKE_SERVER.updated)
+ self.assertEqual(instance['created'], self.FAKE_SERVER.created)
self.assertEqual(instance['id'], self.FAKE_SERVER.id)
self.assertEqual(instance['flavor'], self.FAKE_SERVER.flavor)
+ self.assertEqual(instance['links'], self.FAKE_SERVER.links)
+ self.assertEqual(instance['addresses'], self.FAKE_SERVER.addresses)
diff --git a/reddwarf/tests/unit/test_database_service.py b/reddwarf/tests/unit/test_database_service.py
index 7f197ff6..f7205854 100644
--- a/reddwarf/tests/unit/test_database_service.py
+++ b/reddwarf/tests/unit/test_database_service.py
@@ -16,9 +16,12 @@
import mox
import logging
+import json
+import novaclient
from reddwarf import tests
from reddwarf.common import config
+from reddwarf.common import utils
from reddwarf.common import wsgi
from reddwarf.database import models
from reddwarf.database import service
@@ -49,18 +52,28 @@ class DummyApp(wsgi.Router):
class TestInstanceController(ControllerTestBase):
DUMMY_INSTANCE_ID = "123"
+ DUMMY_INSTANCE = {"id": DUMMY_INSTANCE_ID,
+ "name": "DUMMY_NAME",
+ "status": "BUILD",
+ "created": "createtime",
+ "updated": "updatedtime",
+ "flavor": {},
+ "links": [],
+ "addresses": {}}
def setUp(self):
self.instances_path = "/tenant/instances"
super(TestInstanceController, self).setUp()
def test_show(self):
- # block = factory_models.IpBlockFactory()
- instance = mox.MockAnything()
+ response = self.app.get("%s/%s" % (self.instances_path,
+ self.DUMMY_INSTANCE_ID),
+ headers={'X-Auth-Token': '123'})
+ self.assertEqual(response.status_int, 404)
+
+ def test_show(self):
self.mock.StubOutWithMock(models.Instance, 'data')
- models.Instance.data().AndReturn({"id": self.DUMMY_INSTANCE_ID,
- "name": "DUMMY_NAME",
- "status": "BUILD"})
+ models.Instance.data().AndReturn(self.DUMMY_INSTANCE)
self.mock.StubOutWithMock(models.Instance, '__init__')
models.Instance.__init__(context=mox.IgnoreArg(), uuid=mox.IgnoreArg())
self.mock.ReplayAll()
@@ -70,3 +83,82 @@ class TestInstanceController(ControllerTestBase):
headers={'X-Auth-Token': '123'})
self.assertEqual(response.status_int, 201)
+
+ def test_index(self):
+ self.mock.StubOutWithMock(models.Instances, 'data')
+ models.Instances.data().AndReturn([self.DUMMY_INSTANCE])
+ self.mock.StubOutWithMock(models.Instances, '__init__')
+ models.Instances.__init__(mox.IgnoreArg())
+ self.mock.ReplayAll()
+ response = self.app.get("%s" % (self.instances_path),
+ headers={'X-Auth-Token': '123'})
+ self.assertEqual(response.status_int, 201)
+
+ def mock_out_client_create(self):
+ """Stubs out a fake server returned from novaclient.
+ This is akin to calling Client.servers.get(uuid)
+ and getting the server object back."""
+ self.FAKE_SERVER = self.mock.CreateMock(object)
+ self.FAKE_SERVER.name = 'my_name'
+ self.FAKE_SERVER.status = 'ACTIVE'
+ self.FAKE_SERVER.updated = utils.utcnow()
+ self.FAKE_SERVER.created = utils.utcnow()
+ self.FAKE_SERVER.id = utils.generate_uuid()
+ self.FAKE_SERVER.flavor = 'http://localhost/1234/flavors/1234'
+ self.FAKE_SERVER.links = [{
+ "href": "http://localhost/1234/instances/123",
+ "rel": "self"
+ },
+ {
+ "href": "http://localhost/1234/instances/123",
+ "rel": "bookmark"
+ }]
+ self.FAKE_SERVER.addresses = {
+ "private": [
+ {
+ "addr": "10.0.0.4",
+ "version": 4
+ }
+ ]
+ }
+
+ client = self.mock.CreateMock(novaclient.v1_1.Client)
+ servers = self.mock.CreateMock(novaclient.v1_1.servers.ServerManager)
+ servers.create(mox.IgnoreArg(),
+ mox.IgnoreArg(),
+ mox.IgnoreArg()).AndReturn(self.FAKE_SERVER)
+ client.servers = servers
+ self.mock.StubOutWithMock(models.RemoteModelBase, 'get_client')
+ models.RemoteModelBase.get_client(mox.IgnoreArg()).AndReturn(client)
+
+ def test_create(self):
+ self.mock.StubOutWithMock(models.Instance, 'data')
+ models.Instance.data().AndReturn(self.DUMMY_INSTANCE)
+
+ self.mock.StubOutWithMock(models.ServiceImage, 'find_by')
+ models.ServiceImage.find_by(service_name=mox.IgnoreArg()).AndReturn(
+ {'image_id': 1234})
+
+ self.mock_out_client_create()
+ self.mock.ReplayAll()
+
+ body = {
+ "instance": {
+ "databases": [
+ {
+ "character_set": "utf8",
+ "collate": "utf8_general_ci",
+ "name": "sampledb"
+ },
+ {
+ "name": "nextround"
+ }
+ ],
+ "flavorRef": "http://localhost/v0.1/tenant/flavors/1",
+ "name": "json_rack_instance",
+ }
+ }
+ response = self.app.post_json("%s" % (self.instances_path), body=body,
+ headers={'X-Auth-Token': '123'},
+ )
+ self.assertEqual(response.status_int, 201)