 e24d7c36fa
			
		
	
	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()
 |