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