Merge pull request #55 from ed-/flavors_api

Flavors api
This commit is contained in:
Michael Basnight 2012-04-02 12:18:28 -07:00
commit 7cb40c224b
5 changed files with 290 additions and 0 deletions

View File

@ -0,0 +1,17 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
# 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
# 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.

80
reddwarf/flavor/models.py Normal file
View File

@ -0,0 +1,80 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010-2012 OpenStack LLC.
# 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
# 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.
"""Model classes that form the core of instance flavor functionality."""
from reddwarf import db
from novaclient import exceptions as nova_exceptions
from reddwarf.common import exception as rd_exceptions
from reddwarf.common import utils
from reddwarf.common.models import NovaRemoteModelBase
from reddwarf.common.remote import create_nova_client
class Flavor(object):
_data_fields = ['id', 'links', 'name', 'ram', 'vcpus']
def __init__(self, flavor=None, context=None, flavor_id=None):
if flavor:
self.flavor = flavor
return
if flavor_id and context:
try:
client = create_nova_client(context)
self.flavor = client.flavors.get(flavor_id)
except nova_exceptions.NotFound, e:
raise rd_exceptions.NotFound(uuid=flavor_id)
except nova_exceptions.ClientException, e:
raise rd_exceptions.ReddwarfError(str(e))
return
msg = ("Flavor is not defined, and"
" context and flavor_id were not specified.")
raise InvalidModelError(msg)
@property
def id(self):
return self.flavor.id
@property
def name(self):
return self.flavor.name
@property
def ram(self):
return self.flavor.ram
@property
def vcpus(self):
return self.flavor.vcpus
@property
def links(self):
return self.flavor.links
class Flavors(NovaRemoteModelBase):
def __init__(self, context):
nova_flavors = create_nova_client(context).flavors.list()
self.flavors = [Flavor(flavor=item) for item in nova_flavors]
def __iter__(self):
for item in self.flavors:
yield item

View File

@ -0,0 +1,91 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010-2012 OpenStack LLC.
# 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
# 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 routes
import webob.exc
from reddwarf.common import exception
from reddwarf.common import wsgi
from reddwarf.flavor import models
from reddwarf.flavor import views
class BaseController(wsgi.Controller):
"""Base controller class."""
exclude_attr = []
exception_map = {
webob.exc.HTTPUnprocessableEntity: [
],
webob.exc.HTTPBadRequest: [
exception.BadRequest,
],
webob.exc.HTTPNotFound: [
exception.NotFound,
],
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 FlavorController(BaseController):
"""Controller for flavor functionality"""
def show(self, req, tenant_id, id):
"""Return a single flavor."""
context = req.environ[wsgi.CONTEXT_KEY]
flavor = models.Flavor(context=context, flavor_id=id)
# Pass in the request to build accurate links.
return wsgi.Result(views.FlavorDetailView(flavor, req).data(), 200)
def detail(self, req, tenant_id):
"""Return a list of flavors, with additional data about each flavor."""
context = req.environ[wsgi.CONTEXT_KEY]
flavors = models.Flavors(context=context)
return wsgi.Result(views.FlavorsDetailView(flavors, req).data(), 200)
def index(self, req, tenant_id):
"""Return all flavors."""
context = req.environ[wsgi.CONTEXT_KEY]
flavors = models.Flavors(context=context)
return wsgi.Result(views.FlavorsView(flavors, req).data(), 200)
class API(wsgi.Router):
"""API"""
def __init__(self):
mapper = routes.Mapper()
super(API, self).__init__(mapper)
self._flavor_router(mapper)
def _flavor_router(self, mapper):
flavor_resource = FlavorController().create_resource()
path = "/{tenant_id}/flavors"
mapper.resource("flavor", path, controller=flavor_resource,
collection={'detail': 'GET', '': 'GET'})
def app_factory(global_conf, **local_conf):
return API()

89
reddwarf/flavor/views.py Normal file
View File

@ -0,0 +1,89 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010-2012 OpenStack LLC.
# 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
# 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.
class FlavorView(object):
def __init__(self, flavor, req=None):
self.flavor = flavor
self.req = req
def data(self):
return {"flavor": {
'id': self.flavor.id,
'links': self._build_links(),
'name': self.flavor.name,
}}
def _build_links(self):
result = []
#scheme = self.req.scheme
scheme = 'https' # Forcing https
endpoint = self.req.host
splitpath = self.req.path.split('/')
detailed = ''
if splitpath[-1] == 'detail':
detailed = '/detail'
splitpath.pop(-1)
flavorid = self.flavor.id
if splitpath[-1] == flavorid:
splitpath.pop(-1)
href_template = "%(scheme)s://%(endpoint)s%(path)s/%(flavorid)s"
for link in self.flavor.links:
rlink = link
href = rlink['href']
if rlink['rel'] == 'self':
path = '/'.join(splitpath)
href = href_template % locals()
elif rlink['rel'] == 'bookmark':
splitpath.pop(2) # Remove the version.
splitpath.pop(1) # Remove the tenant id.
path = '/'.join(splitpath)
href = href_template % locals()
rlink['href'] = href
result.append(rlink)
return result
class FlavorDetailView(FlavorView):
def data(self):
result = super(FlavorDetailView, self).data()
details = {
'ram': self.flavor.ram,
'vcpus': self.flavor.vcpus,
}
result["flavor"].update(details)
return result
class FlavorsView(object):
view = FlavorView
def __init__(self, flavors, req=None):
self.flavors = flavors
self.req = req
def data(self, detailed=False):
data = []
for flavor in self.flavors:
data.append(self.view(flavor, req=self.req).data()['flavor'])
return {"flavors": data}
class FlavorsDetailView(FlavorsView):
view = FlavorDetailView

View File

@ -26,6 +26,11 @@ from reddwarf.common import wsgi
from reddwarf.instance import models, views
from reddwarf.common import exception as rd_exceptions
#TODO(ed-): Import these properly after this is restructured
from reddwarf.flavor import models as flavormodels
from reddwarf.flavor import views as flavorviews
from reddwarf.flavor import service as flavorservice
CONFIG = config.Config
LOG = logging.getLogger(__name__)
@ -262,6 +267,7 @@ class API(wsgi.Router):
mapper = routes.Mapper()
super(API, self).__init__(mapper)
self._instance_router(mapper)
self._flavor_router(mapper) #TODO(ed-): Remove after restructure
def _instance_router(self, mapper):
instance_resource = InstanceController().create_resource()
@ -269,6 +275,13 @@ class API(wsgi.Router):
mapper.resource("instance", path, controller=instance_resource,
collection={'detail': 'GET'})
#TODO(ed-): remove this when all mention of flavorservice et cetera are moved away
def _flavor_router(self, mapper):
flavor_resource = flavorservice.FlavorController().create_resource()
path = "/{tenant_id}/flavors"
mapper.resource("flavor", path, controller=flavor_resource,
collection={'detail': 'GET'})
def app_factory(global_conf, **local_conf):
return API()