diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | openstack_dashboard/api/__init__.py | 1 | ||||
-rw-r--r-- | openstack_dashboard/api/management.py | 93 | ||||
-rw-r--r-- | openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json | 6 | ||||
-rw-r--r-- | openstack_dashboard/dashboards/infrastructure/models.py | 30 | ||||
-rw-r--r-- | openstack_dashboard/settings.py | 13 | ||||
-rw-r--r-- | openstack_dashboard/test/api_tests/management_tests.py | 65 |
7 files changed, 206 insertions, 3 deletions
@@ -25,3 +25,4 @@ dist AUTHORS ChangeLog tags +openstack_dashboard/dummydb.sqlite diff --git a/openstack_dashboard/api/__init__.py b/openstack_dashboard/api/__init__.py index dd3bdedc..7c9f8300 100644 --- a/openstack_dashboard/api/__init__.py +++ b/openstack_dashboard/api/__init__.py @@ -39,6 +39,7 @@ from openstack_dashboard.api import glance from openstack_dashboard.api import heat from openstack_dashboard.api import keystone from openstack_dashboard.api import lbaas +from openstack_dashboard.api import management from openstack_dashboard.api import network from openstack_dashboard.api import neutron from openstack_dashboard.api import nova diff --git a/openstack_dashboard/api/management.py b/openstack_dashboard/api/management.py new file mode 100644 index 00000000..9a19c323 --- /dev/null +++ b/openstack_dashboard/api/management.py @@ -0,0 +1,93 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# +# 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. + +import logging +from openstack_dashboard.api import base +import openstack_dashboard.dashboards.infrastructure.models as dummymodels + +LOG = logging.getLogger(__name__) + + +class StringIdAPIResourceWrapper(base.APIResourceWrapper): + # horizon DataTable class expects ids to be string, + # if it's not string, then comparison in + # horizon/tables/base.py:get_object_by_id fails. + # Because of this, ids returned from dummy api are converted to string + # (luckily django autoconverts strings to integers when passing string to + # django model id) + @property + def id(self): + return str(self._apiresource.id) + + +class ResourceClass(StringIdAPIResourceWrapper): + """Wrapper for the ResourceClass object returned by the + dummy model. + """ + _attrs = ['name', 'service_type'] + + @property + def flavors(self): + if "_flavors" not in self.__dict__: + self._flavors = [Flavor(f) for f in + self._apiresource.flavors.all()] + return self.__dict__['_flavors'] + + +class Flavor(StringIdAPIResourceWrapper): + """Wrapper for the Flavor object returned by the + dummy model. + """ + _attrs = ['name'] + + +def resource_class_list(request): + return [ResourceClass(rc) for rc in + dummymodels.ResourceClass.objects.all()] + + +def resource_class_get(request, resource_class_id): + return ResourceClass(dummymodels.ResourceClass.objects.get( + id=resource_class_id)) + + +def resource_class_create(request, name, service_type): + rc = dummymodels.ResourceClass(name=name, + service_type=service_type) + # TODO: save() and delete() operations don't return any value, + # we might wrap this up in future if needed + rc.save() + + +def resource_class_delete(request, resource_class_id): + dummymodels.ResourceClass.objects.get(id=resource_class_id).delete() + + +def flavor_list(request): + return [Flavor(f) for f in dummymodels.Flavor.objects.all()] + + +def flavor_get(request, flavor_id): + return Flavor(dummymodels.Flavor.objects.get(id=flavor_id)) + + +def flavor_create(request, name): + flavor = dummymodels.Flavor(name=name) + flavor.save() + + +def flavor_delete(request, flavor_id): + dummymodels.Flavor.objects.get(id=flavor_id).delete() diff --git a/openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json b/openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json new file mode 100644 index 00000000..a6ea0c3d --- /dev/null +++ b/openstack_dashboard/dashboards/infrastructure/fixtures/initial_data.json @@ -0,0 +1,6 @@ +[ + {"pk": 1, "model": "infrastructure.flavor", "fields": {"name": "flavor1"}}, + {"pk": 1, "model": "infrastructure.resourceclass", "fields": {"service_type": "compute", "flavors": [1], "name": "rclass1"}}, + {"pk": 2, "model": "infrastructure.resourceclass", "fields": {"service_type": "compute", "flavors": [], "name": "rclass2"}}, + {"pk": 3, "model": "infrastructure.resourceclass", "fields": {"service_type": "storage", "flavors": [], "name": "rclass3"}} +] diff --git a/openstack_dashboard/dashboards/infrastructure/models.py b/openstack_dashboard/dashboards/infrastructure/models.py index 14d87bfb..da900d27 100644 --- a/openstack_dashboard/dashboards/infrastructure/models.py +++ b/openstack_dashboard/dashboards/infrastructure/models.py @@ -14,6 +14,30 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Stub file to work around django bug: https://code.djangoproject.com/ticket/7198 -""" +# FIXME: configuration for dummy data +from django.db import models + + +class Flavor(models.Model): + class Meta: + db_table = 'infrastructure_flavor' + + name = models.CharField(max_length=50, unique=True) + # TODO: proper capacities representation + + def capacities(): + return [] + + +class ResourceClass(models.Model): + class Meta: + # syncdb by default creates 'openstack_dashboard_resourceclass' table, + # but it's better to keep models under + # openstack_dashboard/dashboards/infrastructure/models.py instead of + # openstack_dashboard/models.py since the models.py stub file is + # required here anyway + db_table = 'infrastructure_resourceclass' + + name = models.CharField(max_length=50, unique=True) + service_type = models.CharField(max_length=50) + flavors = models.ManyToManyField(Flavor) diff --git a/openstack_dashboard/settings.py b/openstack_dashboard/settings.py index ed739894..e7fb4a5a 100644 --- a/openstack_dashboard/settings.py +++ b/openstack_dashboard/settings.py @@ -192,3 +192,16 @@ COMPRESS_OFFLINE_CONTEXT = { if DEBUG: logging.basicConfig(level=logging.DEBUG) + +# FIXME: configuration for dummy data +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'openstack_dashboard/dummydb.sqlite', + } +} + +# FIXME: configuration for dummy data +FIXTURE_DIRS = ( + 'openstack_dashboard/dashboards/infrastructure/fixtures/', +) diff --git a/openstack_dashboard/test/api_tests/management_tests.py b/openstack_dashboard/test/api_tests/management_tests.py new file mode 100644 index 00000000..19fb81a6 --- /dev/null +++ b/openstack_dashboard/test/api_tests/management_tests.py @@ -0,0 +1,65 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# +# 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 __future__ import absolute_import + +from django import http +from django.conf import settings +from django.test.utils import override_settings + +from mox import IsA + +from openstack_dashboard import api +from openstack_dashboard.test import helpers as test +import openstack_dashboard.dashboards.infrastructure.models as dummymodels + + +class ManagementApiTests(test.APITestCase): + def setUp(self): + super(ManagementApiTests, self).setUp() + # dummy data are seeded from fixtures + self.rclass1 = dummymodels.ResourceClass.objects.get(name='rclass1') + self.flavor1 = dummymodels.Flavor.objects.get(name='flavor1') + + def test_resource_class_list(self): + rc_list = api.management.resource_class_list(self.request) + self.assertEquals(3, len(rc_list)) + for rc in rc_list: + self.assertIsInstance(rc, api.management.ResourceClass) + + def test_resource_class_get(self): + rc = api.management.resource_class_get(self.request, self.rclass1.id) + self.assertIsInstance(rc, api.management.ResourceClass) + self.assertEquals(rc.name, self.rclass1.name) + + def test_resource_class_flavors(self): + rc = api.management.resource_class_get(self.request, self.rclass1.id) + for f in rc.flavors: + self.assertIsInstance(f, api.management.Flavor) + self.assertEquals(1, len(rc.flavors)) + + # TODO: create, delete operations + + def test_flavor_list(self): + flist = api.management.flavor_list(self.request) + self.assertEquals(1, len(flist)) + for f in flist: + self.assertIsInstance(f, api.management.Flavor) + + def test_flavor_get(self): + flavor = api.management.flavor_get(self.request, self.flavor1.id) + self.assertIsInstance(flavor, api.management.Flavor) + self.assertEquals(flavor.name, self.flavor1.name) |