e24d7c36fa
Get configparser, queue, http_client modules from six.moves. Patch generated by the six_moves operation of the sixer tool: https://pypi.python.org/pypi/sixer Change-Id: I666241ab50101b8cc6f992dd80134ce27327bd7d
161 lines
5.9 KiB
Python
161 lines
5.9 KiB
Python
# Copyright (c) 2013 OpenStack Foundation
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import errno
|
|
import hashlib
|
|
import hmac
|
|
import os
|
|
import time
|
|
|
|
from six.moves import configparser
|
|
|
|
from swift import gettext_ as _
|
|
from swift.common.utils import get_valid_utf8_str
|
|
|
|
|
|
class ContainerSyncRealms(object):
|
|
"""
|
|
Loads and parses the container-sync-realms.conf, occasionally
|
|
checking the file's mtime to see if it needs to be reloaded.
|
|
"""
|
|
|
|
def __init__(self, conf_path, logger):
|
|
self.conf_path = conf_path
|
|
self.logger = logger
|
|
self.next_mtime_check = 0
|
|
self.mtime_check_interval = 300
|
|
self.conf_path_mtime = 0
|
|
self.data = {}
|
|
self.reload()
|
|
|
|
def reload(self):
|
|
"""Forces a reload of the conf file."""
|
|
self.next_mtime_check = 0
|
|
self.conf_path_mtime = 0
|
|
self._reload()
|
|
|
|
def _reload(self):
|
|
now = time.time()
|
|
if now >= self.next_mtime_check:
|
|
self.next_mtime_check = now + self.mtime_check_interval
|
|
try:
|
|
mtime = os.path.getmtime(self.conf_path)
|
|
except OSError as err:
|
|
if err.errno == errno.ENOENT:
|
|
log_func = self.logger.debug
|
|
else:
|
|
log_func = self.logger.error
|
|
log_func(_('Could not load %r: %s'), self.conf_path, err)
|
|
else:
|
|
if mtime != self.conf_path_mtime:
|
|
self.conf_path_mtime = mtime
|
|
try:
|
|
conf = configparser.SafeConfigParser()
|
|
conf.read(self.conf_path)
|
|
except configparser.ParsingError as err:
|
|
self.logger.error(
|
|
_('Could not load %r: %s'), self.conf_path, err)
|
|
else:
|
|
try:
|
|
self.mtime_check_interval = conf.getint(
|
|
'DEFAULT', 'mtime_check_interval')
|
|
self.next_mtime_check = \
|
|
now + self.mtime_check_interval
|
|
except configparser.NoOptionError:
|
|
self.mtime_check_interval = 300
|
|
self.next_mtime_check = \
|
|
now + self.mtime_check_interval
|
|
except (configparser.ParsingError, ValueError) as err:
|
|
self.logger.error(
|
|
_('Error in %r with mtime_check_interval: %s'),
|
|
self.conf_path, err)
|
|
realms = {}
|
|
for section in conf.sections():
|
|
realm = {}
|
|
clusters = {}
|
|
for option, value in conf.items(section):
|
|
if option in ('key', 'key2'):
|
|
realm[option] = value
|
|
elif option.startswith('cluster_'):
|
|
clusters[option[8:].upper()] = value
|
|
realm['clusters'] = clusters
|
|
realms[section.upper()] = realm
|
|
self.data = realms
|
|
|
|
def realms(self):
|
|
"""Returns a list of realms."""
|
|
self._reload()
|
|
return self.data.keys()
|
|
|
|
def key(self, realm):
|
|
"""Returns the key for the realm."""
|
|
self._reload()
|
|
result = self.data.get(realm.upper())
|
|
if result:
|
|
result = result.get('key')
|
|
return result
|
|
|
|
def key2(self, realm):
|
|
"""Returns the key2 for the realm."""
|
|
self._reload()
|
|
result = self.data.get(realm.upper())
|
|
if result:
|
|
result = result.get('key2')
|
|
return result
|
|
|
|
def clusters(self, realm):
|
|
"""Returns a list of clusters for the realm."""
|
|
self._reload()
|
|
result = self.data.get(realm.upper())
|
|
if result:
|
|
result = result.get('clusters')
|
|
if result:
|
|
result = result.keys()
|
|
return result or []
|
|
|
|
def endpoint(self, realm, cluster):
|
|
"""Returns the endpoint for the cluster in the realm."""
|
|
self._reload()
|
|
result = None
|
|
realm_data = self.data.get(realm.upper())
|
|
if realm_data:
|
|
cluster_data = realm_data.get('clusters')
|
|
if cluster_data:
|
|
result = cluster_data.get(cluster.upper())
|
|
return result
|
|
|
|
def get_sig(self, request_method, path, x_timestamp, nonce, realm_key,
|
|
user_key):
|
|
"""
|
|
Returns the hexdigest string of the HMAC-SHA1 (RFC 2104) for
|
|
the information given.
|
|
|
|
:param request_method: HTTP method of the request.
|
|
:param path: The path to the resource.
|
|
:param x_timestamp: The X-Timestamp header value for the request.
|
|
:param nonce: A unique value for the request.
|
|
:param realm_key: Shared secret at the cluster operator level.
|
|
:param user_key: Shared secret at the user's container level.
|
|
:returns: hexdigest str of the HMAC-SHA1 for the request.
|
|
"""
|
|
nonce = get_valid_utf8_str(nonce)
|
|
realm_key = get_valid_utf8_str(realm_key)
|
|
user_key = get_valid_utf8_str(user_key)
|
|
return hmac.new(
|
|
realm_key,
|
|
'%s\n%s\n%s\n%s\n%s' % (
|
|
request_method, path, x_timestamp, nonce, user_key),
|
|
hashlib.sha1).hexdigest()
|