# 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 novaclient.exceptions as nova_ex import savanna.exceptions as ex import savanna.plugins.base as plugin_base import savanna.service.api as api import savanna.utils.openstack.nova as nova def _get_plugin_configs(plugin_name, hadoop_version, scope=None): pl_confs = {} for config in plugin_base.PLUGINS.get_plugin( plugin_name).get_configs(hadoop_version): if pl_confs.get(config.applicable_target): pl_confs[config.applicable_target].append(config.name) else: pl_confs[config.applicable_target] = [config.name] return pl_confs ## Common validation checks def check_plugin_name_exists(name): if name not in [p.name for p in api.get_plugins()]: raise ex.InvalidException("Savanna doesn't contain plugin with name %s" % name) def check_plugin_supports_version(p_name, version): if version not in plugin_base.PLUGINS.get_plugin(p_name).get_versions(): raise ex.InvalidException("Requested plugin '%s' doesn't support" " version '%s'" % (p_name, version)) def check_image_exists(image_id): try: # TODO(aignatov): Check supported images by plugin instead of it api.get_image(id=image_id) except nova_ex.NotFound: raise ex.InvalidException("Requested image '%s' not found" % image_id) def check_node_group_configs(plugin_name, hadoop_version, ng_configs, plugin_configs=None): # TODO(aignatov): Should have scope and config type validations pl_confs = plugin_configs or _get_plugin_configs(plugin_name, hadoop_version) for app_target, configs in ng_configs.items(): if app_target not in pl_confs: raise ex.InvalidException("Plugin doesn't contain applicable " "target '%s'" % app_target) for name, values in configs.items(): if name not in pl_confs[app_target]: raise ex.InvalidException("Plugin's applicable target '%s' " "doesn't contain config with name " "'%s'" % (app_target, name)) def check_all_configurations(data): pl_confs = _get_plugin_configs(data['plugin_name'], data['hadoop_version']) if data.get('cluster_configs'): check_node_group_configs(data['plugin_name'], data['hadoop_version'], data['cluster_configs'], plugin_configs=pl_confs) if data.get('node_groups'): for ng in data['node_groups']: check_node_group_basic_fields(data['plugin_name'], data['hadoop_version'], ng, pl_confs) ## NodeGroup related checks def check_node_group_basic_fields(plugin_name, hadoop_version, ng, plugin_configs=None): if ng.get('node_group_template_id'): check_node_group_template_exists(ng['node_group_template_id']) if ng.get('node_configs'): check_node_group_configs(plugin_name, hadoop_version, ng['node_configs'], plugin_configs) if ng.get('flavor_id'): check_flavor_exists(ng['flavor_id']) if ng.get('node_processes'): check_node_processes(plugin_name, hadoop_version, ng['node_processes']) if ng.get('image_id'): check_image_exists(ng['image_id']) def check_flavor_exists(flavor_id): try: nova.client().flavors.get(flavor_id) except nova_ex.NotFound: raise ex.InvalidException("Requested flavor '%s' not found" % flavor_id) def check_node_processes(plugin_name, version, node_processes): if len(set(node_processes)) != len(node_processes): raise ex.InvalidException("Duplicates in node processes " "have been detected") plugin_procesess = [] for process in plugin_base.PLUGINS.get_plugin( plugin_name).get_node_processes(version).values(): plugin_procesess += process if not set(node_processes).issubset(set(plugin_procesess)): raise ex.InvalidException("Plugin supports the following " "node procesess: %s" % plugin_procesess) def check_duplicates_node_groups_names(node_groups): ng_names = [ng['name'] for ng in node_groups] if len(set(ng_names)) < len(node_groups): raise ex.InvalidException("Duplicates in node group names " "are detected") ## Cluster creation related checks def check_cluster_unique_name(name): if name in [cluster.name for cluster in api.get_clusters()]: raise ex.NameAlreadyExistsException("Cluster with name '%s' already" " exists" % name) def check_keypair_exists(keypair): try: nova.client().keypairs.get(keypair) except nova_ex.NotFound: raise ex.InvalidException("Requested keypair '%s' not found" % keypair) ## Cluster templates creation related checks def check_cluster_template_unique_name(name): if name in [t.name for t in api.get_cluster_templates()]: raise ex.NameAlreadyExistsException("Cluster template with name '%s'" " already exists" % name) ## NodeGroup templates related checks def check_node_group_template_unique_name(name): if name in [t.name for t in api.get_node_group_templates()]: raise ex.NameAlreadyExistsException("NodeGroup template with name '%s'" " already exists" % name) def check_node_group_template_exists(ng_tmpl_id): if not api.get_node_group_templates(id=ng_tmpl_id): raise ex.InvalidException("NodeGroup template with id '%s'" " doesn't exist" % ng_tmpl_id) ## Cluster scaling def check_resize(cluster, r_node_groups): cluster_ng_names = [ng.name for ng in cluster.node_groups] check_duplicates_node_groups_names(r_node_groups) for ng in r_node_groups: if ng['name'] not in cluster_ng_names: raise ex.InvalidException("Cluster doesn't contain node group " "with name '%s'" % ng['name']) def check_add_node_groups(cluster, add_node_groups): cluster_ng_names = [ng.name for ng in cluster.node_groups] check_duplicates_node_groups_names(add_node_groups) pl_confs = _get_plugin_configs(cluster.plugin_name, cluster.hadoop_version) for ng in add_node_groups: if ng['name'] in cluster_ng_names: raise ex.InvalidException("Can't add new nodegroup. Cluster " "already has nodegroup with name '%s'" % ng['name']) check_node_group_basic_fields(cluster.plugin_name, cluster.hadoop_version, ng, pl_confs)