~ubuntu-branches/ubuntu/vivid/sahara/vivid-proposed

« back to all changes in this revision

Viewing changes to sahara/service/validations/base.py

  • Committer: Package Import Robot
  • Author(s): Thomas Goirand
  • Date: 2014-09-24 16:34:46 UTC
  • Revision ID: package-import@ubuntu.com-20140924163446-8gu3zscu5e3n9lr2
Tags: upstream-2014.2~b3
ImportĀ upstreamĀ versionĀ 2014.2~b3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2013 Mirantis Inc.
 
2
#
 
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
 
6
#
 
7
#    http://www.apache.org/licenses/LICENSE-2.0
 
8
#
 
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
 
12
# implied.
 
13
# See the License for the specific language governing permissions and
 
14
# limitations under the License.
 
15
 
 
16
import novaclient.exceptions as nova_ex
 
17
from oslo.config import cfg
 
18
 
 
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
 
29
 
 
30
 
 
31
CONF = cfg.CONF
 
32
conductor = cond.API
 
33
 
 
34
MAX_HOSTNAME_LENGTH = 64
 
35
 
 
36
 
 
37
def _get_plugin_configs(plugin_name, hadoop_version, scope=None):
 
38
    pl_confs = {}
 
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)
 
43
        else:
 
44
            pl_confs[config.applicable_target] = [config.name]
 
45
    return pl_confs
 
46
 
 
47
 
 
48
# Common validation checks
 
49
 
 
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)
 
54
 
 
55
 
 
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})
 
61
 
 
62
 
 
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)
 
67
 
 
68
 
 
69
def check_node_group_configs(plugin_name, hadoop_version, ng_configs,
 
70
                             plugin_configs=None):
 
71
    # TODO(aignatov): Should have scope and config type validations
 
72
    pl_confs = plugin_configs or _get_plugin_configs(plugin_name,
 
73
                                                     hadoop_version)
 
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'")
 
78
                % app_target)
 
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})
 
85
 
 
86
 
 
87
def check_all_configurations(data):
 
88
    pl_confs = _get_plugin_configs(data['plugin_name'], data['hadoop_version'])
 
89
 
 
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)
 
94
 
 
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'],
 
101
                                          ng, pl_confs)
 
102
 
 
103
# NodeGroup related checks
 
104
 
 
105
 
 
106
def check_node_group_basic_fields(plugin_name, hadoop_version, ng,
 
107
                                  plugin_configs=None):
 
108
 
 
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'],
 
115
                                      plugin_configs)
 
116
 
 
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'])
 
122
 
 
123
    if ng.get('node_processes'):
 
124
        check_node_processes(plugin_name, hadoop_version, ng['node_processes'])
 
125
 
 
126
    if ng.get('image_id'):
 
127
        check_image_registered(ng['image_id'])
 
128
 
 
129
    if ng.get('volumes_per_node'):
 
130
        check_cinder_exists()
 
131
 
 
132
    if ng.get('floating_ip_pool'):
 
133
        check_floatingip_pool_exists(ng['name'], ng['floating_ip_pool'])
 
134
 
 
135
    if ng.get('security_groups'):
 
136
        check_security_groups_exist(ng['security_groups'])
 
137
 
 
138
 
 
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)
 
144
 
 
145
 
 
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)
 
152
 
 
153
 
 
154
def check_floatingip_pool_exists(ng_name, pool_id):
 
155
    network = None
 
156
    if CONF.use_neutron:
 
157
        network = nova.get_network(id=pool_id)
 
158
    else:
 
159
        for net in nova.client().floating_ip_pools.list():
 
160
            if net.name == pool_id:
 
161
                network = net.name
 
162
                break
 
163
 
 
164
    if not network:
 
165
        raise ex.InvalidException(
 
166
            _("Floating IP pool %(pool)s for node group '%(group)s' "
 
167
              "not found") % {'pool': pool_id, 'group': ng_name})
 
168
 
 
169
 
 
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
 
178
 
 
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))
 
183
 
 
184
 
 
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"))
 
190
 
 
191
 
 
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)
 
200
 
 
201
 
 
202
# Cluster creation related checks
 
203
 
 
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)
 
209
 
 
210
 
 
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")
 
217
                    % cluster_name)
 
218
 
 
219
 
 
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)
 
224
 
 
225
 
 
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})
 
238
 
 
239
 
 
240
def check_keypair_exists(keypair):
 
241
    try:
 
242
        nova.client().keypairs.get(keypair)
 
243
    except nova_ex.NotFound:
 
244
        raise ex.InvalidException(
 
245
            _("Requested keypair '%s' not found") % keypair)
 
246
 
 
247
 
 
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)
 
251
 
 
252
 
 
253
# Cluster templates related checks
 
254
 
 
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)
 
259
 
 
260
 
 
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)
 
266
 
 
267
 
 
268
def check_node_groups_in_cluster_templates(cluster_name, plugin_name,
 
269
                                           hadoop_version,
 
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)
 
278
 
 
279
# NodeGroup templates related checks
 
280
 
 
281
 
 
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)
 
286
 
 
287
 
 
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)
 
292
 
 
293
 
 
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'))
 
299
 
 
300
 
 
301
def _get_floating_ip_pool(node_group):
 
302
    if node_group.get('floating_ip_pool'):
 
303
        return node_group['floating_ip_pool']
 
304
 
 
305
    if node_group.get('node_group_template_id'):
 
306
        ctx = context.ctx()
 
307
        ngt = conductor.node_group_template_get(
 
308
            ctx,
 
309
            node_group['node_group_template_id'])
 
310
        if ngt.get('floating_ip_pool'):
 
311
            return ngt['floating_ip_pool']
 
312
 
 
313
    return None
 
314
 
 
315
 
 
316
# Cluster scaling
 
317
 
 
318
def check_resize(cluster, r_node_groups):
 
319
    cluster_ng_names = [ng.name for ng in cluster.node_groups]
 
320
 
 
321
    check_duplicates_node_groups_names(r_node_groups)
 
322
 
 
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'")
 
327
                % ng['name'])
 
328
 
 
329
 
 
330
def check_add_node_groups(cluster, add_node_groups):
 
331
    cluster_ng_names = [ng.name for ng in cluster.node_groups]
 
332
 
 
333
    check_duplicates_node_groups_names(add_node_groups)
 
334
 
 
335
    pl_confs = _get_plugin_configs(cluster.plugin_name, cluster.hadoop_version)
 
336
 
 
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'])
 
342
 
 
343
        check_node_group_basic_fields(cluster.plugin_name,
 
344
                                      cluster.hadoop_version, ng, pl_confs)
 
345
        check_auto_security_group(cluster.name, ng)
 
346
 
 
347
 
 
348
# Cinder
 
349
 
 
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"))
 
355
 
 
356
 
 
357
# Tags
 
358
 
 
359
 
 
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})
 
370
 
 
371
 
 
372
# EDP
 
373
 
 
374
 
 
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)