sahara/savanna/service/api.py

246 lines
6.5 KiB
Python

# Copyright (c) 2013 Mirantis Inc.
#
# 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 eventlet
from oslo.config import cfg
from savanna.utils.api import abort_and_log
from savanna.service import cluster_ops
from savanna.openstack.common import log as logging
import savanna.storage.storage as storage
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
CONF.import_opt('allow_cluster_ops', 'savanna.config')
## Node Template ops:
def get_node_template(**args):
return _node_template(storage.get_node_template(**args))
def get_node_templates(**args):
return [_node_template(tmpl) for tmpl
in storage.get_node_templates(**args)]
def create_node_template(values, headers):
"""
Creates new node template from values dict
:param values: dict
:return: created node template resource
"""
values = values.pop('node_template')
name = values.pop('name')
node_type_id = storage.get_node_type(name=values.pop('node_type')).id
tenant_id = headers['X-Tenant-Id']
flavor_id = values.pop('flavor_id')
nt = storage.create_node_template(name, node_type_id, tenant_id,
flavor_id, values)
return get_node_template(id=nt.id)
def terminate_node_template(**args):
return storage.terminate_node_template(**args)
## Cluster ops:
def get_cluster(**args):
return _cluster(storage.get_cluster(**args))
def get_clusters(**args):
return [_cluster(cluster) for cluster in
storage.get_clusters(**args)]
def create_cluster(values, headers):
values = values.pop('cluster')
name = values.pop('name')
base_image_id = values.pop('base_image_id')
tenant_id = headers['X-Tenant-Id']
templates = values.pop('node_templates')
# todo(slukjanov): check that we can create objects in the specified tenant
cluster = storage.create_cluster(name, base_image_id, tenant_id, templates)
eventlet.spawn(_cluster_creation_job, headers, cluster.id)
return get_cluster(id=cluster.id)
def _cluster_creation_job(headers, cluster_id):
cluster = storage.get_cluster(id=cluster_id)
LOG.debug("Starting cluster '%s' creation: %s", cluster_id,
_cluster(cluster).dict)
if CONF.allow_cluster_ops:
cluster_ops.launch_cluster(headers, cluster)
else:
LOG.info("Cluster ops are disabled, use --allow-cluster-ops flag")
# update cluster status
storage.update_cluster_status('Active', id=cluster.id)
def terminate_cluster(headers, **args):
cluster = storage.update_cluster_status('Stoping', **args)
eventlet.spawn(_cluster_termination_job, headers, cluster.id)
def _cluster_termination_job(headers, cluster_id):
cluster = storage.get_cluster(id=cluster_id)
LOG.debug("Stoping cluster '%s' creation: %s", cluster_id,
_cluster(cluster).dict)
if CONF.allow_cluster_ops:
cluster_ops.stop_cluster(headers, cluster)
else:
LOG.info("Cluster ops are disabled, use --allow-cluster-ops flag")
storage.terminate_cluster(id=cluster.id)
## Node Type ops:
def get_node_type(**args):
return _node_type(storage.get_node_type(**args))
def get_node_types(**args):
return [_node_type(t) for t in storage.get_node_types(**args)]
## Utils and DB object to Resource converters
def _clean_nones(obj):
d_type = type(obj)
if d_type is not dict or d_type is not list:
return obj
if d_type is dict:
remove = []
for key in obj:
value = _clean_nones(obj.get(key))
if value is None or len(value) == 0:
remove.append(key)
for key in remove:
obj.pop(key)
elif d_type is list:
new_list = []
for elem in obj:
elem = _clean_nones(elem)
if elem is not None and len(elem) == 0:
new_list.append(elem)
return new_list
return obj
class Resource(object):
def __init__(self, _name, _info):
self._name = _name
self._info = _clean_nones(_info)
def __getattr__(self, k):
if k not in self.__dict__:
return self._info.get(k)
return self.__dict__[k]
def __repr__(self):
return '<%s %s>' % (self._name, self._info)
def __eq__(self, other):
return self._name == other._name and self._info == other._info
@property
def dict(self):
return self._info
@property
def wrapped_dict(self):
return {self._name: self._info}
def _node_template(nt):
if not nt:
abort_and_log(404, 'NodeTemplate not found')
d = {
'id': nt.id,
'name': nt.name,
'node_type': {
'name': nt.node_type.name,
'processes': [p.name for p in nt.node_type.processes]},
'flavor_id': nt.flavor_id
}
for conf in nt.node_template_configs:
c_section = conf.node_process_property.node_process.name
c_name = conf.node_process_property.name
c_value = conf.value
if c_section not in d:
d[c_section] = dict()
d[c_section][c_name] = c_value
return Resource('node_template', d)
def _cluster(cluster):
if not cluster:
abort_and_log(404, 'Cluster not found')
d = {
'id': cluster.id,
'name': cluster.name,
'base_image_id': cluster.base_image_id,
'status': cluster.status,
'service_urls': {},
'node_templates': {},
'nodes': [{'vm_id': n.vm_id,
'node_template': {
'id': n.node_template.id,
'name': n.node_template.name
}}
for n in cluster.nodes]
}
for ntc in cluster.node_counts:
d['node_templates'][ntc.node_template.name] = ntc.count
for service in cluster.service_urls:
d['service_urls'][service.name] = service.url
return Resource('cluster', d)
def _node_type(nt):
if not nt:
abort_and_log(404, 'NodeType not found')
d = {
'id': nt.id,
'name': nt.name,
'processes': [p.name for p in nt.processes]
}
return Resource('node_type', d)