mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Use namespace-aware meta importer for ipaplatform
Instead of symlinks and build-time configuration the ipaplatform module is now able to auto-detect platforms on import time. The meta importer uses the platform 'ID' from /etc/os-releases. It falls back to 'ID_LIKE' on platforms like CentOS, which has ID=centos and ID_LIKE="rhel fedora". The meta importer is able to handle namespace packages and the ipaplatform package has been turned into a namespace package in order to support external platform specifications. https://fedorahosted.org/freeipa/ticket/6474 Signed-off-by: Christian Heimes <cheimes@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
parent
f6adf4f3a8
commit
a48f6511f6
6
.gitignore
vendored
6
.gitignore
vendored
@ -108,11 +108,7 @@ freeipa2-dev-doc
|
||||
/client/ipa-join
|
||||
/client/ipa-rmkeytab
|
||||
|
||||
/ipaplatform/override.py
|
||||
/ipapython/version.py
|
||||
/ipapython/.DEFAULT_PLUGINS
|
||||
|
||||
/ipaplatform/__init__.py
|
||||
/ipaplatform/constants.py
|
||||
/ipaplatform/paths.py
|
||||
/ipaplatform/services.py
|
||||
/ipaplatform/tasks.py
|
||||
|
@ -28,9 +28,9 @@ env:
|
||||
test_install
|
||||
test_ipaclient
|
||||
test_ipalib
|
||||
test_ipaplatform
|
||||
test_ipapython
|
||||
test_ipaserver
|
||||
test_integration/test_ipalib_util.py
|
||||
test_xmlrpc/test_[l-z]*.py"
|
||||
- TASK_TO_RUN="run-tests"
|
||||
PYTHON=/usr/bin/python3
|
||||
@ -43,9 +43,9 @@ env:
|
||||
test_install
|
||||
test_ipaclient
|
||||
test_ipalib
|
||||
test_ipaplatform
|
||||
test_ipapython
|
||||
test_ipaserver
|
||||
test_integration/test_ipalib_util.py
|
||||
test_xmlrpc/test_[l-uw-z]*.py"
|
||||
# FIXME: add vault tests once PKI finally fixes vault
|
||||
install:
|
||||
|
22
Makefile.am
22
Makefile.am
@ -8,10 +8,14 @@ if WITH_IPATESTS
|
||||
IPATESTS_SUBDIRS = ipatests
|
||||
endif
|
||||
|
||||
IPACLIENT_SUBDIRS = ipaclient ipalib ipapython
|
||||
IPA_PLACEHOLDERS = freeipa ipa ipaplatform ipaserver ipatests
|
||||
IPACLIENT_SUBDIRS = ipaclient ipalib ipaplatform ipapython
|
||||
IPA_PLACEHOLDERS = freeipa ipa ipaserver ipatests
|
||||
SUBDIRS = asn1 util client contrib po pypi \
|
||||
$(IPACLIENT_SUBDIRS) ipaplatform $(IPATESTS_SUBDIRS) $(SERVER_SUBDIRS)
|
||||
$(IPACLIENT_SUBDIRS) $(IPATESTS_SUBDIRS) $(SERVER_SUBDIRS)
|
||||
|
||||
GENERATED_PYTHON_FILES = \
|
||||
$(top_builddir)/ipaplatform/override.py \
|
||||
$(top_builddir)/ipapython/version.py
|
||||
|
||||
MOSTLYCLEANFILES = ipasetup.pyc ipasetup.pyo \
|
||||
pylint_plugins.pyc pylint_plugins.pyo
|
||||
@ -133,7 +137,7 @@ _srpms-body: _rpms-prep
|
||||
rm -f rm -f $(top_builddir)/.version
|
||||
|
||||
.PHONY: lite-server
|
||||
lite-server: $(top_builddir)/ipapython/version.py
|
||||
lite-server: $(GENERATED_PYTHON_FILES)
|
||||
+$(MAKE) -C $(top_builddir)/install/ui
|
||||
PYTHONPATH=$(top_srcdir) $(PYTHON) -bb \
|
||||
contrib/lite-server.py $(LITESERVER_ARGS)
|
||||
@ -179,16 +183,20 @@ else
|
||||
endif
|
||||
@echo "All tests passed."
|
||||
|
||||
.PHONY: $(top_builddir)/ipaplatform/override.py
|
||||
$(top_builddir)/ipaplatform/override.py:
|
||||
(cd $(top_builddir)/ipaplatform && make override.py)
|
||||
|
||||
.PHONY: $(top_builddir)/ipapython/version.py
|
||||
$(top_builddir)/ipapython/version.py:
|
||||
(cd $(top_builddir)/ipapython && make version.py)
|
||||
|
||||
.PHONY: acilint
|
||||
acilint: $(top_builddir)/ipapython/version.py
|
||||
acilint: $(GENERATED_PYTHON_FILES)
|
||||
cd $(srcdir); ./makeaci --validate
|
||||
|
||||
.PHONY: apilint
|
||||
apilint: $(top_builddir)/ipapython/version.py
|
||||
apilint: $(GENERATED_PYTHON_FILES)
|
||||
cd $(srcdir); ./makeapi --validate
|
||||
|
||||
.PHONY: polint
|
||||
@ -203,7 +211,7 @@ polint:
|
||||
.PHONY: pylint
|
||||
|
||||
if WITH_PYLINT
|
||||
pylint: $(top_builddir)/ipapython/version.py ipasetup.py
|
||||
pylint: $(GENERATED_PYTHON_FILES) ipasetup.py
|
||||
FILES=`find $(top_srcdir) \
|
||||
-type d -exec test -e '{}/__init__.py' \; -print -prune -o \
|
||||
-path './rpmbuild' -prune -o \
|
||||
|
@ -520,13 +520,6 @@ AC_SUBST(LDFLAGS)
|
||||
|
||||
|
||||
# Files
|
||||
AC_CONFIG_LINKS([ipaplatform/__init__.py:ipaplatform/$IPAPLATFORM/__init__.py
|
||||
ipaplatform/constants.py:ipaplatform/$IPAPLATFORM/constants.py
|
||||
ipaplatform/paths.py:ipaplatform/$IPAPLATFORM/paths.py
|
||||
ipaplatform/services.py:ipaplatform/$IPAPLATFORM/services.py
|
||||
ipaplatform/tasks.py:ipaplatform/$IPAPLATFORM/tasks.py
|
||||
])
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
asn1/Makefile
|
||||
@ -594,7 +587,6 @@ AC_CONFIG_FILES([
|
||||
pypi/Makefile
|
||||
pypi/freeipa/Makefile
|
||||
pypi/ipa/Makefile
|
||||
pypi/ipaplatform/Makefile
|
||||
pypi/ipaserver/Makefile
|
||||
pypi/ipatests/Makefile
|
||||
po/Makefile.in
|
||||
|
@ -1637,6 +1637,7 @@ fi
|
||||
%{python_sitelib}/ipapython-*.egg-info
|
||||
%{python_sitelib}/ipalib-*.egg-info
|
||||
%{python_sitelib}/ipaplatform-*.egg-info
|
||||
%{python_sitelib}/ipaplatform-*-nspkg.pth
|
||||
|
||||
|
||||
%files common -f %{gettext_domain}.lang
|
||||
@ -1658,6 +1659,7 @@ fi
|
||||
%{python3_sitelib}/ipapython-*.egg-info
|
||||
%{python3_sitelib}/ipalib-*.egg-info
|
||||
%{python3_sitelib}/ipaplatform-*.egg-info
|
||||
%{python3_sitelib}/ipaplatform-*-nspkg.pth
|
||||
|
||||
%endif # with_python3
|
||||
|
||||
|
@ -28,6 +28,7 @@ of the process.
|
||||
|
||||
For the per-request thread-local information, see `ipalib.request`.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
from os import path
|
||||
@ -39,6 +40,7 @@ from six.moves.urllib.parse import urlparse, urlunparse
|
||||
from six.moves.configparser import RawConfigParser, ParsingError
|
||||
# pylint: enable=import-error
|
||||
|
||||
from ipaplatform.tasks import tasks
|
||||
from ipapython.dn import DN
|
||||
from ipalib.base import check_name
|
||||
from ipalib.constants import (
|
||||
@ -47,12 +49,6 @@ from ipalib.constants import (
|
||||
TLS_VERSIONS
|
||||
)
|
||||
from ipalib import errors
|
||||
try:
|
||||
# pylint: disable=ipa-forbidden-import
|
||||
from ipaplatform.tasks import tasks
|
||||
# pylint: enable=ipa-forbidden-import
|
||||
except ImportError:
|
||||
tasks = None
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
@ -451,10 +447,7 @@ class Env(object):
|
||||
self.script = path.abspath(sys.argv[0])
|
||||
self.bin = path.dirname(self.script)
|
||||
self.home = os.environ.get('HOME', None)
|
||||
|
||||
# Set fips_mode only if ipaplatform module was loaded
|
||||
if tasks is not None:
|
||||
self.fips_mode = tasks.is_fips_enabled()
|
||||
self.fips_mode = tasks.is_fips_enabled()
|
||||
|
||||
# Merge in overrides:
|
||||
self._merge(**overrides)
|
||||
|
@ -37,6 +37,7 @@ if __name__ == '__main__':
|
||||
"ipalib.install",
|
||||
],
|
||||
install_requires=[
|
||||
"ipaplatform",
|
||||
"ipapython",
|
||||
"netaddr",
|
||||
"pyasn1",
|
||||
|
@ -55,6 +55,7 @@ from ipalib.constants import (
|
||||
TLS_VERSIONS, TLS_VERSION_MINIMAL, TLS_HIGH_CIPHERS
|
||||
)
|
||||
from ipalib.text import _
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.ssh import SSHPublicKey
|
||||
from ipapython.dn import DN, RDN
|
||||
from ipapython.dnsutil import DNSName
|
||||
@ -1101,9 +1102,9 @@ def check_client_configuration():
|
||||
"""
|
||||
Check if IPA client is configured on the system.
|
||||
"""
|
||||
if (not os.path.isfile(_IPA_DEFAULT_CONF) or
|
||||
not os.path.isdir(_IPA_CLIENT_SYSRESTORE) or
|
||||
not os.listdir(_IPA_CLIENT_SYSRESTORE)):
|
||||
if (not os.path.isfile(paths.IPA_DEFAULT_CONF) or
|
||||
not os.path.isdir(paths.IPA_CLIENT_SYSRESTORE) or
|
||||
not os.listdir(paths.IPA_CLIENT_SYSRESTORE)):
|
||||
raise ScriptError('IPA client is not configured on this system')
|
||||
|
||||
|
||||
|
@ -1 +1,12 @@
|
||||
include $(top_srcdir)/Makefile.python.am
|
||||
|
||||
EXTRA_DIST = override.py.in
|
||||
|
||||
all-local: override.py
|
||||
dist-hook: override.py
|
||||
install-exec-local: override.py
|
||||
|
||||
override.py: override.py.in $(top_builddir)/$(CONFIG_STATUS)
|
||||
$(AM_V_GEN)sed \
|
||||
-e 's|@IPAPLATFORM[@]|$(IPAPLATFORM)|g' \
|
||||
$< > $@
|
||||
|
11
ipaplatform/__init__.py
Normal file
11
ipaplatform/__init__.py
Normal file
@ -0,0 +1,11 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
"""ipaplatform namespace package
|
||||
|
||||
In the presence of a namespace package, any code in this module will be
|
||||
ignore.
|
||||
"""
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
|
||||
NAME = None # initialized by IpaMetaImporter
|
150
ipaplatform/_importhook.py
Normal file
150
ipaplatform/_importhook.py
Normal file
@ -0,0 +1,150 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
"""Meta import hook for ipaplatform.
|
||||
|
||||
Known Linux distros with /etc/os-release
|
||||
----------------------------------------
|
||||
|
||||
- alpine
|
||||
- centos (like rhel, fedora)
|
||||
- debian
|
||||
- fedora
|
||||
- rhel
|
||||
- ubuntu (like debian)
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import io
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
|
||||
import ipaplatform
|
||||
try:
|
||||
from ipaplatform.override import OVERRIDE
|
||||
except ImportError:
|
||||
OVERRIDE = None
|
||||
|
||||
|
||||
_osrelease_line = re.compile(
|
||||
u"^(?!#)(?P<name>[a-zA-Z0-9_]+)="
|
||||
u"(?P<quote>[\"\']?)(?P<value>.+)(?P=quote)$"
|
||||
)
|
||||
|
||||
|
||||
class IpaMetaImporter(object):
|
||||
"""Meta import hook and platform detector.
|
||||
|
||||
The meta import hook uses /etc/os-release to auto-detects the best
|
||||
matching ipaplatform provider. It is compatible with external namespace
|
||||
packages, too.
|
||||
"""
|
||||
modules = {
|
||||
'ipaplatform.constants',
|
||||
'ipaplatform.paths',
|
||||
'ipaplatform.services',
|
||||
'ipaplatform.tasks'
|
||||
}
|
||||
|
||||
bsd_family = (
|
||||
'freebsd',
|
||||
'openbsd',
|
||||
'netbsd',
|
||||
'dragonfly',
|
||||
'gnukfreebsd'
|
||||
)
|
||||
|
||||
def __init__(self, override=OVERRIDE):
|
||||
self.override = override
|
||||
self.platform_ids = self._get_platform_ids(self.override)
|
||||
self.platform = self._get_platform(self.platform_ids)
|
||||
|
||||
def _get_platform_ids(self, override):
|
||||
platforms = []
|
||||
# allow RPM and Debian packages to override platform
|
||||
if override is not None:
|
||||
platforms.append(override)
|
||||
|
||||
if sys.platform.startswith('linux'):
|
||||
# Linux, get distribution from /etc/os-release
|
||||
try:
|
||||
platforms.extend(self._parse_osrelease())
|
||||
except Exception as e:
|
||||
warnings.warn("Failed to read /etc/os-release: {}".format(e))
|
||||
elif sys.platform == 'win32':
|
||||
# Windows 32 or 64bit platform
|
||||
platforms.append('win32')
|
||||
elif sys.platform == 'darwin':
|
||||
# macOS
|
||||
platforms.append('macos')
|
||||
elif sys.platform.startswith(self.bsd_family):
|
||||
# BSD family, look for e.g. ['freebsd10', 'freebsd']
|
||||
platforms.append(sys.platform)
|
||||
simple = sys.platform.rstrip('0123456789')
|
||||
if simple != sys.platform:
|
||||
platforms.append(simple)
|
||||
|
||||
if not platforms:
|
||||
raise ValueError("Unsupported platform: {}".format(sys.platform))
|
||||
|
||||
return platforms
|
||||
|
||||
def _parse_osrelease(self, filename='/etc/os-release'):
|
||||
release = {}
|
||||
with io.open(filename, encoding='utf-8') as f:
|
||||
for line in f:
|
||||
mo = _osrelease_line.match(line)
|
||||
if mo is not None:
|
||||
release[mo.group('name')] = mo.group('value')
|
||||
|
||||
platforms = [
|
||||
release['ID'],
|
||||
]
|
||||
if "ID_LIKE" in release:
|
||||
platforms.extend(
|
||||
v.strip() for v in release['ID_LIKE'].split(' ') if v.strip()
|
||||
)
|
||||
|
||||
return platforms
|
||||
|
||||
def _get_platform(self, platform_ids):
|
||||
for platform in platform_ids:
|
||||
try:
|
||||
importlib.import_module('ipaplatform.{}'.format(platform))
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return platform
|
||||
raise ImportError('No ipaplatform available for "{}"'.format(
|
||||
', '.join(platform_ids)))
|
||||
|
||||
def find_module(self, fullname, path=None):
|
||||
"""Meta importer hook"""
|
||||
if fullname in self.modules:
|
||||
return self
|
||||
return None
|
||||
|
||||
def load_module(self, fullname):
|
||||
"""Meta importer hook"""
|
||||
suffix = fullname.split('.', 1)[1]
|
||||
alias = 'ipaplatform.{}.{}'.format(self.platform, suffix)
|
||||
platform_mod = importlib.import_module(alias)
|
||||
base_mod = sys.modules.get(fullname)
|
||||
if base_mod is not None:
|
||||
# module has been imported before, update its __dict__
|
||||
base_mod.__dict__.update(platform_mod.__dict__)
|
||||
for key in list(base_mod.__dict__):
|
||||
if not hasattr(platform_mod, key):
|
||||
delattr(base_mod, key)
|
||||
else:
|
||||
sys.modules[fullname] = platform_mod
|
||||
return platform_mod
|
||||
|
||||
|
||||
metaimporter = IpaMetaImporter()
|
||||
sys.meta_path.insert(0, metaimporter)
|
||||
|
||||
fixup_module = metaimporter.load_module
|
||||
ipaplatform.NAME = metaimporter.platform
|
@ -37,3 +37,6 @@ class BaseConstantsNamespace(object):
|
||||
'httpd_dbus_sssd': 'on',
|
||||
}
|
||||
SSSD_USER = "sssd"
|
||||
|
||||
|
||||
constants = BaseConstantsNamespace()
|
||||
|
@ -355,5 +355,7 @@ class BasePathNamespace(object):
|
||||
GSSPROXY_CONF = '/etc/gssproxy/10-ipa.conf'
|
||||
KRB5CC_HTTPD = '/tmp/krb5cc-httpd'
|
||||
IF_INET6 = '/proc/net/if_inet6'
|
||||
AUTHCONFIG = None
|
||||
|
||||
path_namespace = BasePathNamespace
|
||||
|
||||
paths = BasePathNamespace()
|
||||
|
@ -505,8 +505,12 @@ class SystemdService(PlatformService):
|
||||
|
||||
# Objects below are expected to be exported by platform module
|
||||
|
||||
service = None
|
||||
knownservices = None
|
||||
def base_service_class_factory(name, api=None):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
service = base_service_class_factory
|
||||
knownservices = KnownServices({})
|
||||
|
||||
# System may support more time&date services. FreeIPA supports ntpd only, other
|
||||
# services will be disabled during IPA installation
|
||||
|
@ -204,6 +204,9 @@ class BaseTaskNamespace(object):
|
||||
"""Configure httpd service to work with IPA"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def configure_http_gssproxy_conf(self, ipauser):
|
||||
raise NotImplementedError()
|
||||
|
||||
def remove_httpd_service_ipa_conf(self):
|
||||
"""Remove configuration of httpd service of IPA"""
|
||||
raise NotImplementedError()
|
||||
@ -219,3 +222,6 @@ class BaseTaskNamespace(object):
|
||||
logger.debug('Done adding user to group')
|
||||
except ipautil.CalledProcessError as e:
|
||||
logger.debug('Failed to add user to group: %s', e)
|
||||
|
||||
|
||||
tasks = BaseTaskNamespace()
|
||||
|
8
ipaplatform/constants.py
Normal file
8
ipaplatform/constants.py
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
"""IpaMetaImporter replaces this module with ipaplatform.$NAME.constants.
|
||||
"""
|
||||
import ipaplatform._importhook
|
||||
|
||||
ipaplatform._importhook.fixup_module('ipaplatform.constants')
|
1
ipaplatform/override.py.in
Normal file
1
ipaplatform/override.py.in
Normal file
@ -0,0 +1 @@
|
||||
OVERRIDE = '@IPAPLATFORM@'
|
8
ipaplatform/paths.py
Normal file
8
ipaplatform/paths.py
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
"""IpaMetaImporter replaces this module with ipaplatform.$NAME.paths.
|
||||
"""
|
||||
import ipaplatform._importhook
|
||||
|
||||
ipaplatform._importhook.fixup_module('ipaplatform.paths')
|
8
ipaplatform/services.py
Normal file
8
ipaplatform/services.py
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
"""IpaMetaImporter replaces this module with ipaplatform.$NAME.services.
|
||||
"""
|
||||
import ipaplatform._importhook
|
||||
|
||||
ipaplatform._importhook.fixup_module('ipaplatform.services')
|
@ -32,6 +32,7 @@ if __name__ == '__main__':
|
||||
name="ipaplatform",
|
||||
doc=__doc__,
|
||||
package_dir={'ipaplatform': ''},
|
||||
namespace_packages=['ipaplatform'],
|
||||
packages=[
|
||||
"ipaplatform",
|
||||
"ipaplatform.base",
|
||||
|
8
ipaplatform/tasks.py
Normal file
8
ipaplatform/tasks.py
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
"""IpaMetaImporter replaces this module with ipaplatform.$NAME.tasks.
|
||||
"""
|
||||
import ipaplatform._importhook
|
||||
|
||||
ipaplatform._importhook.fixup_module('ipaplatform.tasks')
|
@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from __future__ import absolute_import
|
||||
|
||||
import collections
|
||||
import logging
|
||||
@ -30,24 +31,12 @@ import shutil
|
||||
|
||||
import cryptography.x509
|
||||
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.dn import DN
|
||||
from ipapython.kerberos import Principal
|
||||
from ipapython import ipautil
|
||||
from ipalib import x509 # pylint: disable=ipa-forbidden-import
|
||||
|
||||
try:
|
||||
# pylint: disable=import-error,ipa-forbidden-import
|
||||
from ipaplatform.paths import paths
|
||||
# pylint: enable=import-error,ipa-forbidden-import
|
||||
except ImportError:
|
||||
CERTUTIL = '/usr/bin/certutil'
|
||||
PK12UTIL = '/usr/bin/pk12util'
|
||||
OPENSSL = '/usr/bin/openssl'
|
||||
else:
|
||||
CERTUTIL = paths.CERTUTIL
|
||||
PK12UTIL = paths.PK12UTIL
|
||||
OPENSSL = paths.OPENSSL
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -188,7 +177,8 @@ def verify_kdc_cert_validity(kdc_cert, ca_certs, realm):
|
||||
|
||||
try:
|
||||
ipautil.run(
|
||||
[OPENSSL, 'verify', '-CAfile', ca_file.name, kdc_file.name],
|
||||
[paths.OPENSSL, 'verify', '-CAfile', ca_file.name,
|
||||
kdc_file.name],
|
||||
capture_output=True)
|
||||
except ipautil.CalledProcessError as e:
|
||||
raise ValueError(e.output)
|
||||
@ -244,7 +234,7 @@ class NSSDatabase(object):
|
||||
self.close()
|
||||
|
||||
def run_certutil(self, args, stdin=None, **kwargs):
|
||||
new_args = [CERTUTIL, "-d", self.secdir]
|
||||
new_args = [paths.CERTUTIL, "-d", self.secdir]
|
||||
new_args = new_args + args
|
||||
new_args.extend(['-f', self.pwd_file])
|
||||
return ipautil.run(new_args, stdin, **kwargs)
|
||||
@ -367,7 +357,7 @@ class NSSDatabase(object):
|
||||
return root_nicknames
|
||||
|
||||
def export_pkcs12(self, nickname, pkcs12_filename, pkcs12_passwd=None):
|
||||
args = [PK12UTIL, "-d", self.secdir,
|
||||
args = [paths.PK12UTIL, "-d", self.secdir,
|
||||
"-o", pkcs12_filename,
|
||||
"-n", nickname,
|
||||
"-k", self.pwd_file]
|
||||
@ -391,7 +381,7 @@ class NSSDatabase(object):
|
||||
pkcs12_password_file.close()
|
||||
|
||||
def import_pkcs12(self, pkcs12_filename, pkcs12_passwd=None):
|
||||
args = [PK12UTIL, "-d", self.secdir,
|
||||
args = [paths.PK12UTIL, "-d", self.secdir,
|
||||
"-i", pkcs12_filename,
|
||||
"-k", self.pwd_file, '-v']
|
||||
pkcs12_password_file = None
|
||||
@ -501,7 +491,7 @@ class NSSDatabase(object):
|
||||
(key_file, filename))
|
||||
|
||||
args = [
|
||||
OPENSSL, 'pkcs8',
|
||||
paths.OPENSSL, 'pkcs8',
|
||||
'-topk8',
|
||||
'-passout', 'file:' + self.pwd_file,
|
||||
]
|
||||
@ -588,7 +578,7 @@ class NSSDatabase(object):
|
||||
out_password = ipautil.ipa_generate_password()
|
||||
out_pwdfile = ipautil.write_tmp_file(out_password)
|
||||
args = [
|
||||
OPENSSL, 'pkcs12',
|
||||
paths.OPENSSL, 'pkcs12',
|
||||
'-export',
|
||||
'-in', in_file.name,
|
||||
'-out', out_file.name,
|
||||
|
@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from __future__ import absolute_import
|
||||
|
||||
# pylint: disable=deprecated-module
|
||||
from optparse import (
|
||||
@ -33,18 +34,10 @@ from six.moves.configparser import SafeConfigParser
|
||||
from six.moves.urllib.parse import urlsplit
|
||||
# pylint: enable=import-error
|
||||
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.dn import DN
|
||||
from ipapython.ipautil import CheckedIPAddress, CheckedIPAddressLoopback
|
||||
|
||||
try:
|
||||
# pylint: disable=ipa-forbidden-import
|
||||
from ipaplatform.paths import paths
|
||||
# pylint: enable=ipa-forbidden-import
|
||||
except ImportError:
|
||||
IPA_DEFAULT_CONF = '/etc/ipa/default.conf'
|
||||
else:
|
||||
IPA_DEFAULT_CONF = paths.IPA_DEFAULT_CONF
|
||||
|
||||
|
||||
class IPAConfigError(Exception):
|
||||
def __init__(self, msg=''):
|
||||
@ -188,7 +181,7 @@ config = IPAConfig()
|
||||
|
||||
def __parse_config(discover_server = True):
|
||||
p = SafeConfigParser()
|
||||
p.read(IPA_DEFAULT_CONF)
|
||||
p.read(paths.IPA_DEFAULT_CONF)
|
||||
|
||||
try:
|
||||
if not config.default_realm:
|
||||
|
@ -42,6 +42,7 @@ if __name__ == '__main__':
|
||||
"dnspython",
|
||||
"gssapi",
|
||||
# "ipalib", # circular dependency
|
||||
"ipaplatform",
|
||||
"netaddr",
|
||||
"netifaces",
|
||||
"six",
|
||||
|
@ -25,22 +25,27 @@ class build_py(setuptools_build_py):
|
||||
"""
|
||||
def initialize_options(self):
|
||||
setuptools_build_py.initialize_options(self)
|
||||
self.skip_package = None
|
||||
self.skip_modules = ()
|
||||
|
||||
def finalize_options(self):
|
||||
setuptools_build_py.finalize_options(self)
|
||||
omit = os.environ.get('IPA_OMIT_INSTALL', '0')
|
||||
if omit == '1':
|
||||
distname = self.distribution.metadata.name
|
||||
self.skip_package = '{}.install'.format(distname)
|
||||
self.skip_modules = (
|
||||
# *.install.* subpackages
|
||||
'{}.install'.format(distname),
|
||||
# platform override module
|
||||
'ipaplatform.override',
|
||||
)
|
||||
log.warn("bdist_wheel: Ignore package: %s",
|
||||
self.skip_package)
|
||||
', '.join(self.skip_modules))
|
||||
|
||||
def build_module(self, module, module_file, package):
|
||||
if isinstance(package, str):
|
||||
package = package.split('.')
|
||||
name = '.'.join(list(package) + [module])
|
||||
if self.skip_package and name.startswith(self.skip_package):
|
||||
if self.skip_modules and name.startswith(self.skip_modules):
|
||||
# remove file in case it has been copied to build/lib before
|
||||
outfile = self.get_module_outfile(self.build_lib, package, module)
|
||||
try:
|
||||
|
@ -41,6 +41,7 @@ if __name__ == '__main__':
|
||||
"ipatests.test_integration",
|
||||
"ipatests.test_ipaclient",
|
||||
"ipatests.test_ipalib",
|
||||
"ipatests.test_ipaplatform",
|
||||
"ipatests.test_ipapython",
|
||||
"ipatests.test_ipaserver",
|
||||
"ipatests.test_ipaserver.test_install",
|
||||
@ -54,6 +55,7 @@ if __name__ == '__main__':
|
||||
'ipatests.test_integration': ['scripts/*'],
|
||||
'ipatests.test_ipaclient': ['data/*/*/*'],
|
||||
'ipatests.test_ipalib': ['data/*'],
|
||||
'ipatests.test_ipaplatform': ['data/*'],
|
||||
"ipatests.test_ipaserver": ['data/*'],
|
||||
'ipatests.test_xmlrpc': ['data/*'],
|
||||
},
|
||||
@ -63,6 +65,7 @@ if __name__ == '__main__':
|
||||
"gssapi",
|
||||
"ipaclient",
|
||||
"ipalib",
|
||||
"ipaplatform",
|
||||
"ipapython",
|
||||
"nose",
|
||||
"polib",
|
||||
|
@ -1,23 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Test the `ipalib.util` module.
|
||||
This tests is in test_integration beucase we only can import ipaplatform here.
|
||||
"""
|
||||
|
||||
from ipalib import util
|
||||
from ipaplatform.paths import paths
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
|
||||
def test_hardcoded_paths_are_right():
|
||||
"""
|
||||
Test if constants created in ipalib.util are in sync with
|
||||
paths declared in ipaplatform.paths
|
||||
"""
|
||||
assert util._IPA_CLIENT_SYSRESTORE == paths.IPA_CLIENT_SYSRESTORE
|
||||
assert util._IPA_DEFAULT_CONF == paths.IPA_DEFAULT_CONF
|
0
ipatests/test_ipaplatform/__init__.py
Normal file
0
ipatests/test_ipaplatform/__init__.py
Normal file
15
ipatests/test_ipaplatform/data/os-release-centos
Normal file
15
ipatests/test_ipaplatform/data/os-release-centos
Normal file
@ -0,0 +1,15 @@
|
||||
NAME="CentOS Linux"
|
||||
VERSION="7 (Core)"
|
||||
ID="centos"
|
||||
ID_LIKE="rhel fedora"
|
||||
VERSION_ID="7"
|
||||
PRETTY_NAME="CentOS Linux 7 (Core)"
|
||||
ANSI_COLOR="0;31"
|
||||
CPE_NAME="cpe:/o:centos:centos:7"
|
||||
HOME_URL="https://www.centos.org/"
|
||||
BUG_REPORT_URL="https://bugs.centos.org/"
|
||||
|
||||
CENTOS_MANTISBT_PROJECT="CentOS-7"
|
||||
CENTOS_MANTISBT_PROJECT_VERSION="7"
|
||||
REDHAT_SUPPORT_PRODUCT="centos"
|
||||
REDHAT_SUPPORT_PRODUCT_VERSION="7"
|
16
ipatests/test_ipaplatform/data/os-release-fedora
Normal file
16
ipatests/test_ipaplatform/data/os-release-fedora
Normal file
@ -0,0 +1,16 @@
|
||||
NAME=Fedora
|
||||
VERSION="26 (Workstation Edition)"
|
||||
ID=fedora
|
||||
VERSION_ID=26
|
||||
PRETTY_NAME="Fedora 26 (Workstation Edition)"
|
||||
ANSI_COLOR="0;34"
|
||||
CPE_NAME="cpe:/o:fedoraproject:fedora:26"
|
||||
HOME_URL="https://fedoraproject.org/"
|
||||
BUG_REPORT_URL="https://bugzilla.redhat.com/"
|
||||
REDHAT_BUGZILLA_PRODUCT="Fedora"
|
||||
REDHAT_BUGZILLA_PRODUCT_VERSION=26
|
||||
REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||
REDHAT_SUPPORT_PRODUCT_VERSION=26
|
||||
PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy
|
||||
VARIANT="Workstation Edition"
|
||||
VARIANT_ID=workstation
|
11
ipatests/test_ipaplatform/data/os-release-ubuntu
Normal file
11
ipatests/test_ipaplatform/data/os-release-ubuntu
Normal file
@ -0,0 +1,11 @@
|
||||
NAME="Ubuntu"
|
||||
VERSION="16.04.3 LTS (Xenial Xerus)"
|
||||
ID=ubuntu
|
||||
ID_LIKE=debian
|
||||
PRETTY_NAME="Ubuntu 16.04.3 LTS"
|
||||
VERSION_ID="16.04"
|
||||
HOME_URL="http://www.ubuntu.com/"
|
||||
SUPPORT_URL="http://help.ubuntu.com/"
|
||||
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
|
||||
VERSION_CODENAME=xenial
|
||||
UBUNTU_CODENAME=xenial
|
54
ipatests/test_ipaplatform/test_importhook.py
Normal file
54
ipatests/test_ipaplatform/test_importhook.py
Normal file
@ -0,0 +1,54 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import ipaplatform.constants
|
||||
import ipaplatform.paths
|
||||
import ipaplatform.services
|
||||
import ipaplatform.tasks
|
||||
from ipaplatform._importhook import metaimporter
|
||||
try:
|
||||
from ipaplatform.override import OVERRIDE
|
||||
except ImportError:
|
||||
OVERRIDE = None
|
||||
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
DATA = os.path.join(HERE, 'data')
|
||||
|
||||
|
||||
@pytest.mark.skipif(OVERRIDE is None,
|
||||
reason='test requires override')
|
||||
def test_override():
|
||||
assert OVERRIDE == metaimporter.platform_ids[0]
|
||||
assert OVERRIDE == metaimporter.platform
|
||||
|
||||
|
||||
@pytest.mark.parametrize('mod, name', [
|
||||
(ipaplatform.constants, 'ipaplatform.constants'),
|
||||
(ipaplatform.paths, 'ipaplatform.paths'),
|
||||
(ipaplatform.services, 'ipaplatform.services'),
|
||||
(ipaplatform.tasks, 'ipaplatform.tasks'),
|
||||
])
|
||||
def test_importhook(mod, name):
|
||||
assert name in metaimporter.modules
|
||||
prefix, suffix = name.split('.')
|
||||
assert prefix == 'ipaplatform'
|
||||
override = '.'.join((prefix, metaimporter.platform, suffix))
|
||||
assert mod.__name__ == override
|
||||
# dicts are equal, modules may not be identical
|
||||
assert mod.__dict__ == sys.modules[override].__dict__
|
||||
|
||||
|
||||
@pytest.mark.parametrize('filename, expected_platforms', [
|
||||
(os.path.join(DATA, 'os-release-centos'), ['centos', 'rhel', 'fedora']),
|
||||
(os.path.join(DATA, 'os-release-fedora'), ['fedora']),
|
||||
(os.path.join(DATA, 'os-release-ubuntu'), ['ubuntu', 'debian']),
|
||||
])
|
||||
def test_parse_os_release(filename, expected_platforms):
|
||||
parsed = metaimporter._parse_osrelease(filename)
|
||||
assert parsed == expected_platforms
|
@ -269,6 +269,49 @@ def pytest_config_transform():
|
||||
register_module_extender(MANAGER, 'pytest', pytest_config_transform)
|
||||
|
||||
|
||||
def ipaplatform_constants_transform():
|
||||
return AstroidBuilder(MANAGER).string_build(textwrap.dedent('''
|
||||
from ipaplatform.base.constants import constants
|
||||
__all__ = ('constants',)
|
||||
'''))
|
||||
|
||||
|
||||
def ipaplatform_paths_transform():
|
||||
return AstroidBuilder(MANAGER).string_build(textwrap.dedent('''
|
||||
from ipaplatform.base.paths import paths
|
||||
__all__ = ('paths',)
|
||||
'''))
|
||||
|
||||
|
||||
def ipaplatform_services_transform():
|
||||
return AstroidBuilder(MANAGER).string_build(textwrap.dedent('''
|
||||
from ipaplatform.base.services import knownservices
|
||||
from ipaplatform.base.services import timedate_services
|
||||
from ipaplatform.base.services import service
|
||||
from ipaplatform.base.services import wellknownservices
|
||||
from ipaplatform.base.services import wellknownports
|
||||
__all__ = ('knownservices', 'timedate_services', 'service',
|
||||
'wellknownservices', 'wellknownports')
|
||||
'''))
|
||||
|
||||
|
||||
def ipaplatform_tasks_transform():
|
||||
return AstroidBuilder(MANAGER).string_build(textwrap.dedent('''
|
||||
from ipaplatform.base.tasks import tasks
|
||||
__all__ = ('tasks',)
|
||||
'''))
|
||||
|
||||
|
||||
register_module_extender(MANAGER, 'ipaplatform.constants',
|
||||
ipaplatform_constants_transform)
|
||||
register_module_extender(MANAGER, 'ipaplatform.paths',
|
||||
ipaplatform_paths_transform)
|
||||
register_module_extender(MANAGER, 'ipaplatform.services',
|
||||
ipaplatform_services_transform)
|
||||
register_module_extender(MANAGER, 'ipaplatform.tasks',
|
||||
ipaplatform_tasks_transform)
|
||||
|
||||
|
||||
class IPAChecker(BaseChecker):
|
||||
__implements__ = IAstroidChecker
|
||||
|
||||
|
6
pylintrc
6
pylintrc
@ -116,9 +116,9 @@ dummy-variables-rgx=_.+
|
||||
[IPA]
|
||||
forbidden-imports=
|
||||
client/:ipaserver,
|
||||
ipaclient/:ipaclient.install:ipalib.install:ipaplatform:ipaserver,
|
||||
ipaclient/:ipaclient.install:ipalib.install:ipaserver,
|
||||
ipaclient/install/:ipaserver,
|
||||
ipalib/:ipaclient.install:ipalib.install:ipaplatform:ipaserver,
|
||||
ipalib/:ipaclient.install:ipalib.install:ipaserver,
|
||||
ipalib/install/:ipaserver,
|
||||
ipaplatform/:ipaclient:ipalib:ipaserver,
|
||||
ipapython/:ipaclient:ipalib:ipaplatform:ipaserver
|
||||
ipapython/:ipaclient:ipalib:ipaserver
|
||||
|
@ -7,7 +7,6 @@ NULL =
|
||||
SUBDIRS = \
|
||||
freeipa \
|
||||
ipa \
|
||||
ipaplatform \
|
||||
ipaserver \
|
||||
ipatests \
|
||||
$(NULL)
|
||||
|
@ -1,3 +0,0 @@
|
||||
include $(top_srcdir)/Makefile.python.am
|
||||
|
||||
pkginstall = false
|
@ -1,2 +0,0 @@
|
||||
This is a dummy package for FreeIPA's ipaplatform.
|
||||
|
@ -1,5 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
raise ImportError("ipaplatform is not yet supported as PyPI package.")
|
@ -1,6 +0,0 @@
|
||||
[bdist_wheel]
|
||||
universal = 1
|
||||
|
||||
[aliases]
|
||||
packages = clean --all egg_info bdist_wheel
|
||||
release = packages register upload
|
@ -1,26 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
"""Dummy package for FreeIPA
|
||||
|
||||
ipaplatform is not yet available as PyPI package.
|
||||
"""
|
||||
|
||||
from os.path import abspath, dirname
|
||||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
# include ../../ for ipasetup.py
|
||||
sys.path.append(dirname(dirname(dirname(abspath(__file__)))))
|
||||
from ipasetup import ipasetup # noqa: E402
|
||||
|
||||
ipasetup(
|
||||
name='ipaplatform',
|
||||
doc = __doc__,
|
||||
packages=[
|
||||
"ipaplatform",
|
||||
],
|
||||
install_requires=[
|
||||
"ipaclient",
|
||||
]
|
||||
)
|
@ -9,13 +9,14 @@ import pytest
|
||||
|
||||
@pytest.mark.parametrize("modname", [
|
||||
# placeholder packages raise ImportError
|
||||
'ipaplatform',
|
||||
'ipaserver',
|
||||
'ipatests',
|
||||
# PyPI packages do not have install subpackage
|
||||
'ipaclient.install',
|
||||
'ipalib.install',
|
||||
'ipapython.install',
|
||||
# override module should not be shipped in wheels
|
||||
'ipaplatform.override',
|
||||
])
|
||||
def test_fail_import(modname):
|
||||
try:
|
||||
@ -29,6 +30,7 @@ def test_fail_import(modname):
|
||||
@pytest.mark.parametrize("modname", [
|
||||
'ipaclient',
|
||||
'ipalib',
|
||||
'ipaplatform',
|
||||
'ipapython',
|
||||
])
|
||||
def test_import(modname):
|
||||
|
Loading…
Reference in New Issue
Block a user