sahara/savanna/service/api.py

270 lines
7.1 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 import exceptions as ex
from savanna.openstack.common import log as logging
from savanna.service import cluster_ops
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 is_node_template_associated(**args):
return storage.is_node_template_associated(**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
flavor_id = values.pop('flavor_id')
nt = storage.create_node_template(name, node_type_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:
launched = cluster_ops.launch_cluster(headers, cluster)
else:
LOG.info("Cluster ops are disabled, use --allow-cluster-ops flag")
launched = True
if launched:
storage.update_cluster_status('Active', id=cluster.id)
def terminate_cluster(headers, **args):
cluster = storage.update_cluster_status('Stopping', **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("Stopping 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)]
def get_node_type_required_params(**args):
result = {}
for process in storage.get_node_type(**args).processes:
result[process.name] = []
for prop in process.node_process_properties:
if prop.required and not prop.default:
result[process.name] += [prop.name]
return result
def get_node_type_all_params(**args):
result = {}
for process in storage.get_node_type(**args).processes:
result[process.name] = [prop.name
for prop in process.node_process_properties]
return result
## Utils and DB object to Resource converters
def _clean_nones(obj):
if not isinstance(obj, dict) and not isinstance(obj, list):
return obj
if isinstance(obj, dict):
remove = []
for key, value in obj.iteritems():
if value is None:
remove.append(key)
for key in remove:
obj.pop(key)
for value in obj.values():
_clean_nones(value)
elif isinstance(obj, list):
new_list = []
for elem in obj:
elem = _clean_nones(elem)
if elem is not None:
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:
raise ex.NodeTemplateNotFoundException(nt)
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:
raise ex.ClusterNotFoundException(cluster)
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:
raise ex.NodeTypeNotFoundException(nt)
d = {
'id': nt.id,
'name': nt.name,
'processes': [p.name for p in nt.processes]
}
return Resource('node_type', d)