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 `str` :param image: Image from list_images :rtype: image: :param ex_fixed_instance_size_id: Fixed instance size ID from list_sizes :rtype: ``str`` :param location: 1&1 Data center Location :type `NodeLocation` :param auth: SSH key or root password :type: :class:`NodeAuthSSHKey` or :class:`NodeAuthPassword` :param ex_ip: IP address :type `str` :param ex_ssh_key: SSH Key :type `str` :param password: Password :type `str` :param ex_monitoring_policy_id: :type `str` :param ex_firewall_policy_id: :type `str` :param ex_loadbalancer_id: :type `str` :param ex_description: :type `str` :param ex_power_on: :type `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 :rtype: ``str`` :param description: New description of the server :rtype: ``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 :rtype: ``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: :rtype: ``str`` :param fixed_instance_size_id: Id of the fixed instance size :rtype: ``str`` :param vcore: Virtual cores count :rtype: ``int`` :param cores_per_processor: Count of cores per procesor :rtype: ``int`` :param ram: Amount of ram for the server :rtype: ``int`` :return: Instance of class ``Node`` :rtype: :class: `Node` """ body = {} if fixed_instance_size_id is not None: body['firewall_policy_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 :rtype: ``str`` :param hdd_id: Id of the hard disk :rtype: ``str`` :param size: Size of the hard disk :rtype: ``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 :rtype: ``str`` :param size: Size of the new disk :rtype: ``str`` :param is_main: Indicates if the disk is going to be the boot disk :rtype: ``boolean`` :return: Instance of class ``Node`` :rtype: :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 :rtype: ``str`` :param hdd_id: Id of the hard disk :rtype: ``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 :rtype: ``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 :rtype: ``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 :rtype: ``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 :rtype: ``str`` :param image_id: Id of the image (Server Appliance) :rtype: ``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 :rtype: ``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 :rtype: ``str`` :param ip_id: ID of the IP address :rtype: ``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 :rtype: ``str`` :param ip_type: Type of the IP address [IPV4,IPV6] :rtype: ``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 :rtype: ``str`` :param ip_id: ID of the IP address :rtype: ``str`` :param keep_ip: Indicates whether IP address will be removed from the Cloud Panel :rtype: ``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 :rtype: ``str`` :param ip_id: ID of the IP address :rtype: ``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_remove_server_firewall_policy(self, server_id, ip_id): """ Removes a firewall policy from server's IP :param server_id: Id of the server :rtype: ``str`` :param ip_id: ID of the IP address :rtype: ``str`` :return: ``Node`` instance :rtype: ``Node`` """ response = self.connection.request( action='/servers/%s/ips/%s/firewall_policy' % (server_id, ip_id), method='DELETE' ) return self._to_node(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 :rtype: ``str`` :param ip_id: ID of the IP address :rtype: ``str`` :param firewall_id: ID of the firewall policy :rtype: ``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': [ { 'protocol': 'TCP', 'port_from': 80, 'port_to': 80, 'source': '0.0.0.0' } ] :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 :rtype: ``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 :rtype: ``str`` :param server_id: Id of the server :rtype: ``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 :rtype:``str`` :param method: Load balancer method :rtype:``str`` :param rules: Load balancer rules :rtype: ``list`` of ``dict`` 'rules': [ { 'protocol': 'TCP', 'port_balancer': 80, 'port_server': 80, 'source': '0.0.0.0' }, { 'protocol': 'TCP', 'port_balancer': 9999, 'port_server': 8888, 'source': '0.0.0.0' } ] :param persistence: Indictes if persistance is set :rtype: ``boolean`` :param persistence_time: Persistance time :rtype: ``int`` :param health_check_test: Type of test :rtype:``str`` :param health_check_interval: Interval of the check :param health_check_path: Path :rtype:``str`` :param health_check_parser: Parser :rtype:``str`` :param datacenter_id: Data center id :rtype:``str`` :param description: Description of load balancer :rtype:``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 :rtype: ``str`` :param server_ips: Array of server IP IDs :rtype: ``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 :rtype: ``str`` :param server_ip: ID of the server IP :rtype: ``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 :rtype: ``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 :rtype: ``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 :rtype: ``str`` :param server_ip: ID of the server IP :rtype: ``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 :rtype: ``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 :rtype: ``str`` :param rule_id: Rule ID :rtype: ``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 :rtype: ``str`` :param rule_id: Rule ID :rtype: ``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] :rtype: ``str`` :param reverse_dns: Reverse DNS :rtype: ``str`` :param datacenter_id: Datacenter ID where IP address will be crated :rtype: ``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 :rtype: ``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 :rtype: ``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 :rtype: ``str`` :param reverse_dns: Reverse DNS :rtype: ``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 :rtype: ``str`` :param description: Description of the private network :rtype: ``str`` :param datacenter_id: ID of the data center for the private network :rtype: ``str`` :param network_address: Network address of the private network :rtype: ``str`` :param subnet_mask: Subnet mask of the private network :rtype: ``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 :rtype: ``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 :rtype: ``str`` :param description: Description of the private network :rtype: ``str`` :param datacenter_id: ID of the data center for the private network :rtype: ``str`` :param network_address: Network address of the private network :rtype: ``str`` :param subnet_mask: Subnet mask of the private network :rtype: ``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 :rtype: ``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 :rtype: ``str`` :param server_ids: List of server IDs :rtype: ``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 :rtype: ``str`` :param server_id: Id of the server :rtype: ``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 :rtype: ``str`` :param thresholds: Thresholds for the monitoring policy :rtype: ``dict`` { 'cpu':{ 'warning':{ 'value':90, 'alert':false }, 'critical':{ 'value':95, 'alert':false } }, 'ram':{ 'warning':{ 'value':90, 'alert':false }, 'critical':{ 'value':95, 'alert':false } }, 'disk':{ 'warning':{ 'value':80, 'alert':false }, 'critical':{ 'value':90, 'alert':false } }, 'transfer':{ 'warning':{ 'value':1000, 'alert':false }, 'critical':{ 'value':2000, 'alert':false } }, 'internal_ping':{ 'warning':{ 'value':50, 'alert':false }, 'critical':{ 'value':100, 'alert':false } } } :param ports: Monitoring policies for ports :rtype: ``dict`` [ { 'protocol':'TCP', 'port':'22', 'alert_if':'RESPONDING', 'email_notification':true } ] :param processes: Processes to be monitored :rtype: ``dict`` [ { 'process':'test', 'alert_if':'NOT_RUNNING', 'email_notification':true } ] :param description: Description for the monitoring policy :rtype: ``str`` :param email: Email for notifications :rtype: ``str`` :param agent: Indicates if agent application will be installed :rtype: ``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 :rtype: ``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 :param email: Email to send notifications to :rtype: ``str`` :param thresholds: Thresholds for the monitoring policy :rtype: ``dict`` :param name: Name of the monitoring policy :rtype: ``str`` :param description: Description of the monitoring policy :rtype: ``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 :rtype: ``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 :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 :rtype: ``str`` :param port_id: Id of the port :rtype: ``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 :rtype: ``str`` :param port_id: Id of the port :rtype: ``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 :rtype: ``str`` :param ports: List of ports :rtype: ``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 :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 :rtype: ``str`` :param process_id: Id of the process :rtype: ``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 :rtype: ``str`` :param process_id: Id of the process :rtype: ``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 :rtype: ``str`` :param processes: List of processes :rtype: ``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 :rtype: ``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 :rtype: ``str`` :param servers: List of server ID :rtype: ``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 :rtype: ``str`` :param server_id: Id of the server :rtype: ``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') pass def _list_fixed_instances(self): response = self.connection.request( action='/servers/fixed_instance_sizes', method='GET' ) return response.object