synergy-scheduler-manager/synergy_scheduler_manager/nova_manager.py

1152 lines
42 KiB
Python

import common.utils as utils
import eventlet
import hashlib
import hmac
import json
import logging
import requests
from common.block_device import BlockDeviceMapping
from common.compute import Compute
from common.flavor import Flavor
from common.hypervisor import Hypervisor
from common.messaging import AMQP
from common.quota import Quota
from common.request import Request
from common.server import Server
from oslo_config import cfg
from sqlalchemy import create_engine
from sqlalchemy.exc import SQLAlchemyError
from synergy.common.manager import Manager
from synergy.exception import SynergyError
__author__ = "Lisa Zangrando"
__email__ = "lisa.zangrando[AT]pd.infn.it"
__copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud
All Rights Reserved
Licensed under the Apache License, Version 2.0;
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."""
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
class ServerEventHandler(object):
def __init__(self, nova_manager):
super(ServerEventHandler, self).__init__()
self.nova_manager = nova_manager
def _makeServer(self, server_info):
if not server_info:
return
flavor = Flavor()
flavor.setMemory(server_info["memory_mb"])
flavor.setVCPUs(server_info["vcpus"])
flavor.setStorage(server_info["root_gb"])
if "instance_type" in server_info:
flavor.setName(server_info["instance_type"])
server = Server()
server.setFlavor(flavor)
server.setUserId(server_info["user_id"])
server.setMetadata(server_info["metadata"])
server.setDeletedAt(server_info["deleted_at"])
server.setTerminatedAt(server_info["terminated_at"])
if "host" in server_info:
server.setHost(server_info["host"])
if "uuid" in server_info:
server.setId(server_info["uuid"])
elif "instance_id" in server_info:
server.setId(server_info["instance_id"])
if "project_id" in server_info:
server.setProjectId(server_info["project_id"])
elif "tenant_id" in server_info:
server.setProjectId(server_info["tenant_id"])
if "vm_state" in server_info:
server.setState(server_info["vm_state"])
elif "state" in server_info:
server.setState(server_info["state"])
return server
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.debug("Notification INFO: event_type=%s payload=%s"
% (event_type, payload))
if payload is None or "state" not in payload:
return
state = payload["state"]
event_types = ["compute.instance.create.end",
"compute.instance.delete.end",
"compute.instance.update",
"scheduler.run_instance"]
if event_type not in event_types:
return
server_info = None
if event_type == "scheduler.run_instance":
server_info = payload["request_spec"]["instance_type"]
else:
server_info = payload
server = self._makeServer(server_info)
self.nova_manager.notify(event_type="SERVER_EVENT", server=server,
event=event_type, state=state)
def warn(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.debug("Notification WARN: event_type=%s, payload=%s metadata=%s"
% (event_type, payload, metadata))
def error(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.debug("Notification ERROR: event_type=%s, payload=%s metadata=%s"
% (event_type, payload, metadata))
class NovaConductorComputeAPI(object):
def __init__(self, synergy_topic, conductor_topic, nova_manager, msg):
self.nova_manager = nova_manager
self.target = msg.getTarget(topic=synergy_topic,
namespace="compute_task",
version="1.16")
self.client = msg.getRPCClient(
target=msg.getTarget(topic=conductor_topic,
namespace="compute_task",
version="1.10"))
def build_instances(self, context, instances, image, filter_properties,
admin_password, injected_files, requested_networks,
security_groups, block_device_mapping=None,
legacy_bdm=True):
for instance in instances:
data = {'instances': [instance],
'image': image,
'filter_properties': filter_properties,
'admin_password': admin_password,
'injected_files': injected_files,
'requested_networks': requested_networks,
'security_groups': security_groups,
'block_device_mapping': block_device_mapping,
'legacy_bdm': legacy_bdm}
req = {"context": context, "data": data,
"action": "build_instances"}
try:
request = Request.fromDict(req)
self.nova_manager.notify(event_type="SERVER_CREATE",
request=request)
except Exception as ex:
LOG.info(ex)
def schedule_and_build_instances(self, context, build_requests,
request_specs, image,
admin_password, injected_files,
requested_networks, block_device_mapping):
index = 0
for build_request in build_requests:
request_spec = request_specs[index]
index += 1
data = {'build_requests': [build_request],
'request_specs': [request_spec],
'image': image,
'admin_password': admin_password,
'injected_files': injected_files,
'requested_networks': requested_networks,
'block_device_mapping': block_device_mapping}
req = {"context": context, "data": data,
"action": "schedule_and_build_instances"}
request = Request.fromDict(req)
self.nova_manager.notify(event_type="SERVER_CREATE",
request=request)
def build_instance(self, context, action, data):
try:
cctxt = self.client.prepare()
cctxt.cast(context, action, **data)
except Exception as ex:
LOG.info(ex)
def migrate_server(self, context, **kwargs):
cctxt = self.client.prepare()
return cctxt.call(context, 'migrate_server', **kwargs)
def unshelve_instance(self, context, **kwargs):
cctxt = self.client.prepare()
cctxt.cast(context, 'unshelve_instance', **kwargs)
def rebuild_instance(self, ctxt, **kwargs):
cctxt = self.client.prepare()
cctxt.cast(ctxt, 'rebuild_instance', **kwargs)
def resize_instance(self, ctxt, **kwargs):
cctxt = self.client.prepare()
cctxt.cast(ctxt, 'resize_instance', **kwargs)
class NovaManager(Manager):
def __init__(self):
super(NovaManager, self).__init__("NovaManager")
self.config_opts = [
cfg.StrOpt("amqp_url",
help="the amqp transport url",
default=None,
required=False),
cfg.StrOpt("amqp_exchange",
help="the amqp exchange",
default="nova",
required=False),
cfg.StrOpt("amqp_backend",
help="the amqp backend tpye (e.g. rabbit, qpid)",
default=None,
required=False),
cfg.ListOpt("amqp_hosts",
help="AMQP HA cluster host:port pairs",
default=None,
required=False),
cfg.StrOpt("amqp_host",
help="the amqp host name",
default="localhost",
required=False),
cfg.IntOpt("amqp_port",
help="the amqp listening port",
default=5672,
required=False),
cfg.StrOpt("amqp_user",
help="the amqp user",
default=None,
required=False),
cfg.StrOpt("amqp_password",
help="the amqp password",
default=None,
required=False),
cfg.StrOpt("amqp_virtual_host",
help="the amqp virtual host",
default="/",
required=False),
cfg.StrOpt("synergy_topic",
help="the Synergy topic",
default="synergy",
required=False),
cfg.StrOpt("notification_topic",
help="the notifiction topic",
default="nova_notification",
required=False),
cfg.StrOpt("conductor_topic",
help="the conductor topic",
default="conductor",
required=False),
cfg.StrOpt("compute_topic",
help="the compute topic",
default="compute",
required=False),
cfg.StrOpt("scheduler_topic",
help="the scheduler topic",
default="scheduler",
required=False),
cfg.StrOpt("metadata_proxy_shared_secret",
help="the metadata proxy shared secret",
default="METADATA_SECRET",
required=True),
cfg.FloatOpt("cpu_allocation_ratio",
help="the cpu allocation ratio",
default=float(16),
required=False),
cfg.FloatOpt("ram_allocation_ratio",
help="the ram allocation ratio",
default=float(1.5),
required=False),
cfg.StrOpt("db_connection",
help="the NOVA database connection",
default=None,
required=True),
cfg.StrOpt("host",
help="the host name",
default="localhost",
required=False),
cfg.IntOpt("timeout",
help="set the http connection timeout",
default=60,
required=False),
cfg.StrOpt("ssl_ca_file",
help="set the PEM encoded Certificate Authority to "
"use when verifying HTTPs connections",
default=None,
required=False),
cfg.StrOpt("ssl_cert_file",
help="set the SSL client certificate (PEM encoded)",
default=None,
required=False)
]
def setup(self):
eventlet.monkey_patch(os=False)
self.ssl_ca_file = CONF.NovaManager.ssl_ca_file
self.ssl_cert_file = CONF.NovaManager.ssl_cert_file
self.timeout = CONF.NovaManager.timeout
if self.getManager("KeystoneManager") is None:
raise SynergyError("KeystoneManager not found!")
if self.getManager("SchedulerManager") is None:
raise SynergyError("SchedulerManager not found!")
self.keystone_manager = self.getManager("KeystoneManager")
amqp_url = self.getParameter("amqp_url")
amqp_backend = self.getParameter("amqp_backend")
amqp_hosts = self.getParameter("amqp_hosts")
amqp_host = self.getParameter("amqp_host")
amqp_port = self.getParameter("amqp_port")
amqp_user = self.getParameter("amqp_user")
amqp_password = self.getParameter("amqp_password")
amqp_virtual_host = self.getParameter("amqp_virtual_host")
amqp_exchange = self.getParameter("amqp_exchange")
db_connection = self.getParameter("db_connection", fallback=True)
host = self.getParameter("host")
synergy_topic = self.getParameter("synergy_topic")
notification_topic = self.getParameter("notification_topic")
conductor_topic = self.getParameter("conductor_topic")
self.getParameter("metadata_proxy_shared_secret", fallback=True)
if not amqp_hosts:
amqp_hosts = ["%s:%s" % (amqp_host, amqp_port)]
try:
LOG.debug("setting up the NOVA database connection: %s"
% db_connection)
self.db_engine = create_engine(db_connection, pool_recycle=30)
self.messaging = AMQP(url=amqp_url, backend=amqp_backend,
username=amqp_user,
password=amqp_password,
hosts=amqp_hosts,
virt_host=amqp_virtual_host,
exchange=amqp_exchange)
self.novaConductorComputeAPI = NovaConductorComputeAPI(
synergy_topic,
conductor_topic,
self,
self.messaging)
self.conductor_rpc = self.messaging.getRPCServer(
target=self.messaging.getTarget(topic=synergy_topic,
server=host),
endpoints=[self.novaConductorComputeAPI])
self.conductor_rpc.start()
self.serverEventHandler = ServerEventHandler(self)
target = self.messaging.getTarget(topic=notification_topic,
exchange=amqp_exchange)
self.listener = self.messaging.getNotificationListener(
targets=[target], endpoints=[self.serverEventHandler])
self.listener.start()
except Exception as ex:
LOG.error("Exception has occured", exc_info=1)
LOG.error("NovaManager initialization failed! %s" % (ex))
raise ex
def execute(self, command, *args, **kargs):
raise SynergyError("command %r not supported!" % command)
def task(self):
pass
def destroy(self):
pass
def getParameter(self, name, fallback=False):
result = CONF.NovaManager.get(name, None)
if result is not None:
return result
if fallback is True:
raise SynergyError("No attribute %r found in [NovaManager] "
"section of synergy.conf" % name)
else:
return None
def getUserData(self, server):
if not server:
return None
secret = CONF.NovaManager.metadata_proxy_shared_secret
if not secret:
raise SynergyError("'metadata_proxy_shared_secret' "
"attribute not defined in synergy.conf")
digest = hmac.new(secret, server.getId(), hashlib.sha256).hexdigest()
self.keystone_manager.authenticate()
token = self.keystone_manager.getToken()
service = token.getService("nova")
if not service:
raise SynergyError("nova service not found!")
endpoint = service.getEndpoint("public")
if not endpoint:
raise SynergyError("nova endpoint not found!")
url = endpoint.getURL()
url = url[:url.rfind(":") + 1] + "8775/openstack/2015-10-15/user_data"
headers = {"Content-Type": "application/text",
"Accept": "application/text",
"User-Agent": "synergy",
"x-instance-id": server.getId(),
"x-tenant-id": server.getProjectId(),
"x-instance-id-signature": digest}
request = requests.get(url, headers=headers,
timeout=self.timeout,
verify=self.ssl_ca_file,
cert=self.ssl_cert_file)
if request.status_code != requests.codes.ok:
if request.status_code == 404:
return None
elif request.status_code == 403:
if "Invalid proxy request signature" in request._content:
raise SynergyError("cannot retrieve the 'userdata' value: "
"check the 'metadata_proxy_shared_"
"secret' attribute value")
else:
request.raise_for_status()
else:
request.raise_for_status()
if request.text:
return request.text
else:
return None
def getFlavors(self):
url = "flavors/detail"
try:
response_data = self.getResource(url, method="GET")
except requests.exceptions.HTTPError as ex:
response = ex.response.json()
raise SynergyError("error on retrieving the flavors list: %s"
% response)
flavors = []
if response_data:
for flavor_data in response_data["flavors"]:
flavor = Flavor()
flavor.setId(flavor_data["id"])
flavor.setName(flavor_data["name"])
flavor.setVCPUs(flavor_data["vcpus"])
flavor.setMemory(flavor_data["ram"])
flavor.setStorage(flavor_data["disk"])
flavors.append(flavor)
return flavors
def getFlavor(self, id):
try:
response_data = self.getResource("flavors/" + id, "GET")
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on retrieving the flavor info (id=%r)"
": %s" % (id, ex.response.json()))
flavor = None
if response_data:
flavor_data = response_data["flavor"]
flavor = Flavor()
flavor.setId(flavor_data["id"])
flavor.setName(flavor_data["name"])
flavor.setVCPUs(flavor_data["vcpus"])
flavor.setMemory(flavor_data["ram"])
flavor.setStorage(flavor_data["disk"])
return flavor
def getServers(self, detail=False, status=None):
params = {}
if status:
params["status"] = status
url = "servers/detail"
try:
response_data = self.getResource(url, "GET", params)
except requests.exceptions.HTTPError as ex:
response = ex.response.json()
raise SynergyError("error on retrieving the servers list"
": %s" % (id, response))
servers = []
if response_data:
for server_data in response_data["servers"]:
server = Server()
server.setId(server_data["id"])
server.setName(server_data["name"])
server.setKeyName(server_data["key_name"])
server.setMetadata(server_data["metadata"])
server.setState(server_data["OS-EXT-STS:vm_state"])
server.setUserId(server_data["user_id"])
server.setProjectId(server_data["tenant_id"])
server.setCreatedAt(server_data["created"])
server.setUpdatedAt(server_data.get("updated", None))
server.setLaunchedAt(
server_data.get("OS-SRV-USG:launched_at", None))
server.setTerminatedAt(
server_data.get("OS-SRV-USG:terminated_at", None))
if "user_data" in server_data:
user_data = server_data["user_data"]
server.setUserData(utils.decodeBase64(user_data))
if detail:
server.setFlavor(self.getFlavor(
server_data["flavor"]["id"]))
servers.append(server)
return servers
def getServer(self, id, detail=False):
try:
response_data = self.getResource("servers/" + id, "GET")
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on retrieving the server info (id=%r)"
": %s" % (id, ex.response.json()))
server = None
if response_data:
server_data = response_data["server"]
server = Server()
server.setId(server_data["id"])
server.setName(server_data["name"])
server.setKeyName(server_data["key_name"])
server.setMetadata(server_data["metadata"])
server.setState(server_data["OS-EXT-STS:vm_state"])
server.setUserId(server_data["user_id"])
server.setProjectId(server_data["tenant_id"])
server.setCreatedAt(server_data["created"])
server.setUpdatedAt(server_data.get("updated", None))
server.setLaunchedAt(
server_data.get("OS-SRV-USG:launched_at", None))
server.setTerminatedAt(
server_data.get("OS-SRV-USG:terminated_at", None))
if "user_data" in server_data:
user_data = server_data["user_data"]
server.setUserData(utils.decodeBase64(user_data))
if detail:
server.setFlavor(self.getFlavor(server_data["flavor"]["id"]))
return server
def buildServer(self, request):
self.novaConductorComputeAPI.build_instance(
request.getContext(),
request.getAction(),
request.getData())
def deleteServer(self, server):
if not server:
return
id = server.getId()
url = "servers/%s" % id
try:
response_data = self.getResource(url, "DELETE")
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on deleting the server (id=%r)"
": %s" % (id, ex.response.json()))
if response_data:
response_data = response_data["server"]
return response_data
def startServer(self, server):
if not server:
return
id = server.getId()
data = {"os-start": None}
url = "servers/%s/action" % id
try:
response_data = self.getResource(url, "POST", data)
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on starting the server %s"
": %s" % (id, ex.response.json()))
if response_data:
response_data = response_data["server"]
return response_data
def stopServer(self, server):
if not server:
return
id = server.getId()
data = {"os-stop": None}
url = "servers/%s/action" % id
try:
response_data = self.getResource(url, "POST", data)
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on stopping the server info (id=%r)"
": %s" % (id, ex.response.json()))
if response_data:
response_data = response_data["server"]
return response_data
def setServerMetadata(self, server, key, value):
if not server:
return
id = server.getId()
data = {"metadata": {key: value}}
url = "servers/%s/metadata" % id
try:
response_data = self.getResource(url, "POST", data)
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on setting the metadata (id=%r)"
": %s" % (id, ex.response.json()))
if response_data:
response_data = response_data["metadata"]
return response_data
def getHosts(self):
data = {}
url = "os-hosts"
# /%s" % id
try:
response_data = self.getResource(url, "GET", data)
except requests.exceptions.HTTPError as ex:
response = ex.response.json()
raise SynergyError("error on retrieving the hypervisors list: %s"
% response["badRequest"]["message"])
if response_data:
response_data = response_data["hosts"]
return response_data
def getHost(self, name):
data = {}
url = "os-hosts/%s" % name
try:
response_data = self.getResource(url, "GET", data)
except requests.exceptions.HTTPError as ex:
response = ex.response.json()
raise SynergyError("error on retrieving the hypervisor info (id=%r"
"): %s" % (id,
response["badRequest"]["message"]))
if response_data:
response_data = response_data["host"]
return response_data
def getHypervisors(self):
data = {"os-stop": None}
url = "os-hypervisors/detail"
try:
response_data = self.getResource(url, "GET", data)
except requests.exceptions.HTTPError as ex:
response = ex.response.json()
raise SynergyError("error on retrieving the hypervisors list: %s"
% response["badRequest"]["message"])
hypervisors = []
if response_data:
hypervisors_data = response_data["hypervisors"]
for hypervisor_data in hypervisors_data:
hypervisor = Hypervisor()
hypervisor.setId(hypervisor_data["id"])
hypervisor.setIP(hypervisor_data["host_ip"])
hypervisor.setName(hypervisor_data["hypervisor_hostname"])
hypervisor.setType(hypervisor_data["hypervisor_type"])
hypervisor.setState(hypervisor_data["state"])
hypervisor.setStatus(hypervisor_data["status"])
hypervisor.setWorkload(hypervisor_data["current_workload"])
hypervisor.setVMs(hypervisor_data["running_vms"])
hypervisor.setVCPUs(hypervisor_data["vcpus"])
hypervisor.setVCPUs(hypervisor_data["vcpus_used"], used=True)
hypervisor.setMemory(hypervisor_data["memory_mb"])
hypervisor.setMemory(hypervisor_data["memory_mb_used"], used=True)
hypervisor.setStorage(hypervisor_data["local_gb"])
hypervisor.setStorage(hypervisor_data["local_gb_used"], used=True)
hypervisors.append(hypervisor)
return hypervisors
def getHypervisor(self, id):
data = {"os-stop": None}
url = "os-hypervisors/%s" % id
try:
response_data = self.getResource(url, "GET", data)
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on retrieving the hypervisor info (id=%r"
"): %s" % (id, ex.response.json()))
hypervisor = None
if response_data:
hypervisor_data = response_data["hypervisor"]
hypervisor = Hypervisor()
hypervisor.setId(hypervisor_data["id"])
hypervisor.setIP(hypervisor_data["host_ip"])
hypervisor.setName(hypervisor_data["hypervisor_hostname"])
hypervisor.setType(hypervisor_data["hypervisor_type"])
hypervisor.setState(hypervisor_data["state"])
hypervisor.setStatus(hypervisor_data["status"])
hypervisor.setWorkload(hypervisor_data["current_workload"])
hypervisor.setVMs(hypervisor_data["running_vms"])
hypervisor.setVCPUs(hypervisor_data["vcpus"])
hypervisor.setVCPUs(hypervisor_data["vcpus_used"], used=True)
hypervisor.setMemory(hypervisor_data["memory_mb"])
hypervisor.setMemory(hypervisor_data["memory_mb_used"], used=True)
hypervisor.setStorage(hypervisor_data["local_gb"])
hypervisor.setStorage(hypervisor_data["local_gb_used"], used=True)
return hypervisor
def getQuota(self, id=None, is_class=False, defaults=False):
if defaults:
try:
url = "os-quota-sets/defaults"
response_data = self.getResource(url, "GET")
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on retrieving the quota defaults"
": %s" % ex.response.json())
elif id is not None:
if is_class:
url = "os-quota-class-sets/%s" % id
else:
url = "os-quota-sets/%s" % id
try:
response_data = self.getResource(url, "GET")
if is_class:
quota_data = response_data["quota_class_set"]
else:
quota_data = response_data["quota_set"]
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on retrieving the quota info (id=%r)"
": %s" % (id, ex.response.json()))
else:
raise SynergyError("wrong arguments")
quota = None
if quota_data:
quota = Quota()
quota.setId(id)
quota.setSize("vcpus", quota_data["cores"])
quota.setSize("memory", quota_data["ram"])
quota.setSize("instances", quota_data["instances"])
return quota
def updateQuota(self, quota, is_class=False):
if is_class:
url = "os-quota-class-sets/%s" % quota.getId()
qs = {"quota_class_set": {"cores": quota.getSize("vcpus"),
"ram": quota.getSize("memory"),
"instances": quota.getSize("instances")}}
else:
url = "os-quota-sets/%s" % quota.getId()
qs = {"quota_set": {"force": True,
"cores": quota.getSize("vcpus"),
"ram": quota.getSize("memory"),
"instances": quota.getSize("instances")}}
try:
self.getResource(url, "PUT", qs)
except requests.exceptions.HTTPError as ex:
raise SynergyError("error on updating the quota info (id=%r)"
": %s" % (id, ex.response.json()))
def getResource(self, resource, method, data=None):
self.keystone_manager.authenticate()
token = self.keystone_manager.getToken()
service = token.getService("nova")
if not service:
raise SynergyError("nova service not found!")
endpoint = service.getEndpoint("public")
if not endpoint:
raise SynergyError("nova endpoint not found!")
url = endpoint.getURL() + "/" + resource
headers = {"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "python-novaclient",
"X-Auth-Project-Id": token.getProject().getName(),
"X-Auth-Token": token.getId()}
if method == "GET":
request = requests.get(url, headers=headers,
params=data, timeout=self.timeout,
verify=self.ssl_ca_file,
cert=self.ssl_cert_file)
elif method == "POST":
request = requests.post(url,
headers=headers,
data=json.dumps(data),
timeout=self.timeout,
verify=self.ssl_ca_file,
cert=self.ssl_cert_file)
elif method == "PUT":
request = requests.put(url,
headers=headers,
data=json.dumps(data),
timeout=self.timeout,
verify=self.ssl_ca_file,
cert=self.ssl_cert_file)
elif method == "HEAD":
request = requests.head(url,
headers=headers,
data=json.dumps(data),
timeout=self.timeout,
verify=self.ssl_ca_file,
cert=self.ssl_cert_file)
elif method == "DELETE":
request = requests.delete(url,
headers=headers,
data=json.dumps(data),
timeout=self.timeout,
verify=self.ssl_ca_file,
cert=self.ssl_cert_file)
else:
raise SynergyError("wrong HTTP method: %s" % method)
if request.status_code != requests.codes.ok:
request.raise_for_status()
if request.text:
return request.json()
else:
return None
def getTarget(self, topic, exchange=None, namespace=None,
version=None, server=None):
return self.messaging.getTarget(topic=topic,
namespace=namespace,
exchange=exchange,
version=version,
server=server)
def getRPCClient(self, target, version_cap=None, serializer=None):
return self.messaging.getRPCClient(target,
version_cap=version_cap,
serializer=serializer)
def getRPCServer(self, target, endpoints, serializer=None):
return self.messaging.getRPCServer(target,
endpoints,
serializer=serializer)
def getNotificationListener(self, targets, endpoints):
return self.messaging.getNotificationListener(targets, endpoints)
def getProjectUsage(self, prj_id, from_date, to_date):
usage = {}
connection = self.db_engine.connect()
try:
QUERY = """select a.user_id, sum(TIMESTAMPDIFF(\
SECOND, IF(a.launched_at<='%(from_date)s', '%(from_date)s', IFNULL(\
a.launched_at, '%(from_date)s')), IF(a.terminated_at>='%(to_date)s', \
'%(to_date)s', IFNULL(a.terminated_at, '%(to_date)s')))*a.memory_mb) as \
memory_usage, sum(TIMESTAMPDIFF(SECOND, IF(a.launched_at<='%(from_date)s', \
'%(from_date)s', IFNULL(a.launched_at, '%(from_date)s')), IF(a.terminated_at\
>='%(to_date)s', '%(to_date)s', IFNULL(a.terminated_at, '%(to_date)s')))\
*a.vcpus) as vcpus_usage from nova.instances as a LEFT OUTER JOIN \
nova.instance_metadata as b ON a.uuid=b.instance_uuid where a.project_id\
='%(prj_id)s' and b.value='shared' and a.launched_at is not NULL and \
a.launched_at<='%(to_date)s' and (a.terminated_at>='%(from_date)s' or \
a.terminated_at is NULL) group by user_id
""" % {"prj_id": prj_id, "from_date": from_date, "to_date": to_date}
LOG.debug("persistent servers query: %s" % QUERY)
result = connection.execute(QUERY)
# for row in result.fetchall():
for row in result:
usage[row[0]] = {"memory": float(row[1]),
"vcpus": float(row[2])}
except SQLAlchemyError as ex:
raise SynergyError(ex.message)
finally:
connection.close()
return usage
def getProjectServers(self, prj_id):
connection = self.db_engine.connect()
servers = []
try:
# retrieve the amount of resources in terms of cores and memory
QUERY = """select a.uuid, a.vcpus, a.memory_mb, a.root_gb, \
a.vm_state from nova.instances as a WHERE a.project_id='%(project_id)s' \
and a.vm_state in ('active', 'building', 'error') and a.deleted_at is NULL \
and a.terminated_at is NULL""" % {"project_id": prj_id}
LOG.debug("getProjectServers query: %s" % QUERY)
result = connection.execute(QUERY)
for row in result.fetchall():
flavor = Flavor()
flavor.setVCPUs(row[1])
flavor.setMemory(row[2])
flavor.setStorage(row[3])
server = Server()
server.setId(row[0])
server.setState(row[4])
server.setFlavor(flavor)
QUERY = """select `key`, value from nova.instance_metadata \
where instance_uuid='%(id)s' and deleted_at is NULL""" % {"id": server.getId()}
LOG.debug("getProjectServers query: %s" % QUERY)
result = connection.execute(QUERY)
metadata = {}
for row in result.fetchall():
metadata[row[0]] = row[1]
server.setMetadata(metadata)
servers.append(server)
except SQLAlchemyError as ex:
raise SynergyError(ex.message)
finally:
connection.close()
return servers
def getExpiredServers(self, prj_id, server_ids, TTL):
servers = []
connection = self.db_engine.connect()
try:
# retrieve all expired instances for the specified
# project and expiration time
ids = ""
if server_ids:
ids = "uuid in ('%s') and " % "', '".join(server_ids)
QUERY = """select uuid, vcpus, memory_mb, root_gb, \
vm_state from nova.instances where project_id = \
'%(project_id)s' and deleted_at is NULL and (vm_state='error' or \
(%(server_ids)s vm_state='active' and terminated_at is NULL \
and timestampdiff(minute, launched_at, utc_timestamp()) >= %(expiration)s))\
""" % {"project_id": prj_id, "server_ids": ids, "expiration": TTL}
LOG.debug("getExpiredServers query: %s" % QUERY)
result = connection.execute(QUERY)
for row in result.fetchall():
flavor = Flavor()
flavor.setVCPUs(row[1])
flavor.setMemory(row[2])
flavor.setStorage(row[3])
server = Server()
server.setId(row[0])
server.setState(row[4])
server.setFlavor(flavor)
QUERY = """select `key`, value from nova.instance_metadata \
where instance_uuid='%(id)s' and deleted_at is NULL""" % {"id": server.getId()}
LOG.debug("getExpiredServers query: %s" % QUERY)
result = connection.execute(QUERY)
metadata = {}
for row in result.fetchall():
metadata[row[0]] = row[1]
server.setMetadata(metadata)
servers.append(server)
except SQLAlchemyError as ex:
raise SynergyError(ex.message)
finally:
connection.close()
return servers
def selectComputes(self, request):
target = self.messaging.getTarget(topic='scheduler',
exchange="nova",
version="4.0")
client = self.messaging.getRPCClient(target)
cctxt = client.prepare(version='4.0')
request_spec = {
'image': request.getImage(),
'instance_properties': request.getInstance(),
'instance_type': request.getFilterProperties()['instance_type'],
'num_instances': 1}
hosts = cctxt.call(request.getContext(),
'select_destinations',
request_spec=request_spec,
filter_properties=request.getFilterProperties())
computes = []
for host in hosts:
compute = Compute()
compute.setHost(host['host'])
compute.setNodeName(host['nodename'])
compute.setLimits(host['limits'])
computes.append(compute)
return computes
def getBlockDeviceMappingList(self, server_id):
connection = self.db_engine.connect()
blockDeviceMapList = []
try:
QUERY = """select id, created_at, updated_at, deleted_at, \
device_name, delete_on_termination, snapshot_id, volume_id, volume_size, \
no_device, connection_info, deleted, source_type, destination_type, \
guest_format, device_type, disk_bus, boot_index, image_id from \
nova.block_device_mapping where instance_uuid='%(server_id)s'
""" % {"server_id": server_id}
LOG.debug("getBlockDeviceMapping query: %s" % QUERY)
result = connection.execute(QUERY)
for row in result.fetchall():
blockDeviceMap = BlockDeviceMapping(row[0])
blockDeviceMap.setCreatedAt(row[1])
blockDeviceMap.setUpdatedAt(row[2])
blockDeviceMap.setDeletedAt(row[3])
blockDeviceMap.setDeviceName(row[4])
blockDeviceMap.setDeleteOnTermination(row[5])
blockDeviceMap.setSnapshotId(row[6])
blockDeviceMap.setVolumeId(row[7])
blockDeviceMap.setVolumeSize(row[8])
blockDeviceMap.setNoDevice(row[9])
blockDeviceMap.setConnectionInfo(row[10])
blockDeviceMap.setDeleted(row[11])
blockDeviceMap.setSourceType(row[12])
blockDeviceMap.setDestinationType(row[13])
blockDeviceMap.setGuestFormat(row[14])
blockDeviceMap.setDeviceType(row[15])
blockDeviceMap.setDiskBus(row[16])
blockDeviceMap.setBootIndex(row[17])
blockDeviceMap.setImageId(row[18])
blockDeviceMap.setInstanceId(server_id)
blockDeviceMapList.append(blockDeviceMap)
except SQLAlchemyError as ex:
raise SynergyError(ex.message)
finally:
connection.close()
return blockDeviceMapList