healthnmon/healthnmon/db/sqlalchemy/vmhost_api.py

444 lines
18 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy.orm import joinedload, joinedload_all
from sqlalchemy import and_, or_
from sqlalchemy.sql.expression import asc
from sqlalchemy.sql.expression import desc
from healthnmon.resourcemodel.healthnmonResourceModel import VmHost, \
Vm, StorageVolume, HostMountPoint, VirtualSwitch, PortGroup, \
Subnet
from healthnmon.db.sqlalchemy.mapper import VirtualSwitchSubnetIds
from nova.openstack.common.db.sqlalchemy import session as nova_session
from nova.db.sqlalchemy import api as context_api
from healthnmon import log as logging
from healthnmon import constants
from healthnmon.utils import get_current_epoch_ms
from healthnmon.db.sqlalchemy.util import _create_filtered_ordered_query, \
__save_and_expunge, __cleanup_session
from healthnmon.db.sqlalchemy import virtualswitch_api, vm_api,\
storagevolume_api
LOG = logging.getLogger(__name__)
def _get_deleted_vSwitches(inv_switch_id_list, db_Switches, epoch_time):
to_be_deleted_switches = []
for old_switch in db_Switches:
if old_switch.get_id() not in inv_switch_id_list:
old_switch.set_deletedEpoch(epoch_time)
old_switch.set_deleted(True)
to_be_deleted_switches.append(old_switch)
return to_be_deleted_switches
def _get_deleted_portgroups(inv_pgroup_id_list, db_pgroups,
epoch_time, res_id):
to_be_deleted_pgroups = []
for old_pgroup in db_pgroups:
if old_pgroup.get_id() not in inv_pgroup_id_list:
if res_id == old_pgroup.get_virtualSwitchId():
old_pgroup.set_deletedEpoch(epoch_time)
old_pgroup.set_deleted(True)
to_be_deleted_pgroups.append(old_pgroup)
return to_be_deleted_pgroups
def __vm_host_set_virtualMachineIds(vmhosts, vmIdsRes):
vmIdDict = {}
for row in vmIdsRes:
hostId = row[0]
vmId = row[1]
if hostId not in vmIdDict:
vmIdDict[hostId] = []
vmIdDict[hostId].append(vmId)
for vmhost in vmhosts:
if vmhost.get_id() in vmIdDict:
vmhost.set_virtualMachineIds(vmIdDict.get(vmhost.get_id()))
def __vm_host_set_storageVolumeIds(vmhosts, volIdsRes):
volIdDict = {}
for row in volIdsRes:
hostId = row[0]
volId = row[1]
if hostId not in volIdDict:
volIdDict[hostId] = []
volIdDict[hostId].append(volId)
for vmhost in vmhosts:
if vmhost.get_id() in volIdDict:
vmhost.set_storageVolumeIds(volIdDict.get(vmhost.get_id()))
def vm_host_save(context, vmhost):
"""This API will create or update a VmHost object and its
associations to DB. For the update to be working the VMHost
object should have been one returned by DB API. Else it will
be considered as a insert.
Parameters:
vmhost - VmHost type object to be saved
context - nova.context.RequestContext object
"""
if vmhost is None:
return
session = None
try:
session = nova_session.get_session()
epoch_time = get_current_epoch_ms()
vmhosts = vm_host_get_by_ids(context, [vmhost.id])
deleted_host_portgroups = []
if vmhosts:
vmhost.set_createEpoch(vmhosts[0].get_createEpoch())
vmhost.set_lastModifiedEpoch(epoch_time)
existingVSwitches = vmhosts[0].get_virtualSwitches()
"Dict to store switch epoch against switchid"
switchDict_Epoch = {}
for existingVSwitch in existingVSwitches:
switchDict_Epoch[existingVSwitch.get_id()] = \
existingVSwitch.get_createEpoch()
existing_host_portgroups = vmhosts[0].get_portGroups()
pGroupDict = {}
for existingPortGroup in existing_host_portgroups:
pGroupDict[existingPortGroup.get_id()] = \
existingPortGroup.get_createEpoch()
vSwitches = vmhost.get_virtualSwitches()
newSwitchList = []
existing_switch_PortGroups = []
for vSwitch in vSwitches:
switchId = vSwitch.get_id()
db_switch = \
virtualswitch_api.virtual_switch_get_by_ids(context,
[switchId])
if len(db_switch) > 0:
existing_switch_PortGroups = db_switch[0].get_portGroups()
newSwitchList.append(switchId)
if switchId in switchDict_Epoch:
vSwitch.set_createEpoch(switchDict_Epoch[switchId])
vSwitch.set_lastModifiedEpoch(epoch_time)
else:
vSwitch.set_createEpoch(epoch_time)
vs_portGroups = vSwitch.get_portGroups()
vs_newportgroupList = []
for vs_portGroup in vs_portGroups:
portId = vs_portGroup.get_id()
vs_newportgroupList.append(portId)
vs_portGroup.set_virtualSwitchId(switchId)
if portId in pGroupDict:
vs_portGroup.set_createEpoch(pGroupDict[portId])
vs_portGroup.set_lastModifiedEpoch(epoch_time)
else:
vs_portGroup.set_createEpoch(epoch_time)
# Get the deleted port groups and set the deleted flag as true
# and deletedEpoch value."
deleted_portgroups = _get_deleted_portgroups(
vs_newportgroupList,
existing_switch_PortGroups,
epoch_time, switchId)
for deleted_portgroup in deleted_portgroups:
vSwitch.add_portGroups(deleted_portgroup)
deleted_host_portgroups.append(deleted_portgroup)
# Get the deleted virtual switches and set the deleted
# flag as true and deletedEpoch value."
deleted_switches = _get_deleted_vSwitches(newSwitchList,
existingVSwitches,
epoch_time)
for deleted_switch in deleted_switches:
deleted_pgs = deleted_switch.get_portGroups()
for deleted_pg in deleted_pgs:
deleted_pg.deleted = True
deleted_pg.set_deletedEpoch(epoch_time)
deleted_host_portgroups.append(deleted_pg)
vmhost.add_virtualSwitches(deleted_switch)
portGroups = vmhost.get_portGroups()
newportgroupList = []
for portGroup in portGroups:
portId = portGroup.get_id()
newportgroupList.append(portId)
if portId in pGroupDict:
portGroup.set_createEpoch(pGroupDict[portId])
portGroup.set_lastModifiedEpoch(epoch_time)
else:
portGroup.set_createEpoch(epoch_time)
# Add the deleted port groups which was appended
# during virtualswitch."
for deleted_pg in deleted_host_portgroups:
vmhost.add_portGroups(deleted_pg)
else:
vmhost.set_createEpoch(epoch_time)
# Add the createEpcoh to the added virtualSwitches
vSwitches = vmhost.get_virtualSwitches()
for vSwitch in vSwitches:
vSwitch.set_createEpoch(epoch_time)
# Add the createEpcoh to the added portGroups
portGroups = vmhost.get_portGroups()
for portGroup in portGroups:
portGroup.set_createEpoch(epoch_time)
__save_and_expunge(session, vmhost)
except Exception:
LOG.exception(_('error while adding vmhost'))
raise
finally:
__cleanup_session(session)
def vm_host_get_by_ids(context, ids):
"""This API will return a list of VmHost objects which corresponds to ids
Parameters:
ids - List of VmHost ids
context - nova.context.RequestContext object
"""
if ids is None:
return
session = None
try:
session = nova_session.get_session()
vmhosts = session.query(VmHost).filter(
and_(VmHost.id.in_(ids),
or_(VmHost.deleted == False,
VmHost.deleted == None))).\
options(joinedload('cost')).\
options(joinedload('os')).\
options(joinedload_all('virtualSwitches.portGroups.cost')).\
options(joinedload_all('portGroups.cost')).\
options(joinedload('ipAddresses')).\
options(joinedload_all('virtualSwitches.subnets')).\
options(joinedload_all('virtualSwitches.networks')).\
options(joinedload_all('virtualSwitches.cost')).\
all()
# Populate virtualMachineIds
vmIdsRes = session.query(Vm.vmHostId, Vm.id).\
filter(Vm.vmHostId.in_(ids)).\
filter(or_(Vm.deleted == False, Vm.deleted == None)).\
all()
__vm_host_set_virtualMachineIds(vmhosts, vmIdsRes)
# Populate storageVolumeIds
volIdsRes = session.query(
HostMountPoint.vmHostId,
HostMountPoint.storageVolumeId).filter(
HostMountPoint.vmHostId.in_(ids)).all()
__vm_host_set_storageVolumeIds(vmhosts, volIdsRes)
return vmhosts
except Exception:
LOG.exception(_('error while obtaining host'))
raise Exception('VmHost_get_by_id exception')
finally:
__cleanup_session(session)
def vm_host_get_all(context):
"""This API will return a list of all the VmHost objects present in DB
Parameters:
context - nova.context.RequestContext object
"""
session = None
try:
session = nova_session.get_session()
vmhosts = session.query(VmHost).filter(
or_(VmHost.deleted == False, VmHost.deleted == None)).\
options(joinedload('cost')).\
options(joinedload('os')).\
options(joinedload_all('virtualSwitches.portGroups.cost')).\
options(joinedload_all('portGroups.cost')).\
options(joinedload('ipAddresses')).\
options(joinedload_all('virtualSwitches.subnets')).\
options(joinedload_all('virtualSwitches.networks')).\
options(joinedload_all('virtualSwitches.cost')).\
all()
# options(joinedload_all('localDisks.mountPoints')).\
# Populate virtualMachineIds
vmIdsRes = session.query(Vm.vmHostId, Vm.id).\
filter(or_(Vm.deleted == False, Vm.deleted == None)).all()
__vm_host_set_virtualMachineIds(vmhosts, vmIdsRes)
# Populate storageVolumeIds
volIdsRes = session.query(HostMountPoint.vmHostId,
HostMountPoint.storageVolumeId).all()
__vm_host_set_storageVolumeIds(vmhosts, volIdsRes)
return vmhosts
except Exception:
LOG.exception(_('error while obtaining hosts'))
raise Exception('VmHost_get_all exception')
finally:
__cleanup_session(session)
def vm_host_delete_by_ids(context, ids):
"""This API will delete VmHost objects which corresponds to ids
Parameters:
ids - List of VmHost ids
context - nova.context.RequestContext object
"""
if ids is None:
return
session = None
try:
session = nova_session.get_session()
vmhosts = vm_host_get_by_ids(context, ids)
delete_epoch_time = get_current_epoch_ms()
for host in vmhosts:
vmid_tuples = \
session.query(Vm.id).filter(
and_(Vm.vmHostId.in_(ids),
or_(Vm.deleted == False,
Vm.deleted == None))).all()
vmIds = []
for vmid_tuple in vmid_tuples:
vmid = vmid_tuple[0]
vmIds.append(vmid)
vm_api.vm_delete_by_ids(context, vmIds)
# StorageVolume deletion
# Loop thru each of the Storage Volumes and check
# whether it has this host attached to its mount point.
storageIds = host.get_storageVolumeIds()
storageObj = storagevolume_api.\
storage_volume_get_by_ids(context, storageIds)
for storage in storageObj:
mountPoints = storage.get_mountPoints()
# If this relation found then create a new list
# of mount points and
# add these to the storage
newMountPoints = []
for mountPoint in mountPoints:
hostId = mountPoint.get_vmHostId()
if host.id != hostId:
newMountPoints.append(mountPoint)
storage.set_mountPoints(newMountPoints)
__save_and_expunge(session, storage)
vSwitches = host.get_virtualSwitches()
for vSwitch in vSwitches:
portGroups = vSwitch.get_portGroups()
for portGroup in portGroups:
portGroup.set_deleted(True)
portGroup.set_deletedEpoch(delete_epoch_time)
vSwitch.set_deleted(True)
vSwitch.set_deletedEpoch(delete_epoch_time)
portGroups = host.get_portGroups()
for portGroup in portGroups:
portGroup.set_deleted(True)
portGroup.set_deletedEpoch(delete_epoch_time)
# Finally delete the host
host.set_deleted(True)
host.set_deletedEpoch(delete_epoch_time)
__save_and_expunge(session, host)
except Exception:
LOG.exception(_('error while deleting host'))
raise
finally:
__cleanup_session(session)
def _load_deleted_objects(session, vmhosts):
for host in vmhosts:
deleted_host_vs = session.query(VirtualSwitch).\
filter(and_(VirtualSwitch.deleted == True,
VirtualSwitch.vmHostId == host.get_id())).\
options(joinedload('cost')).\
options(joinedload('networks')).\
options(joinedload('subnets')).all()
deleted_host_pgs = []
for vsd in deleted_host_vs:
host.add_virtualSwitches(vsd)
for vs in host.get_virtualSwitches():
vs_id = vs.get_id()
deleted_vs_pg = session.query(PortGroup).\
filter(and_(PortGroup.deleted == True,
PortGroup.virtualSwitchId == vs_id)).\
options(joinedload('cost')).all()
for pg in deleted_vs_pg:
vs.add_portGroups(pg)
deleted_host_pgs.append(pg)
for deleted_host_pg in deleted_host_pgs:
host.add_portGroups(deleted_host_pg)
def vm_host_get_all_by_filters(context, filters, sort_key, sort_dir):
"""
Get all the vm_hosts that match all filters and sorted with sort_key.
Deleted rows will be returned by default,
unless there's a filter that says
otherwise
Arguments:
context - nova.context.RequestContext object
filters - dictionary of filters to be applied
keys should be fields of VmHost model
if value is simple value = filter is applied and
if value is list or tuple 'IN' filter is applied
eg : {'connectionState':'Connected',
'name':['n1', 'n2']} will filter as
connectionState = 'Connected' AND name in ('n1', 'n2')
sort_key - Column on which sorting is to be applied
sort_dir - asc for Ascending sort direction,
desc for descending sort direction
Returns:
list of vm_hosts that match all filters and sorted with sort_key
"""
session = None
deleted_val = None
# Make a copy of the filters dictionary to not effect caller's use of it.
if filters is not None and 'deleted' in filters:
vm_host_filters = filters.copy()
deleted_val = vm_host_filters.pop('deleted')
try:
session = nova_session.get_session()
filtered_query = _create_filtered_ordered_query(session,
VmHost,
filters=filters,
sort_key=sort_key,
sort_dir=sort_dir)
vmhosts = filtered_query.options(joinedload('cost')).\
options(joinedload('os')).\
options(joinedload_all('virtualSwitches.portGroups.cost')).\
options(joinedload_all('portGroups.cost')).\
options(joinedload('ipAddresses')).\
options(joinedload_all('virtualSwitches.subnets')).\
options(joinedload_all('virtualSwitches.networks')).\
options(joinedload_all('virtualSwitches.cost')).all()
# Populate virtualMachineIds
if deleted_val and deleted_val == 'true':
_load_deleted_objects(session, vmhosts)
vmIdsRes = session.query(
Vm.vmHostId, Vm.id).filter(Vm.deleted == True).all()
else:
vmIdsRes = session.query(
Vm.vmHostId, Vm.id).filter(or_(Vm.deleted == False,
Vm.deleted == None)).all()
__vm_host_set_virtualMachineIds(vmhosts, vmIdsRes)
# Populate storageVolumeIds
volIdsRes = session.query(HostMountPoint.vmHostId,
HostMountPoint.storageVolumeId).all()
__vm_host_set_storageVolumeIds(vmhosts, volIdsRes)
return vmhosts
except Exception:
LOG.exception(_('Error while obtaining hosts'))
raise
finally:
__cleanup_session(session)