Source code for libcloud.compute.drivers.oneandone

# 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.
"""
1&1 Cloud Server Compute driver
"""
import json

from libcloud.compute.providers import Provider
from libcloud.common.base import JsonResponse, ConnectionKey
from libcloud.compute.base import (
    NodeSize,
    NodeImage,
    NodeLocation,
    Node,
    NodeAuthPassword,
    NodeAuthSSHKey,
)
from libcloud.common.types import InvalidCredsError
from libcloud.compute.types import NodeState
from libcloud.utils.py3 import httplib
from libcloud.compute.base import NodeDriver

from time import sleep

API_HOST = "cloudpanel-api.1and1.com"
API_VERSION = "/v1/"

__all__ = [
    "API_HOST",
    "API_VERSION",
    "OneAndOneResponse",
    "OneAndOneConnection",
    "OneAndOneNodeDriver",
]


[docs]class OneAndOneResponse(JsonResponse): """ OneAndOne response parsing. """ valid_response_codes = [httplib.OK, httplib.CREATED, httplib.ACCEPTED]
[docs] def parse_error(self): if self.status == httplib.UNAUTHORIZED: body = self.parse_body() raise InvalidCredsError(body["message"]) else: body = self.parse_body() if "message" in body: error = "%s (code: %s)" % (body["message"], self.status) else: error = body return error
[docs] def success(self): return self.status in self.valid_response_codes
[docs]class OneAndOneConnection(ConnectionKey): """ Connection class for the 1&1 driver """ host = API_HOST api_prefix = API_VERSION responseCls = OneAndOneResponse
[docs] def encode_data(self, data): return json.dumps(data)
[docs] def add_default_headers(self, headers): """ Add headers that are necessary for every request This method adds ``token`` and ``Content-Type`` to the request. """ headers["X-Token"] = self.key headers["Content-Type"] = "application/json" return headers
[docs] def request( self, action, params=None, data=None, headers=None, method="GET", raw=False ): """ Some requests will use the href attribute directly. If this is not the case, then we should formulate the url based on the action specified. If we are using a full url, we need to remove the host and protocol components. """ action = self.api_prefix + action.lstrip("/") return super(OneAndOneConnection, self).request( action=action, params=params, data=data, headers=headers, method=method, raw=raw, )
[docs]class OneAndOneNodeDriver(NodeDriver): """ Base OneAndOne node driver. """ connectionCls = OneAndOneConnection name = "1and1" website = "http://www.1and1.com" type = Provider.ONEANDONE NODE_STATE_MAP = { "POWERING_ON": NodeState.STARTING, "POWERING_OFF": NodeState.PENDING, "POWERED_OFF": NodeState.STOPPING, "POWERED_ON": NodeState.RUNNING, "REBOOTING": NodeState.REBOOTING, "CONFIGURING": NodeState.RECONFIGURING, "REMOVING": NodeState.UNKNOWN, "DEPLOYING": NodeState.STARTING, } """ Core Functions """
[docs] def list_sizes(self): """ Lists all sizes :return: A list of all configurable node sizes. :rtype: ``list`` of :class:`NodeSize` """ sizes = [] fixed_instances = self._list_fixed_instances() for value in fixed_instances: node_size = self._to_node_size(value) sizes.append(node_size) return sizes
[docs] def list_locations(self): """ Lists all locations :return: ``list`` of :class:`NodeLocation` :rtype: ``list`` """ datacenters = self.ex_list_datacenters() locations = [] for values in datacenters: node_size = self._to_location(values) locations.append(node_size) return locations
[docs] def list_images(self, image_type=None): """ :return: ``list`` of :class: `NodeImage` :rtype: ``list`` """ response = self.connection.request(action="server_appliances", method="GET") return self._to_images(response.object, image_type)
[docs] def get_image(self, image_id): response = self.connection.request( action="server_appliances/%s" % image_id, method="GET" ) return self._to_image(response.object)
""" Node functions """
[docs] def create_node( self, name, image, ex_fixed_instance_size_id, location=None, auth=None, ex_ip=None, ex_monitoring_policy_id=None, ex_firewall_policy_id=None, ex_loadbalancer_id=None, ex_description=None, ex_power_on=None, ): """ Creates a node. :param name: The name of the new node :type name: `str` :param ex_fixed_instance_size_id: Fixed instance size ID from list_sizes :type ex_fixed_instance_size_id: ``str`` :param location: 1&1 Data center Location :type location: `NodeLocation` :param ex_ip: IP address :type ex_ip: `str` :param ex_ssh_key: SSH Key :type ex_ssh_key: `str` :param password: Password :type password: `str` :param ex_monitoring_policy_id: :type ex_firewall_policy_id: `str` :param ex_firewall_policy_id: :type ex_firewall_policy_id: `str` :param ex_loadbalancer_id: :type ex_loadbalancer_id: `str` :param ex_description: :type ex_description: `str` :param ex_power_on: :type ex_power_on: `bool` :return: Instance of class ``Node`` :rtype: :class:`Node` """ body = { "name": name, "appliance_id": image.id, "hardware": {"fixed_instance_size_id": ex_fixed_instance_size_id}, } if location is not None: body["datacenter_id"] = location.id if ex_power_on is not None: body["power_on"] = ex_power_on if ex_description is not None: body["description"] = ex_description if ex_firewall_policy_id is not None: body["firewall_policy_id"] = ex_firewall_policy_id if ex_monitoring_policy_id is not None: body["monitoring_policy_id"] = ex_monitoring_policy_id if ex_loadbalancer_id is not None: body["loadbalancer_id"] = ex_loadbalancer_id if auth is not None: if isinstance(auth, NodeAuthPassword): body["password"] = auth.password elif isinstance(auth, NodeAuthSSHKey): body["rsa_key"] = auth.pubkey if ex_ip is not None: body["ip_id"] = ex_ip response = self.connection.request( action="servers", data=body, method="POST", ) return self._to_node(response.object)
[docs] def list_nodes(self): """ List all nodes. :return: ``list`` of :class:`Node` :rtype: ``list`` """ response = self.connection.request(action="servers", method="GET") return self._to_nodes(response.object)
[docs] def destroy_node(self, node, ex_keep_ips=False): """ Destroys a node. :param node: The node you wish to destroy. :type volume: :class:`Node` :param ex_keep_ips: True to keep all IP addresses assigned to the node :type ex_keep_ips: : ``bool`` :return: Instance of class ``Node`` :rtype: :class: `Node` """ self.ex_shutdown_server(node.id) self._wait_for_state(node.id, "POWERED_OFF") response = self.connection.request( action="servers/%s" % node.id, params={"keep_ips": ex_keep_ips}, method="DELETE", ) return self._to_node(response.object)
[docs] def reboot_node(self, node): """ Reboots the node. :param node: The node you wish to destroy. :type volume: :class:`Node` :return: Instance of class ``Node`` :rtype: :class: `Node` """ shutdown_body = {"action": "REBOOT", "method": "HARDWARE"} response = self.connection.request( action="servers/%s/status/action" % node.id, data=shutdown_body, method="PUT", ) return self._to_node(response.object)
""" Extension functions """
[docs] def ex_rename_server(self, server_id, name=None, description=None): """ Renames the server :param server_id: ID of the server you want to rename :param name: New name of the server :type: ``str`` :param description: New description of the server :type: ``str`` :return: Instance of class ``Node`` :rtype: :class: `Node` """ body = {} if name is not None: body["name"] = name if description is not None: body["description"] = description response = self.connection.request( action="servers/%s" % server_id, data=body, method="PUT" ) return self._to_node(response.object)
[docs] def ex_get_server_hardware(self, server_id): """ Gets all server hardware :param server_id: Id of the server :type: ``str`` :return: Server's hardware :rtype: ``dict`` """ response = self.connection.request( action="servers/%s/hardware" % server_id, method="GET" ) return response.object
""" Hardware operations """
[docs] def ex_modify_server_hardware( self, server_id, fixed_instance_size_id=None, vcore=None, cores_per_processor=None, ram=None, ): """ Modifies server's hardware :param server_id: :type: ``str`` :param fixed_instance_size_id: Id of the fixed instance size :type: ``str`` :param vcore: Virtual cores count :type: ``int`` :param cores_per_processor: Count of cores per procesor :type: ``int`` :param ram: Amount of ram for the server :type: ``int`` :return: Instance of class ``Node`` :type: :class: `Node` """ body = {} if fixed_instance_size_id is not None: body["fixed_instance_size_id"] = fixed_instance_size_id if vcore is not None: body["vcore"] = vcore if cores_per_processor is not None: body["cores_per_processor"] = cores_per_processor if ram is not None: body["ram"] = ram response = self.connection.request( action="servers/%s/hardware" % server_id, data=body, method="PUT" ) return self._to_node(response.object)
""" HDD operations """
[docs] def ex_modify_server_hdd(self, server_id, hdd_id=None, size=None): """ Modifies server hard disk drives :param server_id: Id of the server :type: ``str`` :param hdd_id: Id of the hard disk :type: ``str`` :param size: Size of the hard disk :type: ``str`` :return: Instance of class ``Node`` :rtype: :class: `Node` """ body = {} if size is not None: body["size"] = size response = self.connection.request( action="servers/%s/hardware/hdds/%s" % (server_id, hdd_id), data=body, method="PUT", ) return self._to_node(response.object)
[docs] def ex_add_hdd(self, server_id, size, is_main): """ Add a hard disk to the server :param server_id: Id of the server :type: ``str`` :param size: Size of the new disk :type: ``str`` :param is_main: Indicates if the disk is going to be the boot disk :type: ``boolean`` :return: Instance of class ``Node`` :type: :class: `Node` """ body = {"size": size, "is_main": is_main} response = self.connection.request( action="servers/%s/hardware/hdds" % server_id, data=body, method="POST" ) return self._to_node(response.object)
[docs] def ex_remove_hdd(self, server_id, hdd_id): """ Removes existing hard disk :param server_id: Id of the server :type: ``str`` :param hdd_id: Id of the hard disk :type: ``str`` :return: Instance of class ``Node`` :rtype: :class: `Node` """ response = self.connection.request( action="servers/%s/hardware/hdds/%s" % (server_id, hdd_id), method="DELETE" ) return self._to_node(response.object)
""" Data center operations """
[docs] def ex_list_datacenters(self): """ Lists all data centers :return: List of data centers :rtype: ``dict`` """ response = self.connection.request(action="datacenters", method="GET") return response.object
[docs] def ex_get_server(self, server_id): """ Gets a server :param server_id: Id of the server to be retrieved :type: ``str`` :return: Instance of class ``Node`` :rtype: :class: `Node` """ response = self.connection.request( action="servers/%s" % (server_id), method="GET" ) return self._to_node(response.object)
[docs] def ex_shutdown_server(self, server_id, method="SOFTWARE"): """ Shuts down the server :param server_id: Id of the server to be shut down :type: ``str`` :param method: Method of shutting down "SOFTWARE" or "HARDWARE" :return: Instance of class ``Node`` :rtype: :class: `Node` """ shutdown_body = {"action": "POWER_OFF", "method": method} response = self.connection.request( action="servers/%s/status/action" % (server_id), data=shutdown_body, method="PUT", ) return self._to_node(response.object)
""" Image operations """
[docs] def ex_get_server_image(self, server_id): """ Gets server image :param server_id: Id of the server :type: ``str`` :return: Server image :rtype: ``dict`` """ response = self.connection.request( action="servers/%s/image" % server_id, method="GET" ) return response.object
[docs] def ex_reinstall_server_image(self, server_id, image_id, password=None): """ Installs a new image on the server :param server_id: Id of the server :type: ``str`` :param image_id: Id of the image (Server Appliance) :type: ``str`` :param password: New password for the server :return: Instance of class ``Node`` :rtype: :class: `Node` """ body = { "id": image_id, } if password is not None: body["password"] = password response = self.connection.request( action="servers/%s/image" % server_id, data=body, method="PUT" ) return self._to_node(response.object)
""" Server IP operations """
[docs] def ex_list_server_ips(self, server_id): """ Gets all server IP objects :param server_id: Id of the server :type: ``str`` :return: List of server IP objects :rtype: ``list`` of ``dict`` """ response = self.connection.request( action="servers/%s/ips" % server_id, method="GET" ) return response.object
[docs] def ex_get_server_ip(self, server_id, ip_id): """ Get a single server IP object :param server_id: Id of the server :type: ``str`` :param ip_id: ID of the IP address :type: ``str`` :return: IP address object :rtype: ``dict`` """ response = self.connection.request( action="servers/%s/ips/%s" % (server_id, ip_id), method="GET" ) return response.object
[docs] def ex_assign_server_ip(self, server_id, ip_type): """ Assigns a new IP address to the server :param server_id: Id of the server :type: ``str`` :param ip_type: Type of the IP address [IPV4,IPV6] :type: ``str`` :return: ``Node`` instance :rtype: ``Node`` """ body = {"type": ip_type} response = self.connection.request( action="servers/%s/ips" % server_id, data=body, method="POST" ) return self._to_node(response.object)
[docs] def ex_remove_server_ip(self, server_id, ip_id, keep_ip=None): """ Removes an IP address from the server :param server_id: Id of the server :type: ``str`` :param ip_id: ID of the IP address :type: ``str`` :param keep_ip: Indicates whether IP address will be removed from the Cloud Panel :type: ``boolean`` :return: ``Node`` instance :rtype: ``Node`` """ body = {} if keep_ip is not None: body["keep_ip"] = keep_ip response = self.connection.request( action="servers/%s/ips/%s" % (server_id, ip_id), data=body, method="DELETE" ) return self._to_node(response.object)
[docs] def ex_get_server_firewall_policies(self, server_id, ip_id): """ Gets a firewall policy of attached to the server's IP :param server_id: Id of the server :type: ``str`` :param ip_id: ID of the IP address :type: ``str`` :return: IP address object :rtype: ``dict`` """ response = self.connection.request( action="/servers/%s/ips/%s/firewall_policy" % (server_id, ip_id), method="GET", ) return response.object
[docs] def ex_add_server_firewall_policy(self, server_id, ip_id, firewall_id): """ Adds a firewall policy to the server's IP address :param server_id: Id of the server :type: ``str`` :param ip_id: ID of the IP address :type: ``str`` :param firewall_id: ID of the firewall policy :type: ``str`` :return: ``Node`` instance :rtype: ``Node`` """ body = {"id": firewall_id} response = self.connection.request( action="/servers/%s/ips/%s/firewall_policy" % (server_id, ip_id), data=body, method="POST", ) return self._to_node(response.object)
""" Firewall Policy operations """
[docs] def ex_create_firewall_policy(self, name, rules, description=None): """ Creates a firewall Policy. :param name: :param description: :param rules: :rtype: `dict` :return: `dict` firewall policy """ body = {"name": name} if description is not None: body["description"] = description if len(rules) == 0: raise ValueError("At least one firewall rule is required.") else: body["rules"] = rules response = self.connection.request( action="firewall_policies", data=body, method="POST", ) return response.object
[docs] def ex_list_firewall_policies(self): """ " List firewall policies :return: 'dict' """ response = self.connection.request(action="firewall_policies", method="GET") return response.object
[docs] def ex_get_firewall_policy(self, fw_id): """ Gets firewall policy :param fw_id: ID of the firewall policy :return: 'dict' """ response = self.connection.request( action="firewall_policy/%s" % fw_id, method="GET" ) return response.object
[docs] def ex_delete_firewall_policy(self, fw_id): """ Deletes firewall policy :param fw_id: ID of the Firewall :return: 'dict' """ response = self.connection.request( action="firewall_policy/%s" % fw_id, method="DELETE" ) return response.object
""" Shared storage operations """
[docs] def ex_list_shared_storages(self): """ List of shared storages :return: 'dict' """ response = self.connection.request(action="shared_storages", method="GET") return response.object
[docs] def ex_get_shared_storage(self, storage_id): """ Gets a shared storage :return: 'dict' """ response = self.connection.request( action="shared_storages/%s" % (storage_id), method="GET" ) return response.object
[docs] def ex_create_shared_storage( self, name, size, datacenter_id=None, description=None ): """ Creates a shared storage :param name: Name of the storage :param size: Size of the storage :param datacenter_id: datacenter where storage should be created :param description: description ot the storage :return: 'dict' """ body = {"name": name, "size": size, "datacenter_id": datacenter_id} if description is not None: body["description"] = description response = self.connection.request( action="shared_storages", data=body, method="POST" ) return response.object
[docs] def ex_delete_shared_storage(self, storage_id): """ Removes a shared storage :param storage_id: Id of the shared storage :type: ``str`` :return: Instnace of shared storage :rtype: ``list`` of ``dict`` """ response = self.connection.request( action="shared_storages/%s" % storage_id, method="DELETE" ) return response.object
[docs] def ex_attach_server_to_shared_storage(self, storage_id, server_id, rights): """ Attaches a single server to a shared storage :param storage_id: Id of the shared storage :param server_id: Id of the server to be attached to the shared storage :param rights: :return: :rtype: 'dict' """ body = {"severs": [{"id": server_id, "rights": rights}]} response = self.connection.request( action="shared_storages/%s/servers" % storage_id, data=body, method="POST" ) return response.object
[docs] def ex_get_shared_storage_server(self, storage_id, server_id): """ Gets a shared storage's server :param storage_id: :param server_id: :return: """ response = self.connection.request( action="shared_storages/%s/servers/%s" % (storage_id, server_id), ) return response.object
[docs] def ex_detach_server_from_shared_storage(self, storage_id, server_id): """ Detaches a server from shared storage :param storage_id: Id of the shared storage :type: ``str`` :param server_id: Id of the server :type: ``str`` :return: Instance of shared storage :rtype: ``dict`` """ response = self.connection.request( action="shared_storages/%s/servers/%s" % (storage_id, server_id), method="DELETE", ) return response.object
""" Load Balancers operations """
[docs] def ex_create_load_balancer( self, name, method, rules, persistence=None, persistence_time=None, health_check_test=None, health_check_interval=None, health_check_path=None, health_check_parser=None, datacenter_id=None, description=None, ): """ :param name: Name of the load balancer :param method: Load balancer method :param rules: Load balancer rules :type rules: ``list`` of ``dict`` :param persistence: Indictes if persistance is set :type persistence: ``boolean`` :param persistence_time: Persistance time :type persistence_time: ``int`` :param health_check_test: Type of test :type health_check_test:``str`` :param health_check_interval: Interval of the check :param health_check_path: Path :type health_check_path: ``str`` :param health_check_parser: Parser :type health_check_parser:``str`` :param datacenter_id: Data center id :type datacenter_id:``str`` :param description: Description of load balancer :type description:``str`` :return: ``dict`` """ body = { "name": name, "method": method, } body["rules"] = [] body["rules"] = rules if persistence is not None: body["persistence"] = persistence if persistence_time is not None: body["persistence_time"] = persistence_time if health_check_test is not None: body["health_check_test"] = health_check_test if health_check_interval is not None: body["health_check_interval"] = health_check_interval if health_check_path is not None: body["health_check_path"] = health_check_path if health_check_parser is not None: body["health_check_parser"] = health_check_parser if datacenter_id is not None: body["datacenter_id"] = datacenter_id if description is not None: body["description"] = description response = self.connection.request( action="load_balancers", data=body, method="POST" ) return response.object
[docs] def ex_update_load_balancer( self, lb_id, name=None, description=None, health_check_test=None, health_check_interval=None, persistence=None, persistence_time=None, method=None, ): body = {} if name is not None: body["name"] = name if description is not None: body["description"] = description if health_check_test is not None: body["health_check_test"] = health_check_test if health_check_interval is not None: body["health_check_interval"] = health_check_interval if persistence is not None: body["persistence"] = persistence if persistence_time is not None: body["persistence_time"] = persistence_time if method is not None: body["method"] = method response = self.connection.request( action="load_balancers/%s" % lb_id, data=body, method="PUT" ) return response.object
[docs] def ex_add_servers_to_load_balancer(self, lb_id, server_ips=[]): """ Adds server's IP address to load balancer :param lb_id: Load balancer ID :type: ``str`` :param server_ips: Array of server IP IDs :type: ``list`` of ``str`` :return: Instance of load balancer :rtype: ``dict`` """ body = { "server_ips": server_ips, } response = self.connection.request( action="load_balancers/%s/server_ips" % lb_id, data=body, method="POST" ) return response.object
[docs] def ex_remove_server_from_load_balancer(self, lb_id, server_ip): """ Removes server's IP from load balancer :param lb_id: Load balancer ID :type: ``str`` :param server_ip: ID of the server IP :type: ``str`` :return: Instance of load balancer :rtype: ``dict`` """ response = self.connection.request( action="/load_balancers/%s/server_ips/%s" % (lb_id, server_ip), method="DELETE", ) return response.object
[docs] def ex_add_load_balancer_rule( self, lb_id, protocol, port_balancer, port_server, source=None ): """ Adds a rule to load balancer :param lb_id: Load balancer ID :rtype: ``str`` :param protocol: Load balancer protocol :rtype: ``str`` :param port_balancer: Port to be balananced :rtype: ``int`` :param port_server: Server port :rtype: ``int`` :param source: Source IP address :rtype: ``str`` :return: Instance of load balancer :rtype: ``dict`` """ body = { "rules": [ { "protocol": protocol, "port_balancer": port_balancer, "port_server": port_server, } ] } if source is not None: body["rules"][0]["source"] = source response = self.connection.request( action="/load_balancers/%s/rules" % lb_id, data=body, method="POST" ) return response.object
[docs] def ex_remove_load_balancer_rule(self, lb_id, rule_id): """ Removes load balancer rule :param lb_id: Load balancer ID :rtype: ``str`` :param rule_id: Rule ID :rtype: ``str`` :return: Instance of load balancer :rtype: ``dict`` """ response = self.connection.request( action="/load_balancers/%s/rules/%s" % (lb_id, rule_id), method="DELETE" ) return response.object
[docs] def ex_list_load_balancers(self): """ Lists all load balancers :return: List of load balancers :rtype: ``list`` of ``dict`` """ response = self.connection.request(action="load_balancers", method="GET") return response.object
[docs] def ex_get_load_balancer(self, lb_id): """ Gets a single load balancer :param lb_id: ID of the load balancer :type lb_id: ``str`` :return: Instance of load balancer :rtype: ``dict`` """ response = self.connection.request( action="load_balancers/%s" % lb_id, method="GET" ) return response.object
[docs] def ex_list_load_balancer_server_ips(self, lb_id): """ List balanced server IP addresses :param lb_id: ID of the load balancer :type lb_id: ``str`` :return: Array of IP address IDs :rtype: ``dict`` """ response = self.connection.request( action="load_balancers/%s/server_ips" % lb_id, method="GET" ) return response.object
[docs] def ex_get_load_balancer_server_ip(self, lb_id, server_ip): """ Gets load balanced server id :param lb_id: ID of the load balancer :type lb_id: ``str`` :param server_ip: ID of the server IP :type server_ip: ``str`` :return: Server IP :rtype: ``dict`` """ response = self.connection.request( action="load_balancers/%s/server_ips/%s" % (lb_id, server_ip), method="GET" ) return response.object
[docs] def ex_list_load_balancer_rules(self, lb_id): """ Lists loadbalancer rules :param lb_id: ID of the load balancer :type lb_id: ``str`` :return: Lists of rules :rtype: ``list`` of ``dict`` """ response = self.connection.request( action="load_balancers/%s/rules" % lb_id, method="GET" ) return response.object
[docs] def ex_get_load_balancer_rule(self, lb_id, rule_id): """ Get a load balancer rule :param lb_id: ID of the load balancer :type lb_id: ``str`` :param rule_id: Rule ID :type rule_id: ``str`` :return: A load balancer rule :rtype: ``dict`` """ response = self.connection.request( action="load_balancers/%s/rules/%s" % (lb_id, rule_id), method="GET" ) return response.object
[docs] def ex_delete_load_balancer(self, lb_id): """ Deletes a load balancer rule :param lb_id: ID of the load balancer :type lb_id: ``str`` :param rule_id: Rule ID :type rule_id: ``str`` :return: Instance of load balancer :rtype: ``dict`` """ response = self.connection.request( action="load_balancers/%s" % lb_id, method="DELETE" ) return response.object
""" Public IP operations """
[docs] def ex_list_public_ips(self): """ Lists all public IP addresses :return: Array of public addresses :rtype: ``list`` of ``dict`` """ response = self.connection.request(action="public_ips", method="GET") return response.object
[docs] def ex_create_public_ip(self, type, reverse_dns=None, datacenter_id=None): """ Creates a public IP :param type: Type of IP (IPV4 or IPV6) :type type: ``str`` :param reverse_dns: Reverse DNS :type reverse_dns: ``str`` :param datacenter_id: Datacenter ID where IP address will be crated :type datacenter_id: ``str`` :return: Instance of Public IP :rtype: ``dict`` """ body = {"type": type} if reverse_dns is not None: body["reverse_dns"] = reverse_dns if datacenter_id is not None: body["datacenter_id"] = datacenter_id response = self.connection.request( action="public_ips", data=body, method="POST" ) return response.object
[docs] def ex_get_public_ip(self, ip_id): """ Gets a Public IP :param ip_id: ID of the IP :type ip_id: ``str`` :return: Instance of Public IP :rtype: ``dict`` """ response = self.connection.request(action="public_ips/%s" % ip_id, method="GET") return response.object
[docs] def ex_delete_public_ip(self, ip_id): """ Deletes a public IP :param ip_id: ID of public IP :type ip_id: ``str`` :return: Instance of IP Address :rtype: ``dict`` """ response = self.connection.request( action="public_ips/%s" % ip_id, method="DELETE" ) return response
[docs] def ex_update_public_ip(self, ip_id, reverse_dns): """ Updates a Public IP :param ip_id: ID of public IP :type ip_id: ``str`` :param reverse_dns: Reverse DNS :type reverse_dns: ``str`` :return: Instance of Public IP :rtype: ``dict`` """ body = {"reverse_dns": reverse_dns} response = self.connection.request( action="public_ips/%s" % ip_id, data=body, method="DELETE" ) return response.object
""" Private Network Operations """
[docs] def ex_list_private_networks(self): """ Lists all private networks :return: List of private networks :rtype: ``dict`` """ response = self.connection.request(action="private_networks", method="GET") return response.object
[docs] def ex_create_private_network( self, name, description=None, datacenter_id=None, network_address=None, subnet_mask=None, ): """ Creates a private network :param name: Name of the private network :type name: ``str`` :param description: Description of the private network :type description: ``str`` :param datacenter_id: ID of the data center for the private network :type datacenter_id: ``str`` :param network_address: Network address of the private network :type network_address: ``str`` :param subnet_mask: Subnet mask of the private network :type subnet_mask: ``str`` :return: Newly created private network :rtype: ``dict`` """ body = {"name": name} if description is not None: body["description"] = description if datacenter_id is not None: body["datacenter_id"] = datacenter_id if network_address is not None: body["network_address"] = network_address if subnet_mask is not None: body["subnet_maks"] = subnet_mask response = self.connection.request( action="private_networks", data=body, method="POST" ) return response.object
[docs] def ex_delete_private_network(self, network_id): """ Deletes a private network :param network_id: Id of the private network :type network_id: ``str`` :return: Instance of the private network being deleted :rtype: ``dict`` """ response = self.connection.request( action="private_networks" % network_id, method="DELETE" ) return response.object
[docs] def ex_update_private_network( self, network_id, name=None, description=None, datacenter_id=None, network_address=None, subnet_mask=None, ): """ Updates a private network :param name: Name of the private network :type name: ``str`` :param description: Description of the private network :type description: ``str`` :param datacenter_id: ID of the data center for the private network :type datacenter_id: ``str`` :param network_address: Network address of the private network :type network_address: ``str`` :param subnet_mask: Subnet mask of the private network :type subnet_mask: ``str`` :return: Instance of private network :rtype: ``dict`` """ body = {} if name is not None: body["name"] = name if description is not None: body["description"] = description if datacenter_id is not None: body["datacenter_id"] = datacenter_id if network_address is not None: body["network_address"] = network_address if subnet_mask is not None: body["subnet_maks"] = subnet_mask response = self.connection.request( action="private_networks/%s", data=body, method="PUT" ) return response.object
[docs] def ex_list_private_network_servers(self, network_id): """ Lists all private network servers :param network_id: Private network ID :type network_id: ``str`` :return: List of private network servers :rtype: ``dict`` """ response = self.connection.request( action="/private_networks/%s/servers" % network_id, method="GET" ) return response.object
[docs] def ex_add_private_network_server(self, network_id, server_ids): """ Add servers to private network :param network_id: Private Network ID :type network_id: ``str`` :param server_ids: List of server IDs :type server_ids: ``list`` of ``str`` :return: List of attached servers :rtype: ``dict`` """ body = {"servers": server_ids} response = self.connection.request( action="/private_networks/%s/servers" % network_id, data=body, method="POST" ) return response.object
[docs] def ex_remove_server_from_private_network(self, network_id, server_id): """ Removes a server from the private network :param network_id: Private Network ID :type network_id: ``str`` :param server_id: Id of the server :type server_id: ``str`` :return: Instance of the private network :rtype: ``dict`` """ response = self.connection.request( action="/private_networks/%s/servers/%s" % (network_id, server_id), method="POST", ) return response.object
""" Monitoring policy operations """
[docs] def ex_list_monitoring_policies(self): """ Lists all monitoring policies :return: List of monitoring policies :rtype: ``dict`` """ response = self.connection.request(action="monitoring_policies", method="GET") return response.object
[docs] def ex_create_monitoring_policy( self, name, thresholds, ports, processes, description=None, email=None, agent=None, ): """ Creates a monitoring policy :param name: Name for the monitoring policy :type name: ``str`` :param thresholds: Thresholds for the monitoring policy :type thresholds: ``dict`` :param ports: Monitoring policies for ports :type ports: ``list`` of ``dict`` :param processes: Processes to be monitored :type processes: ``list`` of ``dict`` :param description: Description for the monitoring policy :type description: ``str`` :param email: Email for notifications :type email: ``str`` :param agent: Indicates if agent application will be installed :type agent: ``boolean`` :return: Newly created instance of monitofing policy :rtype: ``dict`` """ body = { "name": name, "thresholds": thresholds, "ports": ports, "processes": processes, } if description is not None: body["description"] = description if email is not None: body["email"] = email if agent is not None: body["agent"] = agent response = self.connection.request( action="monitoring_policies", data=body, method="POST" ) return response.object
[docs] def ex_delete_monitoring_policy(self, policy_id): """ Deletes a monitoring policy :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :return: Instance of the monitoring policy being deleted :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies" % policy_id, method="DELETE" ) return response.object
[docs] def ex_update_monitoring_policy( self, policy_id, email, thresholds, name=None, description=None ): """ Updates monitoring policy :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param email: Email to send notifications to :type email: ``str`` :param thresholds: Thresholds for the monitoring policy :type thresholds: ``dict`` :param name: Name of the monitoring policy :type name: ``str`` :param description: Description of the monitoring policy :type description: ``str`` :return: Instance of the monitoring policy being deleted :rtype: ``dict`` """ body = {} if name is not None: body["name"] = name if description is not None: body["description"] = description if thresholds is not None: body["thresholds"] = thresholds if email is not None: body["email"] = email response = self.connection.request( action="monitoring_policies/%s" % policy_id, data=body, method="PUT" ) return response.object
[docs] def ex_get_monitoring_policy(self, policy_id): """ Fetches a monitoring policy :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :return: Instance of a monitoring policy :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies/%s" % policy_id, method="GET" ) return response.object
[docs] def ex_get_monitoring_policy_ports(self, policy_id): """ Fetches monitoring policy ports :param policy_id: Id of the monitoring policy :type policy_id: :return: Instance of a monitoring policy :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies/%s/ports" % policy_id, method="GET" ) return response.object
[docs] def ex_get_monitoring_policy_port(self, policy_id, port_id): """ Fetches monitoring policy port :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param port_id: Id of the port :type port_id: ``str`` :return: Instance of a monitoring policy :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies/%s/ports/%s" % (policy_id, port_id), method="GET", ) return response.object
[docs] def ex_remove_monitoring_policy_port(self, policy_id, port_id): """ Removes monitoring policy port :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param port_id: Id of the port :type port_id: ``str`` :return: Instance of a monitoring policy :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies/%s/ports/%s" % (policy_id, port_id), method="DELETE", ) return response.object
[docs] def ex_add_monitoring_policy_ports(self, policy_id, ports): """ Add monitoring policy ports :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param ports: List of ports :type ports: ``dict`` [ { 'protocol':'TCP', 'port':'80', 'alert_if':'RESPONDING', 'email_notification':true } ] :return: Instance of a monitoring policy :rtype: ``dict`` """ body = {"ports": ports} response = self.connection.request( action="monitoring_policies/%s/ports" % policy_id, data=body, method="POST" ) return response.object
[docs] def ex_get_monitoring_policy_processes(self, policy_id): """ Fetches monitoring policy processes :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :return: Instance of a monitoring policy :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies/%s/processes" % policy_id, method="GET" ) return response.object
[docs] def ex_get_monitoring_policy_process(self, policy_id, process_id): """ Fetches monitoring policy process :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param process_id: Id of the process :type process_id: ``str`` :return: Instance of a monitoring policy :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies/%s/processes/%s" % (policy_id, process_id), method="GET", ) return response.object
[docs] def ex_remove_monitoring_policy_process(self, policy_id, process_id): """ Removes monitoring policy process :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param process_id: Id of the process :type process_id: ``str`` :return: Instance of a monitoring policy :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies/%s/processes/%s" % (policy_id, process_id), method="DELETE", ) return response.object
[docs] def ex_add_monitoring_policy_processes(self, policy_id, processes): """ Add monitoring policy processes :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param processes: List of processes :type processes: ``list`` of ``dict`` [ { 'process': 'taskmmgr', 'alert_if': 'RUNNING', 'email_notification': true } ] :return: Instance of a monitoring policy :rtype: ``dict`` """ body = {"processes": processes} response = self.connection.request( action="monitoring_policies/%s/processes" % policy_id, data=body, method="POST", ) return response.object
[docs] def ex_list_monitoring_policy_servers(self, policy_id): """ List all servers that are being monitoried by the policy :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :return: List of servers being monitored :rtype: ``list`` of ``dict`` """ response = self.connection.request( action="monitoring_policies/%s/servers" % policy_id, method="GET" ) return response.object
[docs] def ex_add_servers_to_monitoring_policy(self, policy_id, servers): """ Adds servers to monitoring policy :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param servers: List of server ID :type servers: ``list`` of ``str`` :return: Instance of a monitoring policy :rtype: ``dict`` """ body = {"servers": servers} response = self.connection.request( action="monitoring_policies/%s/servers" % policy_id, data=body, method="POST", ) return response.object
[docs] def ex_remove_server_from_monitoring_policy(self, policy_id, server_id): """ Removes a server from monitoring policy :param policy_id: Id of the monitoring policy :type policy_id: ``str`` :param server_id: Id of the server :type server_id: ``str`` :return: Instance of a monitoring policy :rtype: ``dict`` """ response = self.connection.request( action="monitoring_policies/%s/servers/%s" % (policy_id, server_id), method="DELETE", ) return response.object
""" Private Functions """ def _to_images(self, object, image_type=None): if image_type is not None: images = [image for image in object if image["type"] == image_type] else: images = [image for image in object] return [self._to_image(image) for image in images] def _to_image(self, data): extra = { "os_family": data["os_family"], "os": data["os"], "os_version": data["os_version"], "os_architecture": data["os_architecture"], "os_image_type": data["os_image_type"], "min_hdd_size": data["min_hdd_size"], "available_datacenters": data["available_datacenters"], "licenses": data["licenses"], "version": data["version"], "categories": data["categories"], } return NodeImage(id=data["id"], name=data["name"], driver=self, extra=extra) def _to_node_size(self, data): return NodeSize( id=data["id"], name=data["name"], ram=data["hardware"]["ram"], disk=data["hardware"]["hdds"][0]["size"], bandwidth=None, price=None, driver=self.connection.driver, extra={ "vcores": data["hardware"]["vcore"], "cores_per_processor": data["hardware"]["cores_per_processor"], }, ) def _to_location(self, location): return NodeLocation( id=location["id"], name=location["country_code"], country=location["location"], driver=self.connection.driver, ) def _to_nodes(self, servers): return [self._to_node(server) for server in servers] def _to_node(self, server): extra = {} extra["datacenter"] = server["datacenter"] if "description" in server: extra["description"] = server["description"] if "status" in server: extra["status"] = server["status"] if "image" in server: extra["image"] = server["image"] if "hardware" in server: extra["hardware"] = server["hardware"] if "dvd" in server: extra["dvd"] = server["dvd"] if "snapshot" in server: extra["snapshot"] = server["snapshot"] if "ips" in server: extra["ips"] = server["ips"] if "alerts" in server: extra["alerts"] = server["alerts"] if "monitoring_policy" in server: extra["monitoring_policy"] = server["monitoring_policy"] if "private_networks" in server: extra["private_networks"] = server["private_networks"] ips = [] if server["ips"] is not None: for ip in server["ips"]: ips.append(ip["ip"]) state = self.NODE_STATE_MAP.get(server["status"]["state"]) return Node( id=server["id"], state=state, name=server["name"], driver=self.connection.driver, public_ips=ips, private_ips=None, extra=extra, ) def _wait_for_state(self, server_id, state, retries=50): for i in (0, retries): server = self.ex_get_server(server_id) if server.extra["status"]["state"] == state: return sleep(5) if i == retries: raise Exception("Retries count reached") def _list_fixed_instances(self): response = self.connection.request( action="/servers/fixed_instance_sizes", method="GET" ) return response.object