nova/nova/api/openstack/servers.py

176 lines
6.4 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 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.
from webob import exc
from nova import context
from nova import exception
from nova import wsgi
from nova.api.openstack import faults
from nova.auth import manager as auth_manager
from nova.compute import api as compute_api
from nova.compute import instance_types
from nova.compute import power_state
import nova.api.openstack
def _entity_list(entities):
""" Coerces a list of servers into proper dictionary format """
return dict(servers=entities)
def _entity_detail(inst):
""" Maps everything to Rackspace-like attributes for return"""
power_mapping = {
power_state.NOSTATE: 'build',
power_state.RUNNING: 'active',
power_state.BLOCKED: 'active',
power_state.PAUSED: 'suspended',
power_state.SHUTDOWN: 'active',
power_state.SHUTOFF: 'active',
power_state.CRASHED: 'error'}
inst_dict = {}
mapped_keys = dict(status='state', imageId='image_id',
flavorId='instance_type', name='display_name', id='internal_id')
for k, v in mapped_keys.iteritems():
inst_dict[k] = inst[v]
inst_dict['status'] = power_mapping[inst_dict['status']]
inst_dict['addresses'] = dict(public=[], private=[])
inst_dict['metadata'] = {}
inst_dict['hostId'] = ''
return dict(server=inst_dict)
def _entity_inst(inst):
""" Filters all model attributes save for id and name """
return dict(server=dict(id=inst['internal_id'], name=inst['display_name']))
class Controller(wsgi.Controller):
""" The Server API controller for the OpenStack API """
_serialization_metadata = {
'application/xml': {
"attributes": {
"server": ["id", "imageId", "name", "flavorId", "hostId",
"status", "progress"]}}}
def __init__(self):
self.compute_api = compute_api.ComputeAPI()
super(Controller, self).__init__()
def index(self, req):
""" Returns a list of server names and ids for a given user """
return self._items(req, entity_maker=_entity_inst)
def detail(self, req):
""" Returns a list of server details for a given user """
return self._items(req, entity_maker=_entity_detail)
def _items(self, req, entity_maker):
"""Returns a list of servers for a given user.
entity_maker - either _entity_detail or _entity_inst
"""
user_id = req.environ['nova.context']['user']['id']
ctxt = context.RequestContext(user_id, user_id)
instance_list = self.compute_api.get_instances(ctxt)
limited_list = nova.api.openstack.limited(instance_list, req)
res = [entity_maker(inst)['server'] for inst in limited_list]
return _entity_list(res)
def show(self, req, id):
""" Returns server details by server id """
user_id = req.environ['nova.context']['user']['id']
ctxt = context.RequestContext(user_id, user_id)
inst = self.compute_api.get_instance(ctxt, int(id))
if inst:
if inst.user_id == user_id:
return _entity_detail(inst)
raise faults.Fault(exc.HTTPNotFound())
def delete(self, req, id):
""" Destroys a server """
user_id = req.environ['nova.context']['user']['id']
ctxt = context.RequestContext(user_id, user_id)
try:
self.compute_api.delete_instance(ctxt, int(id))
except exception.NotFound:
return faults.Fault(exc.HTTPNotFound())
return exc.HTTPAccepted()
def create(self, req):
""" Creates a new server for a given user """
env = self._deserialize(req.body, req)
if not env:
return faults.Fault(exc.HTTPUnprocessableEntity())
user_id = req.environ['nova.context']['user']['id']
ctxt = context.RequestContext(user_id, user_id)
key_pair = auth_manager.AuthManager.get_key_pairs(ctxt)[0]
instances = self.compute_api.create_instances(ctxt,
instance_types.get_by_flavor_id(env['server']['flavorId']),
env['server']['imageId'],
display_name=env['server']['name'],
description=env['server']['name'],
key_name=key_pair['name'],
key_data=key_pair['public_key'])
return _entity_inst(instances[0])
def update(self, req, id):
""" Updates the server name or password """
user_id = req.environ['nova.context']['user']['id']
ctxt = context.RequestContext(user_id, user_id)
inst_dict = self._deserialize(req.body, req)
if not inst_dict:
return faults.Fault(exc.HTTPUnprocessableEntity())
update_dict = {}
if 'adminPass' in inst_dict['server']:
update_dict['admin_pass'] = inst_dict['server']['adminPass']
if 'name' in inst_dict['server']:
update_dict['display_name'] = inst_dict['server']['name']
try:
self.compute_api.update_instance(ctxt, instance['id'],
**update_dict)
except exception.NotFound:
return faults.Fault(exc.HTTPNotFound())
return exc.HTTPNoContent()
def action(self, req, id):
""" Multi-purpose method used to reboot, rebuild, and
resize a server """
user_id = req.environ['nova.context']['user']['id']
ctxt = context.RequestContext(user_id, user_id)
input_dict = self._deserialize(req.body, req)
try:
reboot_type = input_dict['reboot']['type']
except Exception:
raise faults.Fault(exc.HTTPNotImplemented())
try:
# TODO(gundlach): pass reboot_type, support soft reboot in
# virt driver
self.compute_api.reboot(ctxt, id)
except:
return faults.Fault(exc.HTTPUnprocessableEntity())
return exc.HTTPAccepted()