1
# Copyright (c) 2013 Mirantis Inc.
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
7
# http://www.apache.org/licenses/LICENSE-2.0
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
16
import novaclient.exceptions as nova_ex
17
from oslo.config import cfg
19
from sahara import conductor as cond
20
from sahara import context
21
import sahara.exceptions as ex
22
from sahara.i18n import _
23
import sahara.plugins.base as plugin_base
24
import sahara.service.api as api
25
from sahara.utils import general as g
26
import sahara.utils.openstack.heat as heat
27
import sahara.utils.openstack.keystone as keystone
28
import sahara.utils.openstack.nova as nova
34
MAX_HOSTNAME_LENGTH = 64
37
def _get_plugin_configs(plugin_name, hadoop_version, scope=None):
39
for config in plugin_base.PLUGINS.get_plugin(
40
plugin_name).get_configs(hadoop_version):
41
if pl_confs.get(config.applicable_target):
42
pl_confs[config.applicable_target].append(config.name)
44
pl_confs[config.applicable_target] = [config.name]
48
# Common validation checks
50
def check_plugin_name_exists(name):
51
if name not in [p.name for p in api.get_plugins()]:
52
raise ex.InvalidException(
53
_("Sahara doesn't contain plugin with name '%s'") % name)
56
def check_plugin_supports_version(p_name, version):
57
if version not in plugin_base.PLUGINS.get_plugin(p_name).get_versions():
58
raise ex.InvalidException(
59
_("Requested plugin '%(name)s' doesn't support version "
60
"'%(version)s'") % {'name': p_name, 'version': version})
63
def check_image_registered(image_id):
64
if image_id not in [i.id for i in nova.client().images.list_registered()]:
65
raise ex.InvalidException(
66
_("Requested image '%s' is not registered") % image_id)
69
def check_node_group_configs(plugin_name, hadoop_version, ng_configs,
71
# TODO(aignatov): Should have scope and config type validations
72
pl_confs = plugin_configs or _get_plugin_configs(plugin_name,
74
for app_target, configs in ng_configs.items():
75
if app_target not in pl_confs:
76
raise ex.InvalidException(
77
_("Plugin doesn't contain applicable target '%s'")
79
for name, values in configs.items():
80
if name not in pl_confs[app_target]:
81
raise ex.InvalidException(
82
_("Plugin's applicable target '%(target)s' doesn't "
83
"contain config with name '%(name)s'") %
84
{'target': app_target, 'name': name})
87
def check_all_configurations(data):
88
pl_confs = _get_plugin_configs(data['plugin_name'], data['hadoop_version'])
90
if data.get('cluster_configs'):
91
check_node_group_configs(data['plugin_name'], data['hadoop_version'],
92
data['cluster_configs'],
93
plugin_configs=pl_confs)
95
if data.get('node_groups'):
96
check_duplicates_node_groups_names(data['node_groups'])
97
for ng in data['node_groups']:
98
check_auto_security_group(data['name'], ng)
99
check_node_group_basic_fields(data['plugin_name'],
100
data['hadoop_version'],
103
# NodeGroup related checks
106
def check_node_group_basic_fields(plugin_name, hadoop_version, ng,
107
plugin_configs=None):
109
if ng.get('node_group_template_id'):
110
ng_tmpl_id = ng['node_group_template_id']
111
check_node_group_template_exists(ng_tmpl_id)
112
ng_tmpl = api.get_node_group_template(ng_tmpl_id).to_wrapped_dict()
113
check_node_group_basic_fields(plugin_name, hadoop_version,
114
ng_tmpl['node_group_template'],
117
if ng.get('node_configs'):
118
check_node_group_configs(plugin_name, hadoop_version,
119
ng['node_configs'], plugin_configs)
120
if ng.get('flavor_id'):
121
check_flavor_exists(ng['flavor_id'])
123
if ng.get('node_processes'):
124
check_node_processes(plugin_name, hadoop_version, ng['node_processes'])
126
if ng.get('image_id'):
127
check_image_registered(ng['image_id'])
129
if ng.get('volumes_per_node'):
130
check_cinder_exists()
132
if ng.get('floating_ip_pool'):
133
check_floatingip_pool_exists(ng['name'], ng['floating_ip_pool'])
135
if ng.get('security_groups'):
136
check_security_groups_exist(ng['security_groups'])
139
def check_flavor_exists(flavor_id):
140
flavor_list = nova.client().flavors.list()
141
if flavor_id not in [flavor.id for flavor in flavor_list]:
142
raise ex.InvalidException(
143
_("Requested flavor '%s' not found") % flavor_id)
146
def check_security_groups_exist(security_groups):
147
security_group_list = nova.client().security_groups.list()
148
security_group_names = [sg.name for sg in security_group_list]
149
for sg in security_groups:
150
if sg not in security_group_names:
151
raise ex.InvalidException(_("Security group '%s' not found") % sg)
154
def check_floatingip_pool_exists(ng_name, pool_id):
157
network = nova.get_network(id=pool_id)
159
for net in nova.client().floating_ip_pools.list():
160
if net.name == pool_id:
165
raise ex.InvalidException(
166
_("Floating IP pool %(pool)s for node group '%(group)s' "
167
"not found") % {'pool': pool_id, 'group': ng_name})
170
def check_node_processes(plugin_name, version, node_processes):
171
if len(set(node_processes)) != len(node_processes):
172
raise ex.InvalidException(
173
_("Duplicates in node processes have been detected"))
174
plugin_processes = []
175
for process in plugin_base.PLUGINS.get_plugin(
176
plugin_name).get_node_processes(version).values():
177
plugin_processes += process
179
if not set(node_processes).issubset(set(plugin_processes)):
180
raise ex.InvalidException(
181
_("Plugin supports the following node procesess: %s")
182
% sorted(plugin_processes))
185
def check_duplicates_node_groups_names(node_groups):
186
ng_names = [ng['name'] for ng in node_groups]
187
if len(set(ng_names)) < len(node_groups):
188
raise ex.InvalidException(
189
_("Duplicates in node group names are detected"))
192
def check_auto_security_group(cluster_name, nodegroup):
193
if nodegroup.get('auto_security_group'):
194
name = g.generate_auto_security_group_name(
195
cluster_name, nodegroup['name'])
196
if name in [security_group.name for security_group in
197
nova.client().security_groups.list()]:
198
raise ex.NameAlreadyExistsException(
199
_("Security group with name '%s' already exists") % name)
202
# Cluster creation related checks
204
def check_cluster_unique_name(name):
205
if name in [cluster.name for cluster in api.get_clusters()]:
206
raise ex.NameAlreadyExistsException(
207
_("Cluster with name '%s' already exists") % name)
208
check_heat_stack_name(name)
211
def check_heat_stack_name(cluster_name):
212
if CONF.infrastructure_engine == 'heat':
213
for stack in heat.client().stacks.list():
214
if stack.stack_name == cluster_name:
215
raise ex.NameAlreadyExistsException(
216
_("Cluster name '%s' is already used as Heat stack name")
220
def check_cluster_exists(id):
221
if not api.get_cluster(id):
222
raise ex.InvalidException(
223
_("Cluster with id '%s' doesn't exist") % id)
226
def check_cluster_hostnames_lengths(cluster_name, node_groups):
227
for ng in node_groups:
228
longest_hostname = g.generate_instance_name(cluster_name,
229
ng['name'], ng['count'])
230
longest_hostname += '.'
231
longest_hostname += CONF.node_domain
232
if len(longest_hostname) > MAX_HOSTNAME_LENGTH:
233
raise ex.InvalidException(
234
_("Composite hostname %(host)s in provisioned cluster exceeds"
235
" maximum limit %(limit)s characters") %
236
{'host': longest_hostname,
237
'limit': MAX_HOSTNAME_LENGTH})
240
def check_keypair_exists(keypair):
242
nova.client().keypairs.get(keypair)
243
except nova_ex.NotFound:
244
raise ex.InvalidException(
245
_("Requested keypair '%s' not found") % keypair)
248
def check_network_exists(net_id):
249
if not nova.get_network(id=net_id):
250
raise ex.InvalidException(_("Network %s not found") % net_id)
253
# Cluster templates related checks
255
def check_cluster_template_unique_name(name):
256
if name in [t.name for t in api.get_cluster_templates()]:
257
raise ex.NameAlreadyExistsException(
258
_("Cluster template with name '%s' already exists") % name)
261
def check_cluster_template_exists(cluster_template_id):
262
if not api.get_cluster_template(id=cluster_template_id):
263
raise ex.InvalidException(
264
_("Cluster template with id '%s' doesn't exist")
265
% cluster_template_id)
268
def check_node_groups_in_cluster_templates(cluster_name, plugin_name,
270
cluster_template_id):
271
c_t = api.get_cluster_template(id=cluster_template_id)
272
n_groups = c_t.to_wrapped_dict()['cluster_template']['node_groups']
273
check_network_config(n_groups)
274
for node_group in n_groups:
275
check_auto_security_group(cluster_name, node_group)
276
check_node_group_basic_fields(plugin_name, hadoop_version, node_group)
277
check_cluster_hostnames_lengths(cluster_name, n_groups)
279
# NodeGroup templates related checks
282
def check_node_group_template_unique_name(name):
283
if name in [t.name for t in api.get_node_group_templates()]:
284
raise ex.NameAlreadyExistsException(
285
_("NodeGroup template with name '%s' already exists") % name)
288
def check_node_group_template_exists(ng_tmpl_id):
289
if not api.get_node_group_template(id=ng_tmpl_id):
290
raise ex.InvalidException(
291
_("NodeGroup template with id '%s' doesn't exist") % ng_tmpl_id)
294
def check_network_config(node_groups):
295
if CONF.use_floating_ips and CONF.use_neutron:
296
for ng in node_groups:
297
if not _get_floating_ip_pool(ng):
298
raise ex.MissingFloatingNetworkException(ng.get('name'))
301
def _get_floating_ip_pool(node_group):
302
if node_group.get('floating_ip_pool'):
303
return node_group['floating_ip_pool']
305
if node_group.get('node_group_template_id'):
307
ngt = conductor.node_group_template_get(
309
node_group['node_group_template_id'])
310
if ngt.get('floating_ip_pool'):
311
return ngt['floating_ip_pool']
318
def check_resize(cluster, r_node_groups):
319
cluster_ng_names = [ng.name for ng in cluster.node_groups]
321
check_duplicates_node_groups_names(r_node_groups)
323
for ng in r_node_groups:
324
if ng['name'] not in cluster_ng_names:
325
raise ex.InvalidException(
326
_("Cluster doesn't contain node group with name '%s'")
330
def check_add_node_groups(cluster, add_node_groups):
331
cluster_ng_names = [ng.name for ng in cluster.node_groups]
333
check_duplicates_node_groups_names(add_node_groups)
335
pl_confs = _get_plugin_configs(cluster.plugin_name, cluster.hadoop_version)
337
for ng in add_node_groups:
338
if ng['name'] in cluster_ng_names:
339
raise ex.InvalidException(
340
_("Can't add new nodegroup. Cluster already has nodegroup with"
341
" name '%s'") % ng['name'])
343
check_node_group_basic_fields(cluster.plugin_name,
344
cluster.hadoop_version, ng, pl_confs)
345
check_auto_security_group(cluster.name, ng)
350
def check_cinder_exists():
351
services = [service.name for service in
352
keystone.client().services.list()]
353
if 'cinder' not in services:
354
raise ex.InvalidException(_("Cinder is not supported"))
360
def check_required_image_tags(plugin_name, hadoop_version, image_id):
361
image = api.get_image(id=image_id)
362
plugin = plugin_base.PLUGINS.get_plugin(plugin_name)
363
req_tags = set(plugin.get_required_image_tags(hadoop_version))
364
if not req_tags.issubset(set(image.tags)):
365
raise ex.InvalidException(
366
_("Tags of requested image '%(image)s' don't contain required"
367
" tags ['%(name)s', '%(version)s']")
368
% {'image': image_id, 'name': plugin_name,
369
'version': hadoop_version})
375
def check_edp_job_support(cluster_id):
376
cluster = api.get_cluster(cluster_id)
377
plugin_base.PLUGINS.get_plugin(cluster.plugin_name).validate_edp(cluster)