URL: https://github.com/freeipa/freeipa/pull/182 Author: tiran Title: #182: Use env var IPA_CONFDIR to get confdir for 'cli' context Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/182/head:pr182 git checkout pr182
From 3805dfba1dc222f3cd6cc6299bfe97c70e3e8bae Mon Sep 17 00:00:00 2001 From: Christian Heimes <chei...@redhat.com> Date: Mon, 28 Nov 2016 16:24:33 +0100 Subject: [PATCH 1/2] Set explicit confdir option for global contexts Some API contexts are used to modify global state (e.g. files in /etc and /var). These contexts do not support confdir overrides. Initialize the API with an explicit confdir argument to paths.ETC_IPA. The special contexts are: * backup * cli_installer * installer * ipctl * renew * restore * server * updates The patch also corrects the context of the ipa-httpd-kdcproxy script to 'server'. https://fedorahosted.org/freeipa/ticket/6389 Signed-off-by: Christian Heimes <chei...@redhat.com> --- client/ipa-client-automount | 1 + install/certmonger/dogtag-ipa-ca-renew-agent-submit | 2 +- install/migration/migration.py | 3 ++- install/oddjob/com.redhat.idm.trust-fetch-domains | 4 +++- install/restart_scripts/renew_ca_cert | 2 +- install/restart_scripts/restart_dirsrv | 3 ++- install/restart_scripts/stop_pkicad | 3 ++- install/share/copy-schema-to-ca.py | 2 +- install/share/wsgi.py | 6 ++++-- install/tools/ipa-httpd-kdcproxy | 3 ++- install/tools/ipa-replica-conncheck | 4 +++- install/tools/ipactl | 5 ++++- ipaclient/install/client.py | 1 + ipaclient/install/ipa_certupdate.py | 2 +- ipaserver/install/ipa_backup.py | 2 +- ipaserver/install/ipa_ldap_updater.py | 2 +- ipaserver/install/ipa_restore.py | 1 + ipaserver/install/ipa_server_upgrade.py | 2 +- ipaserver/install/ipa_winsync_migrate.py | 3 ++- ipaserver/install/ldapupdate.py | 4 +++- ipaserver/install/server/install.py | 2 ++ ipaserver/install/server/replicainstall.py | 19 +++++++++++++------ 22 files changed, 52 insertions(+), 24 deletions(-) diff --git a/client/ipa-client-automount b/client/ipa-client-automount index 0dd15b3..18914bd 100755 --- a/client/ipa-client-automount +++ b/client/ipa-client-automount @@ -384,6 +384,7 @@ def main(): cfg = dict( context='cli_installer', + confdir=paths.ETC_IPA, in_server=False, debug=options.debug, verbose=0, diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit index 7389a5e..2e137ad 100755 --- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit +++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit @@ -494,7 +494,7 @@ def main(): 'ipaCACertRenewal': renew_ca_cert, } - api.bootstrap(in_server=True, context='renew') + api.bootstrap(in_server=True, context='renew', confdir=paths.ETC_IPA) api.finalize() api.Backend.ldap2.connect() diff --git a/install/migration/migration.py b/install/migration/migration.py index 4743279..73e4777 100644 --- a/install/migration/migration.py +++ b/install/migration/migration.py @@ -24,6 +24,7 @@ import errno from wsgiref.util import request_uri +from ipaplatform.paths import paths from ipapython.ipa_log_manager import root_logger from ipapython.dn import DN from ipapython import ipaldap @@ -72,7 +73,7 @@ def application(environ, start_response): # API object only for configuration, finalize() not needed api = create_api(mode=None) - api.bootstrap(context='server', in_server=True) + api.bootstrap(context='server', confdir=paths.ETC_IPA, in_server=True) try: bind(api.env.ldap_uri, api.env.basedn, form_data['username'].value, form_data['password'].value) diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains index a0d8a31..e5c2e8c 100755 --- a/install/oddjob/com.redhat.idm.trust-fetch-domains +++ b/install/oddjob/com.redhat.idm.trust-fetch-domains @@ -8,6 +8,7 @@ from ipapython.dn import DN from ipalib.config import Env from ipalib.constants import DEFAULT_CONFIG from ipaplatform.constants import constants +from ipaplatform.paths import paths import sys import os import pwd @@ -95,7 +96,8 @@ env._bootstrap(debug=options.debug, log=None) env._finalize_core(**dict(DEFAULT_CONFIG)) # Initialize the API with the proper debug level -api.bootstrap(in_server=True, debug=env.debug, log=None, context='server') +api.bootstrap(in_server=True, debug=env.debug, log=None, + context='server', confdir=paths.ETC_IPA) api.finalize() # Only import trust plugin after api is initialized or internal imports diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert index 46e4242..bbeae1a 100644 --- a/install/restart_scripts/renew_ca_cert +++ b/install/restart_scripts/renew_ca_cert @@ -40,7 +40,7 @@ from ipaplatform.paths import paths def _main(): nickname = sys.argv[1] - api.bootstrap(in_server=True, context='restart') + api.bootstrap(in_server=True, context='restart', confdir=paths.ETC_IPA) api.finalize() api.Backend.ldap2.connect() diff --git a/install/restart_scripts/restart_dirsrv b/install/restart_scripts/restart_dirsrv index 72d3c54..b4c9490 100644 --- a/install/restart_scripts/restart_dirsrv +++ b/install/restart_scripts/restart_dirsrv @@ -24,6 +24,7 @@ import syslog import traceback from ipalib import api from ipaplatform import services +from ipaplatform.paths import paths from ipaserver.install import certs @@ -33,7 +34,7 @@ def _main(): except IndexError: instance = "" - api.bootstrap(in_server=True, context='restart') + api.bootstrap(in_server=True, context='restart', confdir=paths.ETC_IPA) api.finalize() syslog.syslog(syslog.LOG_NOTICE, "certmonger restarted dirsrv instance '%s'" % instance) diff --git a/install/restart_scripts/stop_pkicad b/install/restart_scripts/stop_pkicad index ae07dcd..133a4ef 100644 --- a/install/restart_scripts/stop_pkicad +++ b/install/restart_scripts/stop_pkicad @@ -23,11 +23,12 @@ import syslog import traceback from ipalib import api from ipaplatform import services +from ipaplatform.paths import paths from ipaserver.install import certs def main(): - api.bootstrap(in_server=True, context='restart') + api.bootstrap(in_server=True, context='restart', confdir=paths.ETC_IPA) api.finalize() dogtag_service = services.knownservices['pki_tomcatd'] diff --git a/install/share/copy-schema-to-ca.py b/install/share/copy-schema-to-ca.py index 658204b..4daed6f 100755 --- a/install/share/copy-schema-to-ca.py +++ b/install/share/copy-schema-to-ca.py @@ -114,7 +114,7 @@ def main(): standard_logging_setup(verbose=True) # In 3.0, restarting needs access to api.env - api.bootstrap_with_global_options(context='server') + api.bootstrap_with_global_options(context='server', confdir=paths.ETC_IPA) add_ca_schema() restart_pki_ds() diff --git a/install/share/wsgi.py b/install/share/wsgi.py index ee9311e..ca97d1e 100644 --- a/install/share/wsgi.py +++ b/install/share/wsgi.py @@ -23,6 +23,7 @@ """ WSGI appliction for IPA server. """ +from ipaplatform.paths import paths from ipalib import api from ipalib.config import Env from ipalib.constants import DEFAULT_CONFIG @@ -31,11 +32,12 @@ # by reading in the configuration file(s). The server always reads # default.conf and will also read in `context'.conf. env = Env() -env._bootstrap(context='server', log=None) +env._bootstrap(context='server', log=None, confdir=paths.ETC_IPA) env._finalize_core(**dict(DEFAULT_CONFIG)) # Initialize the API with the proper debug level -api.bootstrap(context='server', debug=env.debug, log=None) +api.bootstrap(context='server', confdir=paths.ETC_IPA, + debug=env.debug, log=None) try: api.finalize() except Exception as e: diff --git a/install/tools/ipa-httpd-kdcproxy b/install/tools/ipa-httpd-kdcproxy index 329565c..bb2949b 100755 --- a/install/tools/ipa-httpd-kdcproxy +++ b/install/tools/ipa-httpd-kdcproxy @@ -184,7 +184,8 @@ class KDCProxyConfig(object): def main(debug=DEBUG, time_limit=TIME_LIMIT): # initialize API without file logging if not api.isdone('bootstrap'): - api.bootstrap(context='ipa-httpd-kdcproxy', log=None, debug=debug) + api.bootstrap(context='server', confdir=paths.ETC_IPA, + log=None, debug=debug) standard_logging_setup(verbose=True, debug=debug) try: diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck index 544116e..2955519 100755 --- a/install/tools/ipa-replica-conncheck +++ b/install/tools/ipa-replica-conncheck @@ -480,7 +480,9 @@ def main(): else: nss_dir = None - api.bootstrap(context='client', xmlrpc_uri=xmlrpc_uri, + api.bootstrap(context='client', + confdir=paths.ETC_IPA, + xmlrpc_uri=xmlrpc_uri, nss_dir=nss_db.secdir) api.finalize() try: diff --git a/install/tools/ipactl b/install/tools/ipactl index ce4fe02..db8ff62 100755 --- a/install/tools/ipactl +++ b/install/tools/ipactl @@ -560,7 +560,10 @@ def main(): else: raise e - api.bootstrap(in_server=True, context='ipactl', debug=options.debug) + api.bootstrap(in_server=True, + context='ipactl', + confdir=paths.ETC_IPA, + debug=options.debug) api.finalize() if '.' not in api.env.host: diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py index 7bd8404..0954c2b 100644 --- a/ipaclient/install/client.py +++ b/ipaclient/install/client.py @@ -2620,6 +2620,7 @@ def _install(options): with certdb.NSSDatabase() as tmp_db: api.bootstrap(context='cli_installer', + confdir=paths.ETC_IPA, debug=options.debug, delegate=False, nss_dir=tmp_db.secdir) diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py index 2c55db4..75c5d97 100644 --- a/ipaclient/install/ipa_certupdate.py +++ b/ipaclient/install/ipa_certupdate.py @@ -53,7 +53,7 @@ def run(self): raise admintool.ScriptError( "IPA client is not configured on this system.") - api.bootstrap(context='cli_installer') + api.bootstrap(context='cli_installer', confdir=paths.ETC_IPA) api.finalize() server = urlsplit(api.env.jsonrpc_uri).hostname diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py index a4261f5..c11120b 100644 --- a/ipaserver/install/ipa_backup.py +++ b/ipaserver/install/ipa_backup.py @@ -256,7 +256,7 @@ def run(self): options = self.options super(Backup, self).run() - api.bootstrap(in_server=True, context='backup') + api.bootstrap(in_server=True, context='backup', confdir=paths.ETC_IPA) api.finalize() self.log.info("Preparing backup on %s", api.env.host) diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py index e6e6b5a..f3e05b8 100644 --- a/ipaserver/install/ipa_ldap_updater.py +++ b/ipaserver/install/ipa_ldap_updater.py @@ -89,7 +89,7 @@ def setup_logging(self): def run(self): super(LDAPUpdater, self).run() - api.bootstrap(in_server=True, context='updates') + api.bootstrap(in_server=True, context='updates', confdir=paths.ETC_IPA) api.finalize() def handle_error(self, exception): diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py index 2987b5a..2fae215 100644 --- a/ipaserver/install/ipa_restore.py +++ b/ipaserver/install/ipa_restore.py @@ -841,6 +841,7 @@ def cert_restore(self): services.knownservices.certmonger.restart() def init_api(self, **overrides): + overrides.setdefault('confdir', paths.ETC_IPA) api.bootstrap(in_server=True, context='restore', **overrides) api.finalize() diff --git a/ipaserver/install/ipa_server_upgrade.py b/ipaserver/install/ipa_server_upgrade.py index c384704..ef31068 100644 --- a/ipaserver/install/ipa_server_upgrade.py +++ b/ipaserver/install/ipa_server_upgrade.py @@ -38,7 +38,7 @@ def setup_logging(self): def run(self): super(ServerUpgrade, self).run() - api.bootstrap(in_server=True, context='updates') + api.bootstrap(in_server=True, context='updates', confdir=paths.ETC_IPA) api.finalize() try: diff --git a/ipaserver/install/ipa_winsync_migrate.py b/ipaserver/install/ipa_winsync_migrate.py index d0653c9..cb77de6 100644 --- a/ipaserver/install/ipa_winsync_migrate.py +++ b/ipaserver/install/ipa_winsync_migrate.py @@ -24,6 +24,7 @@ from ipalib import api from ipalib import errors +from ipaplatform.paths import paths from ipapython import admintool from ipapython.dn import DN from ipapython.ipautil import realm_to_suffix, posixify @@ -346,7 +347,7 @@ def main(cls, argv): sys.exit(e) # Finalize API - api.bootstrap(in_server=True, context='server') + api.bootstrap(in_server=True, context='server', confdir=paths.ETC_IPA) api.finalize() # Setup LDAP connection diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index 576b035..bc2673b 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -308,7 +308,9 @@ def __init__(self, dm_password=None, sub_dict={}, self.sub_dict["TOTAL_EXCLUDES"] = "(objectclass=*) $ EXCLUDE " + \ " ".join(constants.REPL_AGMT_TOTAL_EXCLUDES) self.api = create_api(mode=None) - self.api.bootstrap(in_server=True, context='updates', + self.api.bootstrap(in_server=True, + context='updates', + confdir=paths.ETC_IPA, ldap_uri=self.ldapuri) self.api.finalize() if online: diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index 1f2e8a4..b30a934 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -566,6 +566,7 @@ def install_check(installer): # we are sure we have the configuration file ready. cfg = dict( context='installer', + confdir=paths.ETC_IPA, in_server=True, # make sure host name specified by user is used instead of default host=host_name, @@ -962,6 +963,7 @@ def uninstall_check(installer): # we are sure we have the configuration file ready. cfg = dict( context='installer', + confdir=paths.ETC_IPA, in_server=True, ) diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index 742848d..f1f7b1b 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -692,7 +692,7 @@ def install_check(installer): # Note: We must do this before bootstraping and finalizing ipalib.api create_ipa_conf(fstore, config, ca_enabled) - api.bootstrap(in_server=True, context='installer') + api.bootstrap(in_server=True, context='installer', confdir=paths.ETC_IPA) api.finalize() installutils.verify_fqdn(config.master_host_name, options.no_host_dns) @@ -731,7 +731,9 @@ def install_check(installer): ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name) remote_api = create_api(mode=None) - remote_api.bootstrap(in_server=True, context='installer', + remote_api.bootstrap(in_server=True, + context='installer', + confdir=paths.ETC_IPA, ldap_uri=ldapuri) remote_api.finalize() conn = remote_api.Backend.ldap2 @@ -954,12 +956,14 @@ def promote_check(installer): fstore = sysrestore.FileStore(paths.SYSRESTORE) env = Env() - env._bootstrap(context='installer', log=None) + env._bootstrap(context='installer', confdir=paths.ETC_IPA, log=None) env._finalize_core(**dict(constants.DEFAULT_CONFIG)) # pylint: disable=no-member xmlrpc_uri = 'https://{}/ipa/xml'.format(ipautil.format_netloc(env.host)) - api.bootstrap(in_server=True, context='installer', + api.bootstrap(in_server=True, + context='installer', + confdir=paths.ETC_IPA, ldap_uri=installutils.realm_to_ldapi_uri(env.realm), xmlrpc_uri=xmlrpc_uri) # pylint: enable=no-member @@ -1056,8 +1060,11 @@ def promote_check(installer): xmlrpc_uri = 'https://{}/ipa/xml'.format( ipautil.format_netloc(config.master_host_name)) remote_api = create_api(mode=None) - remote_api.bootstrap(in_server=True, context='installer', - ldap_uri=ldapuri, xmlrpc_uri=xmlrpc_uri) + remote_api.bootstrap(in_server=True, + context='installer', + confdir=paths.ETC_IPA, + ldap_uri=ldapuri, + xmlrpc_uri=xmlrpc_uri) remote_api.finalize() check_remote_version(remote_api) From 0ee2abb01a52136ed47dc2cf1707089d54db02b0 Mon Sep 17 00:00:00 2001 From: Christian Heimes <chei...@redhat.com> Date: Mon, 24 Oct 2016 10:35:41 +0200 Subject: [PATCH 2/2] Use env var IPA_CONFDIR to get confdir The environment variable IPA_CONFDIR overrides the default confdir path. The value of the environment variable must be an absolute path to an existing directory. The new variable makes it much simpler to use the 'ipa' command and ipalib with a local configuration directory. Some contexts like server, installer, and upgrades set the confdir explicitly and do not support the env var. Signed-off-by: Christian Heimes <chei...@redhat.com> --- client/man/ipa.1 | 4 ++++ ipalib/config.py | 12 ++++++++++- ipalib/plugable.py | 4 ++++ ipatests/test_ipalib/test_plugable.py | 40 +++++++++++++++++++++++++++++++++-- ipatests/util.py | 6 ++++++ 5 files changed, 63 insertions(+), 3 deletions(-) diff --git a/client/man/ipa.1 b/client/man/ipa.1 index cc5641b..f35f557 100644 --- a/client/man/ipa.1 +++ b/client/man/ipa.1 @@ -190,6 +190,10 @@ The ipa client will determine which server to connect to in this order: .TP If a kerberos error is raised by any of the requests then it will stop processing and display the error message. +.SH "ENVIRONMENT VARIABLES" +.TP +\fBIPA_CONFDIR\fR +Override path to confdir (default: \fB/etc/ipa\fR). .SH "FILES" .TP \fB/etc/ipa/default.conf\fR diff --git a/ipalib/config.py b/ipalib/config.py index 1075d62..c46d033 100644 --- a/ipalib/config.py +++ b/ipalib/config.py @@ -43,6 +43,7 @@ from ipalib.base import check_name from ipalib.constants import CONFIG_SECTION from ipalib.constants import OVERRIDE_ERROR, SET_ERROR, DEL_ERROR +from ipapython.admintool import ScriptError if six.PY3: unicode = str @@ -460,8 +461,17 @@ def _bootstrap(self, **overrides): self.context = 'default' # Set confdir: + self.confdir_env = False if 'confdir' not in self: - if self.in_tree: + ipa_confdir = os.environ.get('IPA_CONFDIR') + if ipa_confdir is not None: + if not path.isabs(ipa_confdir) or not path.isdir(ipa_confdir): + raise ScriptError( + 'IPA_CONFDIR env var must be an absolute path to an ' + 'existing directory.') + self.confdir = ipa_confdir + self.confdir_env = True + elif self.in_tree: self.confdir = self.dot_ipa else: self.confdir = path.join('/', 'etc', 'ipa') diff --git a/ipalib/plugable.py b/ipalib/plugable.py index 503534f..e9d4c80 100644 --- a/ipalib/plugable.py +++ b/ipalib/plugable.py @@ -713,6 +713,10 @@ def finalize(self): self.__doing('finalize') self.__do_if_not_done('load_plugins') + if self.env.confdir_env: + self.log.info("IPA_CONFDIR env var sets confdir to '%s'.", + self.env.confdir) + for plugin in self.__plugins: if not self.env.validate_api: if plugin.full_name not in DEFAULT_PLUGINS: diff --git a/ipatests/test_ipalib/test_plugable.py b/ipatests/test_ipalib/test_plugable.py index 1ee1102..ff22446 100644 --- a/ipatests/test_ipalib/test_plugable.py +++ b/ipatests/test_ipalib/test_plugable.py @@ -24,9 +24,13 @@ # FIXME: Pylint errors # pylint: disable=no-member +import os +import textwrap + +from ipalib import plugable, errors, create_api +from ipapython.admintool import ScriptError from ipatests.util import raises, read_only -from ipatests.util import ClassChecker, create_test_api -from ipalib import plugable, errors +from ipatests.util import ClassChecker, create_test_api, TempHome import pytest @@ -272,3 +276,35 @@ def test_load_plugins(self): assert o.isdone('load_plugins') is True e = raises(Exception, o.load_plugins) assert str(e) == 'API.load_plugins() already called' + + def test_ipaconf_env(self): + ipa_confdir = os.environ.get('IPA_CONFDIR', None) + try: + with TempHome() as home: + defaultconf = home.join('default.conf') + with open(defaultconf, 'w') as f: + f.write(textwrap.dedent(""" + [global] + basedn = dc=ipa,dc=test + realm = IPA.TEST + domain = ipa.test + """) + ) + os.environ['IPA_CONFDIR'] = home.path + api = create_api(mode='unit_test') + api.bootstrap() + api.finalize() + assert api.env.confdir == home.path + assert api.env.conf_default == defaultconf + assert api.env.realm == 'IPA.TEST' + assert api.env.domain == 'ipa.test' + + os.environ['IPA_CONFDIR'] = home.join('invalid') + api = create_api(mode='unit_test') + with pytest.raises(ScriptError): + api.bootstrap() + finally: + if ipa_confdir: + os.environ['IPA_CONFDIR'] = ipa_confdir + else: + os.environ.pop('IPA_CONFDIR') diff --git a/ipatests/util.py b/ipatests/util.py index 3f66b59..7b5e317 100644 --- a/ipatests/util.py +++ b/ipatests/util.py @@ -96,6 +96,12 @@ def join(self, *parts): def __del__(self): self.rmtree() + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.rmtree() + class TempHome(TempDir): def __init__(self):
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code