# 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. """ Dimension Data Common Components """ from time import sleep from base64 import b64encode # TODO: use distutils.version when Travis CI fixed the pylint issue with version # from distutils.version import LooseVersion from libcloud.utils.py3 import b, httplib, basestring from libcloud.utils.xml import findtext from libcloud.common.base import RawResponse, XmlResponse, ConnectionUserAndKey from libcloud.compute.base import Node from libcloud.compute.types import LibcloudError, InvalidCredsError # Roadmap / TODO: # # 1.0 - Copied from OpSource API, named provider details. # setup a few variables to represent all of the DimensionData cloud namespaces NAMESPACE_BASE = "http://oec.api.opsource.net/schemas" ORGANIZATION_NS = NAMESPACE_BASE + "/organization" SERVER_NS = NAMESPACE_BASE + "/server" NETWORK_NS = NAMESPACE_BASE + "/network" DIRECTORY_NS = NAMESPACE_BASE + "/directory" GENERAL_NS = NAMESPACE_BASE + "/general" BACKUP_NS = NAMESPACE_BASE + "/backup" # API 2.0 Namespaces and URNs TYPES_URN = "urn:didata.com:api:cloud:types" # API end-points API_ENDPOINTS = { "dd-na": { "name": "North America (NA)", "host": "api-na.dimensiondata.com", "vendor": "DimensionData", }, "dd-eu": { "name": "Europe (EU)", "host": "api-eu.dimensiondata.com", "vendor": "DimensionData", }, "dd-au": { "name": "Australia (AU)", "host": "api-au.dimensiondata.com", "vendor": "DimensionData", }, "dd-au-gov": { "name": "Australia Canberra ACT (AU)", "host": "api-canberra.dimensiondata.com", "vendor": "DimensionData", }, "dd-af": { "name": "Africa (AF)", "host": "api-mea.dimensiondata.com", "vendor": "DimensionData", }, "dd-ap": { "name": "Asia Pacific (AP)", "host": "api-ap.dimensiondata.com", "vendor": "DimensionData", }, "dd-latam": { "name": "South America (LATAM)", "host": "api-latam.dimensiondata.com", "vendor": "DimensionData", }, "dd-canada": { "name": "Canada (CA)", "host": "api-canada.dimensiondata.com", "vendor": "DimensionData", }, "is-na": { "name": "North America (NA)", "host": "usapi.cloud.is.co.za", "vendor": "InternetSolutions", }, "is-eu": { "name": "Europe (EU)", "host": "euapi.cloud.is.co.za", "vendor": "InternetSolutions", }, "is-au": { "name": "Australia (AU)", "host": "auapi.cloud.is.co.za", "vendor": "InternetSolutions", }, "is-af": { "name": "Africa (AF)", "host": "meaapi.cloud.is.co.za", "vendor": "InternetSolutions", }, "is-ap": { "name": "Asia Pacific (AP)", "host": "apapi.cloud.is.co.za", "vendor": "InternetSolutions", }, "is-latam": { "name": "South America (LATAM)", "host": "latamapi.cloud.is.co.za", "vendor": "InternetSolutions", }, "is-canada": { "name": "Canada (CA)", "host": "canadaapi.cloud.is.co.za", "vendor": "InternetSolutions", }, "ntta-na": { "name": "North America (NA)", "host": "cloudapi.nttamerica.com", "vendor": "NTTNorthAmerica", }, "ntta-eu": { "name": "Europe (EU)", "host": "eucloudapi.nttamerica.com", "vendor": "NTTNorthAmerica", }, "ntta-au": { "name": "Australia (AU)", "host": "aucloudapi.nttamerica.com", "vendor": "NTTNorthAmerica", }, "ntta-af": { "name": "Africa (AF)", "host": "sacloudapi.nttamerica.com", "vendor": "NTTNorthAmerica", }, "ntta-ap": { "name": "Asia Pacific (AP)", "host": "hkcloudapi.nttamerica.com", "vendor": "NTTNorthAmerica", }, "cisco-na": { "name": "North America (NA)", "host": "iaas-api-na.cisco-ccs.com", "vendor": "Cisco", }, "cisco-eu": { "name": "Europe (EU)", "host": "iaas-api-eu.cisco-ccs.com", "vendor": "Cisco", }, "cisco-au": { "name": "Australia (AU)", "host": "iaas-api-au.cisco-ccs.com", "vendor": "Cisco", }, "cisco-af": { "name": "Africa (AF)", "host": "iaas-api-mea.cisco-ccs.com", "vendor": "Cisco", }, "cisco-ap": { "name": "Asia Pacific (AP)", "host": "iaas-api-ap.cisco-ccs.com", "vendor": "Cisco", }, "cisco-latam": { "name": "South America (LATAM)", "host": "iaas-api-sa.cisco-ccs.com", "vendor": "Cisco", }, "cisco-canada": { "name": "Canada (CA)", "host": "iaas-api-ca.cisco-ccs.com", "vendor": "Cisco", }, } # Default API end-point for the base connection class. DEFAULT_REGION = "dd-na" BAD_CODE_XML_ELEMENTS = ( ("responseCode", SERVER_NS), ("responseCode", TYPES_URN), ("result", GENERAL_NS), ) BAD_MESSAGE_XML_ELEMENTS = ( ("message", SERVER_NS), ("message", TYPES_URN), ("resultDetail", GENERAL_NS), ) def dd_object_to_id(obj, obj_type, id_value="id"): """ Takes in a DD object or string and prints out it's id This is a helper method, as many of our functions can take either an object or a string, and we need an easy way of converting them :param obj: The object to get the id for :type obj: ``object`` :param func: The function to call, e.g. ex_get_vlan. Note: This function needs to return an object which has ``status`` attribute. :type func: ``function`` :rtype: ``str`` """ if isinstance(obj, obj_type): return getattr(obj, id_value) elif isinstance(obj, (basestring)): return obj else: raise TypeError( "Invalid type {} looking for basestring or {}".format( type(obj).__name__, obj_type.__name__ ) ) # TODO: use distutils.version when Travis CI fixed the pylint issue with version # This is a temporary workaround. def LooseVersion(version): return float(version) class NetworkDomainServicePlan: ESSENTIALS = "ESSENTIALS" ADVANCED = "ADVANCED" class DimensionDataRawResponse(RawResponse): pass class DimensionDataResponse(XmlResponse): def parse_error(self): if self.status == httplib.UNAUTHORIZED: raise InvalidCredsError(self.body) elif self.status == httplib.FORBIDDEN: raise InvalidCredsError(self.body) body = self.parse_body() if self.status == httplib.BAD_REQUEST: for response_code in BAD_CODE_XML_ELEMENTS: code = findtext(body, response_code[0], response_code[1]) if code is not None: break for message in BAD_MESSAGE_XML_ELEMENTS: message = findtext(body, message[0], message[1]) if message is not None: break raise DimensionDataAPIException(code=code, msg=message, driver=self.connection.driver) if self.status is not httplib.OK: raise DimensionDataAPIException( code=self.status, msg=body, driver=self.connection.driver ) return self.body class DimensionDataAPIException(LibcloudError): def __init__(self, code, msg, driver): self.code = code self.msg = msg self.driver = driver def __str__(self): return "{}: {}".format(self.code, self.msg) def __repr__(self): return "".format( self.code, self.msg, ) class DimensionDataConnection(ConnectionUserAndKey): """ Connection class for the DimensionData driver """ api_path_version_1 = "/oec" api_path_version_2 = "/caas" api_version_1 = 0.9 # Earliest version supported oldest_api_version = "2.2" # Latest version supported latest_api_version = "2.4" # Default api version active_api_version = "2.4" _orgId = None responseCls = DimensionDataResponse rawResponseCls = DimensionDataRawResponse allow_insecure = False def __init__( self, user_id, key, secure=True, host=None, port=None, url=None, timeout=None, proxy_url=None, api_version=None, **conn_kwargs, ): super().__init__( user_id=user_id, key=key, secure=secure, host=host, port=port, url=url, timeout=timeout, proxy_url=proxy_url, ) if conn_kwargs["region"]: self.host = conn_kwargs["region"]["host"] if api_version: if LooseVersion(api_version) < LooseVersion(self.oldest_api_version): msg = ( "API Version specified is too old. No longer " "supported. Please upgrade to the latest version {}".format( self.active_api_version ) ) raise DimensionDataAPIException(code=None, msg=msg, driver=self.driver) elif LooseVersion(api_version) > LooseVersion(self.latest_api_version): msg = ( "Unsupported API Version. The version specified is " "not release yet. Please use the latest supported " "version {}".format(self.active_api_version) ) raise DimensionDataAPIException(code=None, msg=msg, driver=self.driver) else: # Overwrite default version using the version user specified self.active_api_version = api_version def add_default_headers(self, headers): headers["Authorization"] = "Basic %s" % b64encode( b("{}:{}".format(self.user_id, self.key)) ).decode("utf-8") headers["Content-Type"] = "application/xml" return headers def request_api_1(self, action, params=None, data="", headers=None, method="GET"): action = "{}/{}/{}".format(self.api_path_version_1, self.api_version_1, action) return super().request( action=action, params=params, data=data, method=method, headers=headers ) def request_api_2(self, path, action, params=None, data="", headers=None, method="GET"): action = "{}/{}/{}/{}".format( self.api_path_version_2, self.active_api_version, path, action, ) return super().request( action=action, params=params, data=data, method=method, headers=headers ) def raw_request_with_orgId_api_1( self, action, params=None, data="", headers=None, method="GET" ): action = "{}/{}".format(self.get_resource_path_api_1(), action) return super().request( action=action, params=params, data=data, method=method, headers=headers, raw=True, ) def request_with_orgId_api_1(self, action, params=None, data="", headers=None, method="GET"): action = "{}/{}".format(self.get_resource_path_api_1(), action) return super().request( action=action, params=params, data=data, method=method, headers=headers ) def request_with_orgId_api_2(self, action, params=None, data="", headers=None, method="GET"): action = "{}/{}".format(self.get_resource_path_api_2(), action) return super().request( action=action, params=params, data=data, method=method, headers=headers ) def paginated_request_with_orgId_api_2( self, action, params=None, data="", headers=None, method="GET", page_size=250 ): """ A paginated request to the MCP2.0 API This essentially calls out to request_with_orgId_api_2 for each page and yields the response to make a generator This generator can be looped through to grab all the pages. :param action: The resource to access (i.e. 'network/vlan') :type action: ``str`` :param params: Parameters to give to the action :type params: ``dict`` or ``None`` :param data: The data payload to be added to the request :type data: ``str`` :param headers: Additional header to be added to the request :type headers: ``str`` or ``dict`` or ``None`` :param method: HTTP Method for the request (i.e. 'GET', 'POST') :type method: ``str`` :param page_size: The size of each page to be returned Note: Max page size in MCP2.0 is currently 250 :type page_size: ``int`` """ if params is None: params = {} params["pageSize"] = page_size resp = self.request_with_orgId_api_2(action, params, data, headers, method).object yield resp if len(resp) <= 0: return pcount = resp.get("pageCount") # pylint: disable=no-member psize = resp.get("pageSize") # pylint: disable=no-member pnumber = resp.get("pageNumber") # pylint: disable=no-member while int(pcount) >= int(psize): params["pageNumber"] = int(pnumber) + 1 resp = self.request_with_orgId_api_2(action, params, data, headers, method).object pcount = resp.get("pageCount") # pylint: disable=no-member psize = resp.get("pageSize") # pylint: disable=no-member pnumber = resp.get("pageNumber") # pylint: disable=no-member yield resp def get_resource_path_api_1(self): """ This method returns a resource path which is necessary for referencing resources that require a full path instead of just an ID, such as networks, and customer snapshots. """ return "{}/{}/{}".format( self.api_path_version_1, self.api_version_1, self._get_orgId(), ) def get_resource_path_api_2(self): """ This method returns a resource path which is necessary for referencing resources that require a full path instead of just an ID, such as networks, and customer snapshots. """ return "{}/{}/{}".format( self.api_path_version_2, self.active_api_version, self._get_orgId(), ) def wait_for_state(self, state, func, poll_interval=2, timeout=60, *args, **kwargs): """ Wait for the function which returns a instance with field status/state to match. Keep polling func until one of the desired states is matched :param state: Either the desired state (`str`) or a `list` of states :type state: ``str`` or ``list`` :param func: The function to call, e.g. ex_get_vlan. Note: This function needs to return an object which has ``status`` attribute. :type func: ``function`` :param poll_interval: The number of seconds to wait between checks :type poll_interval: `int` :param timeout: The total number of seconds to wait to reach a state :type timeout: `int` :param args: The arguments for func :type args: Positional arguments :param kwargs: The arguments for func :type kwargs: Keyword arguments :return: Result from the calling function. """ cnt = 0 result = None object_state = None while cnt < timeout / poll_interval: result = func(*args, **kwargs) if isinstance(result, Node): object_state = result.state else: object_state = result.status if object_state is state or str(object_state) in state: return result sleep(poll_interval) cnt += 1 msg = "Status check for object %s timed out" % (result) raise DimensionDataAPIException(code=object_state, msg=msg, driver=self.driver) def _get_orgId(self): """ Send the /myaccount API request to DimensionData cloud and parse the 'orgId' from the XML response object. We need the orgId to use most of the other API functions """ if self._orgId is None: body = self.request_api_1("myaccount").object self._orgId = findtext(body, "orgId", DIRECTORY_NS) return self._orgId def get_account_details(self): """ Get the details of this account :rtype: :class:`DimensionDataAccountDetails` """ body = self.request_api_1("myaccount").object return DimensionDataAccountDetails( user_name=findtext(body, "userName", DIRECTORY_NS), full_name=findtext(body, "fullName", DIRECTORY_NS), first_name=findtext(body, "firstName", DIRECTORY_NS), last_name=findtext(body, "lastName", DIRECTORY_NS), email=findtext(body, "emailAddress", DIRECTORY_NS), ) class DimensionDataAccountDetails: """ Dimension Data account class details """ def __init__(self, user_name, full_name, first_name, last_name, email): self.user_name = user_name self.full_name = full_name self.first_name = first_name self.last_name = last_name self.email = email class DimensionDataStatus: """ DimensionData API pending operation status class action, request_time, user_name, number_of_steps, update_time, step.name, step.number, step.percent_complete, failure_reason, """ def __init__( self, action=None, request_time=None, user_name=None, number_of_steps=None, update_time=None, step_name=None, step_number=None, step_percent_complete=None, failure_reason=None, ): self.action = action self.request_time = request_time self.user_name = user_name self.number_of_steps = number_of_steps self.update_time = update_time self.step_name = step_name self.step_number = step_number self.step_percent_complete = step_percent_complete self.failure_reason = failure_reason def __repr__(self): return ( "" ) % ( self.action, self.request_time, self.user_name, self.number_of_steps, self.update_time, self.step_name, self.step_number, self.step_percent_complete, self.failure_reason, ) class DimensionDataNetwork: """ DimensionData network with location. """ def __init__(self, id, name, description, location, private_net, multicast, status): self.id = str(id) self.name = name self.description = description self.location = location self.private_net = private_net self.multicast = multicast self.status = status def __repr__(self): return ( "" ) % ( self.id, self.name, self.description, self.location, self.private_net, self.multicast, ) class DimensionDataNetworkDomain: """ DimensionData network domain with location. """ def __init__(self, id, name, description, location, status, plan): self.id = str(id) self.name = name self.description = description self.location = location self.status = status self.plan = plan def __repr__(self): return ( "" ) % ( self.id, self.name, self.description, self.location, self.status, self.plan, ) class DimensionDataPublicIpBlock: """ DimensionData Public IP Block with location. """ def __init__(self, id, base_ip, size, location, network_domain, status): self.id = str(id) self.base_ip = base_ip self.size = size self.location = location self.network_domain = network_domain self.status = status def __repr__(self): return ( "" ) % (self.id, self.base_ip, self.size, self.location, self.status) class DimensionDataServerCpuSpecification: """ A class that represents the specification of the CPU(s) for a node """ def __init__(self, cpu_count, cores_per_socket, performance): """ Instantiate a new :class:`DimensionDataServerCpuSpecification` :param cpu_count: The number of CPUs :type cpu_count: ``int`` :param cores_per_socket: The number of cores per socket, the recommendation is 1 :type cores_per_socket: ``int`` :param performance: The performance type, e.g. HIGHPERFORMANCE :type performance: ``str`` """ self.cpu_count = cpu_count self.cores_per_socket = cores_per_socket self.performance = performance def __repr__(self): return ( "" ) % (self.cpu_count, self.cores_per_socket, self.performance) class DimensionDataServerDisk: """ A class that represents the disk on a server """ def __init__(self, id=None, scsi_id=None, size_gb=None, speed=None, state=None): """ Instantiate a new :class:`DimensionDataServerDisk` :param id: The id of the disk :type id: ``str`` :param scsi_id: Representation for scsi :type scsi_id: ``int`` :param size_gb: Size of the disk :type size_gb: ``int`` :param speed: Speed of the disk (i.e. STANDARD) :type speed: ``str`` :param state: State of the disk (i.e. PENDING) :type state: ``str`` """ self.id = id self.scsi_id = scsi_id self.size_gb = size_gb self.speed = speed self.state = state def __repr__(self): return ("" ) % (self.status, self.version_status, self.api_version) class DimensionDataFirewallRule: """ DimensionData Firewall Rule for a network domain """ def __init__( self, id, name, action, location, network_domain, status, ip_version, protocol, source, destination, enabled, ): self.id = str(id) self.name = name self.action = action self.location = location self.network_domain = network_domain self.status = status self.ip_version = ip_version self.protocol = protocol self.source = source self.destination = destination self.enabled = enabled def __repr__(self): return ( "" ) % ( self.id, self.name, self.action, self.location, self.network_domain, self.status, self.ip_version, self.protocol, self.source, self.destination, self.enabled, ) class DimensionDataFirewallAddress: """ The source or destination model in a firewall rule """ def __init__( self, any_ip, ip_address, ip_prefix_size, port_begin, port_end, address_list_id, port_list_id, ): self.any_ip = any_ip self.ip_address = ip_address self.ip_prefix_size = ip_prefix_size self.port_list_id = port_list_id self.port_begin = port_begin self.port_end = port_end self.address_list_id = address_list_id self.port_list_id = port_list_id def __repr__(self): return ( "" % ( self.any_ip, self.ip_address, self.ip_prefix_size, self.port_begin, self.port_end, self.address_list_id, self.port_list_id, ) ) class DimensionDataNatRule: """ An IP NAT rule in a network domain """ def __init__(self, id, network_domain, internal_ip, external_ip, status): self.id = id self.network_domain = network_domain self.internal_ip = internal_ip self.external_ip = external_ip self.status = status def __repr__(self): return ("") % (self.id, self.status) class DimensionDataAntiAffinityRule: """ Anti-Affinity rule for DimensionData An Anti-Affinity rule ensures that servers in the rule will not reside on the same VMware ESX host. """ def __init__(self, id, node_list): """ Instantiate a new :class:`DimensionDataAntiAffinityRule` :param id: The ID of the Anti-Affinity rule :type id: ``str`` :param node_list: List of node ids that belong in this rule :type node_list: ``list`` of ``str`` """ self.id = id self.node_list = node_list def __repr__(self): return ("") % (self.id) class DimensionDataVlan: """ DimensionData VLAN. """ def __init__( self, id, name, description, location, network_domain, status, private_ipv4_range_address, private_ipv4_range_size, ipv6_range_address, ipv6_range_size, ipv4_gateway, ipv6_gateway, ): """ Initialize an instance of ``DimensionDataVlan`` :param id: The ID of the VLAN :type id: ``str`` :param name: The name of the VLAN :type name: ``str`` :param description: Plan text description of the VLAN :type description: ``str`` :param location: The location (data center) of the VLAN :type location: ``NodeLocation`` :param network_domain: The Network Domain that owns this VLAN :type network_domain: :class:`DimensionDataNetworkDomain` :param status: The status of the VLAN :type status: :class:`DimensionDataStatus` :param private_ipv4_range_address: The host address of the VLAN IP space :type private_ipv4_range_address: ``str`` :param private_ipv4_range_size: The size (e.g. '24') of the VLAN as a CIDR range size :type private_ipv4_range_size: ``int`` :param ipv6_range_address: The host address of the VLAN IP space :type ipv6_range_address: ``str`` :param ipv6_range_size: The size (e.g. '32') of the VLAN as a CIDR range size :type ipv6_range_size: ``int`` :param ipv4_gateway: The IPv4 default gateway address :type ipv4_gateway: ``str`` :param ipv6_gateway: The IPv6 default gateway address :type ipv6_gateway: ``str`` """ self.id = str(id) self.name = name self.location = location self.description = description self.network_domain = network_domain self.status = status self.private_ipv4_range_address = private_ipv4_range_address self.private_ipv4_range_size = private_ipv4_range_size self.ipv6_range_address = ipv6_range_address self.ipv6_range_size = ipv6_range_size self.ipv4_gateway = ipv4_gateway self.ipv6_gateway = ipv6_gateway def __repr__(self): return ( "" ) % (self.id, self.name, self.description, self.location, self.status) class DimensionDataPool: """ DimensionData VIP Pool. """ def __init__( self, id, name, description, status, load_balance_method, health_monitor_id, service_down_action, slow_ramp_time, ): """ Initialize an instance of ``DimensionDataPool`` :param id: The ID of the pool :type id: ``str`` :param name: The name of the pool :type name: ``str`` :param description: Plan text description of the pool :type description: ``str`` :param status: The status of the pool :type status: :class:`DimensionDataStatus` :param load_balance_method: The load balancer method :type load_balance_method: ``str`` :param health_monitor_id: The ID of the health monitor :type health_monitor_id: ``str`` :param service_down_action: Action to take when pool is down :type service_down_action: ``str`` :param slow_ramp_time: The ramp-up time for service recovery :type slow_ramp_time: ``int`` """ self.id = str(id) self.name = name self.description = description self.status = status self.load_balance_method = load_balance_method self.health_monitor_id = health_monitor_id self.service_down_action = service_down_action self.slow_ramp_time = slow_ramp_time def __repr__(self): return ("") % ( self.id, self.name, self.description, self.status, ) class DimensionDataPoolMember: """ DimensionData VIP Pool Member. """ def __init__(self, id, name, status, ip, port, node_id): """ Initialize an instance of ``DimensionDataPoolMember`` :param id: The ID of the pool member :type id: ``str`` :param name: The name of the pool member :type name: ``str`` :param status: The status of the pool :type status: :class:`DimensionDataStatus` :param ip: The IP of the pool member :type ip: ``str`` :param port: The port of the pool member :type port: ``int`` :param node_id: The ID of the associated node :type node_id: ``str`` """ self.id = str(id) self.name = name self.status = status self.ip = ip self.port = port self.node_id = node_id def __repr__(self): return ( "" ) % (self.id, self.name, self.ip, self.status, self.port, self.node_id) class DimensionDataVIPNode: def __init__( self, id, name, status, ip, connection_limit="10000", connection_rate_limit="10000", ): """ Initialize an instance of :class:`DimensionDataVIPNode` :param id: The ID of the node :type id: ``str`` :param name: The name of the node :type name: ``str`` :param status: The status of the node :type status: :class:`DimensionDataStatus` :param ip: The IP of the node :type ip: ``str`` :param connection_limit: The total connection limit for the node :type connection_limit: ``int`` :param connection_rate_limit: The rate limit for the node :type connection_rate_limit: ``int`` """ self.id = str(id) self.name = name self.status = status self.ip = ip self.connection_limit = connection_limit self.connection_rate_limit = connection_rate_limit def __repr__(self): return ("") % ( self.id, self.name, self.status, self.ip, ) class DimensionDataVirtualListener: """ DimensionData Virtual Listener. """ def __init__(self, id, name, status, ip): """ Initialize an instance of :class:`DimensionDataVirtualListener` :param id: The ID of the listener :type id: ``str`` :param name: The name of the listener :type name: ``str`` :param status: The status of the listener :type status: :class:`DimensionDataStatus` :param ip: The IP of the listener :type ip: ``str`` """ self.id = str(id) self.name = name self.status = status self.ip = ip def __repr__(self): return ("") % ( self.id, self.name, self.status, self.ip, ) class DimensionDataDefaultHealthMonitor: """ A default health monitor for a VIP (node, pool or listener) """ def __init__(self, id, name, node_compatible, pool_compatible): """ Initialize an instance of :class:`DimensionDataDefaultHealthMonitor` :param id: The ID of the monitor :type id: ``str`` :param name: The name of the monitor :type name: ``str`` :param node_compatible: Is a monitor capable of monitoring nodes :type node_compatible: ``bool`` :param pool_compatible: Is a monitor capable of monitoring pools :type pool_compatible: ``bool`` """ self.id = id self.name = name self.node_compatible = node_compatible self.pool_compatible = pool_compatible def __repr__(self): return ("") % ( self.id, self.name, ) class DimensionDataPersistenceProfile: """ Each Persistence Profile declares the combination of Virtual Listener type and protocol with which it is compatible and whether or not it is compatible as a Fallback Persistence Profile. """ def __init__(self, id, name, compatible_listeners, fallback_compatible): """ Initialize an instance of :class:`DimensionDataPersistenceProfile` :param id: The ID of the profile :type id: ``str`` :param name: The name of the profile :type name: ``str`` :param compatible_listeners: List of compatible Virtual Listener types :type compatible_listeners: ``list`` of :class:`DimensionDataVirtualListenerCompatibility` :param fallback_compatible: Is capable as a fallback profile :type fallback_compatible: ``bool`` """ self.id = id self.name = name self.compatible_listeners = compatible_listeners self.fallback_compatible = fallback_compatible def __repr__(self): return ("") % ( self.id, self.name, ) class DimensionDataDefaultiRule: """ A default iRule for a network domain, can be applied to a listener """ def __init__(self, id, name, compatible_listeners): """ Initialize an instance of :class:`DimensionDataDefaultiRule` :param id: The ID of the iRule :type id: ``str`` :param name: The name of the iRule :type name: ``str`` :param compatible_listeners: List of compatible Virtual Listener types :type compatible_listeners: ``list`` of :class:`DimensionDataVirtualListenerCompatibility` """ self.id = id self.name = name self.compatible_listeners = compatible_listeners def __repr__(self): return ("") % (self.id, self.name) class DimensionDataVirtualListenerCompatibility: """ A compatibility preference for a persistence profile or iRule specifies which virtual listener types this profile or iRule can be applied to. """ def __init__(self, type, protocol): self.type = type self.protocol = protocol def __repr__(self): return ("") % ( self.type, self.protocol, ) class DimensionDataBackupDetails: """ Dimension Data Backup Details represents information about a targets backups configuration """ def __init__(self, asset_id, service_plan, status, clients=None): """ Initialize an instance of :class:`DimensionDataBackupDetails` :param asset_id: Asset identification for backups :type asset_id: ``str`` :param service_plan: The service plan for backups. i.e (Essentials) :type service_plan: ``str`` :param status: The overall status this backup target. i.e. (unregistered) :type status: ``str`` :param clients: Backup clients attached to this target :type clients: ``list`` of :class:`DimensionDataBackupClient` """ self.asset_id = asset_id self.service_plan = service_plan self.status = status self.clients = clients def __repr__(self): return ("") % (self.asset_id) class DimensionDataBackupClient: """ An object that represents a backup client """ def __init__( self, id, type, status, schedule_policy, storage_policy, download_url, alert=None, running_job=None, ): """ Initialize an instance of :class:`DimensionDataBackupClient` :param id: Unique ID for the client :type id: ``str`` :param type: The type of client that this client is :type type: :class:`DimensionDataBackupClientType` :param status: The states of this particular backup client. i.e. (Unregistered) :type status: ``str`` :param schedule_policy: The schedule policy for this client NOTE: Dimension Data only sends back the name of the schedule policy, no further details :type schedule_policy: ``str`` :param storage_policy: The storage policy for this client NOTE: Dimension Data only sends back the name of the storage policy, no further details :type storage_policy: ``str`` :param download_url: The download url for this client :type download_url: ``str`` :param alert: The alert configured for this backup client (optional) :type alert: :class:`DimensionDataBackupClientAlert` :param alert: The running job for the client (optional) :type alert: :class:`DimensionDataBackupClientRunningJob` """ self.id = id self.type = type self.status = status self.schedule_policy = schedule_policy self.storage_policy = storage_policy self.download_url = download_url self.alert = alert self.running_job = running_job def __repr__(self): return ("") % (self.id) class DimensionDataBackupClientAlert: """ An alert for a backup client """ def __init__(self, trigger, notify_list=[]): """ Initialize an instance of :class:`DimensionDataBackupClientAlert` :param trigger: Trigger type for the client i.e. ON_FAILURE :type trigger: ``str`` :param notify_list: List of email addresses that are notified when the alert is fired :type notify_list: ``list`` of ``str`` """ self.trigger = trigger self.notify_list = notify_list def __repr__(self): return ("") % (self.trigger) class DimensionDataBackupClientRunningJob: """ A running job for a given backup client """ def __init__(self, id, status, percentage=0): """ Initialize an instance of :class:`DimensionDataBackupClientRunningJob` :param id: The unique ID of the job :type id: ``str`` :param status: The status of the job i.e. Waiting :type status: ``str`` :param percentage: The percentage completion of the job :type percentage: ``int`` """ self.id = id self.percentage = percentage self.status = status def __repr__(self): return ("") % (self.id) class DimensionDataBackupClientType: """ A client type object for backups """ def __init__(self, type, is_file_system, description): """ Initialize an instance of :class:`DimensionDataBackupClientType` :param type: The type of client i.e. (FA.Linux, MySQL, etc.) :type type: ``str`` :param is_file_system: The name of the iRule :type is_file_system: ``bool`` :param description: Description of the client :type description: ``str`` """ self.type = type self.is_file_system = is_file_system self.description = description def __repr__(self): return ("") % (self.type) class DimensionDataBackupStoragePolicy: """ A representation of a storage policy """ def __init__(self, name, retention_period, secondary_location): """ Initialize an instance of :class:`DimensionDataBackupStoragePolicy` :param name: The name of the storage policy i.e. 14 Day Storage Policy :type name: ``str`` :param retention_period: How long to keep the backup in days :type retention_period: ``int`` :param secondary_location: The secondary location i.e. Primary :type secondary_location: ``str`` """ self.name = name self.retention_period = retention_period self.secondary_location = secondary_location def __repr__(self): return ("") % (self.name) class DimensionDataBackupSchedulePolicy: """ A representation of a schedule policy """ def __init__(self, name, description): """ Initialize an instance of :class:`DimensionDataBackupSchedulePolicy` :param name: The name of the policy i.e 12AM - 6AM :type name: ``str`` :param description: Short summary of the details of the policy :type description: ``str`` """ self.name = name self.description = description def __repr__(self): return ("") % (self.name) class DimensionDataTag: """ A representation of a Tag in Dimension Data A Tag first must have a Tag Key, then an asset is tag with a key and an option value. Tags can be queried later to filter assets and also show up on usage report if so desired. """ def __init__(self, asset_type, asset_id, asset_name, datacenter, key, value): """ Initialize an instance of :class:`DimensionDataTag` :param asset_type: The type of asset. Current asset types: SERVER, VLAN, NETWORK_DOMAIN, CUSTOMER_IMAGE, PUBLIC_IP_BLOCK, ACCOUNT :type asset_type: ``str`` :param asset_id: The GUID of the asset that is tagged :type asset_id: ``str`` :param asset_name: The name of the asset that is tagged :type asset_name: ``str`` :param datacenter: The short datacenter name of the tagged asset :type datacenter: ``str`` :param key: The tagged key :type key: :class:`DimensionDataTagKey` :param value: The tagged value :type value: ``None`` or ``str`` """ self.asset_type = asset_type self.asset_id = asset_id self.asset_name = asset_name self.datacenter = datacenter self.key = key self.value = value def __repr__(self): return ("") % ( self.asset_name, self.key.name, self.value, ) class DimensionDataTagKey: """ A representation of a Tag Key in Dimension Data A tag key is required to tag an asset """ def __init__(self, id, name, description, value_required, display_on_report): """ Initialize an instance of :class:`DimensionDataTagKey` :param id: GUID of the tag key :type id: ``str`` :param name: Name of the tag key :type name: ``str`` :param description: Description of the tag key :type description: ``str`` :param value_required: If a value is required for this tag key :type value_required: ``bool`` :param display_on_report: If this tag key should be displayed on usage reports :type display_on_report: ``bool`` """ self.id = id self.name = name self.description = description self.value_required = value_required self.display_on_report = display_on_report def __repr__(self): return ("") % (self.name) class DimensionDataIpAddressList: """ DimensionData IP Address list """ def __init__( self, id, name, description, ip_version, ip_address_collection, state, create_time, child_ip_address_lists=None, ): """" Initialize an instance of :class:`DimensionDataIpAddressList` :param id: GUID of the IP Address List key :type id: ``str`` :param name: Name of the IP Address List :type name: ``str`` :param description: Description of the IP Address List :type description: ``str`` :param ip_version: IP version. E.g. IPV4, IPV6 :type ip_version: ``str`` :param ip_address_collection: Collection of DimensionDataIpAddress :type ip_address_collection: ``List`` :param state: IP Address list state :type state: ``str`` :param create_time: IP Address List created time :type create_time: ``date time`` :param child_ip_address_lists: List of IP address list to be included :type child_ip_address_lists: List \ of :class:'DimensionDataIpAddressList' """ self.id = id self.name = name self.description = description self.ip_version = ip_version self.ip_address_collection = ip_address_collection self.state = state self.create_time = create_time self.child_ip_address_lists = child_ip_address_lists def __repr__(self): return ( "" % ( self.id, self.name, self.description, self.ip_version, self.ip_address_collection, self.state, self.create_time, self.child_ip_address_lists, ) ) class DimensionDataChildIpAddressList: """ DimensionData Child IP Address list """ def __init__(self, id, name): """ " Initialize an instance of :class:`DimensionDataChildIpAddressList` :param id: GUID of the IP Address List key :type id: ``str`` :param name: Name of the IP Address List :type name: ``str`` """ self.id = id self.name = name def __repr__(self): return "".format( self.id, self.name, ) class DimensionDataIpAddress: """ A representation of IP Address in Dimension Data """ def __init__(self, begin, end=None, prefix_size=None): """ Initialize an instance of :class:`DimensionDataIpAddress` :param begin: IP Address Begin :type begin: ``str`` :param end: IP Address end :type end: ``str`` :param prefixSize: IP Address prefix size :type prefixSize: ``int`` """ self.begin = begin self.end = end self.prefix_size = prefix_size def __repr__(self): return "".format( self.begin, self.end, self.prefix_size, ) class DimensionDataPortList: """ DimensionData Port list """ def __init__( self, id, name, description, port_collection, child_portlist_list, state, create_time, ): """ " Initialize an instance of :class:`DimensionDataPortList` :param id: GUID of the Port List key :type id: ``str`` :param name: Name of the Port List :type name: ``str`` :param description: Description of the Port List :type description: ``str`` :param port_collection: Collection of DimensionDataPort :type port_collection: ``List`` :param child_portlist_list: Collection of DimensionDataChildPort :type child_portlist_list: ``List`` :param state: Port list state :type state: ``str`` :param create_time: Port List created time :type create_time: ``date time`` """ self.id = id self.name = name self.description = description self.port_collection = port_collection self.child_portlist_list = child_portlist_list self.state = state self.create_time = create_time def __repr__(self): return ( "" % ( self.id, self.name, self.description, self.port_collection, self.child_portlist_list, self.state, self.create_time, ) ) class DimensionDataChildPortList: """ DimensionData Child Port list """ def __init__(self, id, name): """ " Initialize an instance of :class:`DimensionDataChildIpAddressList` :param id: GUID of the child port list key :type id: ``str`` :param name: Name of the child port List :type name: ``str`` """ self.id = id self.name = name def __repr__(self): return "".format(self.id, self.name) class DimensionDataPort: """ A representation of Port in Dimension Data """ def __init__(self, begin, end=None): """ Initialize an instance of :class:`DimensionDataPort` :param begin: Port Number Begin :type begin: ``str`` :param end: Port Number end :type end: ``str`` """ self.begin = begin self.end = end def __repr__(self): return "".format(self.begin, self.end) class DimensionDataNic: """ A representation of Network Adapter in Dimension Data """ def __init__(self, private_ip_v4=None, vlan=None, network_adapter_name=None): """ Initialize an instance of :class:`DimensionDataNic` :param private_ip_v4: IPv4 :type private_ip_v4: ``str`` :param vlan: Network VLAN :type vlan: class: DimensionDataVlan or ``str`` :param network_adapter_name: Network Adapter Name :type network_adapter_name: ``str`` """ self.private_ip_v4 = private_ip_v4 self.vlan = vlan self.network_adapter_name = network_adapter_name def __repr__(self): return "" % ( self.private_ip_v4, self.vlan, self.network_adapter_name, )