Source code for libcloud.compute.drivers.brightbox

# 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.
"""
Brightbox Driver
"""

from libcloud.utils.py3 import httplib
from libcloud.utils.py3 import b

from libcloud.common.brightbox import BrightboxConnection
from libcloud.compute.types import Provider, NodeState
from libcloud.compute.base import NodeDriver
from libcloud.compute.base import Node, NodeImage, NodeSize, NodeLocation

import base64


API_VERSION = "1.0"


def _extract(d, keys):
    return dict((k, d[k]) for k in keys if k in d and d[k] is not None)


[docs]class BrightboxNodeDriver(NodeDriver): """ Brightbox node driver """ connectionCls = BrightboxConnection type = Provider.BRIGHTBOX name = "Brightbox" website = "http://www.brightbox.co.uk/" NODE_STATE_MAP = { "creating": NodeState.PENDING, "active": NodeState.RUNNING, "inactive": NodeState.UNKNOWN, "deleting": NodeState.UNKNOWN, "deleted": NodeState.TERMINATED, "failed": NodeState.UNKNOWN, "unavailable": NodeState.UNKNOWN, } def __init__( self, key, secret=None, secure=True, host=None, port=None, api_version=API_VERSION, **kwargs, ): super(BrightboxNodeDriver, self).__init__( key=key, secret=secret, secure=secure, host=host, port=port, api_version=api_version, **kwargs, ) def _to_node(self, data): extra_data = _extract( data, [ "fqdn", "user_data", "status", "interfaces", "snapshots", "server_groups", "hostname", "started_at", "created_at", "deleted_at", ], ) extra_data["zone"] = self._to_location(data["zone"]) ipv6_addresses = [ interface["ipv6_address"] for interface in data["interfaces"] if "ipv6_address" in interface ] private_ips = [ interface["ipv4_address"] for interface in data["interfaces"] if "ipv4_address" in interface ] public_ips = [cloud_ip["public_ip"] for cloud_ip in data["cloud_ips"]] public_ips += ipv6_addresses return Node( id=data["id"], name=data["name"], state=self.NODE_STATE_MAP[data["status"]], private_ips=private_ips, public_ips=public_ips, driver=self.connection.driver, size=self._to_size(data["server_type"]), image=self._to_image(data["image"]), extra=extra_data, ) def _to_image(self, data): extra_data = _extract( data, [ "arch", "compatibility_mode", "created_at", "description", "disk_size", "min_ram", "official", "owner", "public", "source", "source_type", "status", "username", "virtual_size", "licence_name", ], ) if data.get("ancestor", None): extra_data["ancestor"] = self._to_image(data["ancestor"]) return NodeImage( id=data["id"], name=data["name"], driver=self, extra=extra_data ) def _to_size(self, data): return NodeSize( id=data["id"], name=data["name"], ram=data["ram"], disk=data["disk_size"], bandwidth=0, price=0, driver=self, ) def _to_location(self, data): if data: return NodeLocation( id=data["id"], name=data["handle"], country="GB", driver=self ) else: return None def _post(self, path, data={}): headers = {"Content-Type": "application/json"} return self.connection.request(path, data=data, headers=headers, method="POST") def _put(self, path, data={}): headers = {"Content-Type": "application/json"} return self.connection.request(path, data=data, headers=headers, method="PUT")
[docs] def create_node( self, name, size, image, location=None, ex_userdata=None, ex_servergroup=None ): """Create a new Brightbox node Reference: https://api.gb1.brightbox.com/1.0/#server_create_server @inherits: :class:`NodeDriver.create_node` :keyword ex_userdata: User data :type ex_userdata: ``str`` :keyword ex_servergroup: Name or list of server group ids to add server to :type ex_servergroup: ``str`` or ``list`` of ``str`` """ data = { "name": name, "server_type": size.id, "image": image.id, } if ex_userdata: data["user_data"] = base64.b64encode(b(ex_userdata)).decode("ascii") if location: data["zone"] = location.id if ex_servergroup: if not isinstance(ex_servergroup, list): ex_servergroup = [ex_servergroup] data["server_groups"] = ex_servergroup data = self._post("/%s/servers" % self.api_version, data).object return self._to_node(data)
[docs] def destroy_node(self, node): response = self.connection.request( "/%s/servers/%s" % (self.api_version, node.id), method="DELETE" ) return response.status == httplib.ACCEPTED
[docs] def list_nodes(self): data = self.connection.request("/%s/servers" % self.api_version).object return list(map(self._to_node, data))
[docs] def list_images(self, location=None): data = self.connection.request("/%s/images" % self.api_version).object return list(map(self._to_image, data))
[docs] def list_sizes(self): data = self.connection.request("/%s/server_types" % self.api_version).object return list(map(self._to_size, data))
[docs] def list_locations(self): data = self.connection.request("/%s/zones" % self.api_version).object return list(map(self._to_location, data))
[docs] def ex_list_cloud_ips(self): """ List Cloud IPs @note: This is an API extension for use on Brightbox :rtype: ``list`` of ``dict`` """ return self.connection.request("/%s/cloud_ips" % self.api_version).object
[docs] def ex_create_cloud_ip(self, reverse_dns=None): """ Requests a new cloud IP address for the account @note: This is an API extension for use on Brightbox :param reverse_dns: Reverse DNS hostname :type reverse_dns: ``str`` :rtype: ``dict`` """ params = {} if reverse_dns: params["reverse_dns"] = reverse_dns return self._post("/%s/cloud_ips" % self.api_version, params).object
[docs] def ex_update_cloud_ip(self, cloud_ip_id, reverse_dns): """ Update some details of the cloud IP address @note: This is an API extension for use on Brightbox :param cloud_ip_id: The id of the cloud ip. :type cloud_ip_id: ``str`` :param reverse_dns: Reverse DNS hostname :type reverse_dns: ``str`` :rtype: ``dict`` """ response = self._put( "/%s/cloud_ips/%s" % (self.api_version, cloud_ip_id), {"reverse_dns": reverse_dns}, ) return response.status == httplib.OK
[docs] def ex_map_cloud_ip(self, cloud_ip_id, interface_id): """ Maps (or points) a cloud IP address at a server's interface or a load balancer to allow them to respond to public requests @note: This is an API extension for use on Brightbox :param cloud_ip_id: The id of the cloud ip. :type cloud_ip_id: ``str`` :param interface_id: The Interface ID or LoadBalancer ID to which this Cloud IP should be mapped to :type interface_id: ``str`` :return: True if the mapping was successful. :rtype: ``bool`` """ response = self._post( "/%s/cloud_ips/%s/map" % (self.api_version, cloud_ip_id), {"destination": interface_id}, ) return response.status == httplib.ACCEPTED
[docs] def ex_unmap_cloud_ip(self, cloud_ip_id): """ Unmaps a cloud IP address from its current destination making it available to remap. This remains in the account's pool of addresses @note: This is an API extension for use on Brightbox :param cloud_ip_id: The id of the cloud ip. :type cloud_ip_id: ``str`` :return: True if the unmap was successful. :rtype: ``bool`` """ response = self._post( "/%s/cloud_ips/%s/unmap" % (self.api_version, cloud_ip_id) ) return response.status == httplib.ACCEPTED
[docs] def ex_destroy_cloud_ip(self, cloud_ip_id): """ Release the cloud IP address from the account's ownership @note: This is an API extension for use on Brightbox :param cloud_ip_id: The id of the cloud ip. :type cloud_ip_id: ``str`` :return: True if the unmap was successful. :rtype: ``bool`` """ response = self.connection.request( "/%s/cloud_ips/%s" % (self.api_version, cloud_ip_id), method="DELETE" ) return response.status == httplib.OK