blob: d5bcb354d6de7fb4b47fe1246f2489c2ffeb7653 [file] [log] [blame]
Jiri Broulik0ce9fc92017-02-01 23:10:40 +01001# -*- coding: utf-8 -*-
2'''
Jiri Broulik5589c012017-06-20 11:28:52 +02003Custom Nova state
Jiri Broulik0ce9fc92017-02-01 23:10:40 +01004'''
Jiri Broulika2c79292017-02-05 21:01:38 +01005import logging
Richard Felkl55d1f572017-02-15 16:41:53 +01006import collections
Jiri Broulika2c79292017-02-05 21:01:38 +01007from functools import wraps
8LOG = logging.getLogger(__name__)
Jiri Broulik0ce9fc92017-02-01 23:10:40 +01009
10
11def __virtual__():
12 '''
13 Only load if the nova module is in __salt__
14 '''
Jiri Broulik5589c012017-06-20 11:28:52 +020015 return 'novang'
Jiri Broulik0ce9fc92017-02-01 23:10:40 +010016
Jiri Broulik70d9e3f2017-02-15 18:37:13 +010017
Jiri Broulik0ce9fc92017-02-01 23:10:40 +010018def flavor_present(name, flavor_id=0, ram=0, disk=0, vcpus=1, profile=None):
19 '''
Jiri Broulik70d9e3f2017-02-15 18:37:13 +010020 Ensures that the nova flavor exists
Jiri Broulik0ce9fc92017-02-01 23:10:40 +010021 '''
Jiri Broulik0ce9fc92017-02-01 23:10:40 +010022 ret = {'name': name,
23 'changes': {},
24 'result': True,
25 'comment': 'Flavor "{0}" already exists'.format(name)}
Adam Tenglere8afccc2017-06-27 17:57:21 +000026 project = __salt__['novang.flavor_list'](profile)
Jiri Broulik0ce9fc92017-02-01 23:10:40 +010027 if 'Error' in project:
28 pass
29 elif name in project:
30 pass
31 else:
Adam Tenglere8afccc2017-06-27 17:57:21 +000032 __salt__['novang.flavor_create'](name, flavor_id, ram, disk, vcpus, profile)
Jiri Broulik0ce9fc92017-02-01 23:10:40 +010033 ret['comment'] = 'Flavor {0} has been created'.format(name)
34 ret['changes']['Flavor'] = 'Created'
35 return ret
36
Jiri Broulik70d9e3f2017-02-15 18:37:13 +010037
Jiri Broulik5589c012017-06-20 11:28:52 +020038def map_instances(name='cell1'):
39 '''
40 Ensures that the nova instances are mapped to cell
41 '''
42 ret = {'name': name,
43 'changes': {},
44 'result': False,
45 'comment': 'Cell "{0}" does not exists'.format(name)}
46 cell_uuid = __salt__['cmd.shell']('nova-manage cell_v2 list_cells 2>&- | grep ' + name + ' | tr -d \"\n\" | awk \'{print $4}\'')
Jiri Broulik7e72aa22017-07-03 16:05:11 +020047 if cell_uuid:
Jiri Broulik5589c012017-06-20 11:28:52 +020048 try:
49 __salt__['cmd.shell']('nova-manage cell_v2 map_instances --cell_uuid ' + cell_uuid)
50 ret['result'] = True
51 ret['comment'] = 'Instances were mapped to cell named {0}'.format(name)
52 ret['changes']['Instances'] = 'Mapped to cell named {0}'.format(name)
53 except:
54 ret['result'] = False
55 ret['comment'] = 'Error while mapping instances to cell named {0}'.format(name)
56 ret['changes']['Instances'] = 'Failed to map to cell named {0}'.format(name)
57 return ret
58
59
Jiri Broulik91104db2017-07-07 08:50:44 +020060def api_db_version_present(name=None, version="20"):
61 '''
62 Ensures that specific api_db version is present
63 '''
64 ret = {'name': 'api_db --version',
65 'changes': {},
66 'result': True,
67 'comment': 'Current Api_db version is not < than "{0}".'.format(version)}
68 api_db_version = __salt__['cmd.shell']('nova-manage api_db version 2>/dev/null')
69 try:
70 api_db_version = int(api_db_version)
Jiri Broulik37189a72017-07-11 16:18:55 +020071 version = int(version)
Jiri Broulik91104db2017-07-07 08:50:44 +020072 except:
73 # nova is not installed
74 ret = _no_change('api_db --version', None, test=True)
75 return ret
76 if api_db_version < version:
77 try:
Jiri Broulik37189a72017-07-11 16:18:55 +020078 __salt__['cmd.shell']('nova-manage api_db sync --version ' + str(version))
Jiri Broulik91104db2017-07-07 08:50:44 +020079 ret['result'] = True
80 ret['comment'] = 'Nova-manage api_db sync --version {0} was successfuly executed'.format(version)
81 ret['changes']['api_db'] = 'api_db sync --version {0}'.format(version)
82 except:
83 ret['result'] = False
84 ret['comment'] = 'Error while executing nova-manage api_db sync --version {0}'.format(version)
85 ret['changes']['api_db'] = 'Failed to execute api_db sync --version {0}'.format(version)
86 return ret
87
88
89def db_version_present(name=None, version="334"):
90 '''
91 Ensures that specific api_db version is present
92 '''
93 ret = {'name': 'db --version',
94 'changes': {},
95 'result': True,
96 'comment': 'Current db version is not < than "{0}".'.format(version)}
97 db_version = __salt__['cmd.shell']('nova-manage db version 2>/dev/null')
98 try:
99 db_version = int(db_version)
Jiri Broulik37189a72017-07-11 16:18:55 +0200100 version = int(version)
Jiri Broulik91104db2017-07-07 08:50:44 +0200101 except:
102 # nova is not installed
103 ret = _no_change('db --version', None, test=True)
104 return ret
105
106 if db_version < version:
107 try:
Jiri Broulik37189a72017-07-11 16:18:55 +0200108 __salt__['cmd.shell']('nova-manage db sync --version ' + str(version))
Jiri Broulik91104db2017-07-07 08:50:44 +0200109 ret['result'] = True
110 ret['comment'] = 'Nova-manage db sync --version {0} was successfuly executed'.format(version)
111 ret['changes']['db'] = 'db sync --version {0}'.format(version)
112 except:
113 ret['result'] = False
114 ret['comment'] = 'Error while executing nova-manage db sync --version {0}'.format(version)
115 ret['changes']['db'] = 'Failed to execute db sync --version {0}'.format(version)
116 return ret
117
Jiri Broulik37189a72017-07-11 16:18:55 +0200118def online_data_migrations_present(name=None, api_db_version="20", db_version="334"):
119 '''
120 Ensures that online_data_migrations are enforced if specific version of api_db and db is present
121 '''
122 ret = {'name': 'online_data_migrations',
123 'changes': {},
124 'result': True,
125 'comment': 'Current api_db version != {0} a db version != {1}.'.format(api_db_version, db_version)}
126 cur_api_db_version = __salt__['cmd.shell']('nova-manage api_db version 2>/dev/null')
127 cur_db_version = __salt__['cmd.shell']('nova-manage db version 2>/dev/null')
128 try:
129 cur_api_db_version = int(cur_api_db_version)
130 cur_db_version = int(cur_db_version)
131 api_db_version = int(api_db_version)
132 db_version = int(db_version)
133 except:
134 # nova is not installed
135 ret = _no_change('online_data_migrations', None, test=True)
136 return ret
137 if cur_api_db_version == api_db_version and cur_db_version == db_version:
138 try:
139 __salt__['cmd.shell']('nova-manage db online_data_migrations')
140 ret['result'] = True
141 ret['comment'] = 'nova-manage db online_data_migrations was successfuly executed'
142 ret['changes']['online_data_migrations'] = 'online_data_migrations on api_db version {0} and db version {1}'.format(api_db_version, db_version)
143 except:
144 ret['result'] = False
145 ret['comment'] = 'Error while executing nova-manage db online_data_migrations'
146 ret['changes']['online_data_migrations'] = 'Failed to execute online_data_migrations on api_db version {0} and db version {1}'.format(api_db_version, db_version)
147 return ret
148
Jiri Broulika2c79292017-02-05 21:01:38 +0100149def quota_present(tenant_name, profile, name=None, **kwargs):
150 '''
151 Ensures that the nova quota exists
152 '''
153 changes = {}
154 for key, value in kwargs.items():
155 quota = __salt__['novang.quota_get'](key, tenant_name, profile)
156 if quota != value:
157 arg = {}
158 arg[key] = value
159 changes[key] = value
160 __salt__['novang.quota_update'](tenant_name, profile, **arg)
161 if bool(changes):
Jiri Broulik70d9e3f2017-02-15 18:37:13 +0100162 return _updated(tenant_name, 'tenant', changes)
Jiri Broulika2c79292017-02-05 21:01:38 +0100163 else:
164 return _no_change(tenant_name, 'tenant')
165
Jiri Broulika2c79292017-02-05 21:01:38 +0100166
Jiri Broulik70d9e3f2017-02-15 18:37:13 +0100167def availability_zone_present(name=None, availability_zone=None, profile=None):
168 '''
169 Ensures that the nova availability zone exists
170 '''
171 name = availability_zone
172 zone_exists = __salt__['novang.availability_zone_get'](name, profile)
173 if zone_exists == False:
174 item_created = __salt__['novang.availability_zone_create'](name, availability_zone, profile)
175 if bool(item_created):
176 return _created(availability_zone, 'availabilty zone', item_created)
Jiri Broulika2c79292017-02-05 21:01:38 +0100177 else:
Jiri Broulik70d9e3f2017-02-15 18:37:13 +0100178 return _already_exists(availability_zone, 'availabilty zone')
179 return existing_availability_zones
180
Damian Szeluga5dca0f02017-04-13 17:27:15 +0200181def aggregate_present(name=None, aggregate=None, profile=None):
182 '''
183 Ensures that the nova aggregate exists
184 '''
185 name = aggregate
186 aggregate_exists = __salt__['novang.aggregate_get'](name, profile)
187 if aggregate_exists == False:
188 item_created = __salt__['novang.aggregate_create'](name, aggregate, profile)
189 if bool(item_created):
190 return _created(aggregate, 'aggregate', item_created)
191 else:
192 return _already_exists(aggregate, 'aggregate')
193 return existing_aggregate
194
Richard Felkl55d1f572017-02-15 16:41:53 +0100195
196def instance_present(name, flavor, image, networks, security_groups=None, profile=None, tenant_name=None):
197 ret = {'name': name,
198 'changes': {},
199 'result': True,
200 'comment': 'Instance "{0}" already exists'.format(name)}
201 kwargs = {}
202 nics = []
203 existing_instances = __salt__['novang.server_list'](profile, tenant_name)
204 if name in existing_instances:
205 return ret
Adam Tenglere8afccc2017-06-27 17:57:21 +0000206 existing_flavors = __salt__['novang.flavor_list'](profile)
Richard Felkl55d1f572017-02-15 16:41:53 +0100207 if flavor in existing_flavors:
Ondrej Smolab7b0dda2017-02-28 14:36:46 +0100208 flavor_id = existing_flavors[flavor]['id']
Richard Felkl55d1f572017-02-15 16:41:53 +0100209 else:
210 return {'name': name,
211 'changes': {},
212 'result': False,
213 'comment': 'Flavor "{0}" doesn\'t exists'.format(flavor)}
214
Adam Tenglere8afccc2017-06-27 17:57:21 +0000215 existing_image = __salt__['novang.image_list'](image, profile)
Richard Felkl55d1f572017-02-15 16:41:53 +0100216 if not existing_image:
217 return {'name': name,
218 'changes': {},
219 'result': False,
220 'comment': 'Image "{0}" doesn\'t exists'.format(image)}
221 else:
222 image_id = existing_image.get(image).get('id')
223 if security_groups is not None:
224 kwargs['security_groups'] = []
225 for secgroup in security_groups:
226 existing_secgroups = __salt__['novang.secgroup_list'](profile, tenant_name)
227 if not secgroup in existing_secgroups:
228 return {'name': name,
229 'changes': {},
230 'result': False,
231 'comment': 'Security group "{0}" doesn\'t exists'.format(secgroup)}
232 else:
233 kwargs['security_groups'].append(secgroup)
234 for net in networks:
235 existing_network = __salt__['novang.network_show'](net.get('name'), profile)
236 if not existing_network:
237 return {'name': name,
238 'changes': {},
239 'result': False,
240 'comment': 'Network "{0}" doesn\'t exists'.format(net.get(name))}
241 else:
242 network_id = existing_network.get('id')
243 if net.get('v4_fixed_ip') is not None:
244 nics.append({'net-id': network_id, 'v4-fixed-ip': net.get('v4_fixed_ip')})
245 else:
246 nics.append({'net-id': network_id})
247 kwargs['nics'] = nics
248 new_instance_id = __salt__['novang.boot'] (name, flavor_id, image_id, profile, tenant_name, **kwargs)
249 return {'name': name,
250 'changes': {},
251 'result': True,
252 'comment': 'Instance "{0}" was successfuly created'.format(name)}
Jiri Broulik70d9e3f2017-02-15 18:37:13 +0100253
254def _already_exists(name, resource):
255 changes_dict = {'name': name,
256 'changes': {},
257 'result': True}
258 changes_dict['comment'] = \
259 '{0} {1} already exists'.format(resource, name)
260 return changes_dict
261
262
263def _created(name, resource, resource_definition):
264 changes_dict = {'name': name,
265 'changes': resource_definition,
266 'result': True,
267 'comment': '{0} {1} created'.format(resource, name)}
268 return changes_dict
269
270def _updated(name, resource, resource_definition):
271 changes_dict = {'name': name,
272 'changes': resource_definition,
273 'result': True,
274 'comment': '{0} {1} tenant was updated'.format(resource, name)}
275 return changes_dict
276
277def _update_failed(name, resource):
278 changes_dict = {'name': name,
279 'changes': {},
280 'comment': '{0} {1} failed to update'.format(resource, name),
281 'result': False}
282 return changes_dict
283
284def _no_change(name, resource, test=False):
285 changes_dict = {'name': name,
286 'changes': {},
287 'result': True}
288 if test:
289 changes_dict['comment'] = \
290 '{0} {1} will be {2}'.format(resource, name, test)
291 else:
292 changes_dict['comment'] = \
293 '{0} {1} is in correct state'.format(resource, name)
Damian Szeluga5dca0f02017-04-13 17:27:15 +0200294 return changes_dict
Adam Tenglere8afccc2017-06-27 17:57:21 +0000295