Server IP : 85.214.239.14 / Your IP : 18.189.143.150 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /usr/lib/python3/dist-packages/libcloud/common/ |
Upload File : |
# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. """ Gandi Live driver base classes """ import json from libcloud.common.base import ConnectionKey, JsonResponse from libcloud.common.types import ProviderError from libcloud.utils.py3 import httplib __all__ = [ 'API_HOST', 'GandiLiveBaseError', 'JsonParseError', 'ResourceNotFoundError', 'InvalidRequestError', 'ResourceConflictError', 'GandiLiveResponse', 'GandiLiveConnection', 'BaseGandiLiveDriver', ] API_HOST = 'dns.api.gandi.net' class GandiLiveBaseError(ProviderError): """ Exception class for Gandi Live driver """ pass class JsonParseError(GandiLiveBaseError): pass # Example: # { # "code": 404, # "message": "Unknown zone", # "object": "LocalizedHTTPNotFound", # "cause": "Not Found" # } class ResourceNotFoundError(GandiLiveBaseError): pass # Example: # { # "code": 400, # "message": "zone or zone_uuid must be set", # "object": "HTTPBadRequest", # "cause": "No zone set.", # "errors": [ # { # "location": "body", # "name": "zone_uuid", # "description": "\"FAKEUUID\" is not a UUID" # } # ] # } class InvalidRequestError(GandiLiveBaseError): pass # Examples: # { # "code": 409, # "message": "Zone Testing already exists", # "object": "HTTPConflict", # "cause": "Duplicate Entry" # } # { # "code": 409, # "message": "The domain example.org already exists", # "object": "HTTPConflict", # "cause": "Duplicate Entry" # } # { # "code": 409, # "message": "This zone is still used by 1 domains", # "object": "HTTPConflict", # "cause": "In use" # } class ResourceConflictError(GandiLiveBaseError): pass class GandiLiveResponse(JsonResponse): """ A Base Gandi Live Response class to derive from. """ def success(self): """ Determine if our request was successful. For the Gandi Live response class, tag all responses as successful and raise appropriate Exceptions from parse_body. :return: C{True} """ return True def parse_body(self): """ Parse the JSON response body, or raise exceptions as appropriate. :return: JSON dictionary :rtype: ``dict`` """ json_error = False try: body = json.loads(self.body) except Exception: # If there is both a JSON parsing error and an unsuccessful http # response (like a 404), we want to raise the http error and not # the JSON one, so don't raise JsonParseError here. body = self.body json_error = True # Service does not appear to return HTTP 202 Accepted for anything. valid_http_codes = [ httplib.OK, httplib.CREATED, ] if self.status in valid_http_codes: if json_error: raise JsonParseError(body, self.status) else: return body elif self.status == httplib.NO_CONTENT: # Parse error for empty body is acceptable, but a non-empty body # is not. if len(body) > 0: msg = '"No Content" response contained content' raise GandiLiveBaseError(msg, self.status) else: return {} elif self.status == httplib.NOT_FOUND: message = self._get_error(body, json_error) raise ResourceNotFoundError(message, self.status) elif self.status == httplib.BAD_REQUEST: message = self._get_error(body, json_error) raise InvalidRequestError(message, self.status) elif self.status == httplib.CONFLICT: message = self._get_error(body, json_error) raise ResourceConflictError(message, self.status) else: message = self._get_error(body, json_error) raise GandiLiveBaseError(message, self.status) # Errors are not described at all in Gandi's official documentation. # It appears when an error arises, a JSON object is returned along with # an HTTP 4xx class code. The object is structured as: # { # code: <code>, # object: <object>, # message: <message>, # cause: <cause>, # errors: [ # { # location: <error-location>, # name: <error-name>, # description: <error-description> # } # ] # } # where # <code> is a number equal to the HTTP response status code # <object> is a string with some internal name for the status code # <message> is a string detailing what the problem is # <cause> is a string that comes from a set of succinct problem summaries # errors is optional; if present: # <error-location> is a string for which part of the request to look in # <error-name> is a string naming the parameter # <error-description> is a string detailing what the problem is # Here we ignore object and combine message and cause along with an error # if one or more exists. def _get_error(self, body, json_error): """ Get the error code and message from a JSON response. Incorporate the first error if there are multiple errors. :param body: The body of the JSON response dictionary :type body: ``dict`` :return: String containing error message :rtype: ``str`` """ if not json_error and 'cause' in body: message = '%s: %s' % (body['cause'], body['message']) if 'errors' in body: err = body['errors'][0] message = '%s (%s in %s: %s)' % (message, err.get('location'), err.get('name'), err.get('description')) else: message = body return message class GandiLiveConnection(ConnectionKey): """ Connection class for the Gandi Live driver """ responseCls = GandiLiveResponse host = API_HOST def add_default_headers(self, headers): """ Returns default headers as a dictionary. """ headers["Content-Type"] = 'application/json' headers["X-Api-Key"] = self.key return headers def encode_data(self, data): """Encode data to JSON""" return json.dumps(data) class BaseGandiLiveDriver(object): """ Gandi Live base driver """ connectionCls = GandiLiveConnection name = 'GandiLive'