# 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 driver base classes """ import time import hashlib from libcloud.utils.py3 import b from libcloud.common.base import ConnectionKey from libcloud.common.xmlrpc import XMLRPCResponse, XMLRPCConnection # Global constants DEFAULT_TIMEOUT = 600 # operation pooling max seconds DEFAULT_INTERVAL = 20 # seconds between 2 operation.info class GandiException(Exception): """ Exception class for Gandi driver """ def __str__(self): # pylint: disable=unsubscriptable-object return "({}) {}".format(self.args[0], self.args[1]) def __repr__(self): # pylint: disable=unsubscriptable-object return ''.format(self.args[0], self.args[1]) class GandiResponse(XMLRPCResponse): """ A Base Gandi Response class to derive from. """ class GandiConnection(XMLRPCConnection, ConnectionKey): """ Connection class for the Gandi driver """ responseCls = GandiResponse host = "rpc.gandi.net" endpoint = "/xmlrpc/" def __init__( self, key, secure=True, timeout=None, retry_delay=None, backoff=None, proxy_url=None, ): # Note: Method resolution order in this case is # XMLRPCConnection -> Connection and Connection doesn't take key as the # first argument so we specify a keyword argument instead. # Previously it was GandiConnection -> ConnectionKey so it worked fine. super().__init__( key=key, secure=secure, timeout=timeout, retry_delay=retry_delay, backoff=backoff, proxy_url=proxy_url, ) self.driver = BaseGandiDriver def request(self, method, *args): args = (self.key,) + args return super().request(method, *args) class BaseGandiDriver: """ Gandi base driver """ connectionCls = GandiConnection name = "Gandi" # Specific methods for gandi def _wait_operation(self, id, timeout=DEFAULT_TIMEOUT, check_interval=DEFAULT_INTERVAL): """Wait for an operation to succeed""" for i in range(0, timeout, check_interval): try: # pylint: disable=no-member op = self.connection.request("operation.info", int(id)).object if op["step"] == "DONE": return True if op["step"] in ["ERROR", "CANCEL"]: return False except (KeyError, IndexError): pass except Exception as e: raise GandiException(1002, e) time.sleep(check_interval) return False class BaseObject: """Base class for objects not conventional""" uuid_prefix = "" def __init__(self, id, state, driver): self.id = str(id) if id else None self.state = state self.driver = driver self.uuid = self.get_uuid() def get_uuid(self): """Unique hash for this object :return: ``str`` The hash is a function of an SHA1 hash of prefix, the object's ID and its driver which means that it should be unique between all interfaces. TODO : to review >>> from libcloud.compute.drivers.dummy import DummyNodeDriver >>> driver = DummyNodeDriver(0) >>> vif = driver.create_interface() >>> vif.get_uuid() 'd3748461511d8b9b0e0bfa0d4d3383a619a2bb9f' Note, for example, that this example will always produce the same UUID! """ hashstring = "{}:{}:{}".format(self.uuid_prefix, self.id, self.driver.type) return hashlib.sha1(b(hashstring)).hexdigest() class IPAddress(BaseObject): """ Provide a common interface for ip addresses """ uuid_prefix = "inet:" def __init__(self, id, state, inet, driver, version=4, extra=None): super().__init__(id, state, driver) self.inet = inet self.version = version self.extra = extra or {} def __repr__(self): return ("") % ( self.id, self.inet, self.state, self.driver.name, ) class NetworkInterface(BaseObject): """ Provide a common interface for network interfaces """ uuid_prefix = "if:" def __init__(self, id, state, mac_address, driver, ips=None, node_id=None, extra=None): super().__init__(id, state, driver) self.mac = mac_address self.ips = ips or {} self.node_id = node_id self.extra = extra or {} def __repr__(self): return ("") % ( self.id, self.mac, self.state, self.driver.name, ) class Disk(BaseObject): """ Gandi disk component """ def __init__(self, id, state, name, driver, size, extra=None): super().__init__(id, state, driver) self.name = name self.size = size self.extra = extra or {} def __repr__(self): return ("") % ( self.id, self.name, self.state, self.size, self.driver.name, )