Skip to content

Commit 8b07eae

Browse files
committed
Manually merge PR244 to add support for new include_sections option in MiGserver.conf which will load SECTIONNAME into parsed configuration for any sectionname.conf files from the corresponding folder. Useful e.g. to keep rather involved cloud sections out of the main MiGserver.conf
git-svn-id: svn+ssh://svn.code.sf.net/p/migrid/code/trunk@6237 b75ad72c-e7d7-11dd-a971-7dbc132099af
1 parent 86d8c38 commit 8b07eae

File tree

13 files changed

+1079
-17
lines changed

13 files changed

+1079
-17
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[CLOUD_MISTY]
2+
# General cloud provider settings and limits
3+
service_name = MISTY
4+
service_title = MISTY-Cloud
5+
service_desc = A misty cloud service
6+
service_provider_flavor = openstack
7+
service_hosts = https://misty:5000/v3
8+
service_max_user_instances = 1
9+
service_max_user_instances_map = john.doe@nosuchplace.org=3
10+
# Semi-colon separated list of img=user login pairs when img and user differs
11+
service_user_map = rocky9=rocky;ubuntu-noble=ubuntu
12+
# Cloud instance defaults
13+
# The general structure is a default option and an optional user override map
14+
# service_flavor_id = INSERT CLOUD FLAVOR ID
15+
# Semi-colon separated list of user=flavor pairs to override for some users
16+
# service_flavor_id_map =
17+
# service_network_id = INSERT CLOUD NETWORK ID
18+
# Semi-colon separated list of user=net pairs to override for some users
19+
# service_network_id_map =
20+
# service_key_id = INSERT DEFAULT KEY ID
21+
# Semi-colon separated list of user=keyid pairs to override for some users
22+
# service_key_id_map =
23+
# service_sec_group_id = INSERT CLOUD SEC GROUP ID
24+
# Semi-colon separated list of user=secgrp pairs to override for some users
25+
# service_sec_group_id_map
26+
# service_floating_network_id = INSERT CLOUD FLOATING NETWORK ID
27+
# Semi-colon separated list of user=floatnet pairs to override for some users
28+
# service_floating_network_id_map =
29+
# service_availability_zone = INSERT CLOUD AVAILABILITY ZONE
30+
# Semi-colon separated list of user=availzone pairs to override for some users
31+
# service_availability_zone_map =
32+
# Optional jump host so that instances are shielded fom direct ssh access
33+
service_jumphost_address = jumpy01
34+
# Semi-colon separated list of user=jumpaddr pairs to override for some users
35+
# service_jumphost_address_map =
36+
service_jumphost_user = misty
37+
# Path to the ssh key used for managing user public keys on cloud jumphost
38+
service_jumphost_key = ~/.ssh/misty-jumphost-key
39+
# Semi-colon separated list of user=jumpuser pairs to override for some users
40+
# service_jumphost_user_map =
41+
# Helper to automatically add user pub keys on jumphost
42+
# The script and coding values are used like this under the hood:
43+
# ssh %(jumphost_user)s@%(jumphost_address)s %(jumphost_manage_keys_script)s add \
44+
# %(jumphost_manage_keys_coding)s %(encoded_client_id)s %(encoded_pub_keys)s
45+
# where coding is applied to client_id and pub_keys to yield encoded_X versions
46+
service_jumphost_manage_keys_script = manage_misty_keys.py
47+
service_jumphost_manage_keys_coding = base16

mig/install/MiGserver-template.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,9 @@ scriptlanguages = sh python java
400400
jobtypes = batch interactive all
401401
lrmstypes = Native Native-execution-leader Batch Batch-execution-leader
402402

403+
# Include any additional section confs files from a per-section conf folder
404+
include_sections = %(mig_server_home)s/MiGserver.d
405+
403406
# Jupyter integration sections
404407
### E.g. ###
405408
# [JUPYTER_DAG]

mig/server/MiGserver.d/.placeholder

Whitespace-only changes.

mig/shared/configuration.py

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,49 @@
6565
default_css_filename, keyword_any, keyword_auto, keyword_all, \
6666
keyword_file, keyword_env, cert_valid_days, oid_valid_days, \
6767
generic_valid_days, DEFAULT_USER_ID_FORMAT, valid_user_id_formats, \
68-
valid_filter_methods, default_twofactor_auth_apps
68+
valid_filter_methods, default_twofactor_auth_apps, \
69+
mig_conf_section_dirname
6970
from mig.shared.logger import Logger, SYSLOG_GDP
7071
from mig.shared.htmlgen import menu_items, vgrid_items
7172
from mig.shared.fileio import read_file, load_json, write_file
7273
except ImportError as ioe:
7374
print("could not import migrid modules")
7475

7576

77+
def include_section_contents(logger, config, section, load_path, verbose=False):
78+
"""Include additional section contents from load_path in config."""
79+
if not os.path.exists(load_path):
80+
msg = "no such %r section config in %s" % (section, load_path)
81+
if verbose:
82+
print(msg)
83+
logger.error(msg)
84+
return False
85+
86+
logger.debug("include %r section from %s" % (section, load_path))
87+
section_config = ConfigParser()
88+
section_config.read([load_path])
89+
if section not in section_config.sections():
90+
msg = "missing required %r section in config %s" % (section, load_path)
91+
if verbose:
92+
print(msg)
93+
logger.error(msg)
94+
return False
95+
other_sections = [i for i in section_config.sections() if not i == section]
96+
if other_sections:
97+
msg = "only %r section will be read from %s" % (section, load_path)
98+
if verbose:
99+
print(msg)
100+
logger.warning(msg)
101+
if section not in config.sections():
102+
logger.debug("add %r section to main config" % section)
103+
config.add_section(section)
104+
for (key, val) in section_config.items(section):
105+
logger.debug("add config key %r in %r section" % (key, section))
106+
config.set(section, key, val)
107+
logger.debug("done including %r section to main config" % section)
108+
return True
109+
110+
76111
def expand_external_sources(logger, val):
77112
"""Expand a string containing ENV::NAME, FILE::PATH or FILE::PATH$$CACHE
78113
references to fill in the content of the corresponding environment, file or
@@ -923,6 +958,45 @@ def reload_config(self, verbose, skip_log=False, disable_auth_log=False,
923958
else:
924959
self.user_db_home = os.path.join(self.state_path, 'user_db_home')
925960

961+
# Allow section confs included from file
962+
if config.has_option('GLOBAL', 'include_sections'):
963+
self.include_sections = config.get('GLOBAL', 'include_sections')
964+
else:
965+
self.include_sections = os.path.join(self.mig_server_home,
966+
mig_conf_section_dirname)
967+
968+
# NOTE: for simplicity we do NOT allow overrides in GLOBAL section
969+
no_override_sections = ['GLOBAL']
970+
self.include_sections = os.path.normpath(self.include_sections)
971+
if os.path.isdir(self.include_sections):
972+
msg = "read extra config sections from %s" % self.include_sections
973+
if verbose:
974+
print(msg)
975+
logger.info(msg)
976+
for section_filename in os.listdir(self.include_sections):
977+
# skip dotfiles and non-confs
978+
if section_filename.startswith('.'):
979+
continue
980+
if not section_filename.endswith('.conf'):
981+
msg = "%r is not on required sectionname.conf form" % \
982+
section_filename
983+
if verbose:
984+
print(msg)
985+
logger.warning(msg)
986+
continue
987+
section_path = os.path.join(self.include_sections,
988+
section_filename)
989+
section = section_filename.replace('.conf', '').upper()
990+
if section in no_override_sections:
991+
msg = "skip unsupported %r section override in %r" % \
992+
(section, section_filename)
993+
if verbose:
994+
print(msg)
995+
logger.warning(msg)
996+
continue
997+
include_section_contents(logger, config, section, section_path,
998+
verbose)
999+
9261000
if config.has_option('GLOBAL', 'admin_list'):
9271001
# Parse semi-colon separated list of admins with optional spaces
9281002
admins = config.get('GLOBAL', 'admin_list')
@@ -1669,15 +1743,12 @@ def reload_config(self, verbose, skip_log=False, disable_auth_log=False,
16691743
self.jupyter_services = []
16701744
# Load generated jupyter sections
16711745
for section in config.sections():
1672-
if 'JUPYTER_' in section:
1746+
if section.startswith('JUPYTER_'):
16731747
# Allow service_desc to be a file that should be read
16741748
if config.has_option(section, 'service_desc'):
1675-
service_desc = config.get(section, 'service_desc')
1676-
if os.path.exists(service_desc) \
1677-
and os.path.isfile(service_desc):
1678-
content = read_file(service_desc, logger)
1679-
if content:
1680-
config.set(section, 'service_desc', content)
1749+
content = expand_external_sources(
1750+
logger, config.get(section, 'service_desc'))
1751+
config.set(section, 'service_desc', content)
16811752

16821753
self.jupyter_services.append({option: config.get(section,
16831754
option)
@@ -1697,15 +1768,12 @@ def reload_config(self, verbose, skip_log=False, disable_auth_log=False,
16971768
'service_jumphost_key']
16981769
# Load generated cloud sections
16991770
for section in config.sections():
1700-
if 'CLOUD_' in section:
1771+
if section.startswith('CLOUD_'):
17011772
# Allow service_desc to be a file that should be read
17021773
if config.has_option(section, 'service_desc'):
1703-
service_desc = config.get(section, 'service_desc')
1704-
if os.path.exists(service_desc) \
1705-
and os.path.isfile(service_desc):
1706-
content = read_file(service_desc, logger)
1707-
if content:
1708-
config.set(section, 'service_desc', content)
1774+
content = expand_external_sources(
1775+
logger, config.get(section, 'service_desc'))
1776+
config.set(section, 'service_desc', content)
17091777

17101778
service = {option: config.get(section, option) for option in
17111779
config.options(section)}

mig/shared/defaults.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@
220220

221221
exe_leader_name = "execution-leader"
222222

223+
mig_conf_section_dirname = "MiGserver.d"
223224
htaccess_filename = '.htaccess'
224225
welcome_filename = 'welcome.txt'
225226
default_mrsl_filename = '.default.mrsl'

mig/shared/install.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,6 +2279,7 @@ def _generate_confs_writefiles(options, user_dict, insert_list=[], cleanup_list=
22792279
("trac-MiG-template.ini", "trac.ini"),
22802280
("logrotate-MiG-template", "logrotate-migrid"),
22812281
("MiGserver-template.conf", "MiGserver.conf"),
2282+
("MiGserver-cloud_misty-template.conf", "MiGserver-cloud_misty.conf"),
22822283
("static-skin-template.css", "static-skin.css"),
22832284
("index-template.html", "index.html"),
22842285
("openssh-MiG-sftp-subsys-template.conf",
@@ -2404,6 +2405,15 @@ def _generate_confs_instructions(options, user_dict):
24042405
and if Trac is enabled, the generated trac.ini to %(mig_code)s/server/:
24052406
cp %(destination)s/trac.ini %(mig_code)s/server/
24062407
2408+
If standalone configuration sections are useful to your site you can
2409+
additionally create a suitable per-section include folder and put appropriately
2410+
named section conf files there as shown here for the generated CLOUD_MISTY
2411+
section in the generated MiGserver-cloud_misty.conf example:
2412+
mkdir -p %(mig_code)s/MiGserver.d
2413+
cp %(destination_dir)s/MiGserver-cloud_misty.conf \
2414+
%(mig_code)s/MiGserver.d/cloud_misty.conf
2415+
such section conf files must accordingly match the lower-cased section name.
2416+
24072417
On a Debian/Ubuntu MiG developer server the dedicated apache init script is
24082418
added with:
24092419
sudo cp %(destination)s/apache-%(user)s /etc/init.d/apache-%(user)s

0 commit comments

Comments
 (0)