blob: 7f3652dd9f6be7194a1dadb4c28cbec897d88d1c [file] [log] [blame]
# 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.
from libcloud.common.base import JsonResponse, ConnectionKey
from libcloud.common.types import InvalidCredsError
from libcloud.compute.base import Node, NodeState, NodeDriver
from libcloud.compute.types import Provider
class GridspotAPIException(Exception):
def __str__(self):
# pylint: disable=unsubscriptable-object
return self.args[0]
def __repr__(self):
# pylint: disable=unsubscriptable-object
return "<GridspotAPIException '%s'>" % (self.args[0])
class GridspotResponse(JsonResponse):
"""
Response class for Gridspot
"""
def parse_body(self):
body = super().parse_body()
if "exception_name" in body and body["exception_name"]:
raise GridspotAPIException(body["exception_name"])
return body
def parse_error(self):
# Gridspot 404s on invalid api key or instance_id
raise InvalidCredsError("Invalid api key/instance_id")
class GridspotConnection(ConnectionKey):
"""
Connection class to connect to Gridspot's API servers
"""
host = "gridspot.com"
responseCls = GridspotResponse
def add_default_params(self, params):
params["api_key"] = self.key
return params
class GridspotNodeDriver(NodeDriver):
"""
Gridspot (http://www.gridspot.com/) node driver.
"""
type = Provider.GRIDSPOT
name = "Gridspot"
website = "http://www.gridspot.com/"
connectionCls = GridspotConnection
NODE_STATE_MAP = {"Running": NodeState.RUNNING, "Starting": NodeState.PENDING}
def list_nodes(self):
data = self.connection.request("/compute_api/v1/list_instances").object
return [self._to_node(n) for n in data["instances"]]
def destroy_node(self, node):
data = {"instance_id": node.id}
self.connection.request("/compute_api/v1/stop_instance", data).object
return True
def _get_node_state(self, state):
result = self.NODE_STATE_MAP.get(state, NodeState.UNKNOWN)
return result
def _add_int_param(self, params, data, field):
if data[field]:
try:
params[field] = int(data[field])
except Exception:
pass
def _to_node(self, data):
port = None
ip = None
state = self._get_node_state(data["current_state"])
if data["vm_ssh_wan_ip_endpoint"] != "null":
parts = data["vm_ssh_wan_ip_endpoint"].split(":")
ip = parts[0]
port = int(parts[1])
extra_params = {"winning_bid_id": data["winning_bid_id"], "port": port}
# Spec is vague and doesn't indicate if these will always be present
self._add_int_param(extra_params, data, "vm_num_logical_cores")
self._add_int_param(extra_params, data, "vm_num_physical_cores")
self._add_int_param(extra_params, data, "vm_ram")
self._add_int_param(extra_params, data, "start_state_time")
self._add_int_param(extra_params, data, "ended_state_time")
self._add_int_param(extra_params, data, "running_state_time")
return Node(
id=data["instance_id"],
name=data["instance_id"],
state=state,
public_ips=[ip],
private_ips=[],
driver=self.connection.driver,
extra=extra_params,
)