Merge "Config updates for stx3.0 upgrades"

This commit is contained in:
Zuul
2020-04-02 12:56:44 +00:00
committed by Gerrit Code Review
11 changed files with 77 additions and 390 deletions
@@ -67,7 +67,7 @@ install -p -D -m 755 scripts/controller_config %{buildroot}%{local_etc_initd}/co
# Install Upgrade scripts
install -d -m 755 %{buildroot}%{local_etc_upgraded}
install -p -D -m 755 upgrade-scripts/* %{buildroot}%{local_etc_upgraded}/
# install -p -D -m 755 upgrade-scripts/* %{buildroot}%{local_etc_upgraded}/
install -d -m 755 %{buildroot}%{local_etc_systemd}
install -p -D -m 664 scripts/controllerconfig.service %{buildroot}%{local_etc_systemd}/controllerconfig.service
@@ -89,7 +89,7 @@ rm -rf $RPM_BUILD_ROOT
%{local_goenabledd}/*
%{local_etc_initd}/*
%dir %{local_etc_upgraded}
%{local_etc_upgraded}/*
# %{local_etc_upgraded}/*
%{local_etc_systemd}/*
%package wheels
@@ -52,6 +52,7 @@ LOG = log.getLogger(__name__)
POSTGRES_MOUNT_PATH = '/mnt/postgresql'
POSTGRES_DUMP_MOUNT_PATH = '/mnt/db_dump'
DB_CONNECTION_FORMAT = "connection=postgresql://%s:%s@127.0.0.1/%s\n"
DB_BARBICAN_CONNECTION_FORMAT = "postgresql://%s:%s@127.0.0.1/%s"
restore_patching_complete = '/etc/platform/.restore_patching_complete'
restore_compute_ready = '/var/run/.restore_compute_ready'
@@ -127,7 +128,10 @@ def get_connection_string(db_credentials, database):
""" Generates a connection string for a given database"""
username = db_credentials[database]['username']
password = db_credentials[database]['password']
return DB_CONNECTION_FORMAT % (username, password, database)
if database == 'barbican':
return DB_BARBICAN_CONNECTION_FORMAT % (username, password, database)
else:
return DB_CONNECTION_FORMAT % (username, password, database)
def create_temp_filesystem(vgname, lvname, mountpoint, size):
@@ -425,45 +429,44 @@ def create_databases(from_release, to_release, db_credentials):
""" Creates databases. """
LOG.info("Creating new databases")
if from_release == '18.03':
# Create databases that are new in this release
# Create databases that are new in this release
conn = psycopg2.connect('dbname=postgres user=postgres')
conn = psycopg2.connect('dbname=postgres user=postgres')
# Postgres won't allow transactions around database create operations
# so we set the connection to autocommit
conn.set_isolation_level(
psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
# Postgres won't allow transactions around database create operations
# so we set the connection to autocommit
conn.set_isolation_level(
psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
databases_to_create = []
if not databases_to_create:
return
databases_to_create = []
if not databases_to_create:
return
with conn:
with conn.cursor() as cur:
for database in databases_to_create:
print("Creating %s database" % database)
username = psycopg2.extensions.AsIs(
'\"%s\"' % db_credentials[database]['username'])
db_name = psycopg2.extensions.AsIs('\"%s\"' % database)
password = db_credentials[database]['password']
with conn:
with conn.cursor() as cur:
for database in databases_to_create:
print("Creating %s database" % database)
username = psycopg2.extensions.AsIs(
'\"%s\"' % db_credentials[database]['username'])
db_name = psycopg2.extensions.AsIs('\"%s\"' % database)
password = db_credentials[database]['password']
try:
# Here we create the new database and the role for it
# The role will be used by the dbsync command to
# connect to the database. This ensures any new tables
# are added with the correct owner
cur.execute('CREATE DATABASE %s', (db_name,))
cur.execute('CREATE ROLE %s', (username,))
cur.execute('ALTER ROLE %s LOGIN PASSWORD %s',
(username, password))
cur.execute('GRANT ALL ON DATABASE %s TO %s',
(db_name, username))
except Exception as ex:
LOG.exception("Failed to create database and role. " +
"(%s : %s) Exception: %s" %
(database, username, ex))
raise
try:
# Here we create the new database and the role for it
# The role will be used by the dbsync command to
# connect to the database. This ensures any new tables
# are added with the correct owner
cur.execute('CREATE DATABASE %s', (db_name,))
cur.execute('CREATE ROLE %s', (username,))
cur.execute('ALTER ROLE %s LOGIN PASSWORD %s',
(username, password))
cur.execute('GRANT ALL ON DATABASE %s TO %s',
(db_name, username))
except Exception as ex:
LOG.exception("Failed to create database and role. " +
"(%s : %s) Exception: %s" %
(database, username, ex))
raise
def migrate_sysinv_database():
@@ -497,15 +500,11 @@ def migrate_databases(from_release, shared_services, db_credentials,
f.write("[database]\n")
f.write(get_connection_string(db_credentials, 'keystone'))
with open("/etc/barbican/barbican-dbsync.conf", "w") as f:
f.write("[database]\n")
f.write(get_connection_string(db_credentials, 'barbican'))
migrate_commands = [
# Migrate barbican
('barbican',
'barbican-manage --config-file /etc/barbican/barbican-dbsync.conf ' +
'db upgrade'),
'barbican-manage db upgrade ' +
'--db-url %s' % get_connection_string(db_credentials, 'barbican')),
]
if sysinv_constants.SERVICE_TYPE_IDENTITY not in shared_services:
@@ -616,20 +615,19 @@ def migrate_hiera_data(from_release, to_release):
shutil.copy(os.path.join(from_hiera_path, f), to_hiera_path)
# Make any necessary updates to the static yaml files.
if from_release == "18.03":
# Update the static.yaml file
static_file = os.path.join(constants.HIERADATA_PERMDIR, "static.yaml")
with open(static_file, 'r') as yaml_file:
static_config = yaml.load(yaml_file)
static_config.update({
'platform::params::software_version': SW_VERSION,
'platform::client::credentials::params::keyring_directory':
KEYRING_PATH,
'platform::client::credentials::params::keyring_file':
os.path.join(KEYRING_PATH, '.CREDENTIAL'),
})
with open(static_file, 'w') as yaml_file:
yaml.dump(static_config, yaml_file, default_flow_style=False)
# Update the static.yaml file
static_file = os.path.join(constants.HIERADATA_PERMDIR, "static.yaml")
with open(static_file, 'r') as yaml_file:
static_config = yaml.load(yaml_file)
static_config.update({
'platform::params::software_version': SW_VERSION,
'platform::client::credentials::params::keyring_directory':
KEYRING_PATH,
'platform::client::credentials::params::keyring_file':
os.path.join(KEYRING_PATH, '.CREDENTIAL'),
})
with open(static_file, 'w') as yaml_file:
yaml.dump(static_config, yaml_file, default_flow_style=False)
def upgrade_controller(from_release, to_release):
@@ -26,32 +26,12 @@ LOG = log.getLogger(__name__)
def get_upgrade_databases(shared_services):
UPGRADE_DATABASES = ('postgres', 'template1', 'nova', 'sysinv',
'ceilometer', 'neutron', 'heat', 'nova_api', 'aodh',
'magnum', 'ironic', 'barbican')
UPGRADE_DATABASES = ('postgres', 'template1', 'sysinv',
'barbican')
UPGRADE_DATABASE_SKIP_TABLES = {'postgres': (), 'template1': (),
'heat': (), 'nova': (), 'nova_api': (),
'sysinv': ('i_alarm',),
'neutron': (),
'aodh': (),
'magnum': (),
'ironic': (),
'barbican': (),
'ceilometer': ('metadata_bool',
'metadata_float',
'metadata_int',
'metadata_text',
'meter', 'sample', 'fault',
'resource')}
if sysinv_constants.SERVICE_TYPE_VOLUME not in shared_services:
UPGRADE_DATABASES += ('cinder',)
UPGRADE_DATABASE_SKIP_TABLES.update({'cinder': ()})
if sysinv_constants.SERVICE_TYPE_IMAGE not in shared_services:
UPGRADE_DATABASES += ('glance',)
UPGRADE_DATABASE_SKIP_TABLES.update({'glance': ()})
'barbican': ()}
if sysinv_constants.SERVICE_TYPE_IDENTITY not in shared_services:
UPGRADE_DATABASES += ('keystone',)
@@ -257,12 +237,10 @@ def abort_upgrade(from_load, to_load, upgrade):
os.path.join(utils.POSTGRES_PATH, "upgrade"),
os.path.join(utils.POSTGRES_PATH, to_load),
os.path.join(utils.RABBIT_PATH, to_load),
os.path.join(tsc.PLATFORM_PATH, "ironic", to_load),
os.path.join(tsc.PLATFORM_PATH, "nfv/vim", to_load),
os.path.join(tsc.PLATFORM_PATH, ".keyring", to_load),
os.path.join(tsc.PLATFORM_PATH, "puppet", to_load),
os.path.join(tsc.PLATFORM_PATH, "sysinv", to_load),
os.path.join(tsc.PLATFORM_PATH, "ceilometer", to_load),
os.path.join(tsc.CONFIG_PATH, 'upgrades')
]
@@ -328,16 +306,12 @@ def complete_upgrade(from_load, to_load):
os.path.join(utils.POSTGRES_PATH, "upgrade"),
os.path.join(utils.POSTGRES_PATH, from_load),
os.path.join(utils.RABBIT_PATH, from_load),
os.path.join(tsc.PLATFORM_PATH, "ironic", from_load),
os.path.join(tsc.PLATFORM_PATH, "nfv/vim", from_load),
os.path.join(tsc.PLATFORM_PATH, ".keyring", from_load),
os.path.join(tsc.PLATFORM_PATH, "puppet", from_load),
os.path.join(tsc.PLATFORM_PATH, "sysinv", from_load),
]
upgrade_dirs.append(
os.path.join(tsc.PLATFORM_PATH, "ceilometer", from_load))
for directory in upgrade_dirs:
try:
shutil.rmtree(directory)
@@ -1,133 +0,0 @@
#!/usr/bin/python
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script will remove all neutron bindings from controller-1.
# This is necessary to match the behaviour on controller-1 after
# the host is locked.
# This should be removed once we support data migration upon a
# swact to controller-1 during an upgrade.
import psycopg2
import sys
from psycopg2.extras import RealDictCursor
from oslo_log import log
LOG = log.getLogger(__name__)
def main():
action = None
from_release = None
to_release = None # noqa
arg = 1
while arg < len(sys.argv):
if arg == 1:
from_release = sys.argv[arg]
elif arg == 2:
to_release = sys.argv[arg] # noqa
elif arg == 3:
action = sys.argv[arg]
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
log.configure()
if from_release == "18.03" and action == "migrate":
try:
move_routers_off_controller_1()
move_networks_off_controller_1()
move_port_bindings_off_controller_1()
move_dhcp_port_device_id_off_controller_1()
move_distributed_port_bindings_off_controller_1()
except Exception as ex:
LOG.exception(ex)
print(ex)
return 1
def run_cmd_postgres(cmd):
"""
This executes the given command as user postgres. This is necessary when
this script is run as root, which is the case on an upgrade activation.
"""
neutron_conn = psycopg2.connect("dbname=neutron user=postgres")
with neutron_conn:
with neutron_conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute(cmd)
LOG.info("Executing '%s'" % cmd)
def move_routers_off_controller_1():
"""
This function moves all routers hosted on controller-1 to controller-0.
This is required to match the DB state after controller-1 is locked as
part of the upgrade, at which point they will be automatically reschduled.
"""
cmd = ("UPDATE routerl3agentbindings SET l3_agent_id="
"(SELECT id FROM agents WHERE agent_type='L3 agent'"
" AND host='controller-0') WHERE l3_agent_id IN"
" (SELECT id FROM agents WHERE agent_type='L3 agent'"
" AND host='controller-1') AND (SELECT count(id)"
" FROM agents WHERE agent_type='L3 agent'"
" AND host='controller-0')=1;")
run_cmd_postgres(cmd)
def move_networks_off_controller_1():
"""
This function moves all dhcp bindings from controller-1 to controller-0.
This is required to match the DB state after controller-1 is locked as
part of the upgrade, at which point they will be automatically reschduled.
"""
cmd = ("UPDATE networkdhcpagentbindings SET dhcp_agent_id="
"(SELECT id FROM agents WHERE agent_type='DHCP agent'"
" AND host='controller-0') WHERE dhcp_agent_id IN"
" (SELECT id FROM agents WHERE agent_type='DHCP agent'"
" AND host='controller-1') AND (SELECT count(id)"
" FROM agents WHERE agent_type='DHCP agent'"
" AND host='controller-0')=1;")
run_cmd_postgres(cmd)
def move_dhcp_port_device_id_off_controller_1():
"""
This function updates all dhcp ports' device IDs bound to controller-0
over to controller-1. Note that because the prefix is based on hostname,
this prefix is constant for both controllers.
controller-0: "dhcpaebe17f8-776d-5ab6-9a5f-e9bdeeaca66f"
controller-1: "dhcpf42f2830-b2ec-5a2c-93f3-e3e3328e20a3"
"""
cmd = ("UPDATE ports SET device_id ="
" REPLACE(device_id,"
" 'dhcpf42f2830-b2ec-5a2c-93f3-e3e3328e20a3',"
" 'dhcpaebe17f8-776d-5ab6-9a5f-e9bdeeaca66f')"
" WHERE device_owner = 'network:dhcp';")
run_cmd_postgres(cmd)
def move_port_bindings_off_controller_1():
"""
This function moves all port bindings from controller-1 to controller-0.
"""
cmd = ("UPDATE ml2_port_bindings SET host='controller-0'"
" WHERE host='controller-1';")
run_cmd_postgres(cmd)
def move_distributed_port_bindings_off_controller_1():
"""
This function deletes all ml2_distributed_port_bindings on contorller-1.
"""
cmd = ("DELETE FROM ml2_distributed_port_bindings"
" WHERE host='controller-1';")
run_cmd_postgres(cmd)
if __name__ == "__main__":
sys.exit(main())
@@ -1,104 +0,0 @@
#!/usr/bin/python
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# This script will update the storage backends for controller-1.
#
import json
import psycopg2
import sys
from sysinv.common import constants
from psycopg2.extras import RealDictCursor
from oslo_log import log
LOG = log.getLogger(__name__)
# Sections that need to be removed from retired Ceph cache tiering feature
SERVICE_PARAM_SECTION_CEPH_CACHE_TIER = 'cache_tiering'
SERVICE_PARAM_SECTION_CEPH_CACHE_TIER_DESIRED = 'cache_tiering.desired'
SERVICE_PARAM_SECTION_CEPH_CACHE_TIER_APPLIED = 'cache_tiering.applied'
def main():
action = None
from_release = None
to_release = None # noqa
arg = 1
while arg < len(sys.argv):
if arg == 1:
from_release = sys.argv[arg]
elif arg == 2:
to_release = sys.argv[arg] # noqa
elif arg == 3:
action = sys.argv[arg]
else:
print("Invalid option %s." % sys.argv[arg])
return 1
arg += 1
log.configure()
if from_release == "18.03" and action == "migrate":
try:
cleanup_ceph_cache_tiering_service_parameters(from_release)
cleanup_ceph_personality_subtype(from_release)
except Exception as ex:
LOG.exception(ex)
return 1
def cleanup_ceph_cache_tiering_service_parameters(from_release):
conn = psycopg2.connect("dbname=sysinv user=postgres")
with conn:
with conn.cursor(cursor_factory=RealDictCursor) as cur:
for s in [SERVICE_PARAM_SECTION_CEPH_CACHE_TIER,
SERVICE_PARAM_SECTION_CEPH_CACHE_TIER_DESIRED,
SERVICE_PARAM_SECTION_CEPH_CACHE_TIER_APPLIED]:
cur.execute("select * from service_parameter where service=%s "
"and section=%s", (constants.SERVICE_TYPE_CEPH,
s,))
parameters = cur.fetchall()
if not parameters:
LOG.info("No service_parameter data for section %s "
"found." % s)
continue
for p in parameters:
LOG.debug("Found %s/%s" % (p['section'], p['name']))
LOG.info("Removing ceph service parameters from section "
"%s" % s)
cur.execute("delete from service_parameter where service=%s "
"and section=%s", (constants.SERVICE_TYPE_CEPH,
s,))
def cleanup_ceph_personality_subtype(from_release):
conn = psycopg2.connect("dbname=sysinv user=postgres")
with conn:
with conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute("select hostname, capabilities from i_host")
parameters = cur.fetchall()
if not parameters:
LOG.info("No capabilities data found ")
return
for p in parameters:
LOG.debug("Found host capabilities %s/%s" %
(p['hostname'], p['capabilities']))
json_dict = json.loads(p['capabilities'])
if 'pers_subtype' in json_dict:
del json_dict['pers_subtype']
LOG.info("Removing ceph pers_subtype from capabilities")
cur.execute("update i_host set capabilities='%s';" %
json.dumps(json_dict))
if __name__ == "__main__":
sys.exit(main())
@@ -65,7 +65,7 @@ install -p -D -m 755 scripts/controller_config %{buildroot}%{local_etc_initd}/co
# Install Upgrade scripts
install -d -m 755 %{buildroot}%{local_etc_upgraded}
install -p -D -m 755 upgrade-scripts/* %{buildroot}%{local_etc_upgraded}/
# install -p -D -m 755 upgrade-scripts/* %{buildroot}%{local_etc_upgraded}/
install -p -D -m 664 scripts/controllerconfig.service %{buildroot}%{_unitdir}/controllerconfig.service
@@ -96,7 +96,7 @@ rm -rf $RPM_BUILD_ROOT
%{local_goenabledd}/*
%{local_etc_initd}/*
%dir %{local_etc_upgraded}
%{local_etc_upgraded}/*
# %{local_etc_upgraded}/*
%{_unitdir}/*
#%%package wheels
@@ -2670,7 +2670,8 @@ class HostController(rest.RestController):
# Set upgrade flag so controller-1 will upgrade after install
# This flag is guaranteed to be written on controller-0, since
# controller-1 must be locked to run the host-upgrade command.
open(tsc.CONTROLLER_UPGRADE_FLAG, "w").close()
# perform rpc to conductor to do the update with root privilege access
pecan.request.rpcapi.update_controller_upgrade_flag(pecan.request.context)
return Host.convert_with_links(rpc_ihost)
+1 -1
View File
@@ -154,7 +154,7 @@ class Health(object):
def _check_license(self, version):
"""Validates the current license is valid for the specified version"""
check_binary = "/usr/bin/sm-license-check"
check_binary = "/usr/bin/verify-license"
license_file = '/etc/platform/.license'
system = self._dbapi.isystem_get_one()
system_type = system.system_type
@@ -5883,6 +5883,12 @@ class ConductorManager(service.PeriodicService):
}
self._config_apply_runtime_manifest(context, config_uuid, config_dict)
def update_controller_upgrade_flag(self, context):
"""Update the controller upgrade flag"""
LOG.info("update_controller_upgrade_flag")
cutils.touch(tsc.CONTROLLER_UPGRADE_FLAG)
def update_storage_config(self, context,
update_storage=False,
reinstall_required=False,
@@ -9161,31 +9167,6 @@ class ConductorManager(service.PeriodicService):
controller_0 = self.dbapi.ihost_get_by_hostname(
constants.CONTROLLER_0_HOSTNAME)
# TODO: This code is only useful for supporting R5 to R6 upgrades.
# Remove in future release.
# update crushmap and remove cache-tier on upgrade
if from_version == tsc.SW_VERSION_1803:
ceph_backend = StorageBackendConfig.get_backend(self.dbapi, constants.CINDER_BACKEND_CEPH)
if ceph_backend and ceph_backend.state == constants.SB_STATE_CONFIGURED:
try:
response, body = self._ceph_api.osd_crush_rule_rm("cache_tier_ruleset",
body='json')
if response.ok:
LOG.info("Successfully removed cache_tier_ruleset "
"[ceph osd crush rule rm cache_tier_ruleset]")
try:
response, body = self._ceph_api.osd_crush_remove("cache-tier",
body='json')
if response.ok:
LOG.info("Successfully removed cache_tier "
"[ceph osd crush remove cache-tier]")
except exception.CephFailure:
LOG.warn("Failed to remove bucket cache-tier from crushmap")
pass
except exception.CephFailure:
LOG.warn("Failed to remove rule cache-tier from crushmap")
pass
if state in [constants.UPGRADE_ABORTING,
constants.UPGRADE_ABORTING_ROLLBACK]:
if upgrade.state != constants.UPGRADE_ABORT_COMPLETING:
@@ -787,6 +787,14 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
"""
return self.call(context, self.make_msg('update_user_config'))
def update_controller_upgrade_flag(self, context):
"""Synchronously, have a conductor update controller upgrade flag
:param context: request context
"""
return self.call(context,
self.make_msg('update_controller_upgrade_flag'))
def update_storage_config(self, context, update_storage=False,
reinstall_required=False, reboot_required=True,
filesystem_list=None):
@@ -16,9 +16,6 @@ from sysinv.puppet import base
HOSTNAME_CLUSTER_HOST_SUFFIX = '-cluster-host'
NOVA_UPGRADE_LEVEL_PIKE = 'pike'
NOVA_UPGRADE_LEVELS = {'18.03': NOVA_UPGRADE_LEVEL_PIKE}
class PlatformPuppet(base.BasePuppet):
"""Class to encapsulate puppet operations for platform configuration"""
@@ -64,7 +61,6 @@ class PlatformPuppet(base.BasePuppet):
config.update(self._get_host_ptp_config(host))
config.update(self._get_host_sysctl_config(host))
config.update(self._get_host_drbd_config(host))
config.update(self._get_host_upgrade_config(host))
config.update(self._get_host_tpm_config(host))
config.update(self._get_host_cpu_config(host))
config.update(self._get_host_memory_config(host))
@@ -176,40 +172,6 @@ class PlatformPuppet(base.BasePuppet):
'platform::config::params::hosts': hosts
}
def _get_host_upgrade_config(self, host):
config = {}
try:
upgrade = self.dbapi.software_upgrade_get_one()
except exception.NotFound:
return config
upgrade_states = [constants.UPGRADE_ACTIVATING,
constants.UPGRADE_ACTIVATION_FAILED,
constants.UPGRADE_ACTIVATION_COMPLETE,
constants.UPGRADE_COMPLETED]
# we don't need compatibility mode after we activate
if upgrade.state in upgrade_states:
return config
upgrade_load_id = upgrade.to_load
host_upgrade = self.dbapi.host_upgrade_get_by_host(host['id'])
if host_upgrade.target_load == upgrade_load_id:
from_load = self.dbapi.load_get(upgrade.from_load)
sw_version = from_load.software_version
nova_level = NOVA_UPGRADE_LEVELS.get(sw_version)
if not nova_level:
raise exception.SysinvException(
("No matching upgrade level found for version %s")
% sw_version)
config.update({
'nova::upgrade_level_compute': nova_level
})
return config
def _get_amqp_config(self):
return {
'platform::amqp::params::host':