blob: 0710bda3f9f7cf9c542517659ed0987b58d0ae7b [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.
import hashlib
import time
from libcloud.utils.py3 import b
from libcloud.common.types import InvalidCredsError, LibcloudError
from libcloud.common.types import MalformedResponseError
from libcloud.common.base import ConnectionUserAndKey, JsonResponse
from libcloud.compute.base import NodeLocation
HOST = 'api.gogrid.com'
PORTS_BY_SECURITY = {True: 443, False: 80}
API_VERSION = '1.8'
__all__ = [
"GoGridResponse",
"GoGridConnection",
"GoGridIpAddress",
"BaseGoGridDriver",
]
class GoGridResponse(JsonResponse):
def __init__(self, *args, **kwargs):
self.driver = BaseGoGridDriver
super(GoGridResponse, self).__init__(*args, **kwargs)
def success(self):
if self.status == 403:
raise InvalidCredsError('Invalid credentials', self.driver)
if self.status == 401:
raise InvalidCredsError('API Key has insufficient rights',
self.driver)
if not self.body:
return None
try:
return self.parse_body()['status'] == 'success'
except ValueError:
raise MalformedResponseError('Malformed reply',
body=self.body,
driver=self.driver)
def parse_error(self):
try:
return self.parse_body()["list"][0]["message"]
except (ValueError, KeyError):
return None
class GoGridConnection(ConnectionUserAndKey):
"""
Connection class for the GoGrid driver
"""
host = HOST
responseCls = GoGridResponse
def add_default_params(self, params):
params["api_key"] = self.user_id
params["v"] = API_VERSION
params["format"] = 'json'
params["sig"] = self.get_signature(self.user_id, self.key)
return params
def get_signature(self, key, secret):
""" create sig from md5 of key + secret + time """
m = hashlib.md5(b(key + secret + str(int(time.time()))))
return m.hexdigest()
def request(self, action, params=None, data='', headers=None, method='GET',
raw=False):
return super(GoGridConnection, self).request(action, params, data,
headers, method, raw)
class GoGridIpAddress(object):
"""
IP Address
"""
def __init__(self, id, ip, public, state, subnet):
self.id = id
self.ip = ip
self.public = public
self.state = state
self.subnet = subnet
class BaseGoGridDriver(object):
"""GoGrid has common object model for services they
provide, like locations and IP, so keep handling of
these things in a single place."""
name = "GoGrid"
def _get_ip(self, element):
return element.get('ip').get('ip')
def _to_ip(self, element):
ip = GoGridIpAddress(id=element['id'],
ip=element['ip'],
public=element['public'],
subnet=element['subnet'],
state=element["state"]["name"])
ip.location = self._to_location(element['datacenter'])
return ip
def _to_ips(self, object):
return [self._to_ip(el)
for el in object['list']]
def _to_location(self, element):
# pylint: disable=no-member
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']]
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
# pylint: disable=no-member
response = self.connection.request('/api/grid/ip/list', params=params)
ips = self._to_ips(response.object)
return ips
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:
# pylint: disable=no-member
raise LibcloudError('No public unassigned IPs left',
self.driver)