Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id EA6F9200C61 for ; Tue, 11 Apr 2017 02:23:58 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id E8E49160B99; Tue, 11 Apr 2017 00:23:58 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 9948F160BAB for ; Tue, 11 Apr 2017 02:23:56 +0200 (CEST) Received: (qmail 33265 invoked by uid 500); 11 Apr 2017 00:23:55 -0000 Mailing-List: contact notifications-help@libcloud.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@libcloud.apache.org Delivered-To: mailing list notifications@libcloud.apache.org Received: (qmail 33180 invoked by uid 500); 11 Apr 2017 00:23:55 -0000 Delivered-To: apmail-libcloud-commits@libcloud.apache.org Received: (qmail 33134 invoked by uid 99); 11 Apr 2017 00:23:55 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 11 Apr 2017 00:23:55 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 89126F170C; Tue, 11 Apr 2017 00:23:55 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: anthonyshaw@apache.org To: commits@libcloud.apache.org Date: Tue, 11 Apr 2017 00:23:58 -0000 Message-Id: <11fe212ea4384c1d9d49fefd19482e26@git.apache.org> In-Reply-To: <4682c88b35a8465587d4770afa87170c@git.apache.org> References: <4682c88b35a8465587d4770afa87170c@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [04/11] libcloud git commit: 1&1 Compute Driver archived-at: Tue, 11 Apr 2017 00:23:59 -0000 1&1 Compute Driver Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/ff028ae2 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/ff028ae2 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/ff028ae2 Branch: refs/heads/trunk Commit: ff028ae26b232e808f303e680aa0d6737224f605 Parents: 419c694 Author: jasminSPC Authored: Tue Apr 11 00:19:46 2017 +0200 Committer: jasminSPC Committed: Tue Apr 11 00:19:46 2017 +0200 ---------------------------------------------------------------------- docs/compute/drivers/oneandone.rst | 295 + .../compute/oneandone/create_firewall_policy.py | 33 + .../compute/oneandone/create_load_balancer.py | 36 + .../oneandone/create_monitoring_policy.py | 90 + docs/examples/compute/oneandone/create_node.py | 36 + .../compute/oneandone/create_private_network.py | 14 + .../compute/oneandone/create_public_ip.py | 14 + .../compute/oneandone/create_shared_storage.py | 21 + .../compute/oneandone/instantiate_driver.py | 9 + libcloud/common/base.py | 1 + libcloud/compute/drivers/oneandone.py | 2263 +++ libcloud/compute/providers.py | 2 + libcloud/compute/types.py | 1 + .../compute/fixtures/oneandone/auth_error.json | 5 + .../compute/fixtures/oneandone/create_node.json | 43 + .../oneandone/describe_firewall_policy.json | 26 + .../oneandone/describe_id_firewall_policy.json | 4 + .../fixtures/oneandone/describe_server.json | 49 + .../oneandone/describe_shared_stoage.json | 29 + .../fixtures/oneandone/ex_list_datacenters.json | 26 + .../oneandone/fixed_instance_sizes.json | 70 + .../compute/fixtures/oneandone/get_image.json | 24 + .../fixtures/oneandone/get_server_image.json | 4 + .../oneandone/list_firewall_policies.json | 54 + .../compute/fixtures/oneandone/list_images.json | 17941 +++++++++++++++++ .../fixtures/oneandone/list_load_balancer.json | 78 + .../oneandone/list_monitoring_policies.json | 152 + .../fixtures/oneandone/list_public_ips.json | 59 + .../fixtures/oneandone/list_servers.json | 197 + .../oneandone/list_shared_storages.json | 64 + .../fixtures/oneandone/load_balancer.json | 38 + .../fixtures/oneandone/load_balancer_rule.json | 7 + .../fixtures/oneandone/load_balancer_rules.json | 16 + .../oneandone/load_balancer_server_ip.json | 5 + .../oneandone/load_balancer_server_ips.json | 6 + .../fixtures/oneandone/monitoring_policy.json | 73 + .../oneandone/monitoring_policy_port.json | 7 + .../oneandone/monitoring_policy_ports.json | 16 + .../oneandone/monitoring_policy_process.json | 6 + .../oneandone/monitoring_policy_processes.json | 14 + .../oneandone/monitoring_policy_servers.json | 10 + .../compute/fixtures/oneandone/public_ip.json | 15 + .../fixtures/oneandone/server_hardware.json | 13 + .../compute/fixtures/oneandone/server_ip.json | 8 + .../compute/fixtures/oneandone/server_ips.json | 10 + .../fixtures/oneandone/shared_storage.json | 24 + .../test/compute/fixtures/oneandone/ttt.json | 73 + libcloud/test/compute/test_oneandone.py | 1281 ++ libcloud/test/secrets.py-dist | 1 + 49 files changed, 23263 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/compute/drivers/oneandone.rst ---------------------------------------------------------------------- diff --git a/docs/compute/drivers/oneandone.rst b/docs/compute/drivers/oneandone.rst new file mode 100644 index 0000000..9145124 --- /dev/null +++ b/docs/compute/drivers/oneandone.rst @@ -0,0 +1,295 @@ +1&1 Compute Driver Documentation +================================ + +`1&1` is one of the world's largest hosting providers. We offer a range of services, including hosting solutions, domains, and websites. + +The data centers/availability zones are located in: + +- United States of America (US) +- Germany (DE) +- United Kingdom or Great Britain and Northern Ireland (GB) +- Spain (ES) + +Instantiating a Driver +---------------------- + +To instantiate a driver you will need to pass the API key using the following constructor parameter: + +* ``key`` - Your 1&1 API Key + +You can obtain your API key in the `1&1 Cloud Panel` under Management -> +Users where an API key will be generated. + +With a newly-generated API token you can instantiate a driver using: + +.. literalinclude:: /examples/compute/oneandone/instantiate_driver.py + :language: python + + +1&1 Implementation of Libcloud +------------------------------ + +The 1&1 driver implements the following ``NodeDriver`` functions: + +* ``list_sizes`` - Returns a list of ``NodeSize`` +* ``list_locations`` - Returns a list of ``NodeLocation`` +* ``list_images`` - Returns a list of ``NodeImage`` +* ``get_image`` - Returns a ``NodeImage`` +* ``create_node`` - Creates a ``Node`` +* ``list_nodes`` - Returns a list of ``Node`` +* ``destroy_node`` - Destroys an existing ``Node`` +* ``reboot_node`` - Reboots a ``Node`` + +1&1 Extension Functions +----------------------- + +Server Functions +----------------- +* ``ex_rename_server`` - Allows you to change server name and description +* ``ex_get_server_hardware`` - Returns server's hardware specification +* ``ex_modify_server_hardware`` - Updates server hardware +* ``ex_modify_server_hdd`` - Updates a single server HDD +* ``ex_add_hdd`` - Adds a new HDD to server +* ``ex_remove_hdd`` - Removes a HDD from server +* ``ex_list_datacenters`` - Returns a list of available 1&1 data centers +* ``ex_get_server`` - Gets a server +* ``ex_shutdown_server`` - Shuts down a server +* ``ex_get_server_image`` - Gets server image +* ``ex_reinstall_server_image`` - Installs a new image on the server +* ``ex_list_server_ips`` - Gets all server IP objects +* ``ex_assign_server_ip`` - Assigns a new IP address to the server +* ``ex_remove_server_ip`` - Removes an IP address from the server +* ``ex_get_server_firewall_policies`` - Gets a firewall policy attached to the server's IP address +* ``ex_remove_server_firewall_policy`` - Removes a firewall policy from the server's IP address +* ``ex_add_server_firewall_policy`` - Adds a firewall policy to the server's IP address + +Monitoring Policy Functions +--------------------------- +* ``ex_list_monitoring_policies`` - Lists all monitoring policies +* ``ex_create_monitoring_policy`` - Creates a monitoring policy +* ``ex_delete_monitoring_policy`` - Deletes a monitoring policy +* ``ex_update_monitoring_policy`` - Updates monitoring policy +* ``ex_get_monitoring_policy`` - Fetches a monitoring policy +* ``ex_get_monitoring_policy_ports`` - Fetches monitoring policy ports +* ``ex_get_monitoring_policy_port`` - Fetches monitoring policy port +* ``ex_remove_monitoring_policy_port`` - Removes monitoring policy port +* ``ex_add_monitoring_policy_ports`` - Adds monitoring policy ports +* ``ex_get_monitoring_policy_processes`` - Fetches monitoring policy processes +* ``ex_get_monitoring_policy_process`` - Fetches monitoring policy process +* ``ex_remove_monitoring_policy_process`` - Removes monitoring policy process +* ``ex_add_monitoring_policy_processes`` - Adds monitoring policy processes +* ``ex_list_monitoring_policy_servers`` - List all servers that are being monitored by the policy +* ``ex_add_servers_to_monitoring_policy`` - Adds servers to monitoring policy +* ``ex_remove_server_from_monitoring_policy`` - Removes a server from monitoring policy + +Shared Storage Functions +------------------------ +* ``ex_list_shared_storages`` - Lists shared storages +* ``ex_get_shared_storage`` - Gets a shared storage +* ``ex_create_shared_storage`` - Creates a shared storage +* ``ex_delete_shared_storage`` - Removes a shared storage +* ``ex_attach_server_to_shared_storage`` - Attaches a single server to a shared storage +* ``ex_get_shared_storage_server`` - Gets a shared storage's server +* ``ex_detach_server_from_shared_storage`` - Detaches a server from shared storage + +Public IP Functions +------------------- +* ``ex_list_public_ips`` - Lists all public IP addresses +* ``ex_create_public_ip`` - Creates a public IP +* ``ex_get_public_ip`` - Gets a public IP +* ``ex_delete_public_ip`` - Deletes a public IP +* ``ex_update_public_ip`` - Updates a Public IP + +Private Network Functions +------------------------- +* ``ex_list_private_networks`` - Lists all private networks +* ``ex_create_private_network`` - Creates a private network +* ``ex_delete_private_network`` - Deletes a private network +* ``ex_update_private_network`` - Updates a private network +* ``ex_list_private_network_servers`` - Lists all private network servers +* ``ex_add_private_network_server`` - Adds servers to private network +* ``ex_remove_server_from_private_network`` - Removes a server from the private network + +Load Balancer Functions +----------------------- +* ``ex_create_load_balancer`` - Creates a load balancer +* ``ex_update_load_balancer`` - Updates a load balancer +* ``ex_add_servers_to_load_balancer`` - Adds servers to a load balancers +* ``ex_remove_server_from_load_balancer`` - Removes a server from a load balancer +* ``ex_add_load_balancer_rule`` - Adds a rule to a load balancer +* ``ex_remove_load_balancer_rule`` - Removes a rule from a load balancer +* ``ex_list_load_balancers`` - Lists all load balancers +* ``ex_get_load_balancer`` - Gets a load balancer +* ``ex_list_load_balancer_server_ips`` - Lists load balanced server IP addresses +* ``ex_get_load_balancer_server_ip`` - Gets a balanced server IP address +* ``ex_list_load_balancer_rules`` - Lists load balancer rules +* ``ex_get_load_balancer_rule`` - Gets a load balancer rule +* ``ex_delete_load_balancer`` - Deletes a load balancer + +Firewall Policy Functions +------------------------- +* ``ex_create_firewall_policy`` - Creates a firewall policy +* ``ex_list_firewall_policies`` - Lists firewall policies +* ``ex_get_firewall_policy`` - Gets a firewall policy +* ``ex_delete_firewall_policy`` - Deletes a firewall policy + +Create a Node +------------- + +To create a node on 1&1 using Libcloud, follow this example: + +.. literalinclude:: /examples/compute/oneandone/create_node.py + :language: python + +This example will create a 1&1 server using 'S' as a small instance in the 'ES' (spain) data center. + +`create_node` has the following parameters: + +Required parameters: + +* ``name`` - Desired node name. Must be unique. +* ``image`` - Image ID retrieved from `list_images`. +* ``ex_fixed_instance_size_id`` - This is an ID of a flavor. + +Optional parameters: + +* ``auth`` - Password for the server. If none is provided, 1&1 will generate one for you, and return it in the response. +* ``location`` - Desired `NodeLocation` +* ``ex_ip`` - ID of a public IP address which can be created using `ex_create_public_ip`. +* ``ex_monitoring_policy_id`` - Id of a monitoring policy which can be created using `ex_create_monitoring_policy`. +* ``ex_firewall_policy_id`` - Id of a firewall policy which can be create using `ex_create_firewall_policy`. +* ``ex_loadbalancer_id`` - Id of a load balancer which can be create using `ex_create_load_balancer`. +* ``ex_description`` - Description for the server. +* ``ex_power_on`` - A boolean indicating whether a server will be `POWERED_ON` or `POWERED_OFF` when provisioned. + + +Create a Firewall Policy +------------------------ + +To create a firewall policy, follow this example: + +.. literalinclude:: /examples/compute/oneandone/create_firewall_policy.py + :language: python + +This example will create a firewall policy with a TCP rule allowing access on port 80. + +`ex_create_firewall_policy` has the following parameters: + +Required parameters: + +* ``name`` - Desired name for the firewall policy. Must be unique. +* ``rules`` - ``list`` of ``dict``: + * ``protocol`` - One of the follwing protocols can be set TCP, UDP, TCP/UDP, ICMP, IPSEC. + * ``port_from`` - Port range start. Must be between 1 and 65535. + * ``port_to`` - Port range end. Must be between 1 and 65535. + * ``source`` - Source IP address. + + +Optional parameters: + +* ``description`` - Description of the firewall policy. + + +Create a Monitoring Policy +-------------------------- + +To create a monitoring policy, follow this example: + +.. literalinclude:: /examples/compute/oneandone/create_monitoring_policy.py + :language: python + +`ex_create_monitoring_policy` has the following parameters: + +Required parameters: + +* ``name`` - Desired name for the monitoring policy. Must be unique. +* ``thresholds`` - ``dict`` of thresholds to be monitored. See the example +* ``ports`` - ``list`` of ``dict`` defining which ports are to be monitored. See the example. +* ``processes`` - ``list`` of ``dict`` defining which processes are to be monitored. See the example. + +Optional parameters: + +* ``description`` - Description of the monitoring policy. +* ``email`` - Email address where notifications will be sent. +* ``agent`` - Indicating whether an agent application should be installed on the host. + +Create a Shared Storage +----------------------- + +To create a shared storage, follow this example: + +.. literalinclude:: /examples/compute/oneandone/create_shared_storage.py + :language: python + +Required parameters: + +* ``name`` - ``str`` Desired name for the shared storage. Must be unique. +* ``size`` - ``int`` Size of the shared storage. +* ``datacenter_id`` - ``str`` 1&1 data center. + +Optional parameters: + +* ``description`` - Description of the shared storage. + +Create a Load Balancer +---------------------- + + +To create a load balancer, follow this example: + + .. literalinclude:: /examples/compute/oneandone/create_load_balancer.py + :language: python + +Required parameters: + +* ``name`` - ``str`` Desired name for the shared storage. Must be unique. +* ``method`` - ``str`` +* ``rules`` - ``list`` of ``dict`` + +Optional parameters: + +* ``persistence`` +* ``persistence_time`` +* ``health_check_test`` +* ``health_check_interval`` +* ``health_check_path`` +* ``health_check_parser`` +* ``datacenter_id`` +* ``description`` + + +Create a Public IP +------------------ + +To create a public IP address, follow this example: + + .. literalinclude:: /examples/compute/oneandone/create_public_ip.py + :language: python + +Required parameters: + +* ``type`` - ``str`` IPV4 or IPV6 + +Optional parameters: + +* ``reverse_dns`` - ``str`` +* ``datacenter_id`` - ``str`` 1&1 Datacenter + + +Create a Private Network +------------------------ + +To create a private network, follow this example: + + .. literalinclude:: /examples/compute/oneandone/create_private_network.py + :language: python + +Required parameters: + +* ``name`` - ``str`` name of the public network. + +Optional parameters: + +* ``datacenter_id`` - ``str`` +* ``network_address`` +* ``subnet_mask`` http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/examples/compute/oneandone/create_firewall_policy.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/oneandone/create_firewall_policy.py b/docs/examples/compute/oneandone/create_firewall_policy.py new file mode 100644 index 0000000..74db619 --- /dev/null +++ b/docs/examples/compute/oneandone/create_firewall_policy.py @@ -0,0 +1,33 @@ +import os + +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +cls = get_driver(Provider.ONEANDONE) +drv = cls(key=os.environ.get('ONEANDONE_TOKEN')) + +my_rules = [ + { + "protocol": "TCP", + "port_from": 80, + "port_to": 80, + "source": "0.0.0.0" + }, + { + "protocol": "TCP", + "port_from": 443, + "port_to": 443, + "source": "0.0.0.0" + } +] + +print(type(my_rules)) + +try: + fw_policy = drv.ex_create_firewall_policy( + name='Firewall Policy', + rules=my_rules, + description='FW Policy Description') + print(fw_policy) +except Exception as e: + print(e) http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/examples/compute/oneandone/create_load_balancer.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/oneandone/create_load_balancer.py b/docs/examples/compute/oneandone/create_load_balancer.py new file mode 100644 index 0000000..5e08ed9 --- /dev/null +++ b/docs/examples/compute/oneandone/create_load_balancer.py @@ -0,0 +1,36 @@ +import os + +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +cls = get_driver(Provider.ONEANDONE) +drv = cls(key=os.environ.get('ONEANDONE_TOKEN')) + +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" + } +] + +try: + shared_storage = drv.ex_create_load_balancer( + name="Test Load Balancer", + method='ROUND_ROBIN', + rules=rules, + persistence=False, + persistence_time=1200, + health_check_test='TCP', + health_check_interval=40) + + print(shared_storage) +except Exception as e: + print(e) http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/examples/compute/oneandone/create_monitoring_policy.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/oneandone/create_monitoring_policy.py b/docs/examples/compute/oneandone/create_monitoring_policy.py new file mode 100644 index 0000000..d84b80d --- /dev/null +++ b/docs/examples/compute/oneandone/create_monitoring_policy.py @@ -0,0 +1,90 @@ +import os + +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +cls = get_driver(Provider.ONEANDONE) +drv = cls(key=os.environ.get('ONEANDONE_TOKEN')) + +ports = [ + { + "protocol": "TCP", + "port": 443, + "alert_if": "NOT_RESPONDING", + "email_notification": True + } +] + +processes = [ + { + "process": "httpdeamon", + "alert_if": "NOT_RUNNING", + "email_notification": False + } +] +thresholds = { + "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": True + } + } +} + +try: + monitoring_policy = drv.ex_create_monitoring_policy( + name='Monitoring Policy', + ports=ports, + thresholds=thresholds, + processes=processes, + description='Monitoring Policy Description', + email="test@test.com", + agent=True + ) + print(monitoring_policy) +except Exception as e: + print(e) http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/examples/compute/oneandone/create_node.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/oneandone/create_node.py b/docs/examples/compute/oneandone/create_node.py new file mode 100644 index 0000000..444de7d --- /dev/null +++ b/docs/examples/compute/oneandone/create_node.py @@ -0,0 +1,36 @@ +import os + +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +cls = get_driver(Provider.ONEANDONE) +drv = cls(key=os.environ.get('ONEANDONE_TOKEN')) + +# First we need to get all avaliable sizes +sizes = drv.list_sizes() + +# Then we select one we want to use to create a node. We pick 'S' as small. +desired_size = [size for size in sizes if size.name == 'S'] + +# Let's get all available images +images = drv.list_images('IMAGE') + +# Now we select an image we want to install on to the node. +# We pick Ubuntu 14.04 +desired_image = \ + [img for img in images if 'ubuntu1404-64min' in img.name.lower()] + +# This step is optional. +# Then we get the list of available datacenters (locations) +locations = drv.list_locations() + +# And we pick one in this case Spain (ES) +desired_location = [loc for loc in locations if loc.name == 'ES'] + +# Now let's create that node: +node = drv.create_node(name="Libcloud Test Node2", + image=desired_image[0], + ex_fixed_instance_size_id=desired_size[0].id, + location=desired_location[0]) + +print(node) http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/examples/compute/oneandone/create_private_network.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/oneandone/create_private_network.py b/docs/examples/compute/oneandone/create_private_network.py new file mode 100644 index 0000000..c6adb70 --- /dev/null +++ b/docs/examples/compute/oneandone/create_private_network.py @@ -0,0 +1,14 @@ +import os + +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +cls = get_driver(Provider.ONEANDONE) +drv = cls(key=os.environ.get('ONEANDONE_TOKEN')) + +try: + public_network = drv.ex_create_private_network( + name='TestPN') + print(public_network) +except Exception as e: + print(e) http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/examples/compute/oneandone/create_public_ip.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/oneandone/create_public_ip.py b/docs/examples/compute/oneandone/create_public_ip.py new file mode 100644 index 0000000..ec76e05 --- /dev/null +++ b/docs/examples/compute/oneandone/create_public_ip.py @@ -0,0 +1,14 @@ +import os + +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +cls = get_driver(Provider.ONEANDONE) +drv = cls(key=os.environ.get('ONEANDONE_TOKEN')) + +try: + public_ip = drv.ex_create_public_ip( + type='IPV4') + print(public_ip) +except Exception as e: + print(e) http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/examples/compute/oneandone/create_shared_storage.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/oneandone/create_shared_storage.py b/docs/examples/compute/oneandone/create_shared_storage.py new file mode 100644 index 0000000..dbec592 --- /dev/null +++ b/docs/examples/compute/oneandone/create_shared_storage.py @@ -0,0 +1,21 @@ +import os + +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +cls = get_driver(Provider.ONEANDONE) +drv = cls(key=os.environ.get('ONEANDONE_TOKEN')) + +locations = drv.list_locations() + +desired_location = [loc for loc in locations if loc.name == 'ES'] + +try: + shared_storage = drv.ex_create_shared_storage( + name="Test Shared Storage", size=50, + datacenter_id=desired_location[0].id, + description=None + ) + print(shared_storage) +except Exception as e: + print(e) http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/docs/examples/compute/oneandone/instantiate_driver.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/oneandone/instantiate_driver.py b/docs/examples/compute/oneandone/instantiate_driver.py new file mode 100644 index 0000000..9111925 --- /dev/null +++ b/docs/examples/compute/oneandone/instantiate_driver.py @@ -0,0 +1,9 @@ +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +# First we need to instantiate desired libcoud driver. +cls = get_driver(Provider.ONEANDONE) + +token = 'your_token' +# Then pass in your security token +drv = cls(key=token) http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/libcloud/common/base.py ---------------------------------------------------------------------- diff --git a/libcloud/common/base.py b/libcloud/common/base.py index c5759f3..f6826d2 100644 --- a/libcloud/common/base.py +++ b/libcloud/common/base.py @@ -514,6 +514,7 @@ class Connection(object): def request(self, action, params=None, data=None, headers=None, method='GET', raw=False, stream=False): + """ Request a given `action`. http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/libcloud/compute/drivers/oneandone.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/oneandone.py b/libcloud/compute/drivers/oneandone.py new file mode 100644 index 0000000..a33fe3d --- /dev/null +++ b/libcloud/compute/drivers/oneandone.py @@ -0,0 +1,2263 @@ +# 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' +] + + +class OneAndOneResponse(JsonResponse): + """ + OneAndOne response parsing. + """ + valid_response_codes = [httplib.OK, httplib.CREATED, httplib.ACCEPTED] + + 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 + + def success(self): + return self.status in self.valid_response_codes + + +class OneAndOneConnection(ConnectionKey): + """ + Connection class for the 1&1 driver + """ + + host = API_HOST + api_prefix = API_VERSION + responseCls = OneAndOneResponse + + def encode_data(self, data): + return json.dumps(data) + + 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 + + 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) + + +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 + """ + + 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 + + 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 + + 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) + + 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 + """ + + 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: ``NodeImage`` + + :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) + + 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) + + 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) + + 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 + """ + + 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) + + 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 + """ + + 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 + """ + + 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) + + 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) + + 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 + """ + + 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 + + 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) + + 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 + """ + + 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 + + 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 + """ + + 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 + + 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 + + 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) + + 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) + + 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 + + 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) + + 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 + """ + + 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 + + def ex_list_firewall_policies(self): + """ + List firewall policies + :return: 'dict' + """ + + response = self.connection.request( + action='firewall_policies', + method='GET' + ) + + return response.object + + 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 + + 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 + """ + + def ex_list_shared_storages(self): + """ + List of shared storages + :return: 'dict' + """ + response = self.connection.request( + action='shared_storages', + method='GET' + ) + + return response.object + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + """ + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + """ + + 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 + + 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 + + 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 + + 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 + + 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 + """ + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + """ + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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): + """ + Convert into NodeSize + """ + 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 http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/libcloud/compute/providers.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/providers.py b/libcloud/compute/providers.py index 2d5127e..df983e9 100644 --- a/libcloud/compute/providers.py +++ b/libcloud/compute/providers.py @@ -143,6 +143,8 @@ DRIVERS = { ('libcloud.compute.drivers.ecs', 'ECSDriver'), Provider.CLOUDSCALE: ('libcloud.compute.drivers.cloudscale', 'CloudscaleNodeDriver'), + Provider.ONEANDONE: + ('libcloud.compute.drivers.oneandone', 'OneAndOneNodeDriver'), } http://git-wip-us.apache.org/repos/asf/libcloud/blob/ff028ae2/libcloud/compute/types.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py index 646725d..d57cc91 100644 --- a/libcloud/compute/types.py +++ b/libcloud/compute/types.py @@ -144,6 +144,7 @@ class Provider(Type): NIMBUS = 'nimbus' NINEFOLD = 'ninefold' NTTA = 'ntta' + ONEANDONE = 'oneandone' OPENNEBULA = 'opennebula' OPENSTACK = 'openstack' OPSOURCE = 'opsource'