1# Licensed to the Apache Software Foundation (ASF) under one or more 2# contributor license agreements. See the NOTICE file distributed with 3# this work for additional information regarding copyright ownership. 4# The ASF licenses this file to You under the Apache License, Version 2.0 5# (the "License"); you may not use this file except in compliance with 6# the License. You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16""" 17libcloud provides a unified interface to the cloud computing resources. 18 19:var __version__: Current version of libcloud 20""" 21 22import os 23import codecs 24import atexit 25 26from libcloud.base import DriverType # NOQA 27from libcloud.base import DriverTypeFactoryMap # NOQA 28from libcloud.base import get_driver # NOQA 29 30try: 31 # TODO: This import is slow and adds overhead in situations when no 32 # requests are made but it's necessary for detecting bad version of 33 # requests 34 import requests # NOQA 35 have_requests = True 36except ImportError: 37 have_requests = False 38 39__all__ = [ 40 '__version__', 41 'enable_debug' 42] 43 44__version__ = '3.4.1' 45 46 47def enable_debug(fo): 48 """ 49 Enable library wide debugging to a file-like object. 50 51 :param fo: Where to append debugging information 52 :type fo: File like object, only write operations are used. 53 """ 54 from libcloud.common.base import Connection 55 from libcloud.utils.loggingconnection import LoggingConnection 56 57 LoggingConnection.log = fo 58 Connection.conn_class = LoggingConnection 59 60 # Ensure the file handle is closed on exit 61 def close_file(fd): 62 try: 63 fd.close() 64 except Exception: 65 pass 66 67 atexit.register(close_file, fo) 68 69 70def _init_once(): 71 """ 72 Utility function that is ran once on Library import. 73 74 This checks for the LIBCLOUD_DEBUG environment variable, which if it exists 75 is where we will log debug information about the provider transports. 76 77 This also checks for known environment/dependency incompatibilities. 78 """ 79 path = os.getenv('LIBCLOUD_DEBUG') 80 81 if path: 82 mode = 'a' 83 84 # Special case for /dev/stderr and /dev/stdout on Python 3. 85 from libcloud.utils.py3 import PY3 86 87 # Opening those files in append mode will throw "illegal seek" 88 # exception there. 89 # Late import to avoid setup.py related side affects 90 if path in ['/dev/stderr', '/dev/stdout'] and PY3: 91 mode = 'w' 92 93 fo = codecs.open(path, mode, encoding='utf8') 94 enable_debug(fo) 95 96 # NOTE: We use lazy import to avoid unnecessary import time overhead 97 try: 98 import paramiko # NOQA 99 have_paramiko = True 100 except ImportError: 101 have_paramiko = False 102 103 if have_paramiko and hasattr(paramiko.util, 'log_to_file'): 104 import logging 105 106 # paramiko always tries to open file path in append mode which 107 # won't work with /dev/{stdout, stderr} so we just ignore those 108 # errors 109 try: 110 paramiko.util.log_to_file(filename=path, level=logging.DEBUG) 111 except OSError as e: 112 if "illegal seek" not in str(e).lower(): 113 raise e 114 115 # check for broken `yum install python-requests` 116 if have_requests and requests.__version__ == '2.6.0': 117 chardet_version = requests.packages.chardet.__version__ 118 required_chardet_version = '2.3.0' 119 assert chardet_version == required_chardet_version, ( 120 'Known bad version of requests detected! This can happen when ' 121 'requests was installed from a source other than PyPI, e.g. via ' 122 'a package manager such as yum. Please either install requests ' 123 'from PyPI or run `pip install chardet==%s` to resolve this ' 124 'issue.' % required_chardet_version 125 ) 126 127 128_init_once() 129