Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
workloadmgr / workloadmgr / api / v1 / migration_plans.py
Size: Mime:
# 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())