|
|
403b09 |
From b738ea5d78d7c6d7ba9d72c7cd57fe10f0f1b305 Mon Sep 17 00:00:00 2001
|
|
|
403b09 |
From: David Kupka <dkupka@redhat.com>
|
|
|
403b09 |
Date: Tue, 26 Jul 2016 13:35:22 +0200
|
|
|
403b09 |
Subject: [PATCH] compat: Save server's API version in for pre-schema servers
|
|
|
403b09 |
|
|
|
403b09 |
When client comunicates with server that doesn't support 'schema'
|
|
|
403b09 |
command it needs to determine its api version to be able to use the
|
|
|
403b09 |
right compat code. Storing information about server version reduces the
|
|
|
403b09 |
need to call 'env' or 'ping' command only to first time the server is
|
|
|
403b09 |
contacted.
|
|
|
403b09 |
|
|
|
403b09 |
https://fedorahosted.org/freeipa/ticket/6069
|
|
|
403b09 |
|
|
|
403b09 |
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
|
|
|
403b09 |
---
|
|
|
403b09 |
ipaclient/remote_plugins/__init__.py | 81 ++++++++++++++++++++++++++++++-
|
|
|
403b09 |
ipaclient/remote_plugins/compat.py | 29 +++++++-----
|
|
|
403b09 |
ipaclient/remote_plugins/schema.py | 92 +++---------------------------------
|
|
|
403b09 |
ipaplatform/base/paths.py | 15 ++++++
|
|
|
403b09 |
4 files changed, 116 insertions(+), 101 deletions(-)
|
|
|
403b09 |
|
|
|
403b09 |
diff --git a/ipaclient/remote_plugins/__init__.py b/ipaclient/remote_plugins/__init__.py
|
|
|
403b09 |
index 6454a4f4ef956a1ef545b82a649ebf26ef6edd7b..2be9222be693a5c4a04a735c216f590d75c1ecfe 100644
|
|
|
403b09 |
--- a/ipaclient/remote_plugins/__init__.py
|
|
|
403b09 |
+++ b/ipaclient/remote_plugins/__init__.py
|
|
|
403b09 |
@@ -2,9 +2,79 @@
|
|
|
403b09 |
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
|
|
403b09 |
#
|
|
|
403b09 |
|
|
|
403b09 |
+import collections
|
|
|
403b09 |
+import errno
|
|
|
403b09 |
+import json
|
|
|
403b09 |
+import os
|
|
|
403b09 |
+
|
|
|
403b09 |
from . import compat
|
|
|
403b09 |
from . import schema
|
|
|
403b09 |
from ipaclient.plugins.rpcclient import rpcclient
|
|
|
403b09 |
+from ipaplatform.paths import paths
|
|
|
403b09 |
+from ipapython.dnsutil import DNSName
|
|
|
403b09 |
+from ipapython.ipa_log_manager import log_mgr
|
|
|
403b09 |
+
|
|
|
403b09 |
+logger = log_mgr.get_logger(__name__)
|
|
|
403b09 |
+
|
|
|
403b09 |
+
|
|
|
403b09 |
+class ServerInfo(collections.MutableMapping):
|
|
|
403b09 |
+ _DIR = os.path.join(paths.USER_CACHE_PATH, 'ipa', 'servers')
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def __init__(self, api):
|
|
|
403b09 |
+ hostname = DNSName(api.env.server).ToASCII()
|
|
|
403b09 |
+ self._path = os.path.join(self._DIR, hostname)
|
|
|
403b09 |
+ self._dict = {}
|
|
|
403b09 |
+ self._dirty = False
|
|
|
403b09 |
+
|
|
|
403b09 |
+ self._read()
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def __enter__(self):
|
|
|
403b09 |
+ return self
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def __exit__(self, *_exc_info):
|
|
|
403b09 |
+ self.flush()
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def flush(self):
|
|
|
403b09 |
+ if self._dirty:
|
|
|
403b09 |
+ self._write()
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def _read(self):
|
|
|
403b09 |
+ try:
|
|
|
403b09 |
+ with open(self._path, 'r') as sc:
|
|
|
403b09 |
+ self._dict = json.load(sc)
|
|
|
403b09 |
+ except EnvironmentError as e:
|
|
|
403b09 |
+ if e.errno != errno.ENOENT:
|
|
|
403b09 |
+ logger.warning('Failed to read server info: {}'.format(e))
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def _write(self):
|
|
|
403b09 |
+ try:
|
|
|
403b09 |
+ try:
|
|
|
403b09 |
+ os.makedirs(self._DIR)
|
|
|
403b09 |
+ except EnvironmentError as e:
|
|
|
403b09 |
+ if e.errno != errno.EEXIST:
|
|
|
403b09 |
+ raise
|
|
|
403b09 |
+ with open(self._path, 'w') as sc:
|
|
|
403b09 |
+ json.dump(self._dict, sc)
|
|
|
403b09 |
+ except EnvironmentError as e:
|
|
|
403b09 |
+ logger.warning('Failed to write server info: {}'.format(e))
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def __getitem__(self, key):
|
|
|
403b09 |
+ return self._dict[key]
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def __setitem__(self, key, value):
|
|
|
403b09 |
+ if key not in self._dict or self._dict[key] != value:
|
|
|
403b09 |
+ self._dirty = True
|
|
|
403b09 |
+ self._dict[key] = value
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def __delitem__(self, key):
|
|
|
403b09 |
+ del self._dict[key]
|
|
|
403b09 |
+ self._dirty = True
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def __iter__(self):
|
|
|
403b09 |
+ return iter(self._dict)
|
|
|
403b09 |
+
|
|
|
403b09 |
+ def __len__(self):
|
|
|
403b09 |
+ return len(self._dict)
|
|
|
403b09 |
|
|
|
403b09 |
|
|
|
403b09 |
def get_package(api):
|
|
|
403b09 |
@@ -13,11 +83,18 @@ def get_package(api):
|
|
|
403b09 |
else:
|
|
|
403b09 |
client = rpcclient(api)
|
|
|
403b09 |
client.finalize()
|
|
|
403b09 |
+
|
|
|
403b09 |
+ try:
|
|
|
403b09 |
+ server_info = api._server_info
|
|
|
403b09 |
+ except AttributeError:
|
|
|
403b09 |
+ server_info = api._server_info = ServerInfo(api)
|
|
|
403b09 |
+
|
|
|
403b09 |
try:
|
|
|
403b09 |
- plugins = schema.get_package(api, client)
|
|
|
403b09 |
+ plugins = schema.get_package(api, server_info, client)
|
|
|
403b09 |
except schema.NotAvailable:
|
|
|
403b09 |
- plugins = compat.get_package(api, client)
|
|
|
403b09 |
+ plugins = compat.get_package(api, server_info, client)
|
|
|
403b09 |
finally:
|
|
|
403b09 |
+ server_info.flush()
|
|
|
403b09 |
if client.isconnected():
|
|
|
403b09 |
client.disconnect()
|
|
|
403b09 |
|
|
|
403b09 |
diff --git a/ipaclient/remote_plugins/compat.py b/ipaclient/remote_plugins/compat.py
|
|
|
403b09 |
index aef5718fcaade157487c0e65562c3bc8a11ad7de..b6d099a075deaaa17143f8ddddfb11d97b75f0ed 100644
|
|
|
403b09 |
--- a/ipaclient/remote_plugins/compat.py
|
|
|
403b09 |
+++ b/ipaclient/remote_plugins/compat.py
|
|
|
403b09 |
@@ -31,23 +31,26 @@ class CompatObject(Object):
|
|
|
403b09 |
pass
|
|
|
403b09 |
|
|
|
403b09 |
|
|
|
403b09 |
-def get_package(api, client):
|
|
|
403b09 |
- if not client.isconnected():
|
|
|
403b09 |
- client.connect(verbose=False)
|
|
|
403b09 |
-
|
|
|
403b09 |
- env = client.forward(u'env', u'api_version', version=u'2.0')
|
|
|
403b09 |
+def get_package(api, server_info, client):
|
|
|
403b09 |
try:
|
|
|
403b09 |
- server_version = env['result']['api_version']
|
|
|
403b09 |
+ server_version = server_info['version']
|
|
|
403b09 |
except KeyError:
|
|
|
403b09 |
- ping = client.forward(u'ping', version=u'2.0')
|
|
|
403b09 |
+ if not client.isconnected():
|
|
|
403b09 |
+ client.connect(verbose=False)
|
|
|
403b09 |
+ env = client.forward(u'env', u'api_version', version=u'2.0')
|
|
|
403b09 |
try:
|
|
|
403b09 |
- match = re.search(u'API version (2\.[0-9]+)', ping['summary'])
|
|
|
403b09 |
+ server_version = env['result']['api_version']
|
|
|
403b09 |
except KeyError:
|
|
|
403b09 |
- match = None
|
|
|
403b09 |
- if match is not None:
|
|
|
403b09 |
- server_version = match.group(1)
|
|
|
403b09 |
- else:
|
|
|
403b09 |
- server_version = u'2.0'
|
|
|
403b09 |
+ ping = client.forward(u'ping', u'api_version', version=u'2.0')
|
|
|
403b09 |
+ try:
|
|
|
403b09 |
+ match = re.search(u'API version (2\.[0-9]+)', ping['summary'])
|
|
|
403b09 |
+ except KeyError:
|
|
|
403b09 |
+ match = None
|
|
|
403b09 |
+ if match is not None:
|
|
|
403b09 |
+ server_version = match.group(1)
|
|
|
403b09 |
+ else:
|
|
|
403b09 |
+ server_version = u'2.0'
|
|
|
403b09 |
+ server_info['version'] = server_version
|
|
|
403b09 |
server_version = LooseVersion(server_version)
|
|
|
403b09 |
|
|
|
403b09 |
package_names = {}
|
|
|
403b09 |
diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py
|
|
|
403b09 |
index 8a77a15d489f067ab1312e863178458570403cc6..553da35127188b1ae842a7a0b58433e632c82b9f 100644
|
|
|
403b09 |
--- a/ipaclient/remote_plugins/schema.py
|
|
|
403b09 |
+++ b/ipaclient/remote_plugins/schema.py
|
|
|
403b09 |
@@ -22,6 +22,7 @@ from ipalib.errors import SchemaUpToDate
|
|
|
403b09 |
from ipalib.frontend import Object
|
|
|
403b09 |
from ipalib.output import Output
|
|
|
403b09 |
from ipalib.parameters import DefaultFrom, Flag, Password, Str
|
|
|
403b09 |
+from ipaplatform.paths import paths
|
|
|
403b09 |
from ipapython.ipautil import fsdecode
|
|
|
403b09 |
from ipapython.dn import DN
|
|
|
403b09 |
from ipapython.dnsutil import DNSName
|
|
|
403b09 |
@@ -59,17 +60,6 @@ _PARAMS = {
|
|
|
403b09 |
'str': parameters.Str,
|
|
|
403b09 |
}
|
|
|
403b09 |
|
|
|
403b09 |
-USER_CACHE_PATH = (
|
|
|
403b09 |
- os.environ.get('XDG_CACHE_HOME') or
|
|
|
403b09 |
- os.path.join(
|
|
|
403b09 |
- os.environ.get(
|
|
|
403b09 |
- 'HOME',
|
|
|
403b09 |
- os.path.expanduser('~')
|
|
|
403b09 |
- ),
|
|
|
403b09 |
- '.cache'
|
|
|
403b09 |
- )
|
|
|
403b09 |
-)
|
|
|
403b09 |
-
|
|
|
403b09 |
logger = log_mgr.get_logger(__name__)
|
|
|
403b09 |
|
|
|
403b09 |
|
|
|
403b09 |
@@ -348,66 +338,6 @@ class NotAvailable(Exception):
|
|
|
403b09 |
pass
|
|
|
403b09 |
|
|
|
403b09 |
|
|
|
403b09 |
-class ServerInfo(collections.MutableMapping):
|
|
|
403b09 |
- _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'servers')
|
|
|
403b09 |
-
|
|
|
403b09 |
- def __init__(self, api):
|
|
|
403b09 |
- hostname = DNSName(api.env.server).ToASCII()
|
|
|
403b09 |
- self._path = os.path.join(self._DIR, hostname)
|
|
|
403b09 |
- self._dict = {}
|
|
|
403b09 |
- self._dirty = False
|
|
|
403b09 |
-
|
|
|
403b09 |
- self._read()
|
|
|
403b09 |
-
|
|
|
403b09 |
- def __enter__(self):
|
|
|
403b09 |
- return self
|
|
|
403b09 |
-
|
|
|
403b09 |
- def __exit__(self, *_exc_info):
|
|
|
403b09 |
- self.flush()
|
|
|
403b09 |
-
|
|
|
403b09 |
- def flush(self):
|
|
|
403b09 |
- if self._dirty:
|
|
|
403b09 |
- self._write()
|
|
|
403b09 |
-
|
|
|
403b09 |
- def _read(self):
|
|
|
403b09 |
- try:
|
|
|
403b09 |
- with open(self._path, 'r') as sc:
|
|
|
403b09 |
- self._dict = json.load(sc)
|
|
|
403b09 |
- except EnvironmentError as e:
|
|
|
403b09 |
- if e.errno != errno.ENOENT:
|
|
|
403b09 |
- logger.warning('Failed to read server info: {}'.format(e))
|
|
|
403b09 |
-
|
|
|
403b09 |
- def _write(self):
|
|
|
403b09 |
- try:
|
|
|
403b09 |
- try:
|
|
|
403b09 |
- os.makedirs(self._DIR)
|
|
|
403b09 |
- except EnvironmentError as e:
|
|
|
403b09 |
- if e.errno != errno.EEXIST:
|
|
|
403b09 |
- raise
|
|
|
403b09 |
- with open(self._path, 'w') as sc:
|
|
|
403b09 |
- json.dump(self._dict, sc)
|
|
|
403b09 |
- except EnvironmentError as e:
|
|
|
403b09 |
- logger.warning('Failed to write server info: {}'.format(e))
|
|
|
403b09 |
-
|
|
|
403b09 |
- def __getitem__(self, key):
|
|
|
403b09 |
- return self._dict[key]
|
|
|
403b09 |
-
|
|
|
403b09 |
- def __setitem__(self, key, value):
|
|
|
403b09 |
- if key not in self._dict or self._dict[key] != value:
|
|
|
403b09 |
- self._dirty = True
|
|
|
403b09 |
- self._dict[key] = value
|
|
|
403b09 |
-
|
|
|
403b09 |
- def __delitem__(self, key):
|
|
|
403b09 |
- del self._dict[key]
|
|
|
403b09 |
- self._dirty = True
|
|
|
403b09 |
-
|
|
|
403b09 |
- def __iter__(self):
|
|
|
403b09 |
- return iter(self._dict)
|
|
|
403b09 |
-
|
|
|
403b09 |
- def __len__(self):
|
|
|
403b09 |
- return len(self._dict)
|
|
|
403b09 |
-
|
|
|
403b09 |
-
|
|
|
403b09 |
class Schema(object):
|
|
|
403b09 |
"""
|
|
|
403b09 |
Store and provide schema for commands and topics
|
|
|
403b09 |
@@ -429,7 +359,7 @@ class Schema(object):
|
|
|
403b09 |
|
|
|
403b09 |
"""
|
|
|
403b09 |
namespaces = {'classes', 'commands', 'topics'}
|
|
|
403b09 |
- _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema', FORMAT)
|
|
|
403b09 |
+ _DIR = os.path.join(paths.USER_CACHE_PATH, 'ipa', 'schema', FORMAT)
|
|
|
403b09 |
|
|
|
403b09 |
def __init__(self, api, server_info, client):
|
|
|
403b09 |
self._dict = {}
|
|
|
403b09 |
@@ -538,8 +468,6 @@ class Schema(object):
|
|
|
403b09 |
self._file.write(f.read())
|
|
|
403b09 |
|
|
|
403b09 |
with zipfile.ZipFile(self._file, 'r') as schema:
|
|
|
403b09 |
- self._dict['fingerprint'] = self._fingerprint
|
|
|
403b09 |
-
|
|
|
403b09 |
for name in schema.namelist():
|
|
|
403b09 |
ns, _slash, key = name.partition('/')
|
|
|
403b09 |
if ns in self.namespaces:
|
|
|
403b09 |
@@ -622,22 +550,14 @@ class Schema(object):
|
|
|
403b09 |
return self._help[namespace][member]
|
|
|
403b09 |
|
|
|
403b09 |
|
|
|
403b09 |
-def get_package(api, client):
|
|
|
403b09 |
+def get_package(api, server_info, client):
|
|
|
403b09 |
try:
|
|
|
403b09 |
schema = api._schema
|
|
|
403b09 |
except AttributeError:
|
|
|
403b09 |
- try:
|
|
|
403b09 |
- server_info = api._server_info
|
|
|
403b09 |
- except AttributeError:
|
|
|
403b09 |
- server_info = api._server_info = ServerInfo(api)
|
|
|
403b09 |
-
|
|
|
403b09 |
- try:
|
|
|
403b09 |
- schema = Schema(api, server_info, client)
|
|
|
403b09 |
- object.__setattr__(api, '_schema', schema)
|
|
|
403b09 |
- finally:
|
|
|
403b09 |
- server_info.flush()
|
|
|
403b09 |
+ schema = Schema(api, server_info, client)
|
|
|
403b09 |
+ object.__setattr__(api, '_schema', schema)
|
|
|
403b09 |
|
|
|
403b09 |
- fingerprint = str(schema['fingerprint'])
|
|
|
403b09 |
+ fingerprint = str(server_info['fingerprint'])
|
|
|
403b09 |
package_name = '{}${}'.format(__name__, fingerprint)
|
|
|
403b09 |
package_dir = '{}${}'.format(os.path.splitext(__file__)[0], fingerprint)
|
|
|
403b09 |
|
|
|
403b09 |
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
|
|
|
403b09 |
index 5ffe689950792a40c179533c8baf2794c2388696..065a2011027bf362abd498d227e24928ccf66724 100644
|
|
|
403b09 |
--- a/ipaplatform/base/paths.py
|
|
|
403b09 |
+++ b/ipaplatform/base/paths.py
|
|
|
403b09 |
@@ -21,6 +21,8 @@
|
|
|
403b09 |
This base platform module exports default filesystem paths.
|
|
|
403b09 |
'''
|
|
|
403b09 |
|
|
|
403b09 |
+import os
|
|
|
403b09 |
+
|
|
|
403b09 |
|
|
|
403b09 |
class BasePathNamespace(object):
|
|
|
403b09 |
BASH = "/bin/bash"
|
|
|
403b09 |
@@ -353,4 +355,17 @@ class BasePathNamespace(object):
|
|
|
403b09 |
IPA_CUSTODIA_AUDIT_LOG = '/var/log/ipa-custodia.audit.log'
|
|
|
403b09 |
IPA_GETKEYTAB = '/usr/sbin/ipa-getkeytab'
|
|
|
403b09 |
|
|
|
403b09 |
+ @property
|
|
|
403b09 |
+ def USER_CACHE_PATH(self):
|
|
|
403b09 |
+ return (
|
|
|
403b09 |
+ os.environ.get('XDG_CACHE_HOME') or
|
|
|
403b09 |
+ os.path.join(
|
|
|
403b09 |
+ os.environ.get(
|
|
|
403b09 |
+ 'HOME',
|
|
|
403b09 |
+ os.path.expanduser('~')
|
|
|
403b09 |
+ ),
|
|
|
403b09 |
+ '.cache'
|
|
|
403b09 |
+ )
|
|
|
403b09 |
+ )
|
|
|
403b09 |
+
|
|
|
403b09 |
path_namespace = BasePathNamespace
|
|
|
403b09 |
--
|
|
|
403b09 |
2.7.4
|
|
|
403b09 |
|