Source code for libcloud.compute.drivers.gogrid

# 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
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.
GoGrid driver
import time
import hashlib
import copy

from libcloud.utils.py3 import b

from libcloud.common.types import InvalidCredsError, LibcloudError
from libcloud.common.gogrid import GoGridConnection, BaseGoGridDriver
from libcloud.compute.providers import Provider
from libcloud.compute.types import NodeState
from libcloud.compute.base import Node, NodeDriver
from libcloud.compute.base import NodeSize, NodeImage, NodeLocation

    "Starting": NodeState.PENDING,
    "On": NodeState.RUNNING,
    "On/Saving": NodeState.RUNNING,
    "Off": NodeState.PENDING,
    "Restarting": NodeState.REBOOTING,
    "Saving": NodeState.PENDING,
    "Restoring": NodeState.PENDING,

    "512MB": {
        "id": "512MB",
        "name": "512MB",
        "ram": 512,
        "disk": 30,
        "bandwidth": None,
    "1GB": {"id": "1GB", "name": "1GB", "ram": 1024, "disk": 60, "bandwidth": None},
    "2GB": {"id": "2GB", "name": "2GB", "ram": 2048, "disk": 120, "bandwidth": None},
    "4GB": {"id": "4GB", "name": "4GB", "ram": 4096, "disk": 240, "bandwidth": None},
    "8GB": {"id": "8GB", "name": "8GB", "ram": 8192, "disk": 480, "bandwidth": None},
    "16GB": {
        "id": "16GB",
        "name": "16GB",
        "ram": 16384,
        "disk": 960,
        "bandwidth": None,
    "24GB": {
        "id": "24GB",
        "name": "24GB",
        "ram": 24576,
        "disk": 960,
        "bandwidth": None,

[docs]class GoGridNode(Node): # Generating uuid based on public ip to get around missing id on # create_node in gogrid api # # Used public ip since it is not mutable and specified at create time, # so uuid of node should not change after add is completed
[docs] def get_uuid(self): return hashlib.sha1( b("%s:%s" % (self.public_ips, self.driver.type)) ).hexdigest()
[docs]class GoGridNodeDriver(BaseGoGridDriver, NodeDriver): """ GoGrid node driver """ connectionCls = GoGridConnection type = Provider.GOGRID api_name = "gogrid" name = "GoGrid" website = "" features = {"create_node": ["generates_password"]} _instance_types = GOGRID_INSTANCE_TYPES def __init__(self, *args, **kwargs): """ @inherits: :class:`NodeDriver.__init__` """ super(GoGridNodeDriver, self).__init__(*args, **kwargs) def _get_state(self, element): try: return STATE[element["state"]["name"]] except Exception: pass return NodeState.UNKNOWN def _get_ip(self, element): return element.get("ip").get("ip") def _get_id(self, element): return element.get("id") def _to_node(self, element, password=None): state = self._get_state(element) ip = self._get_ip(element) id = self._get_id(element) n = GoGridNode( id=id, name=element["name"], state=state, public_ips=[ip], private_ips=[], extra={ "ram": element.get("ram").get("name"), "description": element.get("description", ""), }, driver=self.connection.driver, ) if password: n.extra["password"] = password return n def _to_image(self, element): n = NodeImage( id=element["id"], name=element["friendlyName"], driver=self.connection.driver, ) return n def _to_images(self, object): return [self._to_image(el) for el in object["list"]] def _to_location(self, element): location = NodeLocation( id=element["id"], name=element["name"], country="US", driver=self.connection.driver, ) return location def _to_locations(self, object): return [self._to_location(el) for el in object["list"]]
[docs] def list_images(self, location=None): params = {} if location is not None: params["datacenter"] = images = self._to_images( self.connection.request("/api/grid/image/list", params).object ) return images
[docs] def list_nodes(self): """ @inherits: :class:`NodeDriver.list_nodes` :rtype: ``list`` of :class:`GoGridNode` """ passwords_map = {} res = self._server_list() try: for password in self._password_list()["list"]: try: passwords_map[password["server"]["id"]] = password["password"] except KeyError: pass except InvalidCredsError: # some gogrid API keys don't have permission to access the # password list. pass return [ self._to_node(el, passwords_map.get(el.get("id"))) for el in res["list"] ]
[docs] def reboot_node(self, node): """ @inherits: :class:`NodeDriver.reboot_node` :type node: :class:`GoGridNode` """ id = power = "restart" res = self._server_power(id, power) if not res.success(): raise Exception(res.parse_error()) return True
[docs] def destroy_node(self, node): """ @inherits: :class:`NodeDriver.reboot_node` :type node: :class:`GoGridNode` """ id = res = self._server_delete(id) if not res.success(): raise Exception(res.parse_error()) return True
def _server_list(self): return self.connection.request("/api/grid/server/list").object def _password_list(self): return self.connection.request("/api/support/password/list").object def _server_power(self, id, power): # power in ['start', 'stop', 'restart'] params = {"id": id, "power": power} return self.connection.request("/api/grid/server/power", params, method="POST") def _server_delete(self, id): params = {"id": id} return self.connection.request("/api/grid/server/delete", params, method="POST") def _get_first_ip(self, location=None): ips = self.ex_list_ips(public=True, assigned=False, location=location) try: return ips[0].ip except IndexError: raise LibcloudError("No public unassigned IPs left", GoGridNodeDriver)
[docs] def list_sizes(self, location=None): sizes = [] for key, values in self._instance_types.items(): attributes = copy.deepcopy(values) attributes.update({"price": self._get_size_price(size_id=key)}) sizes.append(NodeSize(driver=self.connection.driver, **attributes)) return sizes
[docs] def list_locations(self): locations = self._to_locations( self.connection.request( "/api/common/lookup/list", params={"lookup": "ip.datacenter"} ).object ) return locations
[docs] def ex_create_node_nowait( self, name, size, image, location=None, ex_description=None, ex_ip=None ): """Don't block until GoGrid allocates id for a node but return right away with id == None. The existence of this method is explained by the fact that GoGrid assigns id to a node only few minutes after creation. :keyword name: String with a name for this new node (required) :type name: ``str`` :keyword size: The size of resources allocated to this node . (required) :type size: :class:`NodeSize` :keyword image: OS Image to boot on node. (required) :type image: :class:`NodeImage` :keyword ex_description: Description of a Node :type ex_description: ``str`` :keyword ex_ip: Public IP address to use for a Node. If not specified, first available IP address will be picked :type ex_ip: ``str`` :rtype: :class:`GoGridNode` """ if not ex_ip: ip = self._get_first_ip(location) params = { "name": name, "image":, "description": ex_description or "", "server.ram":, "ip": ip, } object = self.connection.request( "/api/grid/server/add", params=params, method="POST" ).object node = self._to_node(object["list"][0]) return node
[docs] def create_node( self, name, size, image, location=None, ex_description=None, ex_ip=None ): """Create a new GoGird node @inherits: :class:`NodeDriver.create_node` :keyword ex_description: Description of a Node :type ex_description: ``str`` :keyword ex_ip: Public IP address to use for a Node. If not specified, first available IP address will be picked :type ex_ip: ``str`` :rtype: :class:`GoGridNode` """ node = self.ex_create_node_nowait( name=name, size=size, image=image, ex_description=ex_description, ex_ip=ex_ip, ) timeout = 60 * 20 waittime = 0 interval = 2 * 60 while is None and waittime < timeout: nodes = self.list_nodes() for i in nodes: if i.public_ips[0] == node.public_ips[0] and is not None: return i waittime += interval time.sleep(interval) if id is None: raise Exception( "Wasn't able to wait for id allocation for the node %s" % str(node) ) return node
[docs] def ex_save_image(self, node, name): """Create an image for node. Please refer to GoGrid documentation to get info how prepare a node for image creation: :keyword node: node to use as a base for image :type node: :class:`GoGridNode` :keyword name: name for new image :type name: ``str`` :rtype: :class:`NodeImage` """ params = {"server":, "friendlyName": name} object = self.connection.request( "/api/grid/image/save", params=params, method="POST" ).object return self._to_images(object)[0]
[docs] def ex_edit_node(self, **kwargs): """Change attributes of a node. :keyword node: node to be edited (required) :type node: :class:`GoGridNode` :keyword size: new size of a node (required) :type size: :class:`NodeSize` :keyword ex_description: new description of a node :type ex_description: ``str`` :rtype: :class:`Node` """ node = kwargs["node"] size = kwargs["size"] params = {"id":, "server.ram":} if "ex_description" in kwargs: params["description"] = kwargs["ex_description"] object = self.connection.request("/api/grid/server/edit", params=params).object return self._to_node(object["list"][0])
[docs] def ex_edit_image(self, **kwargs): """Edit metadata of a server image. :keyword image: image to be edited (required) :type image: :class:`NodeImage` :keyword public: should be the image public (required) :type public: ``bool`` :keyword ex_description: description of the image (optional) :type ex_description: ``str`` :keyword name: name of the image :type name: ``str`` :rtype: :class:`NodeImage` """ image = kwargs["image"] public = kwargs["public"] params = {"id":, "isPublic": str(public).lower()} if "ex_description" in kwargs: params["description"] = kwargs["ex_description"] if "name" in kwargs: params["friendlyName"] = kwargs["name"] object = self.connection.request("/api/grid/image/edit", params=params).object return self._to_image(object["list"][0])
[docs] def ex_list_ips(self, **kwargs): """Return list of IP addresses assigned to the account. :keyword public: set to True to list only public IPs or False to list only private IPs. Set to None or not specify at all not to filter by type :type public: ``bool`` :keyword assigned: set to True to list only addresses assigned to servers, False to list unassigned addresses and set to None or don't set at all not no filter by state :type assigned: ``bool`` :keyword location: filter IP addresses by location :type location: :class:`NodeLocation` :rtype: ``list`` of :class:`GoGridIpAddress` """ params = {} if "public" in kwargs and kwargs["public"] is not None: params["ip.type"] = {True: "Public", False: "Private"}[kwargs["public"]] if "assigned" in kwargs and kwargs["assigned"] is not None: params["ip.state"] = {True: "Assigned", False: "Unassigned"}[ kwargs["assigned"] ] if "location" in kwargs and kwargs["location"] is not None: params["datacenter"] = kwargs["location"].id ips = self._to_ips( self.connection.request("/api/grid/ip/list", params=params).object ) return ips