
In the script when updating the CentOs partition to Debian occurs a mismatch with multipath paths. This fix is specific to upgrade multipath systems Test Plan: PASS: Upgrade AIO-SX with multipath PASS: Upgrade AIO-DX with multipath PASS: Upgrade AIO-SX without multipath PASS: Upgrade AIO-DX without multipath Closes-bug: 2007690 Change-Id: I833381a7dfdc89327e271d3772ee90012383cb95 Signed-off-by: Lucas Borges <lucas.borges@windriver.com>
614 lines
23 KiB
Python
Executable File
614 lines
23 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright (c) 2022 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
# This is a data migration script to pickup the partition changes during
|
|
# upgrade to Debian OS.
|
|
# The migration refreshes the partition, i_pv and i_lvg tables
|
|
# with the new partition configuration on filessytem of Debian StarlingX
|
|
# after controller-1 is upgraded.
|
|
#
|
|
import copy
|
|
import sys
|
|
import psycopg2
|
|
from controllerconfig.common import log
|
|
from datetime import datetime
|
|
import operator
|
|
from psycopg2.extras import DictCursor
|
|
import uuid
|
|
|
|
from sysinv.common import constants
|
|
from sysinv.common import utils as cutils
|
|
from sysinv.agent import partition as Partition
|
|
|
|
LOG = log.get_logger(__name__)
|
|
|
|
# set partition end_mib to END_OF_DISK_MIB to indicate
|
|
# that the partition will take all the remaining disk spaces
|
|
END_OF_DISK_MIB = "-1"
|
|
ONE_GIB = 1024 * 1024 * 1024
|
|
|
|
|
|
def main():
|
|
action = None
|
|
from_release = None
|
|
to_release = None
|
|
arg = 1
|
|
|
|
while arg < len(sys.argv):
|
|
if arg == 1:
|
|
from_release = sys.argv[arg]
|
|
elif arg == 2:
|
|
to_release = sys.argv[arg]
|
|
elif arg == 3:
|
|
action = sys.argv[arg]
|
|
else:
|
|
print("Invalid option %s." % sys.argv[arg])
|
|
return 1
|
|
arg += 1
|
|
|
|
log.configure()
|
|
LOG.info("%s invoked from_release = %s to_release = %s action = %s"
|
|
% (sys.argv[0], from_release, to_release, action))
|
|
res = 0
|
|
if action == "migrate" and (from_release in ['22.06', '21.12'] and
|
|
to_release == '22.12'):
|
|
try:
|
|
res = do_update()
|
|
except Exception:
|
|
LOG.exception("Remapping partition action failed")
|
|
res = 1
|
|
|
|
return res
|
|
|
|
|
|
IPARTITION_COLUMNS = 'created_at', 'updated_at', 'deleted_at', 'uuid', \
|
|
'start_mib', 'end_mib', 'size_mib', 'device_path', \
|
|
'type_guid', 'type_name', 'idisk_id', 'idisk_uuid', \
|
|
'capabilities', 'status', 'foripvid', 'forihostid', \
|
|
'device_node'
|
|
|
|
# worker node partition template
|
|
WORKER_PARTITION_LIST = [
|
|
{'start_mib': '1', 'end_mib': '2', 'size_mib': '1',
|
|
'type_guid': '21686148-6449-6e6f-744e-656564454649',
|
|
'type_name': 'BIOS boot partition'},
|
|
{'start_mib': '2', 'end_mib': '302', 'size_mib': '300',
|
|
'type_guid': 'c12a7328-f81f-11d2-ba4b-00a0c93ec93b',
|
|
'type_name': 'EFI system partition'},
|
|
{'start_mib': '302', 'end_mib': '2350', 'size_mib': '2048',
|
|
'type_guid': '0fc63daf-8483-4772-8e79-3d69d8477de4',
|
|
'type_name': 'Linux filesystem'},
|
|
{'start_mib': '2350', 'end_mib': END_OF_DISK_MIB, 'size_mib': '0',
|
|
'type_guid': 'e6d6d379-f507-44c2-a23c-238f2a3df928',
|
|
'type_name': 'Linux LVM'}]
|
|
|
|
|
|
def get_disk_uuid_mapping(conn, forihostid):
|
|
# return map of idisk uuid indexed by device_node
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
sql = "SELECT uuid, device_node FROM i_idisk WHERE forihostid = %s;"
|
|
cur.execute(sql, (forihostid, ))
|
|
vals = cur.fetchall()
|
|
mappings = {}
|
|
for val in vals:
|
|
pair = {val["device_node"]: val["uuid"]}
|
|
mappings.update(pair)
|
|
return mappings
|
|
|
|
|
|
def get_idisks(conn, forihostid):
|
|
# do not consider disk change (replace, remove, or add new disk)
|
|
# during upgrade
|
|
sql = "SELECT * FROM i_idisk WHERE forihostid = %s;"
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
cur.execute(sql, (forihostid, ))
|
|
idisks = cur.fetchall()
|
|
return idisks
|
|
|
|
|
|
def get_cur_host(conn):
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
cur.execute("SELECT system_mode FROM i_system;")
|
|
system = cur.fetchone()
|
|
upgrade_controller = "controller-1"
|
|
if system["system_mode"] == "simplex":
|
|
upgrade_controller = "controller-0"
|
|
|
|
cur.execute("SELECT id, boot_device FROM i_host WHERE hostname = %s;",
|
|
(upgrade_controller,))
|
|
instance = cur.fetchone()
|
|
if instance is None:
|
|
raise Exception("Failed to retrieve host id for %s" %
|
|
upgrade_controller)
|
|
return instance
|
|
|
|
|
|
def get_disk_by_device_node(disks, device_path):
|
|
for disk in disks:
|
|
if disk["device_path"] in device_path:
|
|
return disk
|
|
elif constants.DEVICE_NAME_MPATH in disk["device_node"]:
|
|
path_split = disk["device_node"].split(constants.DEVICE_NAME_MPATH)
|
|
if path_split[0] in device_path and path_split[1] in device_path:
|
|
return disk
|
|
|
|
raise Exception("Cannot locate the disk for %s" % device_path)
|
|
|
|
|
|
def get_rootdisk_partitions(conn, forihostid):
|
|
# get partitions on root disk of N release configuration
|
|
# the corresponding vg name is ammended to the end of each partition.
|
|
col_fmt = "p." + ", p.".join(IPARTITION_COLUMNS)
|
|
sql_fmt = "select %s, pv.lvm_vg_name " \
|
|
"from partition as p left join i_pv pv on pv.id = foripvid " \
|
|
"where idisk_uuid in" \
|
|
" (select d.uuid from i_host join i_idisk d on" \
|
|
" d.device_node = boot_device or" \
|
|
" d.device_path = boot_device" \
|
|
" where d.forihostid = %%s and i_host.id = %%s) " \
|
|
"order by start_mib;" % col_fmt
|
|
sql = sql_fmt % (forihostid, forihostid)
|
|
partitions = []
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
cur.execute(sql, (forihostid, forihostid))
|
|
partitions = cur.fetchall()
|
|
return partitions
|
|
|
|
|
|
def get_controller_partition_template(rootdisk):
|
|
# return list of partitions created on rootdisk, sorted by physical
|
|
# order (start_mib)
|
|
|
|
root_device_path = rootdisk["device_path"]
|
|
root_device_node = rootdisk["device_node"]
|
|
po = Partition.PartitionOperator()
|
|
partitions = po.ipartition_get(skip_gpt_check=True)
|
|
|
|
# sort by start_mib
|
|
now = datetime.now()
|
|
|
|
partition_additions = {
|
|
"created_at": now,
|
|
"updated_at": now,
|
|
"deleted_at": None,
|
|
# foripvid will be populated when updating i_pv table
|
|
"foripvid": None,
|
|
# TODO: check to load capabilities
|
|
"capabilities": None,
|
|
# These are the partitions that have already created
|
|
"status": 1
|
|
}
|
|
|
|
bootdisk_partitions = []
|
|
for partition in partitions:
|
|
partition.update(partition_additions)
|
|
part_device_path = partition["device_path"]
|
|
if is_device_path_on_disk(part_device_path, root_device_path,
|
|
root_device_node):
|
|
partition["device_path"] = None
|
|
partition["device_node"] = None
|
|
bootdisk_partitions.append(partition)
|
|
sorted_list = sorted(bootdisk_partitions,
|
|
key=operator.itemgetter('start_mib'))
|
|
|
|
# the last partition takes all the rest of disk spaces
|
|
sorted_list[-1]["end_mib"] = END_OF_DISK_MIB
|
|
return sorted_list
|
|
|
|
|
|
def get_node_partition_template(part_list):
|
|
# create a partition template from a list of partitions
|
|
template = copy.deepcopy(part_list)
|
|
|
|
now = datetime.now()
|
|
partition_additions = {
|
|
"created_at": now,
|
|
"updated_at": now,
|
|
"deleted_at": None,
|
|
# foripvid will be populated when updating i_pv table
|
|
"foripvid": None,
|
|
# TODO: check to load capabilities
|
|
"capabilities": None,
|
|
# These are the partitions that have already created
|
|
"status": 1,
|
|
"device_path": None,
|
|
"device_node": None
|
|
}
|
|
|
|
for partition in template:
|
|
partition.update(partition_additions)
|
|
|
|
return template
|
|
|
|
|
|
def get_ipartitions(forihostid, template, rootdisk):
|
|
# localize default partitions on rootdisk
|
|
partitions = copy.deepcopy(template)
|
|
|
|
rootdisk_device_node = rootdisk["device_node"]
|
|
rootdisk_device_path = rootdisk["device_path"]
|
|
idx = 1
|
|
for partition in partitions:
|
|
# regenerate uuid
|
|
partition["uuid"] = "%s" % uuid.uuid4()
|
|
partition["idisk_id"] = rootdisk["id"]
|
|
partition["idisk_uuid"] = rootdisk["uuid"]
|
|
partition["forihostid"] = forihostid
|
|
device_node, device_path = \
|
|
build_device_node_path(rootdisk_device_node, rootdisk_device_path,
|
|
idx)
|
|
partition["device_node"] = device_node
|
|
partition["device_path"] = device_path
|
|
if partition["end_mib"] == END_OF_DISK_MIB:
|
|
# get all the rest of disk spaces
|
|
end_mib = int(rootdisk["size_mib"]) + 1
|
|
partition["end_mib"] = str(end_mib)
|
|
partition["size_mib"] = str(end_mib - int(partition["start_mib"]))
|
|
idx += 1
|
|
|
|
return partitions
|
|
|
|
|
|
def build_device_node_path(disk_device_node, disk_device_path, device_idx):
|
|
"""Builds the partition device path and device node based on last
|
|
partition number and assigned disk.
|
|
"""
|
|
if constants.DEVICE_NAME_NVME in disk_device_node:
|
|
device_node = "%sp%s" % (disk_device_node, device_idx)
|
|
else:
|
|
device_node = "%s%s" % (disk_device_node, device_idx)
|
|
device_path = cutils.get_part_device_path(disk_device_path,
|
|
str(device_idx))
|
|
return device_node, device_path
|
|
|
|
|
|
def is_device_path_on_disk(device_path, disk_device_path, disk_device_node):
|
|
if disk_device_path in device_path:
|
|
return True
|
|
elif constants.DEVICE_NAME_MPATH in disk_device_node:
|
|
split_path = device_path.split("-part")
|
|
if split_path[0] in disk_device_path:
|
|
return True
|
|
return False
|
|
|
|
|
|
def append_additional_partitions(conn, new_rootdisk_partitions,
|
|
host, rootdisk):
|
|
# append user created partitions on rootdisk from the N release
|
|
# new_rootdisk_partitions is new default partitions on root disk
|
|
# will append additional user partitions on root disk to the list
|
|
# to form the entier partition list on root disk
|
|
|
|
forihostid = host["id"]
|
|
# get partitions on rootdisk from N db
|
|
rootdisk_partitions = get_rootdisk_partitions(conn, forihostid)
|
|
|
|
rootdisk_device_node = rootdisk["device_node"]
|
|
LOG.info("Previous release ipartitions on root disk %s \n%s" %
|
|
(rootdisk_device_node, rootdisk_partitions))
|
|
|
|
# find the last default partition in ordered list. All default
|
|
# partitions will be replaced with new default partitions.
|
|
for partition in rootdisk_partitions:
|
|
if partition["lvm_vg_name"] == "cgts-vg":
|
|
# found the 1st cgts-vg.
|
|
# cgts-vg in new load will replace the existing cgts-vg partition
|
|
# on the node as PV of cgts-vg
|
|
new_rootdisk_partitions[-1]["foripvid"] = partition["foripvid"]
|
|
break
|
|
else:
|
|
# a cgts-vg is not found on root disk... game over
|
|
raise Exception("cgts-vg partition is not found on rootdisk")
|
|
|
|
ipartitions = []
|
|
for partition in new_rootdisk_partitions:
|
|
ipartition = [partition[key] for key in IPARTITION_COLUMNS]
|
|
ipartitions.append(ipartition)
|
|
return ipartitions
|
|
|
|
|
|
def update_partition(conn, ipartitions, forihostid, rootdisk):
|
|
dp_idx = IPARTITION_COLUMNS.index("device_path")
|
|
partition_disk_uuid_idx = IPARTITION_COLUMNS.index("idisk_uuid")
|
|
rootdisk_uuid = rootdisk["uuid"]
|
|
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
# 1. delete all partitions on rootdisk
|
|
sql = "DELETE FROM partition where idisk_uuid = %s;"
|
|
LOG.info("Delete partition records on root disk: uuid(%s)" %
|
|
rootdisk_uuid)
|
|
cur.execute(sql, (rootdisk_uuid, ))
|
|
count = cur.rowcount
|
|
LOG.info("%s partition records are deleted" % count)
|
|
|
|
# 2. recreate records for the partitions on created root disk
|
|
LOG.info("recreate partition record on root disk %s" % rootdisk_uuid)
|
|
for ipartition in ipartitions:
|
|
if ipartition[partition_disk_uuid_idx] != rootdisk_uuid:
|
|
# skip non-rootdisk partitions
|
|
continue
|
|
|
|
device_path = ipartition[dp_idx]
|
|
col_fmt = ", ".join(["%s"] * len(IPARTITION_COLUMNS))
|
|
values_fmt = ", ".join(["%%s"] * len(IPARTITION_COLUMNS))
|
|
sql_fmt = "INSERT INTO partition (%s) VALUES(%s)" % \
|
|
(col_fmt, values_fmt)
|
|
sql = sql_fmt % IPARTITION_COLUMNS
|
|
cur.execute(sql, ipartition)
|
|
if cur.rowcount == 1:
|
|
LOG.info("Create new partition %s, %s" %
|
|
(device_path, ipartition[partition_disk_uuid_idx]))
|
|
|
|
LOG.info("Done recreate partitions on root disk")
|
|
|
|
sql = "SELECT id, uuid, device_node, device_path, foripvid " \
|
|
"FROM partition WHERE forihostid = %s"
|
|
cur.execute(sql, (forihostid, ))
|
|
partitions = [{"id": d[0], "uuid": d[1], "device_node": d[2],
|
|
"device_path": d[3], "foripvid": d[4],
|
|
"type": "partition"}
|
|
for d in cur.fetchall()]
|
|
return partitions
|
|
|
|
|
|
def update_pvs(conn, forihostid):
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
# partition records are pointing to i_pv, but the i_pv reference
|
|
# to partition uuid (disk_or_part_uuid) and device_node
|
|
# (disk_or_part_device_node) needs to relink.
|
|
# this is a double link
|
|
|
|
# update primary cgts-vg pv, this pv and partition have been
|
|
# provisioned
|
|
sql = "UPDATE i_pv " \
|
|
"SET disk_or_part_uuid = p.uuid, " \
|
|
"disk_or_part_device_node = p.device_node, " \
|
|
"disk_or_part_device_path = p.device_path, " \
|
|
"lvm_pv_name = p.device_node " \
|
|
"FROM i_pv AS v JOIN partition AS p ON p.foripvid = v.id " \
|
|
"WHERE v.forihostid = %s AND p.forihostid = %s AND" \
|
|
" i_pv.id = v.id AND p.status <> %s"
|
|
cur.execute(sql, (forihostid, forihostid,
|
|
constants.PARTITION_CREATE_ON_UNLOCK_STATUS))
|
|
LOG.info("Updated %s PVs" % cur.rowcount)
|
|
|
|
# Delete the PVs that link to user partition on boot disk.
|
|
# As the user partitions on boot disk are deleted during
|
|
# update_partition, the orphan partition PVs are to be deleted.
|
|
sql = "DELETE FROM i_pv " \
|
|
"WHERE pv_type = 'partition' AND forihostid = %s AND id NOT IN" \
|
|
" (SELECT foripvid FROM partition WHERE forihostid = %s AND " \
|
|
"foripvid IS NOT Null)"
|
|
cur.execute(sql, (forihostid, forihostid))
|
|
count = cur.rowcount
|
|
if count > 0:
|
|
LOG.info("Deleted %s PVs on user partition" % cur.rowcount)
|
|
|
|
sql = "SELECT id, uuid, lvm_pv_name, pv_type, pv_state, " \
|
|
"disk_or_part_uuid " \
|
|
"FROM i_pv WHERE forihostid = %s"
|
|
cur.execute(sql, (forihostid, ))
|
|
pvs = [{"id": d[0], "uuid": d[1], "lvm_pv_name": d[2], "pv_type":
|
|
d[3], "pv_state": d[4], "disk_or_part_uuid": d[5]}
|
|
for d in cur.fetchall()]
|
|
return pvs
|
|
|
|
|
|
def update_lvgs(conn, forihostid):
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
# delete the lvgs that don't have any PVs.
|
|
# PVs can be deleted in update_pvs when associated partition is
|
|
# deleted as root disk space is reallocated to cgts-vg.
|
|
# nova-local can be deleted if all nova-local PVs are partitions
|
|
# on root disk. In this case all partitions and PVs are deleted
|
|
# in update_partition and update_pvs.
|
|
sql = "DELETE FROM i_lvg " \
|
|
"WHERE forihostid = %s AND id NOT IN " \
|
|
"(SELECT forilvgid FROM i_pv WHERE forihostid = %s AND " \
|
|
"forilvgid IS NOT Null);"
|
|
cur.execute(sql, (forihostid, forihostid))
|
|
count = cur.rowcount
|
|
if count > 0:
|
|
LOG.info("Deleted %s unused lvg" % count)
|
|
|
|
# mark lvgs to be recreated during host unlock
|
|
sql = "UPDATE i_lvg SET vg_state = %s " \
|
|
"WHERE lvm_vg_name <> 'cgts-vg' AND forihostid = %s;"
|
|
cur.execute(sql, (constants.LVG_ADD, forihostid))
|
|
count = cur.rowcount
|
|
if count > 0:
|
|
LOG.info("%s lvg will be recreated" % count)
|
|
|
|
sql = "SELECT id, uuid, lvm_vg_name FROM i_lvg WHERE forihostid = %s"
|
|
cur.execute(sql, (forihostid, ))
|
|
lvgs = [{"id": d[0], "uuid": d[1], "lvm_vg_name": d[2]}
|
|
for d in cur.fetchall()]
|
|
return lvgs
|
|
|
|
|
|
def get_disk_or_partition(conn, hostid):
|
|
sql = "SELECT uuid, device_node, device_path, foripvid, 'disk' as type " \
|
|
"FROM i_idisk WHERE forihostid = %s UNION " \
|
|
"SELECT uuid, device_node, device_path, foripvid, " \
|
|
"'partition' as type FROM partition WHERE forihostid = %s;"
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
cur.execute(sql, (hostid, hostid))
|
|
dops = [{"uuid": d[0], "device_node": d[1], "device_path": d[2],
|
|
"foripvid": d[3], "type": d[4]}
|
|
for d in cur.fetchall()]
|
|
return dops
|
|
|
|
|
|
def get_rootdisk(conn, hostid, boot_device):
|
|
# return device_node and device_path of rootdisk
|
|
sql = "SELECT id, uuid, device_node, device_path, size_mib " \
|
|
"FROM i_idisk " \
|
|
"WHERE (device_node = %s OR device_path = %s) AND forihostid = %s"
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
cur.execute(sql, (boot_device, boot_device, hostid))
|
|
rootdisk = cur.fetchone()
|
|
return rootdisk
|
|
|
|
|
|
def get_hosts(conn):
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
cur.execute("SELECT id, hostname, personality, boot_device, "
|
|
"subfunctions "
|
|
"FROM i_host WHERE personality "
|
|
"IN ('controller', 'worker');")
|
|
nodes = cur.fetchall()
|
|
return nodes
|
|
|
|
|
|
def update_host(conn, host, partition_template):
|
|
hostid = host["id"]
|
|
hostname = host["hostname"]
|
|
|
|
rootdisk = get_rootdisk(conn, hostid, host["boot_device"])
|
|
ipartitions = get_ipartitions(hostid,
|
|
partition_template, rootdisk)
|
|
|
|
ipartitions = append_additional_partitions(conn, ipartitions,
|
|
host, rootdisk)
|
|
ipartitions = update_partition(conn, ipartitions, hostid, rootdisk)
|
|
|
|
pvs = update_pvs(conn, hostid)
|
|
lvgs = update_lvgs(conn, hostid)
|
|
|
|
LOG.info("partition migration summary %s:" % hostname)
|
|
LOG.info("=" * 60)
|
|
LOG.info("new list of lvgs:")
|
|
for lvg in lvgs:
|
|
LOG.info("%s" % lvg)
|
|
|
|
LOG.info("new list of pvs:")
|
|
for pv in pvs:
|
|
LOG.info("%s" % pv)
|
|
|
|
LOG.info("new list of partitions:")
|
|
for ip in ipartitions:
|
|
LOG.info(ip)
|
|
LOG.info("=" * 60)
|
|
|
|
|
|
def get_nova_local_pvs(conn, hostid):
|
|
sql = "SELECT pv_type, lvm_vg_name, lvm_pv_size, disk_or_part_uuid " \
|
|
"FROM i_pv WHERE forihostid = %s AND lvm_vg_name='nova-local';"
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
cur.execute(sql, (hostid,))
|
|
pvs = cur.fetchall()
|
|
return pvs
|
|
|
|
|
|
def create_instances_lv(conn, host, rootdisk_nova_local_size):
|
|
# size_gib is rounded up to nearest Gib
|
|
sql = "INSERT INTO host_fs" \
|
|
"(created_at, uuid, name, size, logical_volume, forihostid) " \
|
|
"VALUES(%s, %s, %s, %s, %s, %s);"
|
|
|
|
created_at = datetime.now()
|
|
fs_uuid = "%s" % uuid.uuid4()
|
|
name = constants.FILESYSTEM_NAME_INSTANCES
|
|
# round up
|
|
size_gib = int((rootdisk_nova_local_size + ONE_GIB - 1) / ONE_GIB)
|
|
lv_name = constants.FILESYSTEM_LV_DICT[name]
|
|
forihostid = host["id"]
|
|
|
|
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
cur.execute(sql, (created_at, fs_uuid, name, size_gib,
|
|
lv_name, forihostid))
|
|
if cur.rowcount == 1:
|
|
LOG.info("%s: created cgts-vg:%s %sGib" %
|
|
(host["hostname"], lv_name, size_gib))
|
|
|
|
|
|
def migrate_nova_local(conn, host, rootdisk):
|
|
# Migrate nova-local on boot disk
|
|
# This only needs to do on nodes with worker subfunction
|
|
# The migration rules:
|
|
# 1. if nova-local only exists on boot disk as a partition,
|
|
# the nova-local partition will be dropped, replaced with
|
|
# same size will be allocated to cgts-vg:instances-lv,
|
|
# 2. if nova-local only exists on separated disk, then no
|
|
# migration operation is needed
|
|
# 3. if nova-local exists on both boot disk partition and
|
|
# separated disk, nova-local partition on boot disk will
|
|
# be dropped, and with no other compensation. This will
|
|
# result total nova-local space reduced.
|
|
pvs = get_nova_local_pvs(conn, host["id"])
|
|
if len(pvs) > 0:
|
|
LOG.info("Found nova-local pvs on rootdisk: %s", pvs)
|
|
|
|
rootdisk_partitions = get_rootdisk_partitions(conn, host["id"])
|
|
rootdisk_part_uuids = [p["uuid"] for p in rootdisk_partitions]
|
|
|
|
rootdisk_nova_local_size = 0
|
|
pv_on_other_disk = False
|
|
for pv in pvs:
|
|
pv_type = pv["pv_type"]
|
|
dop_uuid = pv["disk_or_part_uuid"]
|
|
if (pv_type == "partition" and dop_uuid in rootdisk_part_uuids):
|
|
rootdisk_nova_local_size += int(pv["lvm_pv_size"])
|
|
else:
|
|
pv_on_other_disk = True
|
|
|
|
if rootdisk_nova_local_size > 0:
|
|
if not pv_on_other_disk:
|
|
create_instances_lv(conn, host, rootdisk_nova_local_size)
|
|
else:
|
|
msg = "Total nova-local is reduced by %s bytes"
|
|
LOG.info(msg % rootdisk_nova_local_size)
|
|
|
|
|
|
def do_update():
|
|
res = 0
|
|
conn = psycopg2.connect("dbname=sysinv user=postgres")
|
|
|
|
try:
|
|
cur_host = get_cur_host(conn)
|
|
rootdisk = get_rootdisk(conn, cur_host["id"], cur_host["boot_device"])
|
|
controller_partitions = get_controller_partition_template(rootdisk)
|
|
worker_partitions = get_node_partition_template(WORKER_PARTITION_LIST)
|
|
|
|
# migrate hosts with the partition template
|
|
hosts = get_hosts(conn)
|
|
for host in hosts:
|
|
personality = host["personality"]
|
|
|
|
if personality == constants.WORKER:
|
|
partition_template = worker_partitions
|
|
elif personality == constants.CONTROLLER:
|
|
partition_template = controller_partitions
|
|
else:
|
|
# nothing to migrate on storage node, as no user partitions
|
|
# are allowed on root disk
|
|
continue
|
|
|
|
if "worker" in host["subfunctions"]:
|
|
migrate_nova_local(conn, host, rootdisk)
|
|
update_host(conn, host, partition_template)
|
|
|
|
except psycopg2.Error as ex:
|
|
conn.rollback()
|
|
LOG.exception(ex)
|
|
LOG.warning("Rollback changes")
|
|
res = 1
|
|
except Exception as ex:
|
|
conn.rollback()
|
|
LOG.exception(ex)
|
|
LOG.warning("Rollback changes")
|
|
res = 1
|
|
else:
|
|
LOG.info("All good, committing all changes into database")
|
|
conn.commit()
|
|
finally:
|
|
conn.close()
|
|
|
|
return res
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|