1""" 2Swift utility class 3=================== 4Author: Anthony Stanton <anthony.stanton@gmail.com> 5""" 6 7import logging 8import sys 9from errno import EEXIST 10from os import makedirs 11from os.path import dirname, isdir 12 13import salt.utils.files 14 15# Get logging started 16log = logging.getLogger(__name__) 17 18HAS_SWIFT = False 19try: 20 from swiftclient import client 21 22 HAS_SWIFT = True 23except ImportError: 24 pass 25 26 27def check_swift(): 28 return HAS_SWIFT 29 30 31def mkdirs(path): 32 try: 33 makedirs(path) 34 except OSError as err: 35 if err.errno != EEXIST: 36 raise 37 38 39# we've been playing fast and loose with kwargs, but the swiftclient isn't 40# going to accept any old thing 41def _sanitize(kwargs): 42 variables = ( 43 "user", 44 "key", 45 "authurl", 46 "retries", 47 "preauthurl", 48 "preauthtoken", 49 "snet", 50 "starting_backoff", 51 "max_backoff", 52 "tenant_name", 53 "os_options", 54 "auth_version", 55 "cacert", 56 "insecure", 57 "ssl_compression", 58 ) 59 ret = {} 60 for var in kwargs: 61 if var in variables: 62 ret[var] = kwargs[var] 63 64 return ret 65 66 67class SaltSwift: 68 """ 69 Class for all swiftclient functions 70 """ 71 72 def __init__( 73 self, user, tenant_name, auth_url, password=None, auth_version=2, **kwargs 74 ): 75 """ 76 Set up openstack credentials 77 """ 78 if not HAS_SWIFT: 79 log.error( 80 "Error:: unable to find swiftclient. Try installing it from the" 81 " appropriate repository." 82 ) 83 return None 84 85 self.kwargs = kwargs.copy() 86 self.kwargs["user"] = user 87 self.kwargs["password"] = password 88 self.kwargs["tenant_name"] = tenant_name 89 self.kwargs["authurl"] = auth_url 90 self.kwargs["auth_version"] = auth_version 91 if "key" not in self.kwargs: 92 self.kwargs["key"] = password 93 94 self.kwargs = _sanitize(self.kwargs) 95 96 self.conn = client.Connection(**self.kwargs) 97 98 def get_account(self): 99 """ 100 List Swift containers 101 """ 102 try: 103 listing = self.conn.get_account() 104 return listing 105 except Exception as exc: # pylint: disable=broad-except 106 log.error("There was an error::") 107 if hasattr(exc, "code") and hasattr(exc, "msg"): 108 log.error(" Code: %s: %s", exc.code, exc.msg) 109 log.error(" Content: \n%s", getattr(exc, "read", lambda: str(exc))()) 110 return False 111 112 def get_container(self, cont): 113 """ 114 List files in a Swift container 115 """ 116 try: 117 listing = self.conn.get_container(cont) 118 return listing 119 except Exception as exc: # pylint: disable=broad-except 120 log.error("There was an error::") 121 if hasattr(exc, "code") and hasattr(exc, "msg"): 122 log.error(" Code: %s: %s", exc.code, exc.msg) 123 log.error(" Content: \n%s", getattr(exc, "read", lambda: str(exc))()) 124 return False 125 126 def put_container(self, cont): 127 """ 128 Create a new Swift container 129 """ 130 try: 131 self.conn.put_container(cont) 132 return True 133 except Exception as exc: # pylint: disable=broad-except 134 log.error("There was an error::") 135 if hasattr(exc, "code") and hasattr(exc, "msg"): 136 log.error(" Code: %s: %s", exc.code, exc.msg) 137 log.error(" Content: \n%s", getattr(exc, "read", lambda: str(exc))()) 138 return False 139 140 def delete_container(self, cont): 141 """ 142 Delete a Swift container 143 """ 144 try: 145 self.conn.delete_container(cont) 146 return True 147 except Exception as exc: # pylint: disable=broad-except 148 log.error("There was an error::") 149 if hasattr(exc, "code") and hasattr(exc, "msg"): 150 log.error(" Code: %s: %s", exc.code, exc.msg) 151 log.error(" Content: \n%s", getattr(exc, "read", lambda: str(exc))()) 152 return False 153 154 def post_container(self, cont, metadata=None): 155 """ 156 Update container metadata 157 """ 158 159 def head_container(self, cont): 160 """ 161 Get container metadata 162 """ 163 164 def get_object(self, cont, obj, local_file=None, return_bin=False): 165 """ 166 Retrieve a file from Swift 167 """ 168 try: 169 if local_file is None and return_bin is False: 170 return False 171 172 headers, body = self.conn.get_object(cont, obj, resp_chunk_size=65536) 173 174 if return_bin is True: 175 fp = sys.stdout 176 else: 177 dirpath = dirname(local_file) 178 if dirpath and not isdir(dirpath): 179 mkdirs(dirpath) 180 # pylint: disable=resource-leakage 181 fp = salt.utils.files.fopen(local_file, "wb") 182 # pylint: enable=resource-leakage 183 184 read_length = 0 185 for chunk in body: 186 read_length += len(chunk) 187 fp.write(chunk) 188 fp.close() 189 return True 190 191 # ClientException 192 # file/dir exceptions 193 except Exception as exc: # pylint: disable=broad-except 194 log.error("There was an error::") 195 if hasattr(exc, "code") and hasattr(exc, "msg"): 196 log.error(" Code: %s: %s", exc.code, exc.msg) 197 log.error(" Content: \n%s", getattr(exc, "read", lambda: str(exc))()) 198 return False 199 200 def put_object(self, cont, obj, local_file): 201 """ 202 Upload a file to Swift 203 """ 204 try: 205 with salt.utils.files.fopen(local_file, "rb") as fp_: 206 self.conn.put_object(cont, obj, fp_) 207 return True 208 except Exception as exc: # pylint: disable=broad-except 209 log.error("There was an error::") 210 if hasattr(exc, "code") and hasattr(exc, "msg"): 211 log.error(" Code: %s: %s", exc.code, exc.msg) 212 log.error(" Content: \n%s", getattr(exc, "read", lambda: str(exc))()) 213 return False 214 215 def delete_object(self, cont, obj): 216 """ 217 Delete a file from Swift 218 """ 219 try: 220 self.conn.delete_object(cont, obj) 221 return True 222 except Exception as exc: # pylint: disable=broad-except 223 log.error("There was an error::") 224 if hasattr(exc, "code") and hasattr(exc, "msg"): 225 log.error(" Code: %s: %s", exc.code, exc.msg) 226 log.error(" Content: \n%s", getattr(exc, "read", lambda: str(exc))()) 227 return False 228 229 def head_object(self, cont, obj): 230 """ 231 Get object metadata 232 """ 233 234 def post_object(self, cont, obj, metadata): 235 """ 236 Update object metadata 237 """ 238