1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
from collections.abc import MutableMapping
import errno
import json
import locale
import logging
import os
import time
from . import compat
from . import schema
from ipaclient.plugins.rpcclient import rpcclient
from ipapython.dnsutil import DNSName
logger = logging.getLogger(__name__)
class ServerInfo(MutableMapping):
def __init__(self, api):
self._dir = os.path.join(api.env.cache_dir, "servers")
hostname = DNSName(api.env.server).ToASCII()
self._filename = os.path.join(self._dir, hostname)
self._force_check = api.env.force_schema_check
self._now = time.time()
self._dict = {}
# copy-paste from ipalib/rpc.py
try:
self._language = locale.setlocale(
locale.LC_MESSAGES, ''
).split('.', maxsplit=1)[0].lower()
except locale.Error:
self._language = 'en_us'
self._read()
def _read(self):
try:
with open(self._filename, 'r') as sc:
self._dict = json.load(sc)
except Exception as e:
if (isinstance(e, EnvironmentError) and
e.errno == errno.ENOENT): # pylint: disable=no-member
# ignore non-existent file, this happens when the cache was
# erased or the server is contacted for the first time
pass
else:
# warn that the file is unreadable, probably corrupted
logger.warning('Failed to read server info: %s', e)
def _write(self):
try:
try:
os.makedirs(self._dir)
except EnvironmentError as e:
if e.errno != errno.EEXIST:
raise
with open(self._filename, 'w') as sc:
json.dump(self._dict, sc)
except EnvironmentError as e:
logger.warning('Failed to write server info: %s', e)
def __getitem__(self, key):
return self._dict[key]
def __setitem__(self, key, value):
self._dict[key] = value
def __delitem__(self, key):
del self._dict[key]
def __iter__(self):
return iter(self._dict)
def __len__(self):
return len(self._dict)
def update_validity(self, ttl):
if not self.is_valid():
self['expiration'] = self._now + ttl
self['language'] = self._language
self._write()
def is_valid(self):
if self._force_check:
return False
try:
expiration = self._dict['expiration']
language = self._dict['language']
except KeyError:
# if any of these is missing consider the entry expired
return False
if expiration < self._now:
return False
if language != self._language:
# language changed since last check
return False
return True
def get_package(api):
if api.env.in_tree:
# server packages are not published on pypi.org
# pylint: disable=useless-suppression
# pylint: disable=import-error,ipa-forbidden-import
from ipaserver import plugins
# pylint: enable=import-error,ipa-forbidden-import
# pylint: enable=useless-suppression
else:
try:
plugins = api._remote_plugins
except AttributeError:
server_info = ServerInfo(api)
client = rpcclient(api)
client.finalize()
try:
plugins = schema.get_package(server_info, client)
except schema.NotAvailable:
plugins = compat.get_package(server_info, client)
finally:
if client.isconnected():
client.disconnect()
object.__setattr__(api, '_remote_plugins', plugins)
return plugins
|