occi-os/occi_os_api/wsgi.py

251 lines
10 KiB
Python

# coding=utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (c) 2012, Intel Performance Learning Solutions Ltd.
#
# 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.
"""
OCCI WSGI app :-)
"""
# W0613:unused args,R0903:too few pub methods
# pylint: disable=W0613,R0903
import logging
from nova import flags
from nova import wsgi
from nova import db
from nova.image import glance
from nova.compute import instance_types
from nova.openstack.common import cfg
from occi_os_api import registry
from occi_os_api.backends import compute
from occi_os_api.backends import openstack
from occi_os_api.backends import network
from occi_os_api.backends import storage
from occi_os_api.extensions import os_mixins
from occi_os_api.extensions import os_addon
from occi import backend
from occi import core_model
from occi import wsgi as occi_wsgi
from occi.extensions import infrastructure
from urllib import quote
LOG = logging.getLogger(__name__)
#Setup options
OCCI_OPTS = [
cfg.IntOpt("occiapi_listen_port",
default=8787,
help="Port OCCI interface will listen on."),
cfg.StrOpt("occi_custom_location_hostname",
default=None,
help="Override OCCI location hostname with custom value")
]
FLAGS = flags.FLAGS
FLAGS.register_opts(OCCI_OPTS)
MIXIN_BACKEND = backend.MixinBackend()
class OCCIApplication(occi_wsgi.Application, wsgi.Application):
"""
Adapter which 'translates' represents a nova WSGI application into and OCCI
WSGI application.
"""
def __init__(self):
"""
Initialize the WSGI OCCI application.
"""
super(OCCIApplication, self).__init__(registry=registry.OCCIRegistry())
self._register_backends()
def _register_backends(self):
"""
Registers the OCCI infrastructure resources to ensure compliance
with GFD184
"""
compute_backend = compute.ComputeBackend()
network_backend = network.NetworkBackend()
networkinterface_backend = network.NetworkInterfaceBackend()
ipnetwork_backend = network.IpNetworkBackend()
ipnetworking_backend = network.IpNetworkInterfaceBackend()
storage_backend = storage.StorageBackend()
storage_link_backend = storage.StorageLinkBackend()
# register kinds with backends
self.register_backend(infrastructure.COMPUTE, compute_backend)
self.register_backend(infrastructure.START, compute_backend)
self.register_backend(infrastructure.STOP, compute_backend)
self.register_backend(infrastructure.RESTART, compute_backend)
self.register_backend(infrastructure.SUSPEND, compute_backend)
self.register_backend(infrastructure.OS_TEMPLATE, MIXIN_BACKEND)
self.register_backend(infrastructure.RESOURCE_TEMPLATE, MIXIN_BACKEND)
self.register_backend(infrastructure.NETWORK, network_backend)
self.register_backend(infrastructure.UP, network_backend)
self.register_backend(infrastructure.DOWN, network_backend)
self.register_backend(infrastructure.NETWORKINTERFACE,
networkinterface_backend)
self.register_backend(infrastructure.IPNETWORK, ipnetwork_backend)
self.register_backend(infrastructure.IPNETWORKINTERFACE,
ipnetworking_backend)
self.register_backend(infrastructure.STORAGE, storage_backend)
self.register_backend(infrastructure.ONLINE, storage_backend)
self.register_backend(infrastructure.OFFLINE, storage_backend)
self.register_backend(infrastructure.BACKUP, storage_backend)
self.register_backend(infrastructure.SNAPSHOT, storage_backend)
self.register_backend(infrastructure.RESIZE, storage_backend)
self.register_backend(infrastructure.STORAGELINK, storage_link_backend)
# add extensions for occi.
self.register_backend(os_addon.SEC_GROUP,
openstack.SecurityGroupBackend())
self.register_backend(os_addon.SEC_RULE,
openstack.SecurityRuleBackend())
self.register_backend(os_addon.OS_VM,
openstack.OsComputeBackend())
self.register_backend(os_addon.OS_CREATE_IMAGE,
openstack.OsComputeBackend())
self.register_backend(os_addon.OS_KEY_PAIR_EXT,
openstack.OsComputeBackend())
self.register_backend(os_addon.OS_CHG_PWD,
openstack.OsComputeBackend())
self.register_backend(os_addon.OS_NET_LINK,
openstack.OsNetLinkBackend())
def __call__(self, environ, response):
"""
This will be called as defined by WSGI.
Deals with incoming requests and outgoing responses
Takes the incoming request, sends it on to the OCCI WSGI application,
which finds the appropriate backend for it and then executes the
request. The backend then is responsible for the return content.
environ -- The environ.
response -- The response.
"""
extras = {'nova_ctx': environ['nova.context']}
# register/refresh openstack images
self._refresh_os_mixins(extras)
# register/refresh openstack instance types (flavours)
self._refresh_resource_mixins(extras)
# register/refresh the openstack security groups as Mixins
self._refresh_security_mixins(extras)
return self._call_occi(environ, response, nova_ctx=extras['nova_ctx'],
registry=self.registry)
def _refresh_os_mixins(self, extras):
"""
Register images as OsTemplate mixins from
information retrieved from glance (shared and user-specific).
"""
template_schema = 'http://schemas.openstack.org/template/os#'
image_service = glance.get_default_image_service()
images = image_service.detail(extras['nova_ctx'])
for img in images:
# If the image is a kernel or ram one
# and we're not to filter them out then register it.
if (((img['container_format'] or img['disk_format']) in ('ari',
'aki'))):
msg = 'Not registering kernel/RAM image.'
LOG.debug(msg)
continue
os_template = os_mixins.OsTemplate(
term=img['id'],
scheme=template_schema,
os_id=img['id'],
related=[infrastructure.OS_TEMPLATE],
attributes=None,
title='This is an OS ' + img['name'] + \
' VM image',
location='/' + quote(img['id']) + '/')
try:
self.registry.get_backend(os_template, extras)
except AttributeError:
msg = 'Registering an OS image type as: %s' % str(os_template)
LOG.debug(msg)
self.register_backend(os_template, MIXIN_BACKEND)
def _refresh_resource_mixins(self, extras):
"""
Register the flavors as ResourceTemplates to which the user has access.
"""
template_schema = 'http://schemas.openstack.org/template/resource#'
os_flavours = instance_types.get_all_types()
for itype in os_flavours.values():
resource_template = os_mixins.ResourceTemplate(
term=itype["flavorid"],
scheme=template_schema,
related=[infrastructure.RESOURCE_TEMPLATE],
title='This is an openstack ' + itype["name"] + ' flavor.',
location='/' + quote(itype["flavorid"]) + '/')
try:
self.registry.get_backend(resource_template, extras)
except AttributeError:
msg = 'Registering an OpenStack flavour/instance type: %s' % \
str(resource_template)
LOG.debug(msg)
self.register_backend(resource_template, MIXIN_BACKEND)
def _refresh_security_mixins(self, extras):
"""
Registers security groups as security mixins
"""
# ensures that preexisting openstack security groups are
# added and only once.
# collect these and add them to an exclusion list so they're
# not created again when listing non-user-defined sec. groups
excld_grps = []
for cat in self.registry.get_categories(extras):
if (isinstance(cat, core_model.Mixin) and
os_addon.SEC_GROUP in cat.related):
excld_grps.append(cat.term)
groups = db.security_group_get_by_project(extras['nova_ctx'],
extras['nova_ctx'].project_id)
sec_grp = 'http://schemas.openstack.org/infrastructure/security/group#'
for group in groups:
if group['name'] not in excld_grps:
sec_mix = os_mixins.UserSecurityGroupMixin(
term=str(group["id"]), # NOTE(aloga): group.id is a long
scheme=sec_grp,
related=[os_addon.SEC_GROUP],
attributes=None,
title=group['name'],
location='/security/' + quote(str(group['id'])) + '/')
try:
self.registry.get_backend(sec_mix, extras)
except AttributeError:
self.register_backend(sec_mix, MIXIN_BACKEND)