772 lines
25 KiB
Python
772 lines
25 KiB
Python
#!/usr/bin/python
|
|
|
|
#
|
|
# Copyright (c) 2019 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
# OpenStack Keystone and Sysinv interactions
|
|
#
|
|
|
|
import os
|
|
import pyudev
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
# The following imports are to make use of the OpenStack cgtsclient and some
|
|
# constants in controllerconfig. When it is time to remove/deprecate these
|
|
# packages, classes OpenStack, Token and referenced constants need to be moved
|
|
# to this standalone script.
|
|
from controllerconfig import ConfigFail
|
|
from controllerconfig.common import constants
|
|
from controllerconfig import openstack
|
|
from controllerconfig import sysinv_api as sysinv
|
|
|
|
from netaddr import IPNetwork
|
|
from sysinv.common import constants as sysinv_constants
|
|
|
|
try:
|
|
from ConfigParser import ConfigParser
|
|
except ImportError:
|
|
from configparser import ConfigParser
|
|
|
|
|
|
COMBINED_LOAD = 'All-in-one'
|
|
RECONFIGURE_SYSTEM = False
|
|
RECONFIGURE_NETWORK = False
|
|
RECONFIGURE_SERVICE = False
|
|
INITIAL_POPULATION = True
|
|
CONF = ConfigParser()
|
|
|
|
|
|
def wait_system_config(client):
|
|
for _ in range(constants.SYSTEM_CONFIG_TIMEOUT):
|
|
try:
|
|
systems = client.sysinv.isystem.list()
|
|
if systems:
|
|
# only one system (default)
|
|
return systems[0]
|
|
except Exception:
|
|
pass
|
|
time.sleep(1)
|
|
else:
|
|
raise ConfigFail('Timeout waiting for default system '
|
|
'configuration')
|
|
|
|
|
|
def populate_system_config(client):
|
|
if not INITIAL_POPULATION and not RECONFIGURE_SYSTEM:
|
|
return
|
|
# Wait for pre-populated system
|
|
system = wait_system_config(client)
|
|
|
|
if INITIAL_POPULATION:
|
|
print("Populating system config...")
|
|
else:
|
|
print("Updating system config...")
|
|
# Update system attributes
|
|
capabilities = {'region_config': False,
|
|
'vswitch_type': 'none',
|
|
'shared_services': '[]',
|
|
'sdn_enabled': False,
|
|
'https_enabled': False,
|
|
'kubernetes_enabled': True}
|
|
|
|
values = {
|
|
'system_mode': CONF.get('BOOTSTRAP_CONFIG', 'SYSTEM_MODE'),
|
|
'capabilities': capabilities,
|
|
'timezone': CONF.get('BOOTSTRAP_CONFIG', 'TIMEZONE'),
|
|
'region_name': 'RegionOne',
|
|
'service_project_name': 'services'
|
|
}
|
|
|
|
if INITIAL_POPULATION:
|
|
values.update(
|
|
{'system_type': CONF.get('BOOTSTRAP_CONFIG', 'SYSTEM_TYPE')}
|
|
)
|
|
|
|
patch = sysinv.dict_to_patch(values)
|
|
client.sysinv.isystem.update(system.uuid, patch)
|
|
|
|
|
|
def populate_load_config(client):
|
|
if not INITIAL_POPULATION:
|
|
return
|
|
print("Populating load config...")
|
|
patch = {'software_version': CONF.get('BOOTSTRAP_CONFIG', 'SW_VERSION'),
|
|
'compatible_version': "N/A",
|
|
'required_patches': "N/A"}
|
|
client.sysinv.load.create(**patch)
|
|
|
|
|
|
def delete_network_and_addrpool(client, network_name):
|
|
networks = client.sysinv.network.list()
|
|
network_uuid = addrpool_uuid = None
|
|
for network in networks:
|
|
if network.name == network_name:
|
|
network_uuid = network.uuid
|
|
addrpool_uuid = network.pool_uuid
|
|
if network_uuid:
|
|
print("Deleting network and address pool for network %s..." %
|
|
network_name)
|
|
host = client.sysinv.ihost.get('controller-0')
|
|
host_addresses = client.sysinv.address.list_by_host(host.uuid)
|
|
for addr in host_addresses:
|
|
print("Deleting address %s" % addr.uuid)
|
|
client.sysinv.address.delete(addr.uuid)
|
|
client.sysinv.network.delete(network_uuid)
|
|
client.sysinv.address_pool.delete(addrpool_uuid)
|
|
|
|
|
|
def populate_mgmt_network(client):
|
|
management_subnet = IPNetwork(
|
|
CONF.get('BOOTSTRAP_CONFIG', 'MANAGEMENT_SUBNET'))
|
|
start_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'MANAGEMENT_START_ADDRESS')
|
|
end_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'MANAGEMENT_END_ADDRESS')
|
|
dynamic_allocation = CONF.getboolean(
|
|
'BOOTSTRAP_CONFIG', 'DYNAMIC_ADDRESS_ALLOCATION')
|
|
|
|
if RECONFIGURE_NETWORK:
|
|
delete_network_and_addrpool(client, 'mgmt')
|
|
print("Updating management network...")
|
|
else:
|
|
print("Populating management network...")
|
|
|
|
# create the address pool
|
|
values = {
|
|
'name': 'management',
|
|
'network': str(management_subnet.network),
|
|
'prefix': management_subnet.prefixlen,
|
|
'ranges': [(start_address, end_address)],
|
|
}
|
|
pool = client.sysinv.address_pool.create(**values)
|
|
|
|
# create the network for the pool
|
|
values = {
|
|
'type': sysinv_constants.NETWORK_TYPE_MGMT,
|
|
'name': sysinv_constants.NETWORK_TYPE_MGMT,
|
|
'dynamic': dynamic_allocation,
|
|
'pool_uuid': pool.uuid,
|
|
}
|
|
|
|
client.sysinv.network.create(**values)
|
|
|
|
|
|
def populate_pxeboot_network(client):
|
|
pxeboot_subnet = IPNetwork(CONF.get('BOOTSTRAP_CONFIG', 'PXEBOOT_SUBNET'))
|
|
start_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'PXEBOOT_START_ADDRESS')
|
|
end_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'PXEBOOT_END_ADDRESS')
|
|
|
|
if RECONFIGURE_NETWORK:
|
|
delete_network_and_addrpool(client, 'pxeboot')
|
|
print("Updating pxeboot network...")
|
|
else:
|
|
print("Populating pxeboot network...")
|
|
|
|
# create the address pool
|
|
values = {
|
|
'name': 'pxeboot',
|
|
'network': str(pxeboot_subnet.network),
|
|
'prefix': pxeboot_subnet.prefixlen,
|
|
'ranges': [(start_address, end_address)],
|
|
}
|
|
pool = client.sysinv.address_pool.create(**values)
|
|
|
|
# create the network for the pool
|
|
values = {
|
|
'type': sysinv_constants.NETWORK_TYPE_PXEBOOT,
|
|
'name': sysinv_constants.NETWORK_TYPE_PXEBOOT,
|
|
'dynamic': True,
|
|
'pool_uuid': pool.uuid,
|
|
}
|
|
client.sysinv.network.create(**values)
|
|
|
|
|
|
def populate_infra_network(client):
|
|
return
|
|
|
|
|
|
def populate_oam_network(client):
|
|
external_oam_subnet = IPNetwork(CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'EXTERNAL_OAM_SUBNET'))
|
|
start_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'EXTERNAL_OAM_START_ADDRESS')
|
|
end_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'EXTERNAL_OAM_END_ADDRESS')
|
|
|
|
if RECONFIGURE_NETWORK:
|
|
delete_network_and_addrpool(client, 'oam')
|
|
print("Updating oam network...")
|
|
else:
|
|
print("Populating oam network...")
|
|
|
|
# create the address pool
|
|
values = {
|
|
'name': 'oam',
|
|
'network': str(external_oam_subnet.network),
|
|
'prefix': external_oam_subnet.prefixlen,
|
|
'ranges': [(start_address, end_address)],
|
|
'floating_address': CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'EXTERNAL_OAM_FLOATING_ADDRESS'),
|
|
}
|
|
|
|
system_mode = CONF.get('BOOTSTRAP_CONFIG', 'SYSTEM_MODE')
|
|
if system_mode != sysinv_constants.SYSTEM_MODE_SIMPLEX:
|
|
values.update({
|
|
'controller0_address': CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'EXTERNAL_OAM_0_ADDRESS'),
|
|
'controller1_address': CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'EXTERNAL_OAM_1_ADDRESS'),
|
|
})
|
|
values.update({
|
|
'gateway_address': CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'EXTERNAL_OAM_GATEWAY_ADDRESS'),
|
|
})
|
|
pool = client.sysinv.address_pool.create(**values)
|
|
|
|
# create the network for the pool
|
|
values = {
|
|
'type': sysinv_constants.NETWORK_TYPE_OAM,
|
|
'name': sysinv_constants.NETWORK_TYPE_OAM,
|
|
'dynamic': False,
|
|
'pool_uuid': pool.uuid,
|
|
}
|
|
|
|
client.sysinv.network.create(**values)
|
|
|
|
|
|
def populate_multicast_network(client):
|
|
management_multicast_subnet = IPNetwork(CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'MANAGEMENT_MULTICAST_SUBNET'))
|
|
start_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'MANAGEMENT_MULTICAST_START_ADDRESS')
|
|
end_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'MANAGEMENT_MULTICAST_END_ADDRESS')
|
|
|
|
if RECONFIGURE_NETWORK:
|
|
delete_network_and_addrpool(client, 'multicast')
|
|
print("Updating multicast network...")
|
|
else:
|
|
print("Populating multicast network...")
|
|
|
|
# create the address pool
|
|
values = {
|
|
'name': 'multicast-subnet',
|
|
'network': str(management_multicast_subnet.network),
|
|
'prefix': management_multicast_subnet.prefixlen,
|
|
'ranges': [(start_address, end_address)],
|
|
}
|
|
pool = client.sysinv.address_pool.create(**values)
|
|
|
|
# create the network for the pool
|
|
values = {
|
|
'type': sysinv_constants.NETWORK_TYPE_MULTICAST,
|
|
'name': sysinv_constants.NETWORK_TYPE_MULTICAST,
|
|
'dynamic': False,
|
|
'pool_uuid': pool.uuid,
|
|
}
|
|
client.sysinv.network.create(**values)
|
|
|
|
|
|
def populate_cluster_host_network(client):
|
|
cluster_host_subnet = IPNetwork(CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'CLUSTER_HOST_SUBNET'))
|
|
start_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'CLUSTER_HOST_START_ADDRESS')
|
|
end_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'CLUSTER_HOST_END_ADDRESS')
|
|
|
|
if RECONFIGURE_NETWORK:
|
|
delete_network_and_addrpool(client, 'cluster-host')
|
|
print("Updating cluster host network...")
|
|
else:
|
|
print("Populating cluster host network...")
|
|
|
|
# create the address pool
|
|
values = {
|
|
'name': 'cluster-host-subnet',
|
|
'network': str(cluster_host_subnet.network),
|
|
'prefix': cluster_host_subnet.prefixlen,
|
|
'ranges': [(start_address, end_address)],
|
|
}
|
|
pool = client.sysinv.address_pool.create(**values)
|
|
|
|
# create the network for the pool
|
|
values = {
|
|
'type': sysinv_constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
'name': sysinv_constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
'dynamic': True,
|
|
'pool_uuid': pool.uuid,
|
|
}
|
|
client.sysinv.network.create(**values)
|
|
|
|
|
|
def populate_cluster_pod_network(client):
|
|
cluster_pod_subnet = IPNetwork(CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'CLUSTER_POD_SUBNET'))
|
|
start_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'CLUSTER_POD_START_ADDRESS')
|
|
end_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'CLUSTER_POD_END_ADDRESS')
|
|
|
|
if RECONFIGURE_NETWORK:
|
|
delete_network_and_addrpool(client, 'cluster-pod')
|
|
print("Updating cluster pod network...")
|
|
else:
|
|
print("Populating cluster pod network...")
|
|
|
|
# create the address pool
|
|
values = {
|
|
'name': 'cluster-pod-subnet',
|
|
'network': str(cluster_pod_subnet.network),
|
|
'prefix': cluster_pod_subnet.prefixlen,
|
|
'ranges': [(start_address, end_address)],
|
|
}
|
|
pool = client.sysinv.address_pool.create(**values)
|
|
|
|
# create the network for the pool
|
|
values = {
|
|
'type': sysinv_constants.NETWORK_TYPE_CLUSTER_POD,
|
|
'name': sysinv_constants.NETWORK_TYPE_CLUSTER_POD,
|
|
'dynamic': False,
|
|
'pool_uuid': pool.uuid,
|
|
}
|
|
client.sysinv.network.create(**values)
|
|
|
|
|
|
def populate_cluster_service_network(client):
|
|
cluster_service_subnet = IPNetwork(CONF.get(
|
|
'BOOTSTRAP_CONFIG', 'CLUSTER_SERVICE_SUBNET'))
|
|
start_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'CLUSTER_SERVICE_START_ADDRESS')
|
|
end_address = CONF.get('BOOTSTRAP_CONFIG',
|
|
'CLUSTER_SERVICE_END_ADDRESS')
|
|
|
|
if RECONFIGURE_NETWORK:
|
|
delete_network_and_addrpool(client, 'cluster-service')
|
|
print("Updating cluster service network...")
|
|
else:
|
|
print("Populating cluster service network...")
|
|
|
|
# create the address pool
|
|
values = {
|
|
'name': 'cluster-service-subnet',
|
|
'network': str(cluster_service_subnet.network),
|
|
'prefix': cluster_service_subnet.prefixlen,
|
|
'ranges': [(start_address, end_address)],
|
|
}
|
|
pool = client.sysinv.address_pool.create(**values)
|
|
|
|
# create the network for the pool
|
|
values = {
|
|
'type': sysinv_constants.NETWORK_TYPE_CLUSTER_SERVICE,
|
|
'name': sysinv_constants.NETWORK_TYPE_CLUSTER_SERVICE,
|
|
'dynamic': False,
|
|
'pool_uuid': pool.uuid,
|
|
}
|
|
client.sysinv.network.create(**values)
|
|
|
|
|
|
def populate_network_config(client):
|
|
if not INITIAL_POPULATION and not RECONFIGURE_NETWORK:
|
|
return
|
|
populate_mgmt_network(client)
|
|
populate_pxeboot_network(client)
|
|
populate_infra_network(client)
|
|
populate_oam_network(client)
|
|
populate_multicast_network(client)
|
|
populate_cluster_host_network(client)
|
|
populate_cluster_pod_network(client)
|
|
populate_cluster_service_network(client)
|
|
print("Network config completed.")
|
|
|
|
|
|
def populate_dns_config(client):
|
|
if not INITIAL_POPULATION and not RECONFIGURE_SYSTEM:
|
|
return
|
|
|
|
if INITIAL_POPULATION:
|
|
print("Populating DNS config...")
|
|
else:
|
|
print("Updating DNS config...")
|
|
|
|
nameservers = CONF.get('BOOTSTRAP_CONFIG', 'NAMESERVERS')
|
|
|
|
dns_list = client.sysinv.idns.list()
|
|
dns_record = dns_list[0]
|
|
values = {
|
|
'nameservers': nameservers.rstrip(','),
|
|
'action': 'apply'
|
|
}
|
|
patch = sysinv.dict_to_patch(values)
|
|
client.sysinv.idns.update(dns_record.uuid, patch)
|
|
|
|
|
|
def populate_docker_config(client):
|
|
if not INITIAL_POPULATION and not RECONFIGURE_SERVICE:
|
|
return
|
|
|
|
if INITIAL_POPULATION:
|
|
print("Populating docker config...")
|
|
else:
|
|
print("Updating docker config...")
|
|
|
|
http_proxy = CONF.get('BOOTSTRAP_CONFIG', 'DOCKER_HTTP_PROXY')
|
|
https_proxy = CONF.get('BOOTSTRAP_CONFIG', 'DOCKER_HTTPS_PROXY')
|
|
no_proxy = CONF.get('BOOTSTRAP_CONFIG', 'DOCKER_NO_PROXY')
|
|
|
|
if http_proxy != 'undef' or https_proxy != 'undef':
|
|
parameters = {}
|
|
if http_proxy != 'undef':
|
|
parameters['http_proxy'] = http_proxy
|
|
if https_proxy != 'undef':
|
|
parameters['https_proxy'] = https_proxy
|
|
|
|
parameters['no_proxy'] = no_proxy
|
|
values = {
|
|
'service': sysinv_constants.SERVICE_TYPE_DOCKER,
|
|
'section': sysinv_constants.SERVICE_PARAM_SECTION_DOCKER_PROXY,
|
|
'personality': None,
|
|
'resource': None,
|
|
'parameters': parameters
|
|
}
|
|
if RECONFIGURE_SERVICE:
|
|
parameters = client.sysinv.service_parameter.list()
|
|
for parameter in parameters:
|
|
if (parameter.name == 'http_proxy' or
|
|
parameter.name == 'https_proxy' or
|
|
parameter.name == 'no_proxy'):
|
|
client.sysinv.service_parameter.delete(parameter.uuid)
|
|
client.sysinv.service_parameter.create(**values)
|
|
print("Docker proxy config completed.")
|
|
|
|
use_default_registries = CONF.getboolean(
|
|
'BOOTSTRAP_CONFIG', 'USE_DEFAULT_REGISTRIES')
|
|
|
|
if not use_default_registries:
|
|
registries = CONF.get('BOOTSTRAP_CONFIG', 'DOCKER_REGISTRIES')
|
|
secure_registry = CONF.getboolean('BOOTSTRAP_CONFIG',
|
|
'IS_SECURE_REGISTRY')
|
|
parameters = {}
|
|
parameters['registries'] = registries
|
|
|
|
if not secure_registry:
|
|
parameters['insecure_registry'] = "True"
|
|
|
|
values = {
|
|
'service': sysinv_constants.SERVICE_TYPE_DOCKER,
|
|
'section': sysinv_constants.SERVICE_PARAM_SECTION_DOCKER_REGISTRY,
|
|
'personality': None,
|
|
'resource': None,
|
|
'parameters': parameters
|
|
}
|
|
if RECONFIGURE_SERVICE:
|
|
parameters = client.sysinv.service_parameter.list()
|
|
for parameter in parameters:
|
|
if (parameter.name == 'registries' or
|
|
parameter.name == 'insecure_registry'):
|
|
client.sysinv.service_parameter.delete(
|
|
parameter.uuid)
|
|
client.sysinv.service_parameter.create(**values)
|
|
print("Docker registry config completed.")
|
|
|
|
|
|
def get_management_mac_address():
|
|
ifname = CONF.get('BOOTSTRAP_CONFIG', 'MANAGEMENT_INTERFACE')
|
|
|
|
try:
|
|
filename = '/sys/class/net/%s/address' % ifname
|
|
with open(filename, 'r') as f:
|
|
return f.readline().rstrip()
|
|
except Exception:
|
|
raise ConfigFail("Failed to obtain mac address of %s" % ifname)
|
|
|
|
|
|
def get_rootfs_node():
|
|
"""Cloned from sysinv"""
|
|
cmdline_file = '/proc/cmdline'
|
|
device = None
|
|
|
|
with open(cmdline_file, 'r') as f:
|
|
for line in f:
|
|
for param in line.split():
|
|
params = param.split("=", 1)
|
|
if params[0] == "root":
|
|
if "UUID=" in params[1]:
|
|
key, uuid = params[1].split("=")
|
|
symlink = "/dev/disk/by-uuid/%s" % uuid
|
|
device = os.path.basename(os.readlink(symlink))
|
|
else:
|
|
device = os.path.basename(params[1])
|
|
|
|
if device is not None:
|
|
if sysinv_constants.DEVICE_NAME_NVME in device:
|
|
re_line = re.compile(r'^(nvme[0-9]*n[0-9]*)')
|
|
else:
|
|
re_line = re.compile(r'^(\D*)')
|
|
match = re_line.search(device)
|
|
if match:
|
|
return os.path.join("/dev", match.group(1))
|
|
|
|
return
|
|
|
|
|
|
def find_boot_device():
|
|
"""Determine boot device """
|
|
boot_device = None
|
|
|
|
context = pyudev.Context()
|
|
|
|
# Get the boot partition
|
|
# Unfortunately, it seems we can only get it from the logfile.
|
|
# We'll parse the device used from a line like the following:
|
|
# BIOSBoot.create: device: /dev/sda1 ; status: False ; type: biosboot ;
|
|
# or
|
|
# EFIFS.create: device: /dev/sda1 ; status: False ; type: efi ;
|
|
#
|
|
logfile = '/var/log/anaconda/storage.log'
|
|
|
|
re_line = re.compile(r'(BIOSBoot|EFIFS).create: device: ([^\s;]*)')
|
|
boot_partition = None
|
|
with open(logfile, 'r') as f:
|
|
for line in f:
|
|
match = re_line.search(line)
|
|
if match:
|
|
boot_partition = match.group(2)
|
|
break
|
|
if boot_partition is None:
|
|
raise ConfigFail("Failed to determine the boot partition")
|
|
|
|
# Find the boot partition and get its parent
|
|
for device in context.list_devices(DEVTYPE='partition'):
|
|
if device.device_node == boot_partition:
|
|
boot_device = device.find_parent('block').device_node
|
|
break
|
|
|
|
if boot_device is None:
|
|
raise ConfigFail("Failed to determine the boot device")
|
|
|
|
return boot_device
|
|
|
|
|
|
def device_node_to_device_path(dev_node):
|
|
device_path = None
|
|
cmd = ["find", "-L", "/dev/disk/by-path/", "-samefile", dev_node]
|
|
|
|
try:
|
|
out = subprocess.check_output(cmd)
|
|
except subprocess.CalledProcessError as e:
|
|
print("Could not retrieve device information: %s" % e)
|
|
return device_path
|
|
|
|
device_path = out.rstrip()
|
|
return device_path
|
|
|
|
|
|
def get_device_from_function(get_disk_function):
|
|
device_node = get_disk_function()
|
|
device_path = device_node_to_device_path(device_node)
|
|
device = device_path if device_path else os.path.basename(device_node)
|
|
|
|
return device
|
|
|
|
|
|
def get_console_info():
|
|
"""Determine console info """
|
|
cmdline_file = '/proc/cmdline'
|
|
|
|
re_line = re.compile(r'^.*\s+console=([^\s]*)')
|
|
|
|
with open(cmdline_file, 'r') as f:
|
|
for line in f:
|
|
match = re_line.search(line)
|
|
if match:
|
|
console_info = match.group(1)
|
|
return console_info
|
|
return ''
|
|
|
|
|
|
def get_tboot_info():
|
|
"""Determine whether we were booted with a tboot value """
|
|
cmdline_file = '/proc/cmdline'
|
|
|
|
# tboot=true, tboot=false, or no tboot parameter expected
|
|
re_line = re.compile(r'^.*\s+tboot=([^\s]*)')
|
|
|
|
with open(cmdline_file, 'r') as f:
|
|
for line in f:
|
|
match = re_line.search(line)
|
|
if match:
|
|
tboot = match.group(1)
|
|
return tboot
|
|
return ''
|
|
|
|
|
|
def get_orig_install_mode():
|
|
"""Determine original install mode, text vs graphical """
|
|
# Post-install, the only way to detemine the original install mode
|
|
# will be to check the anaconda install log for the parameters passed
|
|
logfile = '/var/log/anaconda/anaconda.log'
|
|
|
|
search_str = 'Display mode = t'
|
|
try:
|
|
subprocess.check_call(['grep', '-q', search_str, logfile])
|
|
return 'text'
|
|
except subprocess.CalledProcessError:
|
|
return 'graphical'
|
|
|
|
|
|
def populate_controller_config(client):
|
|
if not INITIAL_POPULATION:
|
|
return
|
|
|
|
mgmt_mac = get_management_mac_address()
|
|
print("Management mac = %s" % mgmt_mac)
|
|
rootfs_device = get_device_from_function(get_rootfs_node)
|
|
print("Root fs device = %s" % rootfs_device)
|
|
boot_device = get_device_from_function(find_boot_device)
|
|
print("Boot device = %s" % boot_device)
|
|
console = get_console_info()
|
|
print("Console = %s" % console)
|
|
tboot = get_tboot_info()
|
|
print("Tboot = %s" % tboot)
|
|
install_output = get_orig_install_mode()
|
|
print("Install output = %s" % install_output)
|
|
|
|
provision_state = sysinv.HOST_PROVISIONED
|
|
system_type = CONF.get('BOOTSTRAP_CONFIG', 'SYSTEM_TYPE')
|
|
if system_type == COMBINED_LOAD:
|
|
provision_state = sysinv.HOST_PROVISIONING
|
|
|
|
values = {
|
|
'personality': sysinv.HOST_PERSONALITY_CONTROLLER,
|
|
'hostname': CONF.get('BOOTSTRAP_CONFIG', 'CONTROLLER_HOSTNAME'),
|
|
'mgmt_ip': CONF.get('BOOTSTRAP_CONFIG', 'CONTROLLER_0_ADDRESS'),
|
|
'mgmt_mac': mgmt_mac,
|
|
'administrative': sysinv.HOST_ADMIN_STATE_LOCKED,
|
|
'operational': sysinv.HOST_OPERATIONAL_STATE_DISABLED,
|
|
'availability': sysinv.HOST_AVAIL_STATE_OFFLINE,
|
|
'invprovision': provision_state,
|
|
'rootfs_device': rootfs_device,
|
|
'boot_device': boot_device,
|
|
'console': console,
|
|
'tboot': tboot,
|
|
'install_output': install_output,
|
|
}
|
|
print("Host values = %s" % values)
|
|
controller = client.sysinv.ihost.create(**values)
|
|
return controller
|
|
|
|
|
|
def wait_disk_config(client, host):
|
|
count = 0
|
|
for _ in range(constants.SYSTEM_CONFIG_TIMEOUT / 10):
|
|
try:
|
|
disks = client.sysinv.idisk.list(host.uuid)
|
|
if disks and count == len(disks):
|
|
return disks
|
|
count = len(disks)
|
|
except Exception:
|
|
pass
|
|
if disks:
|
|
time.sleep(1) # We don't need to wait that long
|
|
else:
|
|
time.sleep(10)
|
|
else:
|
|
raise ConfigFail('Timeout waiting for controller disk '
|
|
'configuration')
|
|
|
|
|
|
def wait_pv_config(client, host):
|
|
count = 0
|
|
for _ in range(constants.SYSTEM_CONFIG_TIMEOUT / 10):
|
|
try:
|
|
pvs = client.sysinv.ipv.list(host.uuid)
|
|
if pvs and count == len(pvs):
|
|
return pvs
|
|
count = len(pvs)
|
|
except Exception:
|
|
pass
|
|
if pvs:
|
|
time.sleep(1) # We don't need to wait that long
|
|
else:
|
|
time.sleep(10)
|
|
else:
|
|
raise ConfigFail('Timeout waiting for controller PV '
|
|
'configuration')
|
|
|
|
|
|
def inventory_config_complete_wait(client, controller):
|
|
# Wait for sysinv-agent to populate disks and PVs
|
|
if not INITIAL_POPULATION:
|
|
return
|
|
|
|
wait_disk_config(client, controller)
|
|
wait_pv_config(client, controller)
|
|
|
|
|
|
def handle_invalid_input():
|
|
raise Exception("Invalid input!\nUsage: <bootstrap-config-file> "
|
|
"[--system] [--network] [--service]")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
argc = len(sys.argv)
|
|
if argc < 2 or argc > 5:
|
|
print("Failed")
|
|
handle_invalid_input()
|
|
|
|
arg = 2
|
|
while arg < argc:
|
|
if sys.argv[arg] == "--system":
|
|
RECONFIGURE_SYSTEM = True
|
|
elif sys.argv[arg] == "--network":
|
|
RECONFIGURE_NETWORK = True
|
|
elif sys.argv[arg] == "--service":
|
|
RECONFIGURE_SERVICE = True
|
|
else:
|
|
handle_invalid_input()
|
|
arg += 1
|
|
|
|
INITIAL_POPULATION = not (RECONFIGURE_SYSTEM or RECONFIGURE_NETWORK or
|
|
RECONFIGURE_SERVICE)
|
|
|
|
config_file = sys.argv[1]
|
|
if not os.path.exists(config_file):
|
|
raise Exception("Config file is not found!")
|
|
|
|
CONF.read(config_file)
|
|
|
|
# Puppet manifest might be applied as part of initial host
|
|
# config, set INITIAL_CONFIG_PRIMARY variable just in case.
|
|
os.environ["INITIAL_CONFIG_PRIMARY"] = "true"
|
|
|
|
try:
|
|
with openstack.OpenStack() as client:
|
|
populate_system_config(client)
|
|
populate_load_config(client)
|
|
populate_network_config(client)
|
|
populate_dns_config(client)
|
|
populate_docker_config(client)
|
|
controller = populate_controller_config(client)
|
|
inventory_config_complete_wait(client, controller)
|
|
os.remove(config_file)
|
|
if INITIAL_POPULATION:
|
|
print("Successfully updated the initial system config.")
|
|
else:
|
|
print("Successfully provisioned the initial system config.")
|
|
except Exception:
|
|
# Print the marker string for Ansible and re raise the exception
|
|
if INITIAL_POPULATION:
|
|
print("Failed to update the initial system config.")
|
|
else:
|
|
print("Failed to provision the initial system config.")
|
|
raise
|