14
14
# under the License.
16
16
'''Implementation of SQLAlchemy backend.'''
17
from datetime import datetime
18
from datetime import timedelta
17
21
from sqlalchemy.orm.session import Session
23
from heat.openstack.common.gettextutils import _
19
25
from heat.common import crypt
20
26
from heat.common import exception
21
27
from heat.db.sqlalchemy import models
28
from heat.db.sqlalchemy.session import get_engine
22
29
from heat.db.sqlalchemy.session import get_session
39
def soft_delete_aware_query(context, *args, **kwargs):
40
"""Stack query helper that accounts for context's `show_deleted` field.
42
:param show_deleted: if present, overrides context's show_deleted field.
45
query = model_query(context, *args)
46
show_deleted = kwargs.get('show_deleted')
49
query = query.filter_by(deleted_at=None)
32
54
def _session(context):
33
55
return (context and context.session) or get_session()
46
def raw_template_get_all(context):
47
results = model_query(context, models.RawTemplate).all()
50
raise exception.NotFound('no raw templates were found')
55
68
def raw_template_create(context, values):
56
69
raw_template_ref = models.RawTemplate()
57
70
raw_template_ref.update(values)
147
def resource_exchange_stacks(context, resource_id1, resource_id2):
148
query = model_query(context, models.Resource)
149
session = query.session
152
res1 = query.get(resource_id1)
153
res2 = query.get(resource_id2)
155
res1.stack, res2.stack = res2.stack, res1.stack
160
def resource_data_delete(resource, key):
161
result = resource_data_get_by_key(resource.context, resource.id, key)
134
165
def resource_create(context, values):
135
166
resource_ref = models.Resource()
136
167
resource_ref.update(values)
152
183
def stack_get_by_name(context, stack_name, owner_id=None):
153
query = model_query(context, models.Stack).\
184
query = soft_delete_aware_query(context, models.Stack).\
154
185
filter_by(tenant=context.tenant_id).\
155
186
filter_by(name=stack_name).\
156
187
filter_by(owner_id=owner_id)
158
189
return query.first()
161
def stack_get(context, stack_id, admin=False):
192
def stack_get(context, stack_id, admin=False, show_deleted=False):
162
193
result = model_query(context, models.Stack).get(stack_id)
195
if result is None or result.deleted_at is not None and not show_deleted:
164
198
# If the admin flag is True, we allow retrieval of a specific
165
199
# stack without the tenant scoping
176
210
def stack_get_all(context):
177
results = model_query(context, models.Stack).\
211
results = soft_delete_aware_query(context, models.Stack).\
178
212
filter_by(owner_id=None).all()
182
216
def stack_get_all_by_tenant(context):
183
results = model_query(context, models.Stack).\
217
results = soft_delete_aware_query(context, models.Stack).\
184
218
filter_by(owner_id=None).\
185
219
filter_by(tenant=context.tenant_id).all()
205
239
stack.update(values)
206
240
stack.save(_session(context))
208
# When the raw_template ID changes, we delete the old template
209
# after storing the new template ID
210
if stack.raw_template_id != old_template_id:
211
session = Session.object_session(stack)
212
rt = raw_template_get(context, old_template_id)
217
243
def stack_delete(context, stack_id):
218
244
s = stack_get(context, stack_id)
241
259
def user_creds_create(context):
242
260
values = context.to_dict()
243
261
user_creds_ref = models.UserCreds()
244
user_creds_ref.update(values)
245
user_creds_ref.password = crypt.encrypt(values['password'])
246
user_creds_ref.aws_creds = crypt.encrypt(values['aws_creds'])
262
if values.get('trust_id'):
263
user_creds_ref.trust_id = crypt.encrypt(values.get('trust_id'))
264
user_creds_ref.trustor_user_id = values.get('trustor_user_id')
265
user_creds_ref.username = None
266
user_creds_ref.password = None
268
user_creds_ref.update(values)
269
user_creds_ref.password = crypt.encrypt(values['password'])
247
270
user_creds_ref.save(_session(context))
248
271
return user_creds_ref
254
277
# or it can be committed back to the DB in decrypted form
255
278
result = dict(db_result)
256
279
result['password'] = crypt.decrypt(result['password'])
257
result['aws_creds'] = crypt.decrypt(result['aws_creds'])
280
result['trust_id'] = crypt.decrypt(result['trust_id'])
267
290
def event_get_all(context):
268
results = model_query(context, models.Event).all()
291
stacks = soft_delete_aware_query(context, models.Stack)
292
stack_ids = [stack.id for stack in stacks]
293
results = model_query(context, models.Event).\
294
filter(models.Event.stack_id.in_(stack_ids)).all()
273
299
def event_get_all_by_tenant(context):
274
stacks = model_query(context, models.Stack).\
300
stacks = soft_delete_aware_query(context, models.Stack).\
275
301
filter_by(tenant=context.tenant_id).all()
277
303
for stack in stacks:
298
324
def watch_rule_get(context, watch_rule_id):
299
result = model_query(context, models.WatchRule).\
300
filter_by(id=watch_rule_id).first()
325
result = model_query(context, models.WatchRule).get(watch_rule_id)
376
401
session.delete(d)
405
def purge_deleted(age):
410
raise exception.Error(_("age should be an integer"))
412
raise exception.Error(_("age should be a positive integer"))
416
time_line = datetime.now() - timedelta(days=age)
417
engine = get_engine()
418
meta = sqlalchemy.MetaData()
421
stack = sqlalchemy.Table('stack', meta, autoload=True)
422
event = sqlalchemy.Table('event', meta, autoload=True)
423
raw_template = sqlalchemy.Table('raw_template', meta, autoload=True)
424
user_creds = sqlalchemy.Table('user_creds', meta, autoload=True)
426
stmt = sqlalchemy.select([stack.c.id,
427
stack.c.raw_template_id,
428
stack.c.user_creds_id]).\
429
where(stack.c.deleted_at < time_line)
430
deleted_stacks = engine.execute(stmt)
432
for s in deleted_stacks:
433
event_del = event.delete().where(event.c.stack_id == s[0])
434
engine.execute(event_del)
435
stack_del = stack.delete().where(stack.c.id == s[0])
436
engine.execute(stack_del)
437
raw_template_del = raw_template.delete().\
438
where(raw_template.c.id == s[1])
439
engine.execute(raw_template_del)
440
user_creds_del = user_creds.delete().where(user_creds.c.id == s[2])
441
engine.execute(user_creds_del)