Source code for libcloud.loadbalancer.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
#
#     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 time

from libcloud.utils.py3 import httplib

try:
    import simplejson as json
except ImportError:
    import json

from libcloud.utils.misc import reverse_dict
from libcloud.common.types import LibcloudError
from libcloud.common.gogrid import GoGridConnection, GoGridResponse,\
    BaseGoGridDriver
from libcloud.loadbalancer.base import LoadBalancer, Member, Driver, Algorithm
from libcloud.loadbalancer.base import DEFAULT_ALGORITHM
from libcloud.loadbalancer.types import State, LibcloudLBImmutableError


[docs]class GoGridLBResponse(GoGridResponse):
[docs] def success(self): if self.status == httplib.INTERNAL_SERVER_ERROR: # Hack, but at least this error message is more useful than # "unexpected server error" body = json.loads(self.body) if body['method'] == '/grid/loadbalancer/add' and \ len(body['list']) >= 1 and \ body['list'][0]['message'].find( 'unexpected server error') != -1: raise LibcloudError( value='You mostly likely tried to add a member with an IP' ' address not assigned to your account', driver=self) return super(GoGridLBResponse, self).success()
[docs]class GoGridLBConnection(GoGridConnection): """ Connection class for the GoGrid load-balancer driver. """ responseCls = GoGridLBResponse
[docs]class GoGridLBDriver(BaseGoGridDriver, Driver): connectionCls = GoGridLBConnection api_name = 'gogrid_lb' name = 'GoGrid LB' website = 'http://www.gogrid.com/' LB_STATE_MAP = {'On': State.RUNNING, 'Unknown': State.UNKNOWN} _VALUE_TO_ALGORITHM_MAP = { 'round robin': Algorithm.ROUND_ROBIN, 'least connect': Algorithm.LEAST_CONNECTIONS } _ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP) def __init__(self, *args, **kwargs): """ @inherits: :class:`Driver.__init__` """ super(GoGridLBDriver, self).__init__(*args, **kwargs)
[docs] def list_protocols(self): # GoGrid only supports http return ['http']
[docs] def list_balancers(self): return self._to_balancers( self.connection.request('/api/grid/loadbalancer/list').object)
[docs] def ex_create_balancer_nowait(self, name, members, protocol='http', port=80, algorithm=DEFAULT_ALGORITHM): """ @inherits: :class:`Driver.create_balancer` """ algorithm = self._algorithm_to_value(algorithm) params = {'name': name, 'loadbalancer.type': algorithm, 'virtualip.ip': self._get_first_ip(), 'virtualip.port': port} params.update(self._members_to_params(members)) resp = self.connection.request('/api/grid/loadbalancer/add', method='GET', params=params) return self._to_balancers(resp.object)[0]
[docs] def create_balancer(self, name, members, protocol='http', port=80, algorithm=DEFAULT_ALGORITHM): balancer = self.ex_create_balancer_nowait(name, members, protocol, port, algorithm) timeout = 60 * 20 waittime = 0 interval = 2 * 15 if balancer.id is not None: return balancer else: while waittime < timeout: balancers = self.list_balancers() for i in balancers: if i.name == balancer.name and i.id is not None: return i waittime += interval time.sleep(interval) raise Exception('Failed to get id')
[docs] def destroy_balancer(self, balancer): try: resp = self.connection.request( '/api/grid/loadbalancer/delete', method='POST', params={'id': balancer.id}) except Exception as e: if "Update request for LoadBalancer" in str(e): raise LibcloudLBImmutableError( "Cannot delete immutable object", GoGridLBDriver) else: raise return resp.status == 200
[docs] def get_balancer(self, **kwargs): params = {} try: params['name'] = kwargs['ex_balancer_name'] except KeyError: balancer_id = kwargs['balancer_id'] params['id'] = balancer_id resp = self.connection.request('/api/grid/loadbalancer/get', params=params) return self._to_balancers(resp.object)[0]
[docs] def balancer_attach_member(self, balancer, member): members = self.balancer_list_members(balancer) members.append(member) params = {"id": balancer.id} params.update(self._members_to_params(members)) resp = self._update_balancer(params) return [m for m in self._to_members(resp.object["list"][0]["realiplist"], balancer) if m.ip == member.ip][0]
[docs] def balancer_detach_member(self, balancer, member): members = self.balancer_list_members(balancer) remaining_members = [n for n in members if n.id != member.id] params = {"id": balancer.id} params.update(self._members_to_params(remaining_members)) resp = self._update_balancer(params) return resp.status == 200
[docs] def balancer_list_members(self, balancer): resp = self.connection.request('/api/grid/loadbalancer/get', params={'id': balancer.id}) return self._to_members(resp.object["list"][0]["realiplist"], balancer)
def _update_balancer(self, params): try: return self.connection.request('/api/grid/loadbalancer/edit', method='POST', params=params) except Exception as e: if "Update already pending" in str(e): raise LibcloudLBImmutableError( "Balancer is immutable", GoGridLBDriver) raise LibcloudError(value='Exception: %s' % str(e), driver=self) def _members_to_params(self, members): """ Helper method to convert list of :class:`Member` objects to GET params. """ params = {} i = 0 for member in members: params["realiplist.%s.ip" % i] = member.ip params["realiplist.%s.port" % i] = member.port i += 1 return params def _to_balancers(self, object): return [self._to_balancer(el) for el in object["list"]] def _to_balancer(self, el): lb = LoadBalancer(id=el.get("id"), name=el["name"], state=self.LB_STATE_MAP.get( el["state"]["name"], State.UNKNOWN), ip=el["virtualip"]["ip"]["ip"], port=el["virtualip"]["port"], driver=self.connection.driver) return lb def _to_members(self, object, balancer=None): return [self._to_member(el, balancer) for el in object] def _to_member(self, el, balancer=None): member = Member(id=el["ip"]["id"], ip=el["ip"]["ip"], port=el["port"], balancer=balancer) return member