Simplify configurator

Template files are now directly loaded in the configurator container, so
that it is possible to run the configurator container directly, outside
of this project.
This commit is contained in:
Régis Behmo 2018-09-15 16:19:35 +02:00
parent b0f2adb931
commit 04a0fb5902
24 changed files with 38 additions and 37 deletions

10
.gitignore vendored
View File

@ -1,12 +1,4 @@
.*.swp
config/config.json
config/android/*.yaml
config/letsencrypt/*.sh
config/mysql/*.env
config/nginx/*.conf
config/openedx/*.json
config/openedx/*.sh
config/xqueue/*.py
config/
data-*/
TODO

View File

@ -1,5 +1,6 @@
# Changelog
- 2018-09-15 [Feature] Add templates to configurator container, which can now be run separately
- 2018-09-15 [Improvement] Rename "up" and "daemon" commands to "run" and "daemonize"
- 2018-09-15 [Feature] Activate course search and discovery
- 2018-09-15 [Bugfix] Deduplicate console logs from lms/cms

View File

@ -32,18 +32,7 @@ all: configure $(post_configure_targets) update migrate assets daemonize
configure: build-configurator
docker run --rm -it --volume="$(PWD)/config:/openedx/config" \
-e USERID=$(USERID) -e SILENT=$(SILENT) -e SETTING_ACTIVATE_HTTPS=$(ACTIVATE_HTTPS) -e SETTING_ACTIVATE_XQUEUE=$(ACTIVATE_XQUEUE) \
regis/openedx-configurator:hawthorn bash -c "./configure.py interactive && \
./configure.py substitute ./config/openedx/templates/lms.env.json.templ ./config/openedx/lms.env.json && \
./configure.py substitute ./config/openedx/templates/cms.env.json.templ ./config/openedx/cms.env.json && \
./configure.py substitute ./config/openedx/templates/lms.auth.json.templ ./config/openedx/lms.auth.json && \
./configure.py substitute ./config/openedx/templates/cms.auth.json.templ ./config/openedx/cms.auth.json && \
./configure.py substitute ./config/openedx/templates/provision.sh.templ ./config/openedx/provision.sh && \
./configure.py substitute ./config/mysql/templates/auth.env.templ ./config/mysql/auth.env && \
./configure.py substitute ./config/nginx/templates/lms.conf.templ ./config/nginx/lms.conf && \
./configure.py substitute ./config/nginx/templates/cms.conf.templ ./config/nginx/cms.conf && \
./configure.py substitute ./config/android/templates/universal.yaml.templ ./config/android/universal.yaml && \
./configure.py substitute ./config/letsencrypt/templates/certonly.sh.templ ./config/letsencrypt/certonly.sh && \
./configure.py substitute ./config/xqueue/templates/universal.py.templ ./config/xqueue/universal.py"
regis/openedx-configurator:hawthorn
update:
$(DOCKER_COMPOSE) pull

View File

@ -8,9 +8,9 @@ RUN mkdir /openedx
VOLUME /openedx/config
COPY ./bin/configure.py /openedx/configure.py
COPY ./bin/docker-entrypoint.sh /openedx/docker-entrypoint.sh
COPY ./templates /openedx/templates
WORKDIR /openedx
ENV SILENT=''
ENV ACTIVATE_HTTPS=''
ENV ACTIVATE_XQUEUE=''
ENTRYPOINT ["./docker-entrypoint.sh"]
CMD ./configure.py -c /openedx/config/config.json interactive && \
./configure.py -c /openedx/config/config.json substitute ./templates/ /openedx/config

View File

@ -36,7 +36,7 @@ class Configurator:
self.__input = None
def add(self, name, question="", default=""):
default = self.default_value(name) or default
default = self.get_default_value(name, default)
message = question + " (default: \"{}\"): ".format(default) if question else None
value = self.ask(message, default)
self.set(name, value)
@ -48,16 +48,21 @@ class Configurator:
value = self.get(name)
if value in [1, '1']:
return self.set(name, True)
if value in [0, '0']:
if value in [0, '0', '']:
return self.set(name, False)
return self
if value in [True, False]:
return self
return self.set(name, bool(value))
def default_value(self, name):
def get_default_value(self, name, default):
setting_name = 'SETTING_' + name.upper()
if setting_name in os.environ:
if os.environ.get(setting_name):
return os.environ[setting_name]
return self.__default_values.get(name)
if name in self.__default_values:
return self.__default_values[name]
return default
def ask(self, message, default):
if self.__input and message:
@ -88,8 +93,8 @@ def main():
parser_interactive.set_defaults(func=interactive)
parser_substitute = subparsers.add_parser('substitute')
parser_substitute.add_argument('src', help="Template source file")
parser_substitute.add_argument('dst', help="Destination configuration file")
parser_substitute.add_argument('src', help="Template source directory")
parser_substitute.add_argument('dst', help="Destination configuration directory")
parser_substitute.set_defaults(func=substitute)
args = parser.parse_args()
@ -153,21 +158,35 @@ def interactive(args):
def substitute(args):
config = load_config(args)
with codecs.open(args.src, encoding='utf-8') as fi:
for root, _, filenames in os.walk(args.src):
for filename in filenames:
if filename.startswith('.'):
# Skip hidden files, such as files generated by the IDE
continue
src_file = os.path.join(root, filename)
dst_file = os.path.join(args.dst, os.path.relpath(src_file, args.src))
substitute_file(config, src_file, dst_file)
def substitute_file(config, src, dst):
with codecs.open(src, encoding='utf-8') as fi:
template = jinja2.Template(fi.read(), undefined=jinja2.StrictUndefined)
try:
substituted = template.render(**config)
except jinja2.exceptions.UndefinedError as e:
sys.stderr.write("ERROR Missing config value '{}' for template {}\n".format(e.args[0], args.src))
sys.stderr.write("ERROR Missing config value '{}' for template {}\n".format(e.args[0], src))
sys.exit(1)
with codecs.open(args.dst, encoding='utf-8', mode='w') as fo:
dst_dir = os.path.dirname(dst)
if not os.path.exists(dst_dir):
os.makedirs(dst_dir)
with codecs.open(dst, encoding='utf-8', mode='w') as fo:
fo.write(substituted)
# Set same permissions as original file
os.chmod(args.dst, os.stat(args.src).st_mode)
os.chmod(dst, os.stat(src).st_mode)
print("Generated file {} from template {}".format(args.dst, args.src))
print("Generated file {} from template {}".format(dst, src))
def random_string(length):