1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright (c) 2012 NTT DOCOMO, INC.
4
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
5
# Copyright 2010 United States Government as represented by the
6
# Administrator of the National Aeronautics and Space Administration.
9
# Licensed under the Apache License, Version 2.0 (the "License"); you may
10
# not use this file except in compliance with the License. You may obtain
11
# a copy of the License at
13
# http://www.apache.org/licenses/LICENSE-2.0
15
# Unless required by applicable law or agreed to in writing, software
16
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18
# License for the specific language governing permissions and limitations
21
"""Implementation of SQLAlchemy backend."""
23
from sqlalchemy import and_
24
from sqlalchemy.exc import IntegrityError
25
from sqlalchemy import or_
26
from sqlalchemy.orm import joinedload
27
from sqlalchemy.orm import joinedload_all
28
from sqlalchemy.sql.expression import asc
29
from sqlalchemy.sql.expression import desc
30
from sqlalchemy.sql.expression import literal_column
31
from sqlalchemy.sql import func
33
from nova.db.sqlalchemy.api import is_user_context
34
from nova.db.sqlalchemy.api import require_admin_context
35
from nova import exception
36
from nova.openstack.common import log as logging
37
from nova.openstack.common import timeutils
38
from nova.virt.baremetal.db.sqlalchemy import models
39
from nova.virt.baremetal.db.sqlalchemy.session import get_session
41
LOG = logging.getLogger(__name__)
44
def model_query(context, *args, **kwargs):
45
"""Query helper that accounts for context's `read_deleted` field.
47
:param context: context to query under
48
:param session: if present, the session to use
49
:param read_deleted: if present, overrides context's read_deleted field.
50
:param project_only: if present and context is user-type, then restrict
51
query to match the context's project_id.
53
session = kwargs.get('session') or get_session()
54
read_deleted = kwargs.get('read_deleted') or context.read_deleted
55
project_only = kwargs.get('project_only')
57
query = session.query(*args)
59
if read_deleted == 'no':
60
query = query.filter_by(deleted=False)
61
elif read_deleted == 'yes':
62
pass # omit the filter to include deleted and active
63
elif read_deleted == 'only':
64
query = query.filter_by(deleted=True)
67
_("Unrecognized read_deleted value '%s'") % read_deleted)
69
if project_only and is_user_context(context):
70
query = query.filter_by(project_id=context.project_id)
75
def _save(ref, session=None):
77
session = get_session()
78
# We must not call ref.save() with session=None, otherwise NovaBase
79
# uses nova-db's session, which cannot access bm-db.
80
ref.save(session=session)
83
def _build_node_order_by(query):
84
query = query.order_by(asc(models.BareMetalNode.memory_mb))
85
query = query.order_by(asc(models.BareMetalNode.cpus))
86
query = query.order_by(asc(models.BareMetalNode.local_gb))
90
@require_admin_context
91
def bm_node_get_all(context, service_host=None):
92
query = model_query(context, models.BareMetalNode, read_deleted="no")
94
query = query.filter_by(service_host=service_host)
98
@require_admin_context
99
def bm_node_find_free(context, service_host=None,
100
cpus=None, memory_mb=None, local_gb=None):
101
query = model_query(context, models.BareMetalNode, read_deleted="no")
102
query = query.filter(models.BareMetalNode.instance_uuid == None)
104
query = query.filter_by(service_host=service_host)
106
query = query.filter(models.BareMetalNode.cpus >= cpus)
107
if memory_mb is not None:
108
query = query.filter(models.BareMetalNode.memory_mb >= memory_mb)
109
if local_gb is not None:
110
query = query.filter(models.BareMetalNode.local_gb >= local_gb)
111
query = _build_node_order_by(query)
115
@require_admin_context
116
def bm_node_get(context, bm_node_id):
117
result = model_query(context, models.BareMetalNode, read_deleted="no").\
118
filter_by(id=bm_node_id).\
123
@require_admin_context
124
def bm_node_get_by_instance_uuid(context, instance_uuid):
125
result = model_query(context, models.BareMetalNode, read_deleted="no").\
126
filter_by(instance_uuid=instance_uuid).\
131
@require_admin_context
132
def bm_node_create(context, values):
133
bm_node_ref = models.BareMetalNode()
134
bm_node_ref.update(values)
139
@require_admin_context
140
def bm_node_update(context, bm_node_id, values, ):
141
model_query(context, models.BareMetalNode, read_deleted="no").\
142
filter_by(id=bm_node_id).\
146
@require_admin_context
147
def bm_node_destroy(context, bm_node_id):
148
model_query(context, models.BareMetalNode).\
149
filter_by(id=bm_node_id).\
150
update({'deleted': True,
151
'deleted_at': timeutils.utcnow(),
152
'updated_at': literal_column('updated_at')})
155
@require_admin_context
156
def bm_pxe_ip_get_all(context, session=None):
157
query = model_query(context, models.BareMetalPxeIp, read_deleted="no")
161
@require_admin_context
162
def bm_pxe_ip_create(context, address, server_address):
163
ref = models.BareMetalPxeIp()
164
ref.address = address
165
ref.server_address = server_address
170
@require_admin_context
171
def bm_pxe_ip_create_direct(context, bm_pxe_ip):
172
ref = bm_pxe_ip_create(context,
173
address=bm_pxe_ip['address'],
174
server_address=bm_pxe_ip['server_address'])
178
@require_admin_context
179
def bm_pxe_ip_destroy(context, ip_id):
180
# Delete physically since it has unique columns
181
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
182
filter_by(id=ip_id).\
186
@require_admin_context
187
def bm_pxe_ip_destroy_by_address(context, address):
188
# Delete physically since it has unique columns
189
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
190
filter_by(address=address).\
194
@require_admin_context
195
def bm_pxe_ip_get(context, ip_id):
196
ref = model_query(context, models.BareMetalPxeIp, read_deleted="no").\
197
filter_by(id=ip_id).\
202
@require_admin_context
203
def bm_pxe_ip_get_by_bm_node_id(context, bm_node_id):
204
ref = model_query(context, models.BareMetalPxeIp, read_deleted="no").\
205
filter_by(bm_node_id=bm_node_id).\
210
@require_admin_context
211
def bm_pxe_ip_associate(context, bm_node_id):
212
session = get_session()
213
with session.begin():
214
# Check if the node really exists
215
node_ref = model_query(context, models.BareMetalNode,
216
read_deleted="no", session=session).\
217
filter_by(id=bm_node_id).\
220
raise exception.NovaException("bm_node %s not found" % bm_node_id)
221
# Check if the node already has a pxe_ip
222
ip_ref = model_query(context, models.BareMetalPxeIp,
223
read_deleted="no", session=session).\
224
filter_by(bm_node_id=bm_node_id).\
228
# with_lockmode('update') and filter_by(bm_node_id=None) will lock all
229
# records. It may cause a performance problem in high-concurrency
231
ip_ref = model_query(context, models.BareMetalPxeIp,
232
read_deleted="no", session=session).\
233
filter_by(bm_node_id=None).\
234
with_lockmode('update').\
237
raise exception.NovaException("free bm_pxe_ip not found")
238
ip_ref.bm_node_id = bm_node_id
243
@require_admin_context
244
def bm_pxe_ip_disassociate(context, bm_node_id):
245
model_query(context, models.BareMetalPxeIp, read_deleted="no").\
246
filter_by(bm_node_id=bm_node_id).\
247
update({'bm_node_id': None})
250
@require_admin_context
251
def bm_interface_get(context, if_id):
252
result = model_query(context, models.BareMetalInterface,
254
filter_by(id=if_id).\
259
def bm_interface_get_all(context):
260
query = model_query(context, models.BareMetalInterface,
265
@require_admin_context
266
def bm_interface_destroy(context, if_id):
267
# Delete physically since it has unique columns
268
model_query(context, models.BareMetalInterface, read_deleted="no").\
269
filter_by(id=if_id).\
273
@require_admin_context
274
def bm_interface_create(context, bm_node_id, address, datapath_id, port_no):
275
ref = models.BareMetalInterface()
276
ref.bm_node_id = bm_node_id
277
ref.address = address
278
ref.datapath_id = datapath_id
279
ref.port_no = port_no
284
@require_admin_context
285
def bm_interface_set_vif_uuid(context, if_id, vif_uuid):
286
session = get_session()
287
with session.begin():
288
ref = model_query(context, models.BareMetalInterface,
289
read_deleted="no", session=session).\
290
filter_by(id=if_id).\
291
with_lockmode('update').\
294
raise exception.NovaException('interface id=%s is not found' %
296
ref.vif_uuid = vif_uuid
300
except IntegrityError:
301
raise exception.NovaException('vif_uuid %s is already assigned' %
305
@require_admin_context
306
def bm_interface_get_by_vif_uuid(context, vif_uuid):
307
result = model_query(context, models.BareMetalInterface,
309
filter_by(vif_uuid=vif_uuid).\
314
@require_admin_context
315
def bm_interface_get_all_by_bm_node_id(context, bm_node_id):
316
result = model_query(context, models.BareMetalInterface,
318
filter_by(bm_node_id=bm_node_id).\
323
@require_admin_context
324
def bm_deployment_create(context, key, image_path, pxe_config_path, root_mb,
326
ref = models.BareMetalDeployment()
328
ref.image_path = image_path
329
ref.pxe_config_path = pxe_config_path
330
ref.root_mb = root_mb
331
ref.swap_mb = swap_mb
336
@require_admin_context
337
def bm_deployment_get(context, dep_id):
338
result = model_query(context, models.BareMetalDeployment,
340
filter_by(id=dep_id).\
345
@require_admin_context
346
def bm_deployment_destroy(context, dep_id):
347
model_query(context, models.BareMetalDeployment).\
348
filter_by(id=dep_id).\
349
update({'deleted': True,
350
'deleted_at': timeutils.utcnow(),
351
'updated_at': literal_column('updated_at')})