179 lines
6.6 KiB
Python
179 lines
6.6 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import logging
|
|
import re
|
|
import shutil
|
|
import time
|
|
|
|
from distutils import version
|
|
|
|
from octane import magic_consts
|
|
from octane.util import env as env_util
|
|
from octane.util import node as node_util
|
|
from octane.util import ssh
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
def get_databases(env):
|
|
node = env_util.get_one_controller(env)
|
|
with ssh.popen([
|
|
'sudo', '-iu', 'root',
|
|
'mysql',
|
|
'--batch',
|
|
'--skip-column-names',
|
|
'--host', 'localhost',
|
|
], stdin=ssh.PIPE, stdout=ssh.PIPE, node=node) as proc:
|
|
proc.stdin.write('SHOW DATABASES')
|
|
out = proc.communicate()[0]
|
|
return out.splitlines()
|
|
|
|
|
|
def does_perform_flavor_data_migration(env):
|
|
env_version = version.StrictVersion(env.data["fuel_version"])
|
|
return env_version == \
|
|
version.StrictVersion(magic_consts.NOVA_FLAVOR_DATA_MIGRATION_VERSION)
|
|
|
|
|
|
def nova_migrate_flavor_data(env, attempts=20, attempt_delay=30):
|
|
node = env_util.get_one_controller(env)
|
|
for i in xrange(attempts):
|
|
output = ssh.call_output(['nova-manage', 'db', 'migrate_flavor_data'],
|
|
node=node, parse_levels=True)
|
|
match = FLAVOR_STATUS_RE.match(output)
|
|
if match is None:
|
|
raise Exception(
|
|
"The format of the migrate_flavor_data command was changed: "
|
|
"'{0}'".format(output))
|
|
params = match.groupdict()
|
|
matched = int(params["matched"])
|
|
completed = int(params["completed"])
|
|
if matched == 0 or matched == completed:
|
|
LOG.info("All flavors were successfully migrated.")
|
|
return
|
|
LOG.debug("Trying to migrate flavors data, iteration %s: %s matches, "
|
|
"%s completed.", i, matched, completed)
|
|
time.sleep(attempt_delay)
|
|
raise Exception(
|
|
"After {0} attempts flavors data migration is still not completed."
|
|
.format(attempts))
|
|
|
|
FLAVOR_STATUS_RE = re.compile(
|
|
r"^(?P<matched>[0-9]+) instances matched query, "
|
|
"(?P<completed>[0-9]+) completed$")
|
|
|
|
|
|
def does_perform_cinder_volume_update_host(env):
|
|
env_version = version.StrictVersion(env.data["fuel_version"])
|
|
return env_version == \
|
|
version.StrictVersion(magic_consts.CINDER_UPDATE_VOLUME_HOST_VERSION)
|
|
|
|
|
|
def cinder_volume_update_host(orig_env, new_env):
|
|
orig_controller = env_util.get_one_controller(orig_env)
|
|
new_controller = env_util.get_one_controller(new_env)
|
|
current_host = get_current_host(orig_controller)
|
|
new_host = get_new_host(new_controller)
|
|
ssh.call(["cinder-manage", "volume", "update_host",
|
|
"--currenthost", current_host,
|
|
"--newhost", new_host],
|
|
node=new_controller, parse_levels=True)
|
|
|
|
|
|
def get_current_host(node):
|
|
parameters = node_util.get_parameters(node, magic_consts.CINDER_CONF, {
|
|
"host": [("DEFAULT", "host")],
|
|
"backend": [("DEFAULT", "volume_backend_name")],
|
|
})
|
|
# NOTE(akscram): result = "rbd:volumes#DEFAULT"
|
|
result = "{host}#{backend}".format(
|
|
host=parameters["host"],
|
|
backend=parameters["backend"],
|
|
)
|
|
return result
|
|
|
|
|
|
def get_new_host(node):
|
|
parameters = node_util.get_parameters(node, magic_consts.CINDER_CONF, {
|
|
"host": [("DEFAULT", "host"), ("RBD-backend", "backend_host")],
|
|
"backend": [("RBD-backend", "volume_backend_name")],
|
|
})
|
|
# NOTE(akscram): result = "rbd:volumes@RBD-backend#RBD-backend"
|
|
result = "{host}@{backend}#RBD-backend".format(
|
|
host=parameters["host"],
|
|
backend=parameters["backend"],
|
|
)
|
|
return result
|
|
|
|
|
|
def mysqldump_from_env(env, role_name, dbs, fname):
|
|
node = env_util.get_one_node_of(env, role_name)
|
|
cmd = [
|
|
'bash', '-c',
|
|
'set -o pipefail; ' + # We want to fail if mysqldump fails
|
|
'sudo -iu root '
|
|
'mysqldump --add-drop-database --lock-all-tables '
|
|
'--host localhost '
|
|
'--databases {0}'.format(' '.join(dbs)) +
|
|
' | gzip',
|
|
]
|
|
with ssh.popen(cmd, stdout=ssh.PIPE, node=node) as proc:
|
|
with open(fname, 'wb') as local_file:
|
|
shutil.copyfileobj(proc.stdout, local_file)
|
|
|
|
|
|
def mysqldump_restore_to_env(env, role_name, fname):
|
|
node = env_util.get_one_node_of(env, role_name)
|
|
with open(fname, 'rb') as local_file:
|
|
with ssh.popen(['sh', '-c', 'zcat | sudo -iu root mysql'],
|
|
stdin=ssh.PIPE, node=node) as proc:
|
|
shutil.copyfileobj(local_file, proc.stdin)
|
|
|
|
|
|
def fix_neutron_migrations(node):
|
|
add_networksecuritybindings_sql = \
|
|
"INSERT INTO networksecuritybindings " \
|
|
"SELECT id, 1 " \
|
|
"FROM networks " \
|
|
"WHERE id NOT IN (SELECT network_id FROM networksecuritybindings);"
|
|
update_network_segments_sql = \
|
|
"UPDATE ml2_network_segments " \
|
|
"SET network_type='flat',physical_network='physnet1' " \
|
|
"WHERE network_id IN (SELECT network_id FROM externalnetworks);"
|
|
insert_physnet1 = \
|
|
"INSERT INTO ml2_flat_allocations " \
|
|
"SELECT b.* FROM (SELECT 'physnet1') AS b " \
|
|
"WHERE NOT EXISTS (" \
|
|
"SELECT 1 FROM ml2_flat_allocations " \
|
|
"WHERE physical_network = 'physnet1'" \
|
|
");"
|
|
cmd = ['sudo', '-iu', 'root', 'mysql', 'neutron']
|
|
with ssh.popen(cmd, node=node, stdin=ssh.PIPE) as proc:
|
|
proc.stdin.write(add_networksecuritybindings_sql)
|
|
proc.stdin.write(insert_physnet1)
|
|
proc.stdin.write(update_network_segments_sql)
|
|
|
|
|
|
def db_sync(env):
|
|
node = env_util.get_one_controller(env)
|
|
ssh.call(['keystone-manage', 'db_sync'], node=node, parse_levels=True)
|
|
ssh.call(['nova-manage', 'db', 'sync'], node=node, parse_levels=True)
|
|
ssh.call(['nova-manage', 'api_db', 'sync'], node=node, parse_levels=True)
|
|
ssh.call(['heat-manage', 'db_sync'], node=node, parse_levels=True)
|
|
ssh.call(['glance-manage', 'db_sync'], node=node, parse_levels=True)
|
|
ssh.call(['neutron-db-manage', '--config-file=/etc/neutron/neutron.conf',
|
|
'upgrade', 'head'], node=node, parse_levels='^(?P<level>[A-Z]+)')
|
|
fix_neutron_migrations(node)
|
|
ssh.call(['cinder-manage', 'db', 'sync'], node=node, parse_levels=True)
|