From c3ba4ee501c2f7074cee0624181ff9224749db15 Mon Sep 17 00:00:00 2001 From: Pete Vander Giessen Date: Tue, 12 Nov 2019 23:19:51 +0000 Subject: [PATCH] Delay creating external bridge until we are initializing Previously, the snap set up a bridge using the default 10.20.20.0/24 network upon install. If there was a good reason not to use this network (e.g., it already exists and is being used for another purpose), MicroStack, and the host machine, could wind up in a broken state. This PR delays setting up the bridge until after we have given an operator a chance to override the default settings. This has been manually tested. To test, do the following: 1) Checkout the code, and run tox -e build 2) Run tools/make-a-microstack.sh 3) snapctl set config.network.ext-cidr and config.network.ext-gateway 4) Run microstack_init 5) Exit the snap shell and run microstack.launch Change-Id: I9e268495f313b29d9781d80a2468fc0a1a450aa0 Closes-Bug: https://bugs.launchpad.net/microstack/+bug/1851521 --- snap-wrappers/init/wait-on-init | 10 +++++ snapcraft.yaml | 8 +++- tools/init/init/main.py | 4 +- tools/init/init/questions/__init__.py | 56 +++++++-------------------- tools/init/init/questions/network.py | 52 +++++++++++++++++++++++++ tools/init/init/questions/question.py | 8 +++- 6 files changed, 92 insertions(+), 46 deletions(-) create mode 100755 snap-wrappers/init/wait-on-init create mode 100644 tools/init/init/questions/network.py diff --git a/snap-wrappers/init/wait-on-init b/snap-wrappers/init/wait-on-init new file mode 100755 index 0000000..f4ae401 --- /dev/null +++ b/snap-wrappers/init/wait-on-init @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e + +if ! [ "$(snapctl get initialized)" == "true" ]; then + echo "Microstack not yet initliazed. Waiting to start." + exit 0; +fi + +exec $@ diff --git a/snapcraft.yaml b/snapcraft.yaml index 46de3d6..2477126 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -209,7 +209,7 @@ apps: # - network external-bridge: - command: bin/setup-br-ex + command: wait-on-init setup-br-ex daemon: oneshot passthrough: after: [ovs-vswitchd] @@ -419,6 +419,12 @@ parts: organize: openstack-wrapper: bin/openstack-wrapper + init-wrapper: + source: ./snap-wrappers/init + plugin: dump + organize: + wait-on-init: bin/wait-on-init + nova-config: after: [openstack-projects] plugin: dump diff --git a/tools/init/init/main.py b/tools/init/init/main.py index df19cf8..3e1c287 100644 --- a/tools/init/init/main.py +++ b/tools/init/init/main.py @@ -95,10 +95,8 @@ def main() -> None: question_list = [ questions.Clustering(), questions.Dns(), - questions.ExtGateway(), - questions.ExtCidr(), + questions.NetworkSettings(), questions.OsPassword(), # TODO: turn this off if COMPUTE. - questions.IpForwarding(), questions.ForceQemu(), # The following are not yet implemented: # questions.VmSwappiness(), diff --git a/tools/init/init/questions/__init__.py b/tools/init/init/questions/__init__.py index cfab02e..a69b35f 100644 --- a/tools/init/init/questions/__init__.py +++ b/tools/init/init/questions/__init__.py @@ -31,7 +31,7 @@ from init.shell import (check, call, check_output, shell, sql, nc_wait, log_wait, restart, download) from init.config import Env, log from init.questions.question import Question -from init.questions import clustering +from init.questions import clustering, network _env = Env().get_env() @@ -128,6 +128,7 @@ class ConfigQuestion(Question): """ check('snap-openstack', 'setup') + # TODO: get rid of this? (I think that it has become redundant) mstackrc = '{SNAP_COMMON}/etc/microstack.rc'.format(**_env) with open(mstackrc, 'r') as rc_file: for line in rc_file.readlines(): @@ -165,37 +166,24 @@ dnsmasq_dns_servers = {answer} # started. Need to figure that out. -class ExtGateway(ConfigQuestion): - """Possibly override default ext gateway.""" - - _type = 'string' - _question = 'External Gateway' - config_key = 'config.network.ext-gateway' +class NetworkSettings(Question): + """Write network settings, and """ + _type = 'auto' + _question = 'Network settings' def yes(self, answer): - clustered = check_output('snapctl', 'get', 'config.clustered') - if clustered.lower() != 'true': - check('snapctl', 'set', 'config.network.control-ip={}'.format( - answer)) - check('snapctl', 'set', 'config.network.compute-ip={}'.format( - answer)) - _env['control_ip'] = _env['compute_ip'] = answer - else: - _env['control_ip'] = check_output('snapctl', 'get', - 'config.network.control-ip') - _env['compute_ip'] = check_output('snapctl', 'get', - 'config.network.compute-ip') + log.info('Configuring networking ...') + network.ExtGateway().ask() + network.ExtCidr().ask() -class ExtCidr(ConfigQuestion): - """Possibly override the cidr.""" + # Now that we have default or overriden values, setup the + # bridge and write all the proper values into our config + # files. + check('setup-br-ex') + check('snap-openstack', 'setup') - _type = 'string' - _question = 'External Ip Range' - config_key = 'config.network.ext-cidr' - - def yes(self, answer): - _env['extcidr'] = answer + network.IpForwarding().ask() class OsPassword(ConfigQuestion): @@ -209,20 +197,6 @@ class OsPassword(ConfigQuestion): # TODO obfuscate the password! -class IpForwarding(Question): - """Possibly setup IP forwarding.""" - - _type = 'boolean' # Auto for now, to maintain old behavior. - _question = 'Do you wish to setup ip forwarding? (recommended)' - config_key = 'config.host.ip-forwarding' - - def yes(self, answer: str) -> None: - """Use sysctl to setup ip forwarding.""" - log.info('Setting up ipv4 forwarding...') - - check('sysctl', 'net.ipv4.ip_forward=1') - - class ForceQemu(Question): _type = 'boolean' config_key = 'config.host.check-qemu' diff --git a/tools/init/init/questions/network.py b/tools/init/init/questions/network.py new file mode 100644 index 0000000..689614c --- /dev/null +++ b/tools/init/init/questions/network.py @@ -0,0 +1,52 @@ +from init.config import Env, log +from init.questions.question import Question +from init.shell import check, check_output + +_env = Env().get_env() + + +class ExtGateway(Question): + """Possibly override default ext gateway.""" + + _type = 'string' + _question = 'External Gateway' + config_key = 'config.network.ext-gateway' + + def yes(self, answer): + clustered = check_output('snapctl', 'get', 'config.clustered') + if clustered.lower() != 'true': + check('snapctl', 'set', 'config.network.control-ip={}'.format( + answer)) + check('snapctl', 'set', 'config.network.compute-ip={}'.format( + answer)) + _env['control_ip'] = _env['compute_ip'] = answer + else: + _env['control_ip'] = check_output('snapctl', 'get', + 'config.network.control-ip') + _env['compute_ip'] = check_output('snapctl', 'get', + 'config.network.compute-ip') + + +class ExtCidr(Question): + """Possibly override the cidr.""" + + _type = 'string' + _question = 'External Ip Range' + config_key = 'config.network.ext-cidr' + + def yes(self, answer): + _env['extcidr'] = answer + + +class IpForwarding(Question): + """Possibly setup IP forwarding.""" + + _type = 'boolean' # Auto for now, to maintain old behavior. + _question = 'Do you wish to setup ip forwarding? (recommended)' + config_key = 'config.host.ip-forwarding' + + def yes(self, answer: str) -> None: + """Use sysctl to setup ip forwarding.""" + log.info('Setting up ipv4 forwarding...') + + check('sysctl', 'net.ipv4.ip_forward=1') diff --git a/tools/init/init/questions/question.py b/tools/init/init/questions/question.py index 20aee4b..06d77ab 100644 --- a/tools/init/init/questions/question.py +++ b/tools/init/init/questions/question.py @@ -74,7 +74,7 @@ class Question(): raise InvalidQuestion( 'Invalid type {} specified'.format(self._type)) - if self.config_key is None: + if self.config_key is None and self._type != 'auto': raise InvalidQuestion( "No config key specified. " "We don't know how to load or save this question!") @@ -118,6 +118,9 @@ class Question(): operator specified settings during updates. """ + if self._type == 'auto': + return + answer = shell.check_output( 'snapctl', 'get', '{key}'.format(key=self.config_key) ) @@ -144,6 +147,9 @@ class Question(): # By this time in the process 'yes' or 'no' answers will have # been converted to booleans. Convert them to a lowercase # 'true' or 'false' string for storage in the snapctl config. + if self._type == 'auto': + return + if self._type == 'boolean': answer = str(answer).lower()