Repository URL to install this package:
|
Version:
5.2.1.1.dev1 ▾
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2013 TrilioData, Inc.
# All Rights Reserved.
"""The workloads api."""
import os
import json
import re
import time
import webob
import ast
from webob import exc
from defusedxml import minidom
from datetime import datetime
import configparser
try:
from cgi import parse_qs
except:
from six.moves.urllib.parse import parse_qs
try:
from cgi import escape
except:
from html import escape
from six.moves.urllib.parse import urlparse
from workloadmgr.api import extensions
from workloadmgr.api import wsgi
from workloadmgr.api import common
from workloadmgr.api.views import migration_plans as migration_plan_views
from workloadmgr.api import xmlutil
from workloadmgr.keymanager import barbican
from workloadmgr.api.validation_models import migration_plans as migration_plan_validator
from workloadmgr import workloads as workloadsAPI
from workloadmgr import exception
from workloadmgr import flags
from workloadmgr.openstack.common import log as logging
from workloadmgr import settings as settings_module
from workloadmgr import exception as wlm_exceptions
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from importlib import reload
import smtplib
import socket
from workloadmgr.utils import decrypt_password, tvault_key_file_name
FLAGS = flags.FLAGS
LOG = logging.getLogger(__name__)
def make_migration_plan(elem):
elem.set("id")
elem.set("status")
elem.set("size")
elem.set("vm_id")
elem.set("object_count")
elem.set("availability_zone")
elem.set("created_at")
elem.set("name")
elem.set("description")
elem.set("fail_reason")
class MigrationPlanTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement("migration_plan", selector="migration_plan")
make_migration_plan(root)
alias = WorkloadMgrs.alias
namespace = WorkloadMgrs.namespace
return xmlutil.MasterTemplate(root, 1, nsmap={alias: namespace})
class MigrationPlansTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement("migration_plans")
elem = xmlutil.SubTemplateElement(root, "migration_plan", selector="migration_plans")
make_migration_plan(elem)
alias = WorkloadMgrs.alias
namespace = WorkloadMgrs.namespace
return xmlutil.MasterTemplate(root, 1, nsmap={alias: namespace})
class CreateDeserializer(wsgi.MetadataXMLDeserializer):
def default(self, string):
dom = minidom.parseString(string)
migration_plan = self._extract_migration_plan(dom)
return {"body": {"migration_plan": migration_plan}}
class UpdateDeserializer(wsgi.MetadataXMLDeserializer):
def default(self, string):
dom = minidom.parseString(string)
migration_plan = self._extract_migration_plan(dom)
return {"body": {"migration_plan": migration_plan}}
def _extract_migration_plan(self, node):
migration_plan = {}
migration_plan_node = self.find_first_child_named(node, "migration_plan")
attributes = ["display_name", "display_description"]
for attr in attributes:
if migration_plan_node.getAttribute(attr):
migration_plan[attr] = migration_plan_node.getAttribute(attr)
return migration_plan
class MigrationPlansController(wsgi.Controller):
"""The API controller """
_view_builder_class = migration_plan_views.ViewBuilder
def __init__(self):
self.migration_plan_api = workloadsAPI.API()
super(MigrationPlansController, self).__init__()
@wsgi.serializers(xml=MigrationPlanTemplate)
def show(self, req, id):
"""Return data about the given migration_plan."""
try:
context = req.environ["workloadmgr.context"]
scheduler_trust = False
if "QUERY_STRING" in req.environ:
var = parse_qs(req.environ["QUERY_STRING"])
scheduler_trust = var.get("scheduler_trust", ['False'])[0]
scheduler_trust = ast.literal_eval(escape(scheduler_trust))
migration_plan = self.migration_plan_api.migration_plan_get(context, migration_plan_id=id)
return self._view_builder.detail(req, migration_plan,
api=self.migration_plan_api,
**{"scheduler_trust": scheduler_trust}
)
except exception.MigrationPlanNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def delete(self, req, id):
"""Delete a migration_plan."""
try:
context = req.environ["workloadmgr.context"]
self.migration_plan_api.migration_plan_delete(context, id)
return webob.Response(status_int=202)
except exception.MigrationPlanNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def unlock(self, req, id):
try:
context = req.environ["workloadmgr.context"]
self.migration_plan_api.migration_plan_unlock(context, id)
return webob.Response(status_int=202)
except exception.MigrationPlanNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
@wsgi.serializers(xml=MigrationPlansTemplate)
def index(self, req):
"""Returns a summary list of migration plans."""
try:
return self._get_migration_plans(req, is_detail=False)
except exception.MigrationPlanNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
@wsgi.serializers(xml=MigrationPlansTemplate)
def detail(self, req):
"""Returns a detailed list of migration plans."""
try:
return self._get_migration_plans(req, is_detail=True)
except exception.MigrationPlanNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def _get_migration_plans(self, req, is_detail):
"""Returns a list of migration plans, transformed through view builder."""
try:
context = req.environ["workloadmgr.context"]
all_migration_plans = None
# Get value of query parameter 'all_workloads'
page_number = None
nfs_share = None
project_id = None
scheduler_trust = False
migration_plan_list = []
if "QUERY_STRING" in req.environ:
var = parse_qs(req.environ["QUERY_STRING"])
all_migration_plans = var.get("all_migration_plans", [""])[0]
all_migration_plans = bool(escape(all_migration_plans))
page_number = var.get("page_number", [""])[0]
nfs_share = var.get("nfs_share", [""])[0]
project_id = var.get("project_id", [""])[0]
scheduler_trust = var.get("scheduler_trust", [""])[0]
scheduler_trust = bool(escape(scheduler_trust))
if var.get("migration_plan_list", []):
migration_plan_list = common.parse_list_from_query_string(var["migration_plan_list"])
if not all_migration_plans:
project_id = context.project_id
migration_plans_all = self.migration_plan_api.migration_plan_get_all(
context,
search_opts={
"page_number": page_number,
"nfs_share": nfs_share,
"all_workloads": all_migration_plans,
"project_id": project_id,
"workload_list": migration_plan_list
},
)
limited_list = common.limited(migration_plans_all, req)
if is_detail:
migration_plans = self._view_builder.detail_list(
req,
migration_plans_all,
self.migration_plan_api,
**{"scheduler_trust": scheduler_trust}
)
else:
migration_plans = self._view_builder.summary_list(
req,
migration_plans_all,
self.migration_plan_api,
**{"scheduler_trust": scheduler_trust}
)
return migration_plans
except exception.MigrationPlanNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
@wsgi.response(202)
@migration_plan_validator.validate_migration_plan
@wsgi.serializers(xml=MigrationPlanTemplate)
@wsgi.deserializers(xml=CreateDeserializer)
def create(self, req, body):
"""Create a new migration plan."""
try:
if not self.is_valid_body(body, "migration_plan"):
raise exc.HTTPBadRequest()
context = req.environ["workloadmgr.context"]
try:
migration_plan = body["migration_plan"]
except KeyError:
msg = _("Incorrect request body format")
raise exc.HTTPBadRequest(explanation=msg)
name = migration_plan.get("name", "") or "migration_plan"
name = name.strip() or "migration_plan"
description = migration_plan.get("description", "") or "no-description"
description = description.strip() or "no-description"
source_platform = migration_plan.get("source_platform", "vmware").strip()
metadata = migration_plan.get("metadata", {})
if not metadata:
metadata = {}
vms = migration_plan.get("vms", {})
if not vms:
vms = {}
try:
new_migration_plan = self.migration_plan_api.migration_plan_create(
context, name, description,
vms, metadata,
source_platform=source_platform
)
new_migration_plan_dict = self.migration_plan_api.migration_plan_get(
context, new_migration_plan.id
)
except Exception as error:
raise exc.HTTPServerError(explanation=str(error))
retval = self._view_builder.summary(req, new_migration_plan_dict)
return retval
except exc.HTTPNotFound as error:
LOG.exception(error)
raise error
except exc.HTTPBadRequest as error:
LOG.exception(error)
raise error
except exc.HTTPServerError as error:
LOG.exception(error)
raise error
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
@wsgi.response(202)
@migration_plan_validator.validate_migration_plan
@wsgi.serializers(xml=MigrationPlanTemplate)
@wsgi.deserializers(xml=UpdateDeserializer)
def update(self, req, id, body):
"""Update migration plan."""
try:
if not self.is_valid_body(body, "migration_plan"):
raise exc.HTTPBadRequest()
is_admin_dashboard = False
if "QUERY_STRING" in req.environ:
var = parse_qs(req.environ["QUERY_STRING"])
is_admin_dashboard = var.get('is_admin_dashboard', ['False'])[0]
is_admin_dashboard = ast.literal_eval(escape(is_admin_dashboard))
context = req.environ["workloadmgr.context"]
try:
try:
workload = body["migration_plan"]
except KeyError:
msg = _("Incorrect request body format")
raise exc.HTTPBadRequest(explanation=msg)
self.migration_plan_api.migration_plan_modify(
context, id, body["migration_plan"])
except exception.MigrationPlanNotFound as error:
raise exc.HTTPNotFound(explanation=str(error))
except exc.HTTPNotFound as error:
LOG.exception(error)
raise error
except exc.HTTPBadRequest as error:
LOG.exception(error)
raise error
except exc.HTTPServerError as error:
LOG.exception(error)
raise error
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def migration_plan_get_vms(self, req):
try:
context = req.environ["workloadmgr.context"]
try:
vms = self.migration_plan_api.migration_plan_vms_get_all(context)
return vms
except Exception as ex:
LOG.exception(ex)
raise ex
except exc.HTTPNotFound as error:
LOG.exception(error)
raise error
except exc.HTTPBadRequest as error:
LOG.exception(error)
raise error
except exc.HTTPServerError as error:
LOG.exception(error)
raise error
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def get_vcenter_vms(self, req):
try:
context = req.environ["workloadmgr.context"]
try:
search_opts = {}
if "QUERY_STRING" in req.environ:
var = parse_qs(req.environ["QUERY_STRING"])
nameregex = var.get("nameregex", [""])[0]
search_opts['nameregex'] = nameregex
vms = self.migration_plan_api.get_vcenter_vms(context, search_opts)
return vms
except Exception as ex:
LOG.exception(ex)
raise ex
except exc.HTTPNotFound as error:
LOG.exception(error)
raise error
except exc.HTTPBadRequest as error:
LOG.exception(error)
raise error
except exc.HTTPServerError as error:
LOG.exception(error)
raise error
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def discovervms(self, req, id):
try:
context = req.environ["workloadmgr.context"]
self.migration_plan_api.migration_plan_discovervms(context, id)
return webob.Response(status_int=202)
except exception.MigrationPlanNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def get_import_migration_plans_list(self, req):
try:
context = req.environ["workloadmgr.context"]
project_id = None
if "QUERY_STRING" in req.environ:
qs = parse_qs(req.environ["QUERY_STRING"])
project_id = qs.get("project_id", [None])[0]
project_id = escape(project_id)
try:
migration_plans = self.migration_plan_api.get_import_migration_plans_list(
context, project_id
)
return self._view_builder.detail_list(req, migration_plans)
except exception.WorkloadNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except exc.HTTPNotFound as error:
LOG.exception(error)
raise error
except exc.HTTPBadRequest as error:
LOG.exception(error)
raise error
except exc.HTTPServerError as error:
LOG.exception(error)
raise error
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def import_migration_plans(self, req, body={}):
try:
context = req.environ["workloadmgr.context"]
migration_plan_ids = []
try:
migration_plan_ids = body["migration_plan_ids"]
except KeyError:
pass
upgrade = True
try:
upgrade = body.get("upgrade")
except KeyError:
pass
try:
migration_plans = self.migration_plan_api.import_migration_plans(
context, migration_plan_ids, upgrade
)
imported_migration_plans = self._view_builder.detail_list(
req, migration_plans["migration_plans"]["imported_migration_plans"]
)
migration_plans["migration_plans"]["imported_migration_plans"] = imported_migration_plans[
"migration_plans"
]
return migration_plans
except exception.WorkloadNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except exc.HTTPNotFound as error:
LOG.exception(error)
raise error
except exc.HTTPBadRequest as error:
LOG.exception(error)
raise error
except exc.HTTPServerError as error:
LOG.exception(error)
raise error
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
@wsgi.serializers(xml=MigrationPlanTemplate)
def migration_plan_get_by_vmid(self, req):
"""Returns a migration plan for a given vmid, transformed through view builder."""
try:
context = req.environ["workloadmgr.context"]
vm_id = None
scheduler_trust = False
if "QUERY_STRING" in req.environ:
var = parse_qs(req.environ["QUERY_STRING"])
vm_id = var.get("vm_id", [""])[0]
scheduler_trust = var.get("scheduler_trust", ['False'])[0]
scheduler_trust = ast.literal_eval(escape(scheduler_trust))
migration_plan = self.migration_plan_api.migration_plan_get_by_vmid(
context,
search_opts={
"vm_id": vm_id
},
) or []
return self._view_builder.summary_list(
req,
migration_plan,
self.migration_plan_api,
**{"scheduler_trust": scheduler_trust}
)
except exception.MigrationPlanNotFound as error:
LOG.exception(error)
raise exc.HTTPNotFound(explanation=str(error))
except exception.InvalidState as error:
LOG.exception(error)
raise exc.HTTPBadRequest(explanation=str(error))
except Exception as error:
LOG.exception(error)
raise exc.HTTPServerError(explanation=str(error))
def create_resource():
return wsgi.Resource(MigrationPlansController())