Remove upgrade scripts

With the release of stx11 some scripts were deprecated and will
not be needed on future upgrades, for example, those who were
needed only from stx10 to stx11 upgrade.

PASS: Full major release deployment stx11 to stx12 in DX
PASS: Check upgrade time didn't increased.

Story: 2011357
Task: 53040

Change-Id: Ib33598355a1e98399786553b10b1da334aa56524
Signed-off-by: Luiz Eduardo Bonatti <LuizEduardo.Bonatti@windriver.com>
This commit is contained in:
Luiz Eduardo Bonatti
2025-11-03 16:05:39 -03:00
committed by Luis Eduardo Bonatti
parent 7850e395ff
commit 8277ce1e10
19 changed files with 4 additions and 2473 deletions
@@ -1,83 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script uses sysinv-conductor API to pin kubernetes control plane containerd images
# particularly kube-apiserver, kube-controller-manager, kube-scheduler on controller hosts.
#
# Note: This script is only required for 24.09 to 25.09 upgrade and should be removed afterwards.
import logging
import sys
from oslo_config import cfg
from oslo_context import context as mycontext
from six.moves import configparser
from software.utilities.utils import configure_logging
from sysinv.conductor import rpcapiproxy as conductor_rpcapi
LOG = logging.getLogger('main_logger')
CONF = cfg.CONF
SYSINV_CONFIG_FILE = '/etc/sysinv/sysinv.conf'
# As this script is only required for 24.09 to 25.09 release, we do not need to use kubernetes APIs
# to get current running version.
KUBE_VERSION = "v1.29.2"
def get_conductor_rpc_bind_ip():
ini_str = '[DEFAULT]\n' + open(SYSINV_CONFIG_FILE, 'r').read()
config_applied = configparser.RawConfigParser()
config_applied.read_string(ini_str)
conductor_bind_ip = None
if config_applied.has_option('DEFAULT', 'rpc_zeromq_conductor_bind_ip'):
conductor_bind_ip = \
config_applied.get('DEFAULT', 'rpc_zeromq_conductor_bind_ip')
return conductor_bind_ip
def pin_kubernetes_control_plane_images():
CONF.rpc_zeromq_conductor_bind_ip = get_conductor_rpc_bind_ip()
context = mycontext.get_admin_context()
rpcapi = conductor_rpcapi.ConductorAPI(topic=conductor_rpcapi.MANAGER_TOPIC)
rpcapi.pin_kubernetes_control_plane_images(context, KUBE_VERSION)
def main():
# Initialize variables
action = None
from_release = None
to_release = None
arg = 1
# Process command-line arguments
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]
arg += 1
configure_logging()
LOG.info(
"%s invoked from_release = %s invoked to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action)
)
try:
if action == "activate" and from_release == "24.09":
pin_kubernetes_control_plane_images()
else:
LOG.info("Nothing to do. Skipping pinning control plane images.")
except Exception as ex:
LOG.warning("Failed to pin kubernetes control-plane images. Ignoring... Error: [%s]" % (ex))
if __name__ == "__main__":
main()
sys.exit(0)
@@ -1,123 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script updates the out_of_tree_drivers service parameter
# name to backup_oot_drivers_24.09 from sysinv DB during upgrade
# from 24.09 to 25.09.
#
import logging
import sys
from packaging import version
import psycopg2
from software.utilities.utils import configure_logging
DEFAULT_POSTGRES_PORT = 5432
LOG = logging.getLogger('main_logger')
PARAM_NAME = "out_of_tree_drivers"
BACKUP_NAME = "backup_oot_drivers_24.09"
PARAM_SERVICE = "platform"
PARAM_SECTION = "kernel"
def main():
action = None
from_release = None
to_release = None
postgres_port = DEFAULT_POSTGRES_PORT
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]
elif arg == 4:
postgres_port = sys.argv[arg]
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
configure_logging()
LOG.info(
"%s invoked from_release=%s to_release=%s action=%s",
sys.argv[0], from_release, to_release, action
)
res = 0
to_release_version = version.Version(to_release)
target_version = version.Version("25.09")
# Only remove service param on migrate to 25.09
if action == 'migrate' and to_release_version == target_version:
try:
conn = psycopg2.connect(
"dbname=sysinv user=postgres port=%s" % postgres_port
)
update_service_param(conn)
conn.close()
except Exception as e:
LOG.exception("Error removing service parameter: %s", e)
res = 1
return res
def update_service_param(conn):
"""Update out_of_tree_drivers service parameter to backup_oot_drivers
and ensure any old backup is cleaned up first.
"""
# Delete any existing backup entry to avoid stale values
cleanup_query = (
"DELETE FROM service_parameter "
"WHERE name='%s' AND service='%s' AND section='%s';"
% (BACKUP_NAME, PARAM_SERVICE, PARAM_SECTION)
)
db_update(conn, cleanup_query)
LOG.info("Cleaned up any existing '%s' backup entry.", BACKUP_NAME)
# Update the original parameter to backup_oot_drivers_24.09
update_query = (
"UPDATE service_parameter "
"SET name='%s' "
"WHERE name='%s' AND service='%s' AND section='%s';"
% (BACKUP_NAME, PARAM_NAME, PARAM_SERVICE, PARAM_SECTION)
)
db_update(conn, update_query)
LOG.info(
"Updated service parameter '%s' to '%s' successfully.",
PARAM_NAME, BACKUP_NAME
)
def db_query(conn, query):
"""Execute a read-only query and return results."""
result = []
with conn.cursor() as cur:
cur.execute(query)
for rec in cur:
result.append(rec)
return result
def db_update(conn, query):
"""Execute a write query and commit changes."""
with conn.cursor() as cur:
cur.execute(query)
conn.commit()
if __name__ == "__main__":
try:
sys.exit(main())
except Exception as e:
LOG.error("An error occurred: %s", e)
raise
@@ -1,174 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script updates the node IP addresses in sysinv DB tables. Only network
# entries with node addresses and only AIO-SX systems will be updated with the
# following actions:
# - address_pools: update controller0_address_id and controller1_address_id
# to None
# - addresses: update floating address IPv4 and IPv6 entries' interface_id
# with controller-0's entries' interface_id
# - addresses: delete IPv4 and IPv6 controller-0 and controller-1 entries'
# interface_id
#
import logging
import sys
from packaging import version
import psycopg2
from six.moves import configparser
from software.utilities.utils import configure_logging
DEFAULT_POSTGRES_PORT = 5432
LOG = logging.getLogger('main_logger')
def main():
action = None
from_release = None
to_release = None
postgres_port = DEFAULT_POSTGRES_PORT
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]
elif arg == 4:
postgres_port = sys.argv[arg]
pass
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
configure_logging()
LOG.info(
"%s invoked from_release = %s to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action)
)
res = 0
to_release_version = version.Version(to_release)
target_version = version.Version("25.09")
if get_system_mode() == "simplex":
if action == 'migrate' and to_release_version == target_version:
try:
conn = psycopg2.connect("dbname=sysinv user=postgres port=%s"
% postgres_port)
del_node_addresses(conn)
conn.close()
except Exception as e:
LOG.exception("Error: {}".format(e))
res = 1
return res
def del_node_addresses(conn):
net_types = (
'mgmt',
'admin',
'cluster-host',
'storage',
'pxeboot',
)
for net_type in net_types:
del_node_addresses_from_db(conn, net_type)
def del_node_addresses_from_db(conn, net_type):
query = (
"SELECT address_pools.id,controller0_address_id,controller1_address_id"
",floating_address_id "
"FROM address_pools "
"JOIN network_addresspools ON address_pools.id "
"= network_addresspools.address_pool_id "
"JOIN networks ON network_addresspools.network_id = networks.id "
f"WHERE networks.type = '{net_type}';"
)
res1 = db_query(conn, query)
LOG.info("%s: Number of address_pools entries found: %s" % (net_type, len(res1)))
controller0_ids = ",".join([str(e[1]) for e in res1 if e[1]])
if not controller0_ids:
LOG.info("Nothing to change")
return
query = (
"SELECT interface_id "
"FROM addresses "
"WHERE id IN (%s);" % controller0_ids
)
res2 = db_query(conn, query)
c0_interface_ids = tuple([e[0] for e in res2])
LOG.info("%s: interface_id found in addresses: %s" % (net_type, (c0_interface_ids,)))
idx = 0
for entry in res1:
address_pools_id = entry[0]
node_ids = entry[1:3]
floating_id = entry[3]
LOG.info("%s: Found controller-0 and controller-1 IDs = %s"
% (net_type, (node_ids,)))
query = (
"UPDATE address_pools "
"SET controller0_address_id = NULL, controller1_address_id = NULL "
"WHERE id = %s;" % address_pools_id
)
db_update(conn, query)
if c0_interface_ids[idx] is None:
LOG.info("Skipping update with no c0_interface_id")
else:
query = (
"UPDATE addresses "
"SET interface_id = %s "
"WHERE id = %s;" % (c0_interface_ids[idx], floating_id)
)
db_update(conn, query)
query = (
"DELETE FROM addresses "
"WHERE id IN %s;" % (node_ids,)
)
db_update(conn, query)
idx += 1
LOG.info("%s: node addresses deleted from address_pools and addresses tables "
"with success" % net_type)
def db_query(conn, query):
result = []
with conn.cursor() as cur:
cur.execute(query)
for rec in cur:
result.append(rec)
return result
def db_update(conn, query):
with conn.cursor() as cur:
cur.execute(query)
conn.commit()
def get_system_mode():
ini_str = '[DEFAULT]\n' + open('/etc/platform/platform.conf', 'r').read()
config_applied = configparser.RawConfigParser()
config_applied.read_string(ini_str)
if config_applied.has_option('DEFAULT', 'system_mode'):
system_mode = config_applied.get('DEFAULT', 'system_mode')
else:
system_mode = None
return system_mode
if __name__ == "__main__":
sys.exit(main())
@@ -1,90 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script will remove load, host_upgrade and software_upgrade
# database table
#
import logging
import sys
from packaging import version
import psycopg2
from software.utilities.utils import configure_logging
DEFAULT_POSTGRES_PORT = 5432
LOG = logging.getLogger('main_logger')
def main():
action = None
from_release = None
to_release = None
postgres_port = DEFAULT_POSTGRES_PORT
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]
elif arg == 4:
postgres_port = sys.argv[arg]
pass
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
configure_logging()
LOG.info(
"%s invoked from_release = %s to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action)
)
res = 0
to_release_version = version.Version(to_release)
minimum_version = version.Version("25.09")
if action == 'migrate' and to_release_version == minimum_version:
try:
conn = psycopg2.connect("dbname=sysinv user=postgres port=%s"
% postgres_port)
delete_software_upgrade_database(conn)
delete_host_upgrade_database(conn)
delete_load_database(conn)
conn.close()
except Exception as e:
LOG.exception("Error: {}".format(e))
res = 1
return res
def delete_load_database(conn):
delete_cmd = "drop table if exists loads;"
db_update(conn, delete_cmd)
LOG.info("Loads table removed with success")
def delete_host_upgrade_database(conn):
delete_cmd = "drop table if exists host_upgrade;"
db_update(conn, delete_cmd)
LOG.info("Host_upgrade table removed with success")
def delete_software_upgrade_database(conn):
delete_cmd = "drop table if exists software_upgrade;"
db_update(conn, delete_cmd)
LOG.info("Software_upgrade table removed with success")
def db_update(conn, query):
with conn.cursor() as cur:
cur.execute(query)
conn.commit()
if __name__ == "__main__":
sys.exit(main())
@@ -1,147 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script deletes the backup_oot_drivers service parameter
# from the sysinv DB when invoked with action=delete.
#
import logging as LOG
import sys
import re
import configparser
import psycopg2
DEFAULT_POSTGRES_PORT = 5432
DB_NAME = "sysinv"
DB_HOST = "localhost"
BACKUP_NAME = "backup_oot_drivers_24.09"
PARAM_SERVICE = "platform"
PARAM_SECTION = "kernel"
LOG.basicConfig(
filename="/var/log/software.log",
format='%(asctime)s: [%(process)s]: %(filename)s(%(lineno)s): '
'%(levelname)s: %(message)s',
level=LOG.INFO,
datefmt="%FT%T"
)
def get_db_credentials():
"""Retrieve DB credentials from sysinv.conf"""
try:
config = configparser.ConfigParser()
config.read("/etc/sysinv/sysinv.conf")
conn_string = config["database"]["connection"]
match = re.match(r"postgresql\+psycopg2://([^:]+):([^@]+)@", conn_string)
if match:
username = match.group(1)
password = match.group(2)
return username, password
else:
raise Exception("Failed to parse DB credentials from sysinv.conf")
except Exception as e:
LOG.error(f"Error getting DB credentials: {e}")
sys.exit(1)
def connect_to_db(port):
"""Establish DB connection"""
username, password = get_db_credentials()
try:
conn = psycopg2.connect(
dbname=DB_NAME,
user=username,
password=password,
host=DB_HOST,
port=port,
)
return conn
except Exception as e:
LOG.error(f"Database connection failed: {e}")
sys.exit(1)
def db_query(conn, query, params=()):
"""Execute SELECT query and return results"""
with conn.cursor() as cur:
cur.execute(query, params)
return cur.fetchall()
def db_update(conn, query, params=(), autocommit=True):
"""Execute UPDATE/DELETE query"""
with conn.cursor() as cur:
cur.execute(query, params)
if autocommit:
conn.commit()
def del_backup_param(conn):
"""Delete backup_oot_drivers_24.09 service parameter from sysinv DB."""
delete_query = (
"DELETE FROM service_parameter "
"WHERE name=%s AND service=%s AND section=%s;"
)
db_update(conn, delete_query, (BACKUP_NAME, PARAM_SERVICE, PARAM_SECTION))
rows = db_query(
conn,
"SELECT COUNT(*) FROM service_parameter "
"WHERE name=%s AND service=%s AND section=%s;",
(BACKUP_NAME, PARAM_SERVICE, PARAM_SECTION),
)
if rows and rows[0][0] > 0:
LOG.info(
"Deleted %d backup parameter(s) named '%s'.",
rows[0][0], BACKUP_NAME
)
else:
LOG.info("No backup parameter '%s' found to delete.", BACKUP_NAME)
def main():
action = None
from_release = None
to_release = None
postgres_port = DEFAULT_POSTGRES_PORT
if len(sys.argv) < 4:
print("Usage: %s from_release to_release action [postgres_port]" % sys.argv[0])
return 1
from_release = sys.argv[1]
to_release = sys.argv[2]
action = sys.argv[3]
if len(sys.argv) > 4:
postgres_port = sys.argv[4]
LOG.info(
"%s invoked from_release=%s to_release=%s action=%s",
sys.argv[0],
from_release,
to_release,
action,
)
if action == "delete":
try:
conn = connect_to_db(postgres_port)
del_backup_param(conn)
conn.close()
except Exception as e:
LOG.exception("Error removing backup service parameter: %s", e)
sys.exit(1)
else:
LOG.info("Nothing to do. Skipping")
return 0
if __name__ == "__main__":
sys.exit(main())
@@ -1,107 +0,0 @@
#!/usr/bin/python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script uses puppet to include the management IP on kube
# apiserver certificate SANs on upgrades from stx10 to stx11.
#
import logging
import os
import sys
import time
from oslo_config import cfg
from oslo_context import context as mycontext
from six.moves import configparser
from software.utilities.utils import configure_logging
from sysinv.conductor import rpcapiproxy as conductor_rpcapi
LOG = logging.getLogger('main_logger')
SUCCESS = 0
ERROR = 1
RETRIES = 3
CONF = cfg.CONF
SYSINV_CONFIG_FILE = '/etc/sysinv/sysinv.conf'
KUBE_CERT_SANS_UPDATE_FLAG = '/etc/platform/.upgrade_kube_apiserver_cert_sans_updated'
def get_conductor_rpc_bind_ip():
ini_str = '[DEFAULT]\n' + open(SYSINV_CONFIG_FILE, 'r').read()
config_applied = configparser.RawConfigParser()
config_applied.read_string(ini_str)
conductor_bind_ip = None
if config_applied.has_option('DEFAULT', 'rpc_zeromq_conductor_bind_ip'):
conductor_bind_ip = \
config_applied.get('DEFAULT', 'rpc_zeromq_conductor_bind_ip')
return conductor_bind_ip
def update_kube_apiserver_cert_rpc():
CONF.rpc_zeromq_conductor_bind_ip = get_conductor_rpc_bind_ip()
context = mycontext.get_admin_context()
rpcapi = conductor_rpcapi.ConductorAPI(topic=conductor_rpcapi.MANAGER_TOPIC)
rpcapi.update_kube_apiserver_cert_sans(context)
def check_kube_apiserver_cert_updated():
return os.path.exists(KUBE_CERT_SANS_UPDATE_FLAG)
def main():
# Initialize variables
action = None
from_release = None
to_release = None
arg = 1
# Process command-line arguments
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]
elif arg == 4:
# port = int(sys.argv[arg])
pass
else:
print(f"Invalid option {sys.argv[arg]}.")
return ERROR
arg += 1
configure_logging()
LOG.info(
"%s invoked from_release = %s invoked to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action)
)
for retry in range(0, RETRIES):
try:
if action == "activate" and from_release == "24.09":
if not check_kube_apiserver_cert_updated():
update_kube_apiserver_cert_rpc()
else:
LOG.info("Nothing to do. "
"Skipping kube-apiserver certificate update.")
except Exception as ex:
if retry == RETRIES - 1:
LOG.error("Error in kube-apiserver certificate update. "
"Please verify logs.")
return ERROR
else:
LOG.exception(ex)
LOG.error("Exception ocurred during script execution, "
"retrying after 5 seconds.")
time.sleep(5)
else:
return SUCCESS
if __name__ == "__main__":
sys.exit(main())
@@ -1,48 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script disables NFV-VIM Web Server. From version 25.x onwards,
# the web server will stay disabled by default in order to optimize
# memory and CPU consumption of the host.
#
# The user can manually reactivate it issuing the command:
# "sm-provision service-group-member vim-services vim-webserver"
#
# shellcheck disable=SC2206
# The script receives these parameters:
FROM_RELEASE=$1
TO_RELEASE=$2
ACTION=$3
SOFTWARE_LOG_PATH="/var/log/software.log"
FROM_RELEASE_ARR=(${FROM_RELEASE//./ })
FROM_RELEASE_MAJOR=${FROM_RELEASE_ARR[0]}
TO_RELEASE_ARR=(${TO_RELEASE//./ })
TO_RELEASE_MAJOR=${TO_RELEASE_ARR[0]}
# Default logging method extracted from script #02
function log {
echo "$(date -Iseconds | cut -d'+' -f1): ${NAME}[$$]: INFO: $*" \
>> "${SOFTWARE_LOG_PATH}" 2>&1
}
if [[ "${ACTION}" == "migrate" ]] && \
[ ${FROM_RELEASE_MAJOR} -lt 25 ] && \
[ ${TO_RELEASE_MAJOR} -ge 25 ]; then
log Disabling the NFV-VIM Web Server...
sm-deprovision service-group-member vim-services vim-webserver
ret_value=$?
[ $ret_value -eq 0 ] && log NFV-VIM Web Server successfully disabled
exit $ret_value
else
log No actions required from $FROM_RELEASE to $TO_RELEASE with action $ACTION
fi
@@ -1,242 +0,0 @@
#!/usr/bin/env python
#
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This migration scripts is used to automaticaly upgrade the PTP
# system configuration, according to changes on linuxptp library,
# drivers, etc.
import logging as log
import psycopg2 as db
import sys
import uuid
from datetime import datetime
from datetime import timezone
from software.utilities.utils import configure_logging
DEFAULT_POSTGRES_PORT = 5432
DB_CONNECT_FORMAT = "dbname=sysinv user=postgres port=%s"
def db_connect(port):
try:
conn = db.connect(DB_CONNECT_FORMAT % port)
return conn
except Exception as e:
log.exception(f"Error: {e}")
def db_close(conn):
try:
conn.close()
except Exception as e:
log.exception(f"Error: {e}")
def db_query(conn, query):
result = []
try:
with conn.cursor() as curs:
curs.execute(query)
result = curs.fetchall()
except Exception as e:
log.exception(f"Error: {e}")
return result
def db_execute(conn, query, params=None):
try:
with conn.cursor() as cursor:
if params:
cursor.execute(query, params)
else:
cursor.execute(query)
conn.commit()
except Exception as e:
conn.rollback()
log.exception(f"Error executing query: {e}")
raise
def get_instances(conn, service=None) -> list:
""" get ts2phc instances from database """
log.info("getting instances ...")
query = (
"SELECT ptp_instances.id, ptp_instances.name, "
"ptp_parameter_owners.uuid "
"FROM ptp_instances "
"INNER JOIN ptp_parameter_owners "
"ON ptp_instances.id = ptp_parameter_owners.id"
)
# Filter by PTP service type
if service:
query += f" WHERE service = '{service}';"
instances = db_query(conn, query)
instances_list = []
for instance in instances:
id = instance[0]
name = instance[1]
owner_id = instance[2]
interfaces = get_interfaces(conn, id)
for interface in interfaces:
parameters = get_parameters(conn, interface['owner_id'])
interface['parameters'] = parameters
instances_list += [{
'name': name,
'id': id,
'owner_id': owner_id,
'interfaces': interfaces
}]
return instances_list
def get_interfaces(conn, instance_id=None) -> list:
""" get interfaces """
log.info("getting interfaces ...")
query = (
"SELECT ptp_interfaces.id, ptp_interfaces.name, "
"ptp_parameter_owners.uuid "
"FROM ptp_interfaces "
"INNER JOIN ptp_parameter_owners "
"ON ptp_interfaces.id = ptp_parameter_owners.id"
)
# Filter by PTP instance id
if instance_id:
query += f" WHERE ptp_interfaces.ptp_instance_id = '{instance_id}';"
interfaces = db_query(conn, query)
interface_list = []
for interface in interfaces:
id = interface[0]
name = interface[1]
owner_id = interface[2]
interface_list += [{'name': name, 'id': id, 'owner_id': owner_id}]
return interface_list
def get_parameters(conn, owner_id=None) -> list:
""" get parameters """
log.info("getting parameters ...")
query = (
"SELECT ptp_parameters.id, ptp_parameters.name, "
"ptp_parameters.value "
"FROM ptp_parameters "
"INNER JOIN ptp_parameter_ownerships "
"ON ptp_parameters.uuid = ptp_parameter_ownerships.parameter_uuid"
)
# Filter by owner id
if owner_id:
query += f" WHERE ptp_parameter_ownerships.owner_uuid = '{owner_id}';"
parameters = db_query(conn, query)
parameter_list = []
for parameter in parameters:
log.info(f"parameter: {parameter}")
id = parameter[0]
key = parameter[1]
value = parameter[2]
parameter_list += [{'id': id, 'key': key, 'value': value}]
return parameter_list
def insert_parameter(conn, key, value, owner_uuid):
""" insert ptp parameter """
log.info("inserting parameter ...")
parameter_uuid = str(uuid.uuid4())
created_at = datetime.now(timezone.utc)
query = (
"INSERT INTO ptp_parameters "
"(uuid, name, value, created_at) "
"VALUES (%s, %s, %s, %s);"
)
values = (parameter_uuid, key, value, created_at)
db_execute(conn, query, values)
ownership_uuid = str(uuid.uuid4())
query = (
"INSERT INTO ptp_parameter_ownerships "
"(uuid, parameter_uuid, owner_uuid, created_at) "
"VALUES (%s, %s, %s, %s)"
)
values = (ownership_uuid, parameter_uuid, owner_uuid, created_at)
db_execute(conn, query, values)
def migrate_ts2phc_database(conn):
""" migrate ts2phc database """
log.info("migrating ts2phc database ...")
# Get list of ts2phc instances, interfaces and parameters.
# If any interface hasn't the ts2phc.pin_index or the
# ts2phc.channel parameter, add them as they're required.
instances = get_instances(conn, 'ts2phc')
for instance in instances:
log.info(f"instance {instance}")
for interface in instance['interfaces']:
if not any(parameter['key'] == 'ts2phc.pin_index'
for parameter in interface['parameters']):
log.info(f"ts2phc instance {instance['name']} "
f"interface {interface['name']} "
"'ts2phc.pin_index' parameter not found.")
insert_parameter(conn, 'ts2phc.pin_index', '1',
interface['owner_id'])
if not any(parameter['key'] == 'ts2phc.channel'
for parameter in interface['parameters']):
log.info(f"ts2phc instance {instance['name']} "
f"interface {interface['name']} "
"'ts2phc.channel' parameter not found.")
insert_parameter(conn, 'ts2phc.channel', '1',
interface['owner_id'])
def main():
"""" main - parsing args and call migration functions """
# migration arguments
action = None
from_release = None
to_release = None
db_port = DEFAULT_POSTGRES_PORT
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]
elif arg == 4:
# optional port parameter for USM upgrade
db_port = sys.argv[arg]
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
configure_logging()
log.info("%s invoked from_release = %s to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action))
if action == 'migrate' and from_release == "24.09":
conn = db_connect(db_port)
if conn:
migrate_ts2phc_database(conn)
db_close(conn)
else:
log.error("%s failed to connect to database." %
sys.argv[0])
else:
log.info("nothing to do")
if __name__ == "__main__":
sys.exit(main())
@@ -1,315 +0,0 @@
#!/usr/bin/python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
import logging
import os
import psycopg2
import subprocess
import sys
import uuid
from cgtsclient import client as cgts_client
from netaddr import valid_ipv4
from netaddr import valid_ipv6
from software.utilities.utils import configure_logging
from sysinv.common import constants as sysinv_constants
from wsme import types as wtypes
DEFAULT_POSTGRES_PORT = 5432
LOG_FILE = "/var/log/software.log"
LOG = logging.getLogger('main_logger')
# CgtsClient class to handle API interactions
class CgtsClient(object):
SYSINV_API_VERSION = 1
def __init__(self):
self.conf = {}
self._sysinv = None
# Loading credentials and configurations from environment variables
# typically set in OpenStack
source_command = 'source /etc/platform/openrc && env'
with open(os.devnull, "w") as fnull:
proc = subprocess.Popen(
['bash', '-c', source_command],
stdout=subprocess.PIPE, stderr=fnull,
universal_newlines=True)
# Strip the configurations starts with 'OS_' and change
# the value to lower
for line in proc.stdout:
key, _, value = line.partition("=")
if key.startswith('OS_'):
self.conf[key[3:].lower()] = value.strip()
proc.communicate()
@property
def sysinv(self):
if not self._sysinv:
self._sysinv = cgts_client.get_client(
self.SYSINV_API_VERSION,
os_username=self.conf['username'],
os_password=self.conf['password'],
os_auth_url=self.conf['auth_url'],
os_project_name=self.conf['project_name'],
os_project_domain_name=self.conf['project_domain_name'],
os_user_domain_name=self.conf['user_domain_name'],
os_region_name=self.conf['region_name'],
os_service_type='platform',
os_endpoint_type='internal')
return self._sysinv
def main():
action = None
from_release = None
to_release = None
postgres_port = DEFAULT_POSTGRES_PORT
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]
elif arg == 4:
# optional port parameter for USM upgrade
postgres_port = sys.argv[arg]
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
configure_logging()
LOG.info("%s invoked from_release = %s to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action))
if action == "migrate" and from_release == "24.09":
LOG.info("Create service parameter dns host record for "
"registry.central")
conn = None
try:
client = CgtsClient()
virtual_system = check_virtual_system(client)
conn = psycopg2.connect(
"dbname=sysinv user=postgres port=%s" % postgres_port)
floating_address_id = get_floating_sc_address_id(
conn, virtual_system)
if not floating_address_id:
LOG.info("System controller address ID not found, exiting.")
return 0
registry_central_ip = get_address_by_id(conn, floating_address_id)
if not registry_central_ip:
LOG.info("System controller address not found, exiting.")
return 0
if virtual_system:
registry_local_ip = get_controller_mgmt_address(conn)
update_dns_registry(
conn, registry_central_ip, registry_local_ip, to_release)
else:
update_dns_registry(conn, registry_central_ip, None,
to_release)
if not check_dns_resolution(registry_central_ip):
return 1
except Exception as ex:
LOG.exception("Error: %s" % ex)
print(ex)
return 1
finally:
if conn:
conn.close()
return 0
def update_dns_registry(conn, registry_central_ip,
registry_local_ip=None, to_release=None):
try:
delete_query = (
"DELETE FROM service_parameter "
"WHERE service='dns' AND section='host-record' "
"AND name IN ('registry.central', 'registry.local');"
)
db_execute(conn, delete_query)
created_at = wtypes.datetime.datetime
central_uuid = str(uuid.uuid4())
insert_central_query = (
"INSERT INTO service_parameter "
"(uuid, service, section, name, value, personality, "
"resource, created_at) "
"VALUES (%s, %s, %s, %s, %s, %s, %s, %s);"
)
central_values = (
central_uuid, 'dns', 'host-record', 'registry.central',
f"registry.central,{registry_central_ip}",
None, None, created_at.utcnow()
)
db_execute(conn, insert_central_query, central_values)
if registry_local_ip:
local_uuid = str(uuid.uuid4())
insert_local_query = (
"INSERT INTO service_parameter "
"(uuid, service, section, name, value, personality, "
"resource, created_at) "
"VALUES (%s, %s, %s, %s, %s, %s, %s, %s);"
)
local_values = (
local_uuid, 'dns', 'host-record', 'registry.local',
f"registry.local,{registry_local_ip}",
None, None, created_at.utcnow()
)
db_execute(conn, insert_local_query, local_values)
LOG.info("DNS host records for registry inserted successfully.")
config_dir = f"/opt/platform/config/{to_release}"
config_file = os.path.join(config_dir, "dnsmasq.addn_conf")
os.makedirs(config_dir, exist_ok=True)
LOG.info("Created config directory: %s" % config_dir)
existing_lines = []
if os.path.exists(config_file):
with open(config_file, "r") as f:
existing_lines = f.readlines()
updated_lines = []
for line in existing_lines:
if not line.startswith("host-record=registry.central,") and \
not line.startswith("host-record=registry.local,"):
updated_lines.append(line.strip())
updated_lines.append(
f"host-record=registry.central,{registry_central_ip}"
)
if registry_local_ip:
updated_lines.append(
f"host-record=registry.local,{registry_local_ip}"
)
with open(config_file, "w") as f:
for line in updated_lines:
f.write(line + "\n")
LOG.info("Updated entry in %s: %s" % (config_file, line))
except Exception as e:
LOG.exception("Failed to update DNS records: %s" % e)
raise
def db_execute(conn, query, params=None):
try:
with conn.cursor() as cursor:
if params:
cursor.execute(query, params)
else:
cursor.execute(query)
conn.commit()
except Exception as e:
conn.rollback()
LOG.exception("Error executing query: %s" % e)
raise
def db_query(conn, query):
try:
with conn.cursor() as cursor:
cursor.execute(query)
result = cursor.fetchone()
return result[0] if result else None
except Exception as e:
LOG.exception("Error executing query: %s" % e)
raise
def check_virtual_system(client):
parameters = client.sysinv.service_parameter.list()
for parameter in parameters:
if (parameter.name ==
sysinv_constants.SERVICE_PARAM_NAME_PLAT_CONFIG_VIRTUAL):
return True
return False
def get_floating_sc_address_id(conn, virtual_system):
if virtual_system:
query = (
"SELECT floating_address_id FROM address_pools "
"WHERE name = 'system-controller-subnet';"
)
else:
query = (
"SELECT floating_address_id FROM address_pools "
"WHERE name = 'system-controller-oam-subnet';"
)
return db_query(conn, query)
def get_controller_mgmt_address(conn):
query = "SELECT address FROM addresses WHERE name = 'controller-mgmt';"
return db_query(conn, query)
def get_address_by_id(conn, floating_address_id):
query = (
"SELECT address FROM addresses WHERE id = %s;"
% floating_address_id
)
return db_query(conn, query)
def check_dns_resolution(ip_address):
if valid_ipv4(ip_address):
record_type = "A"
ip_type = "IPv4"
elif valid_ipv6(ip_address):
record_type = "AAAA"
ip_type = "IPv6"
else:
LOG.error("Invalid IP address: %s" % ip_address)
return False
LOG.info("Checking resolution to registry.central")
result = subprocess.run(
["dig", "registry.central", record_type, "+short"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True
)
if result.returncode != 0 or not result.stdout.strip():
LOG.error(
"Failed to resolve %s address %s to a name associated with "
"the domain (registry.central). No valid DNS record found." %
(ip_type, ip_address)
)
return False
return True
if __name__ == "__main__":
sys.exit(main())
@@ -1,249 +0,0 @@
#!/usr/bin/python
# Copyright (c) 2024-2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script perform the apply command for service-parameters for
# kube-apiserver added/removed/modified in the scrips listed below
# (which need to be executed before this one), and monitors the
# kube-apiserver PID restart in the active controller.
#
# An update of kube-apiserver port (6443 -> 16443) relies on this
# procedure to reconfigure the k8s control plane.
#
# Scripts that should be executed before this one:
# - k8s-disable-sched-controllermanager-leader-election.sh
#
import logging
import subprocess
import sys
import os
import time
from oslo_config import cfg
from oslo_context import context as mycontext
from six.moves import configparser
from software.utilities.utils import configure_logging
from sysinv.common.kubernetes import k8s_wait_for_endpoints_health
from sysinv.conductor import rpcapiproxy as conductor_rpcapi
LOG = logging.getLogger('main_logger')
SUCCESS = 0
ERROR = 1
RETRIES = 3
KUBE_PORT_UPDATED_FLAG = '/etc/platform/.upgrade_kube_apiserver_port_updated'
CONF = cfg.CONF
SYSINV_CONFIG_FILE = '/etc/sysinv/sysinv.conf'
class ServiceParametersApplier(object):
"""
The main purpose of this class is to safely apply service parameters
previously configured in the system.
The command: "system service-parameters-apply kubernetes" will trigger
many system events including the restart of kube-apiserver process.
"""
def __init__(self) -> None:
self.SP_APPLY_CMD = 'system service-parameter-apply kubernetes'
self.initial_kube_apiserver_pid = -1
def __system_cmd(self, command: str) -> str:
sub = subprocess.Popen(["bash", "-c", command],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = sub.communicate()
if sub.returncode != 0:
raise Exception(stderr.decode('utf-8'))
return stdout.decode('utf-8')
def __service_parameter_apply(self) -> None:
command = self.SP_APPLY_CMD
LOG.info('Applying service parameters...')
self.__system_cmd(command)
def __get_kube_apiserver_pid(self) -> int:
try:
return subprocess.check_output(["pidof", "-s", "kube-apiserver"])
except Exception:
return -1
def __register_kube_apiserver_pid(self):
self.initial_kube_apiserver_pid = self.__get_kube_apiserver_pid()
def __wait_kube_apiserver_pid_ready(self):
LOG.info("Waiting kube-apiserver PID to restart")
for _ in range(0, 300):
if check_kube_apiserver_port_updated():
current_pid = self.__get_kube_apiserver_pid()
if (current_pid != self.initial_kube_apiserver_pid and
current_pid != -1):
LOG.info("kube-apiserver PID is restarted!")
return
time.sleep(2)
else:
LOG.error("Timeout restarting kube-apiserver.")
sys.exit(ERROR)
def apply(self):
# Perform service parameter apply and wait kube-apiserver restart
self.__register_kube_apiserver_pid()
self.__service_parameter_apply()
self.__wait_kube_apiserver_pid_ready()
def rollback(self):
# Perform service parameter apply and wait kube-apiserver restart
self.__register_kube_apiserver_pid()
self.__service_parameter_apply()
self.__wait_kube_apiserver_pid_ready()
def check_kube_apiserver_port_updated():
return os.path.exists(KUBE_PORT_UPDATED_FLAG)
def get_conductor_rpc_bind_ip():
ini_str = '[DEFAULT]\n' + open(SYSINV_CONFIG_FILE, 'r').read()
config_applied = configparser.RawConfigParser()
config_applied.read_string(ini_str)
conductor_bind_ip = None
if config_applied.has_option('DEFAULT', 'rpc_zeromq_conductor_bind_ip'):
conductor_bind_ip = \
config_applied.get('DEFAULT', 'rpc_zeromq_conductor_bind_ip')
return conductor_bind_ip
def create_kube_apiserver_port_rollback_flag_rpc():
CONF.rpc_zeromq_conductor_bind_ip = get_conductor_rpc_bind_ip()
context = mycontext.get_admin_context()
rpcapi = conductor_rpcapi.ConductorAPI(topic=conductor_rpcapi.MANAGER_TOPIC)
rpcapi.flag_k8s_port_update_rollback(context)
def run_kubernetes_health_audit_rpc():
CONF.rpc_zeromq_conductor_bind_ip = get_conductor_rpc_bind_ip()
context = mycontext.get_admin_context()
rpcapi = conductor_rpcapi.ConductorAPI(topic=conductor_rpcapi.MANAGER_TOPIC)
rpcapi.run_kubernetes_health_audit(context)
def wait_kube_apiserver_port_update(desired_status):
LOG.info("Wait kube-apiserver port update finish.")
retries = 60
sleep = 3
for _ in range(0, retries):
if check_kube_apiserver_port_updated() == desired_status:
LOG.info("kube-apiserver port update status: %s" %
str(desired_status))
return
time.sleep(sleep)
msg = "The port for kube-apiserver was not updated in the allotted time."
raise Exception(msg)
def check_conductor_restarted():
output = subprocess.check_output('/usr/bin/sm-dump', shell=True)
for line in output.splitlines():
if 'sysinv-conductor' in line.decode('utf-8'):
if line.decode('utf-8').count('enabled-active') == 2:
return True
break
return False
def wait_conductor_restarted():
retries = 30
sleep = 3
for _ in range(0, retries):
if check_conductor_restarted():
LOG.info("Sysinv-conductor is enabled-active")
return True
time.sleep(sleep)
LOG.error("Sysinv-conductor not restarted in expected time")
return False
def main():
# Initialize variables
action = None
from_release = None
to_release = None
arg = 1
# Process command-line arguments
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]
elif arg == 4:
# port = int(sys.argv[arg])
pass
else:
print(f"Invalid option {sys.argv[arg]}.")
return ERROR
arg += 1
configure_logging()
LOG.info(
"%s invoked from_release = %s invoked to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action)
)
for retry in range(0, RETRIES):
try:
if action == "activate" and from_release == "24.09":
if not check_kube_apiserver_port_updated():
ServiceParametersApplier().apply()
wait_kube_apiserver_port_update(True)
if not wait_conductor_restarted():
# No point in retrying without sysinv-conductor
LOG.error("Conductor is unhealthy, check sysinv logs")
return ERROR
if not k8s_wait_for_endpoints_health():
# k8s_wait_for_endpoints_health already has retries
LOG.error("K8s is unhealthy, aborting. "
"Please check logs.")
return ERROR
run_kubernetes_health_audit_rpc()
elif action == "activate-rollback" and to_release == "24.09":
if check_kube_apiserver_port_updated():
create_kube_apiserver_port_rollback_flag_rpc()
ServiceParametersApplier().rollback()
wait_kube_apiserver_port_update(False)
if not wait_conductor_restarted():
# No point in retrying without sysinv-conductor
LOG.error("Conductor is unhealthy, check sysinv logs")
return ERROR
if not k8s_wait_for_endpoints_health():
# k8s_wait_for_endpoints_health already has retries
LOG.error("K8s is unhealthy, aborting. "
"Please check logs.")
return ERROR
run_kubernetes_health_audit_rpc()
else:
LOG.info("Nothing to do. "
"Skipping K8s service parameter apply.")
except Exception as ex:
if retry == RETRIES - 1:
LOG.error("Error applying K8s service parameters. "
"Please verify logs.")
return ERROR
else:
LOG.exception(ex)
LOG.error("Exception ocurred during script execution, "
"retrying after 5 seconds.")
time.sleep(5)
else:
return SUCCESS
if __name__ == "__main__":
sys.exit(main())
@@ -1,91 +0,0 @@
#!/usr/bin/python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
import logging
import psycopg2
import sys
from software.utilities.utils import configure_logging
DEFAULT_POSTGRES_PORT = 5432
LOG_FILE = "/var/log/software.log"
DB_NAME = "sysinv"
DB_USER = "postgres"
LOG = logging.getLogger('main_logger')
def main():
action = None
from_release = None
to_release = None
postgres_port = DEFAULT_POSTGRES_PORT
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]
elif arg == 4:
# optional port parameter for USM upgrade
postgres_port = sys.argv[arg]
pass
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
configure_logging()
res = 0
LOG.info("%s invoked from_release = %s to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action))
if action == "migrate" and from_release == "24.09":
LOG.info("Updating addresses table entries.")
try:
update_address_name_from_db(postgres_port)
except Exception as ex:
LOG.exception("Error: {}".format(ex))
print(ex)
res = 1
return res
def update_address_name_from_db(postgres_port):
query = """
UPDATE addresses
SET name = REGEXP_REPLACE(
name, '^system-controller-gateway-ip-', 'controller-gateway-')
WHERE name LIKE 'system-controller-gateway-ip-%';
"""
try:
with psycopg2.connect(
dbname=DB_NAME,
user=DB_USER,
port=postgres_port
) as conn:
with conn.cursor() as cursor:
cursor.execute(query)
rows_updated = cursor.rowcount
conn.commit()
if rows_updated:
LOG.info(
"Updated %d entries in addresses table.", rows_updated)
else:
LOG.info("No entries updated in addresses table.")
except Exception as e:
LOG.error(f"Failed to update IP addresses in the "
f"database: {e}")
raise
if __name__ == "__main__":
sys.exit(main())
@@ -167,9 +167,9 @@ def main():
for retry in range(0, RETRIES):
try:
if action == "activate" and from_release == "24.09":
if action == "activate":
PortierisWebhookDisabler(from_release).apply()
elif action == "activate-rollback" and to_release == "24.09":
elif action == "activate-rollback":
PortierisWebhookDisabler(to_release).rollback()
else:
LOG.info("Nothing to do. "
@@ -1,101 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script reconfigure the keystone endpoints using the sysinv
# version (not puppet).
# Needs to run at the end of the upgrade activation, to reduce the
# stabilization time after upgrade is concluded (less reconfigurations).
import logging
import socket
import sys
from time import sleep
from oslo_config import cfg
from oslo_context import context as mycontext
from six.moves import configparser
from sysinv.conductor import rpcapiproxy as conductor_rpcapi
from software.utilities.utils import configure_logging
LOG = logging.getLogger('main_logger')
CONF = cfg.CONF
SYSINV_CONFIG_FILE = '/etc/sysinv/sysinv.conf'
def get_conductor_rpc_bind_ip():
ini_str = '[DEFAULT]\n' + open(SYSINV_CONFIG_FILE, 'r').read()
config_applied = configparser.RawConfigParser()
config_applied.read_string(ini_str)
conductor_bind_ip = None
if config_applied.has_option('DEFAULT', 'rpc_zeromq_conductor_bind_ip'):
conductor_bind_ip = \
config_applied.get('DEFAULT', 'rpc_zeromq_conductor_bind_ip')
return conductor_bind_ip
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]
elif arg == 4:
# optional port parameter for USM upgrade
# port = sys.argv[arg]
pass
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
configure_logging()
# Activate
if action == 'activate':
LOG.info("%s invoked with from_release = %s to_release = %s "
"action = %s"
% (sys.argv[0], from_release, to_release, action))
# Options of bind ip to the rpc call
rpc_ip_options = [get_conductor_rpc_bind_ip(), 'controller.internal']
while None in rpc_ip_options:
rpc_ip_options.remove(None)
for index, ip in enumerate(rpc_ip_options):
try:
CONF.rpc_zeromq_conductor_bind_ip = ip
context = mycontext.get_admin_context()
rpcapi = conductor_rpcapi.ConductorAPI(
topic=conductor_rpcapi.MANAGER_TOPIC)
host = rpcapi.get_ihost_by_hostname(
context, socket.gethostname())
LOG.info("Call Conductor to reconfigure keystone endpoints. "
"Bind ip: %s." % CONF.rpc_zeromq_conductor_bind_ip)
rpcapi.reconfigure_service_endpoints(context, host)
except Exception as e:
if index == (len(rpc_ip_options) - 1):
LOG.error("Error configuring keystone endpoints. "
"Please verify logs.")
return 1
else:
LOG.exception(e)
LOG.error("Exception ocurred during script execution, "
"retrying after 5 seconds.")
sleep(5)
else:
return 0
if __name__ == "__main__":
sys.exit(main())
@@ -6,7 +6,6 @@
# This script install fluxcd controllers in the flux-helm namespace
# in kubernetes
#
# This script can be removed in the release that follows stx7
import logging
import subprocess
@@ -1,55 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This migration script is used to create keystone roles
# operator and configurator during upgrade, also deletes
# roles when the rollback is executed
#
# The migration scripts are passed these parameters:
NAME=$(basename $0)
FROM_RELEASE=$1
TO_RELEASE=$2
ACTION=$3
ROLES=("operator" "configurator")
function log {
echo "$(date -Iseconds | cut -d'+' -f1): ${NAME}[$$]: INFO: $*" >> "/var/log/software.log" 2>&1
}
# Only run this script during upgrade-activate and from release 24.09
if [[ "$ACTION" == "activate" && "$FROM_RELEASE" == "24.09" ]]; then
log "creating keystone roles operator,configurator"
for role in "${ROLES[@]}"; do
openstack role show $role
RC=$?
if [ ${RC} == 1 ]; then
openstack role create $role
RC=$?
if [ ${RC} == 0 ]; then
log "Successfully added keystone role ${role}"
else
log "Failed to add keystone role ${role}"
exit 1
fi
fi
done
elif [[ "$ACTION" == "activate-rollback" && "$TO_RELEASE" == "24.09" ]]; then
for role in "${ROLES[@]}"; do
openstack role show $role
RC=$?
if [ ${RC} == 0 ]; then
openstack role delete $role
RC=$?
if [ ${RC} == 0 ]; then
log "Successfully deleted keystone role ${role}"
else
log "Failed to delete keystone role ${role}"
exit 1
fi
fi
done
fi
@@ -1,329 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
# This script performs database updation and rollback operations
# for the `interfaces` table in the `sysinv` PostgreSQL database,
# specifically targeting VF interfaces with PCI SR-IOV class.
import sys
import psycopg2
import logging
from psycopg2 import sql
import json
import re
import configparser
import subprocess
import time
from software.utilities.utils import configure_logging
DB_NAME = "sysinv"
DB_HOST = "localhost"
TABLE_NAME = "interfaces"
MAX_TX_RATE = "max_tx_rate"
MAX_RX_RATE = "max_rx_rate"
IFCAPABILITIES = "ifcapabilities"
VF_TYPE = "vf"
PCI_CLASS = "pci-sriov"
DEFAULT_POSTGRES_PORT = "5432"
LOG = logging.getLogger('main_logger')
configure_logging()
def get_db_credentials():
""" Retrieve DB credentials from sysinv.conf """
try:
config = configparser.ConfigParser()
config.read('/etc/sysinv/sysinv.conf')
conn_string = config['database']['connection']
match = re.match(r'postgresql\+psycopg2://([^:]+):([^@]+)@',
conn_string)
if match:
username = match.group(1)
password = match.group(2)
return username, password
else:
raise Exception("Failed to parse DB credentials from sysinv.conf")
except Exception as e:
LOG.error(f"Error getting DB credentials: {e}")
sys.exit(1)
def connect_to_db(port):
""" Establish DB connection """
username, password = get_db_credentials()
try:
conn = psycopg2.connect(
dbname=DB_NAME,
user=username,
password=password,
host=DB_HOST,
port=port
)
return conn
except Exception as e:
LOG.error(f"Database connection failed: {e}")
sys.exit(1)
def db_query(conn, query, params=()):
""" Execute SELECT query and return results """
with conn.cursor() as cur:
cur.execute(query, params)
return cur.fetchall()
def db_update(conn, query, params=(), autocommit=True):
""" Execute UPDATE query """
with conn.cursor() as cur:
cur.execute(query, params)
if autocommit:
conn.commit()
def columns_exist(conn):
""" Verify required columns exist in the table """
query = f"""
SELECT column_name
FROM information_schema.columns
WHERE table_name = '{TABLE_NAME}'
AND column_name IN ('{MAX_TX_RATE}', '{MAX_RX_RATE}',
'{IFCAPABILITIES}');
"""
cols = db_query(conn, query)
existing_cols = {col[0] for col in cols}
if {MAX_TX_RATE, MAX_RX_RATE, IFCAPABILITIES}.issubset(existing_cols):
return True
else:
missing_cols = (
{MAX_TX_RATE, MAX_RX_RATE, IFCAPABILITIES} - existing_cols
)
LOG.error(f"Missing columns: {', '.join(missing_cols)}")
sys.exit(1)
def update_data(conn):
LOG.info("Starting data updation...")
select_query = sql.SQL(f"""
SELECT id, uuid, {IFCAPABILITIES}
FROM {TABLE_NAME}
WHERE iftype = %s AND ifclass = %s;
""")
vf_interfaces = []
vf_interfaces = db_query(
conn, select_query, (VF_TYPE, PCI_CLASS)
)
LOG.info(f"Found {len(vf_interfaces)} VF interfaces to update.")
if len(vf_interfaces) == 0:
LOG.info("No VF interfaces found to update. No changes required")
return
updated = False
for iface_id, iface_uuid, ifcapabilities in vf_interfaces:
if ifcapabilities:
try:
capabilities_dict = json.loads(ifcapabilities)
except (json.JSONDecodeError, TypeError) as e:
raise ValueError(
f"Malformed ifcapabilities for UUID {iface_uuid}: {e}"
)
tx_rate = capabilities_dict.get("max_tx_rate", None)
if "max_tx_rate" in capabilities_dict:
del capabilities_dict["max_tx_rate"]
cleaned_ifcapabilities = json.dumps(capabilities_dict) if \
capabilities_dict else None
# Only update the database if either tx_rate or
# cleaned_ifcapabilities has a value
if tx_rate is not None or cleaned_ifcapabilities is not None:
update_query = sql.SQL(f"""
UPDATE {TABLE_NAME}
SET {MAX_TX_RATE} = %s, {IFCAPABILITIES} = %s
WHERE id = %s;
""")
db_update(
conn,
update_query,
(tx_rate, cleaned_ifcapabilities, iface_id),
autocommit=False
)
updated = True
LOG.info(f"Updated {TABLE_NAME} for UUID: {iface_uuid} "
f"with max_tx_rate: {tx_rate}")
if updated:
conn.commit()
LOG.info("All applicable records updated successfully.")
else:
LOG.info("No changes were made to the database.")
def rollback_data(conn):
"""Rollback migration by moving data back to ifcapabilities"""
LOG.info("Starting data rollback...")
select_query = sql.SQL(f"""
SELECT id, uuid, {MAX_TX_RATE}, {IFCAPABILITIES}
FROM {TABLE_NAME}
WHERE iftype = %s AND ifclass = %s;
""")
vf_interfaces = []
vf_interfaces = db_query(
conn, select_query, (VF_TYPE, PCI_CLASS)
)
LOG.info(f"Found {len(vf_interfaces)} VF interfaces to rollback.")
if len(vf_interfaces) == 0:
LOG.info("No VF interfaces found to rollback. No changes required")
return
updated = False
for iface_id, iface_uuid, max_tx_rate, ifcapabilities in vf_interfaces:
capabilities = {}
if max_tx_rate is not None:
capabilities["max_tx_rate"] = max_tx_rate
if ifcapabilities:
try:
existing = json.loads(ifcapabilities)
capabilities.update(existing)
except (json.JSONDecodeError, TypeError) as e:
raise ValueError(
f"Malformed ifcapabilities for UUID {iface_uuid}: {e}"
)
if not capabilities:
continue
new_ifcap = json.dumps(capabilities) if capabilities else None
if new_ifcap or max_tx_rate is not None:
update_query = sql.SQL(f"""
UPDATE {TABLE_NAME}
SET {IFCAPABILITIES} = %s, {MAX_TX_RATE} = NULL
WHERE id = %s;
""")
db_update(
conn, update_query, (new_ifcap, iface_id), autocommit=False
)
updated = True
LOG.info(
f"Rolled back {TABLE_NAME} for UUID: {iface_uuid} "
f"with ifcapabilities: {new_ifcap}"
)
if updated:
conn.commit()
LOG.info("All applicable records rolled back successfully.")
else:
LOG.info("No changes were made to the database.")
def patch_felix_configuration():
"""Ensure FelixConfiguration chainInsertMode is set to Append."""
LOG.info("Patching FelixConfiguration to Append...")
cmd = [
"kubectl", "--kubeconfig=/etc/kubernetes/admin.conf",
"patch", "felixconfiguration", "default", "--type=merge",
"-p", '{"spec":{"chainInsertMode":"Append"}}'
]
retries, delay = 3, 5
timeout = 15
for attempt in range(retries):
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=True,
timeout=timeout
)
LOG.info(f"Patch applied successfully: {result.stdout}")
return
except subprocess.TimeoutExpired:
LOG.warning(f"Attempt {attempt + 1} timed out after {timeout}s.")
except subprocess.CalledProcessError as e:
LOG.warning(f"Attempt {attempt + 1} failed: {e.stderr}")
if attempt < retries - 1:
time.sleep(delay)
else:
LOG.error("FelixConfiguration patch failed after retries.")
def main():
action = None
from_release = None
to_release = None
postgres_port = DEFAULT_POSTGRES_PORT
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]
elif arg == 4:
postgres_port = sys.argv[arg]
else:
LOG.error(f"Invalid option {sys.argv[arg]}.")
return 1
arg += 1
if action not in ["activate", "activate-rollback"]:
LOG.warning(f"Action '{action}' is not valid. Skipping...")
return 0
try:
conn = connect_to_db(postgres_port)
columns_exist(conn)
if to_release == "25.09" and action == "activate":
update_data(conn)
patch_felix_configuration()
elif from_release == "25.09" and action == "activate-rollback":
rollback_data(conn)
else:
LOG.error(f"Unknown action: {action}")
return 1
except Exception as e:
LOG.error(f"Exception during {action}: {e}", exc_info=True)
return 1
finally:
if 'conn' in locals():
conn.close()
if __name__ == "__main__":
main()
@@ -6,7 +6,6 @@
# This script will remove the etcd folder of upgrade.
#
#
import logging
import os
import shutil
@@ -20,8 +19,6 @@ from software.utilities.utils import configure_logging
LOG = logging.getLogger('main_logger')
ETCD_DIR_NAME = 'db'
UPGRADE_FLAG_NAME = '.upgrade'
ROLLBACK_FLAG_NAME = '.rollback'
def main():
@@ -56,11 +53,10 @@ def main():
else:
major_release = from_major_release
# Check delete action, upgrade and rollback scenario.
if action == 'delete' and (to_major_release == '25.09' or (from_major_release == '25.09'
and to_major_release == '24.09')):
if action == 'delete':
try:
clean_up_deployment_data(major_release)
create_etcd_flag(from_major_release)
restart_etcd_service()
except Exception as e:
LOG.exception("Error: {}".format(e))
res = 1
@@ -95,20 +91,5 @@ def restart_etcd_service():
LOG.error("Error restarting etcd: %s", str(e))
def create_etcd_flag(from_release):
"""
Creates the right flag accordingly to upgrade or rollback
"""
if utils.compare_release_version(SW_VERSION, from_release) and from_release == '24.09':
etcd_upgrade_flag_path = os.path.join(constants.ETCD_PATH, UPGRADE_FLAG_NAME)
subprocess.run(["touch", etcd_upgrade_flag_path], check=True)
LOG.info("Flag %s created.", etcd_upgrade_flag_path)
else:
etcd_rollback_flag_path = os.path.join(constants.ETCD_PATH, ROLLBACK_FLAG_NAME)
subprocess.run(["touch", etcd_rollback_flag_path], check=True)
LOG.info("Flag %s created.", etcd_rollback_flag_path)
restart_etcd_service()
if __name__ == "__main__":
sys.exit(main())
@@ -1,117 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
# This script is responsible to update swanctl configuration
# file in multinodes systems.
import logging
import sys
import time
from oslo_config import cfg
from oslo_context import context as mycontext
from six.moves import configparser
from software.utilities.utils import configure_logging
from sysinv.conductor import rpcapiproxy as conductor_rpcapi
# Constants
CONF = cfg.CONF
LOG = logging.getLogger('main_logger')
SYSINV_CONFIG_FILE = '/etc/sysinv/sysinv.conf'
PLATFORM_CONFIG_FILE = '/etc/platform/platform.conf'
ACTION_ACTIVATE = 'activate'
ACTION_ACTIVATE_ROLLBACK = 'activate-rollback'
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]
elif arg == 4:
# optional port parameter for USM upgrade
# port = sys.argv[arg]
pass
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
configure_logging()
LOG.info(
"%s invoked from_release = %s to_release = %s action = %s"
% (sys.argv[0], from_release, to_release, action)
)
res = 0
system_mode = get_system_mode()
if system_mode != "simplex" and action in [ACTION_ACTIVATE,
ACTION_ACTIVATE_ROLLBACK]:
# Options of bind ip to the rpc call
rpc_ip_options = [get_conductor_rpc_bind_ip(), 'controller.internal']
while None in rpc_ip_options:
rpc_ip_options.remove(None)
for index, ip in enumerate(rpc_ip_options):
try:
CONF.rpc_zeromq_conductor_bind_ip = ip
context = mycontext.get_admin_context()
rpcapi = conductor_rpcapi.ConductorAPI(
topic=conductor_rpcapi.MANAGER_TOPIC)
LOG.info("Call Conductor to reconfigure IPsec. "
"Bind ip: %s." % CONF.rpc_zeromq_conductor_bind_ip)
rpcapi.reconfigure_ipsec(context, action)
except Exception as e:
if index == (len(rpc_ip_options) - 1):
LOG.error("Error configuring keystone endpoints. "
"Please verify logs.")
res = 1
break
else:
LOG.exception(e)
LOG.error("Exception ocurred during script execution, "
"retrying after 5 seconds.")
time.sleep(5)
else:
LOG.info(f"Nothing to do for action {action} in {system_mode} environment.")
LOG.info("%s completed execution." % (sys.argv[0]))
return res
def get_system_mode():
ini_str = '[DEFAULT]\n' + open(PLATFORM_CONFIG_FILE, 'r').read()
config_applied = configparser.RawConfigParser()
config_applied.read_string(ini_str)
if config_applied.has_option('DEFAULT', 'system_mode'):
system_mode = config_applied.get('DEFAULT', 'system_mode')
else:
system_mode = None
return system_mode
def get_conductor_rpc_bind_ip():
ini_str = '[DEFAULT]\n' + open(SYSINV_CONFIG_FILE, 'r').read()
config_applied = configparser.RawConfigParser()
config_applied.read_string(ini_str)
conductor_bind_ip = None
if config_applied.has_option('DEFAULT', 'rpc_zeromq_conductor_bind_ip'):
conductor_bind_ip = \
config_applied.get('DEFAULT', 'rpc_zeromq_conductor_bind_ip')
return conductor_bind_ip
if __name__ == "__main__":
sys.exit(main())
@@ -1,178 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
#####################################################################
#
# This script sets the Maintenance Heartbeat period service parameter
# according to the release upgrade or rollback activate actions:
#
# Upgrade - To Release - 25.09 release - heartbeat_period=1000
# Rollback - To Release - 24.09 release - heartbeat_period=100
#
# Performance Features to improve exeution time.
#
# 1. Only source openrc if its needed
# 2. If a service parameter apply change is required,
# it is launched in the background asynchronously.
# The script does not wait around.
#
# These features are seen to reduce execution time
# down to 4-5 seconds from 20-23 seconds.
#
# Assumptions: platform.conf and openrc are already part of the
# environment passed to this script.
#
####################################################################
NAME=$(basename "$0")
# The script can be called with the start,
# migration, activation and delete actions
# with these parameters:
FROM_RELEASE=$1
TO_RELEASE=$2
ACTION=$3
# List of supported actions
MY_SUPPORTED_ACTIONS=("activate" "activate-rollback")
# Safe valid action checker
is_valid_action=false
for action in "${MY_SUPPORTED_ACTIONS[@]}"; do
if [[ "${ACTION}" == "${action}" ]]; then
is_valid_action=true
break
fi
done
# Exit silently on unsupported actions
! ${is_valid_action} && exit 0
start_time=${SECONDS}
# The file to log to
SOFTWARE_LOG_PATH="/var/log/software.log"
PLATFORM_CONF_FILE="/etc/platform/platform.conf"
OPENRC_FILE="/etc/platform/openrc"
# Make this script's logging consistent
LOG_PREFIX="Maintenance Heartbeat Period"
# The desired heartbeat period in these releases
HEARTBEAT_PERIOD_24_09=100
HEARTBEAT_PERIOD_25_09=1000
function log {
echo "$(date -Iseconds | cut -d'+' -f1): ${NAME}[$$]: INFO: $*" >> "${SOFTWARE_LOG_PATH}" 2>&1
}
if [ $# -lt 3 ]; then
error_str="Error: ${LOG_PREFIX} update script requires at least 3 arguments"
echo "${error_str}"
log "${error_str}"
usage_str="Usage: $0 'FROM_RELEASE' 'TO_RELEASE' 'ACTION'"
echo "${usage_str}"
log "${usage_str}"
exit 1
fi
function script_exit {
delta=$((SECONDS-start_time))
log "${LOG_PREFIX} service parameter update for ${ACTION} from ${FROM_RELEASE} to ${TO_RELEASE} - Completed in ${delta} secs"
exit 0
}
# Backup plan if called without nodetype being set
if [ -z "${nodetype}" ]; then
log "${LOG_PREFIX} need to source ${PLATFORM_CONF_FILE}"
# shellcheck disable=SC1090
source "${PLATFORM_CONF_FILE}"
fi
# Backup plan if called without required environment credentials
# Check to see if we need to source openrc
if [ -z "${OS_USERNAME+x}" ] || [ -z "${OS_PASSWORD+x}" ]; then
if [ -e ${OPENRC_FILE} ]; then
log "${LOG_PREFIX} need to source ${OPENRC_FILE}"
# shellcheck disable=SC1090
source "${OPENRC_FILE}" >/dev/null 2>&1
rc=$?
if [ "${rc}" -ne 0 ]; then
log "No actions required for inactive controller"
script_exit
fi
else
log "${LOG_PREFIX} missing ${OPENRC_FILE} ... exiting"
exit 1
fi
fi
log "${LOG_PREFIX} ${ACTION} from ${FROM_RELEASE} to ${TO_RELEASE} - Start"
# shellcheck disable=SC2154
if [ "${nodetype}" = "controller" ]; then
# Query the heartbeat period
period=$(system service-parameter-list --service platform \
--section maintenance \
--name heartbeat_period \
--format value | \
awk '/heartbeat_period/ {print $5}')
if ! [[ "${period}" =~ ^[0-9]+$ ]]; then
log "Invalid heartbeat period: '${period}'"
script_exit
fi
log "${LOG_PREFIX} current value is ${period}"
if [ "${period}" -lt 100 ] || [ "${period}" -gt 1000 ]; then
log "No actions required for invalid heartbeat period of '${period}'"
script_exit
fi
# Case: Upgrade to 25.09
if [[ "${ACTION}" == "activate" && "${TO_RELEASE}" == "25.09" ]]; then
if [ "${period}" -ne "${HEARTBEAT_PERIOD_25_09}" ]; then
system "service-parameter-modify" "platform" "maintenance" "heartbeat_period=${HEARTBEAT_PERIOD_25_09}" >/dev/null 2>&1
rc=$?
# shellcheck disable=SC2181
if [ "${rc}" -eq 0 ]; then
# Note: The service parameter apply operation is seen to take upwards
# of 10 seconds or more.
#
# For this reason and that it is the last operation in the script
# a choice was made to post the apply in the background rather
# than wait around for inline completion before continuing.
#
# The disown option was used in the background launch so that the
# apply continues even if this script exits (which it will).
system service-parameter-apply platform >/dev/null 2>&1 & disown
log "${LOG_PREFIX} service parameter apply change, from ${period} to ${HEARTBEAT_PERIOD_25_09}, posted to sysinv"
fi
else
log "${LOG_PREFIX} no change required"
fi
elif [[ "${ACTION}" == "activate-rollback" && "${TO_RELEASE}" == "24.09" ]]; then
if [ "${period}" -ne "${HEARTBEAT_PERIOD_24_09}" ]; then
system "service-parameter-modify" "platform" "maintenance" "heartbeat_period=${HEARTBEAT_PERIOD_24_09}" >/dev/null 2>&1
rc=$?
# shellcheck disable=SC2181
if [ "${rc}" -eq 0 ]; then
# Posting ther apply operation. See Note above.
system "service-parameter-apply" "platform" >/dev/null 2>&1 & disown
log "${LOG_PREFIX} service parameter apply change, from ${period} to ${HEARTBEAT_PERIOD_24_09}, posted to sysinv"
fi
else
log "${LOG_PREFIX} no change required"
fi
else
log "No actions for ${ACTION} for ${FROM_RELEASE} to ${TO_RELEASE} transition"
fi
else
log "No actions required for ${nodetype}"
fi
script_exit