fenix/fenix/api/v1/controllers/maintenance.py

435 lines
16 KiB
Python

# Copyright (c) 2019 OpenStack Foundation.
# 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 json
import jsonschema
from pecan import abort
from pecan import expose
from pecan import request
from pecan import response
from pecan import rest
import six
from oslo_log import log
from oslo_messaging import RemoteError
from oslo_serialization import jsonutils
from fenix.api.v1 import maintenance
from fenix.api.v1 import schema
import fenix.db.exceptions as db_exceptions
import fenix.exceptions as exceptions
from fenix import policy
LOG = log.getLogger(__name__)
def _format_ex_message(ex):
if len(ex.path) > 0:
return ("Invalid input for field/attribute %(path)s."
" Value: %(value)s. %(message)s" % {'path': ex.path.pop(),
'value': ex.instance,
'message': ex.message})
else:
return ex.message
return
class BaseController(rest.RestController):
def handle_remote_error(self, e):
cls = getattr(db_exceptions, e.exc_type, None)
cls = cls or getattr(exceptions, e.exc_type, None)
if cls is not None:
if e.value:
description = e.value
elif "msg_fmt" in vars(cls).keys():
description = cls.msg_fmt
else:
description = ""
abort(cls.code, description)
abort(500)
class ProjectController(BaseController):
name = 'project'
def __init__(self):
self.engine_rpcapi = maintenance.EngineRPCAPI()
# GET /v1/maintenance/<session_id>/<project_id>
@policy.authorize('maintenance:session:project', 'get')
@expose(content_type='application/json')
def get(self, session_id, project_id):
if request.body:
LOG.error("Unexpected data")
abort(400)
try:
jsonschema.validate(session_id, schema.uid)
jsonschema.validate(project_id, schema.uid)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
engine_data = self.engine_rpcapi.project_get_session(session_id,
project_id)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)
# PUT /v1/maintenance/<session_id>/<project_id>
@policy.authorize('maintenance:session:project', 'put')
@expose(content_type='application/json')
def put(self, session_id, project_id):
data = json.loads(request.body.decode('utf8'))
try:
jsonschema.validate(session_id, schema.uid)
jsonschema.validate(project_id, schema.uid)
jsonschema.validate(data, schema.maintenance_session_project_put)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
try:
engine_data = self.engine_rpcapi.project_update_session(session_id,
project_id,
data)
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)
class ProjectInstanceController(BaseController):
name = 'project_instance'
def __init__(self):
self.engine_rpcapi = maintenance.EngineRPCAPI()
# PUT /v1/maintenance/<session_id>/<project_id>/<instance_id>
@policy.authorize('maintenance:session:project:instance', 'put')
@expose(content_type='application/json')
def put(self, session_id, project_id, instance_id):
data = json.loads(request.body.decode('utf8'))
try:
jsonschema.validate(session_id, schema.uid)
jsonschema.validate(project_id, schema.uid)
jsonschema.validate(instance_id, schema.uid)
jsonschema.validate(
data,
schema.maintenance_session_project_instance_put)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
try:
engine_data = (
self.engine_rpcapi.project_update_session_instance(session_id,
project_id,
instance_id,
data))
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)
class SessionController(BaseController):
name = 'session'
def __init__(self):
self.engine_rpcapi = maintenance.EngineRPCAPI()
# GET /v1/maintenance/<session_id>
@policy.authorize('maintenance:session', 'get')
@expose(content_type='application/json')
def get(self, session_id):
try:
jsonschema.validate(session_id, schema.uid)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
if request.body:
LOG.error("Unexpected data")
abort(400)
try:
session = self.engine_rpcapi.admin_get_session(session_id)
except RemoteError as e:
self.handle_remote_error(e)
if session is None:
description = "Invalid session"
LOG.error(description)
abort(422, six.text_type(description))
try:
response.text = jsonutils.dumps(session)
except TypeError:
response.body = jsonutils.dumps(session)
# PUT /v1/maintenance/<session_id>
@policy.authorize('maintenance:session', 'put')
@expose(content_type='application/json')
def put(self, session_id):
data = json.loads(request.body.decode('utf8'))
try:
jsonschema.validate(session_id, schema.uid)
jsonschema.validate(data, schema.maintenance_session_put)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
try:
engine_data = self.engine_rpcapi.admin_update_session(session_id,
data)
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)
# DELETE /v1/maintenance/<session_id>
@policy.authorize('maintenance:session', 'delete')
@expose(content_type='application/json')
def delete(self, session_id):
try:
jsonschema.validate(session_id, schema.uid)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
if request.body:
LOG.error("Unexpected data")
abort(400)
try:
engine_data = self.engine_rpcapi.admin_delete_session(session_id)
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)
class MaintenanceController(BaseController):
name = 'maintenance'
def __init__(self):
self.engine_rpcapi = maintenance.EngineRPCAPI()
# GET /v1/maintenance
@policy.authorize('maintenance', 'get')
@expose(content_type='application/json')
def get(self):
if request.body:
LOG.error("Unexpected data")
abort(400)
try:
sessions = self.engine_rpcapi.admin_get()
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(sessions)
except TypeError:
response.body = jsonutils.dumps(sessions)
# POST /v1/maintenance
@policy.authorize('maintenance', 'post')
@expose(content_type='application/json')
def post(self):
data = json.loads(request.body.decode('utf8'))
try:
jsonschema.validate(data, schema.maintenance_post)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
try:
session = self.engine_rpcapi.admin_create_session(data)
except RemoteError as e:
self.handle_remote_error(e)
if session is None:
LOG.error("Too many sessions")
abort(509)
try:
response.text = jsonutils.dumps(session)
except TypeError:
response.body = jsonutils.dumps(session)
class InstanceController(BaseController):
name = 'instance'
def __init__(self):
self.engine_rpcapi = maintenance.EngineRPCAPI()
# GET /v1/instance/<instance_id>
@policy.authorize('instance', 'get')
@expose(content_type='application/json')
def get(self, instance_id):
try:
jsonschema.validate(instance_id, schema.uid)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
if request.body:
LOG.error("Unexpected data")
abort(400)
try:
instance = self.engine_rpcapi.get_instance(instance_id)
except RemoteError as e:
self.handle_remote_error(e)
if instance is None:
description = "Invalid instance: %s" % instance_id
LOG.error(description)
abort(422, six.text_type(description))
try:
response.text = jsonutils.dumps(instance)
except TypeError:
response.body = jsonutils.dumps(instance)
# PUT /v1/instance/<instance_id>
@policy.authorize('instance', 'put')
@expose(content_type='application/json')
def put(self, instance_id):
data = json.loads(request.body.decode('utf8'))
try:
jsonschema.validate(instance_id, schema.uid)
jsonschema.validate(data, schema.instance_put)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
try:
engine_data = self.engine_rpcapi.update_instance(instance_id,
data)
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)
# DELETE /v1/instance/<instance_id>
@policy.authorize('instance', 'delete')
@expose(content_type='application/json')
def delete(self, instance_id):
try:
jsonschema.validate(instance_id, schema.uid)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
if request.body:
LOG.error("Unexpected data")
abort(400)
try:
engine_data = self.engine_rpcapi.delete_instance(instance_id)
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)
class InstanceGroupController(BaseController):
name = 'instance_group'
def __init__(self):
self.engine_rpcapi = maintenance.EngineRPCAPI()
# GET /v1/instance_group/<group_id>
@policy.authorize('instance_group', 'get')
@expose(content_type='application/json')
def get(self, group_id):
try:
jsonschema.validate(group_id, schema.uid)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
if request.body:
LOG.error("Unexpected data")
abort(400)
try:
group = self.engine_rpcapi.get_instance_group(group_id)
except RemoteError as e:
self.handle_remote_error(e)
if group is None:
description = "Invalid instance_group: %s" % group_id
LOG.error(description)
abort(422, six.text_type(description))
try:
response.text = jsonutils.dumps(group)
except TypeError:
response.body = jsonutils.dumps(group)
# PUT /v1/instance_group/<group_id>
@policy.authorize('instance_group', 'put')
@expose(content_type='application/json')
def put(self, group_id):
data = json.loads(request.body.decode('utf8'))
try:
jsonschema.validate(group_id, schema.uid)
jsonschema.validate(data, schema.instance_group_put)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
try:
engine_data = (
self.engine_rpcapi.update_instance_group(group_id, data))
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)
# DELETE /v1/instance_group/<group_id>
@policy.authorize('instance_group', 'delete')
@expose(content_type='application/json')
def delete(self, group_id):
try:
jsonschema.validate(group_id, schema.uid)
except jsonschema.exceptions.ValidationError as e:
description = _format_ex_message(e)
LOG.error(description)
abort(422, six.text_type(description))
if request.body:
LOG.error("Unexpected data")
abort(400)
try:
engine_data = (
self.engine_rpcapi.delete_instance_group(group_id))
except RemoteError as e:
self.handle_remote_error(e)
try:
response.text = jsonutils.dumps(engine_data)
except TypeError:
response.body = jsonutils.dumps(engine_data)