Source code for libcloud.loadbalancer.drivers.cloudstack

# 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.utils.misc import reverse_dict
from libcloud.common.cloudstack import CloudStackDriverMixIn
from libcloud.loadbalancer.base import DEFAULT_ALGORITHM, Driver, Member, Algorithm, LoadBalancer
from libcloud.loadbalancer.types import State, Provider


[docs]class CloudStackLBDriver(CloudStackDriverMixIn, Driver): """Driver for CloudStack load balancers.""" api_name = "cloudstack_lb" name = "CloudStack" website = "http://cloudstack.org/" type = Provider.CLOUDSTACK _VALUE_TO_ALGORITHM_MAP = { "roundrobin": Algorithm.ROUND_ROBIN, "leastconn": Algorithm.LEAST_CONNECTIONS, } _ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP) LB_STATE_MAP = { "Active": State.RUNNING, } def __init__( self, key, secret=None, secure=True, host=None, path=None, port=None, *args, **kwargs, ): """ @inherits: :class:`Driver.__init__` """ host = host if host else self.host path = path if path else self.path if path is not None: self.path = path if host is not None: self.host = host if (self.type == Provider.CLOUDSTACK) and (not host or not path): raise Exception( "When instantiating CloudStack driver directly " + "you also need to provide host and path argument" ) super().__init__(key=key, secret=secret, secure=secure, host=host, port=port)
[docs] def list_protocols(self): """ We don't actually have any protocol awareness beyond TCP. :rtype: ``list`` of ``str`` """ return ["tcp"]
[docs] def list_balancers(self): balancers = self._sync_request(command="listLoadBalancerRules", method="GET") balancers = balancers.get("loadbalancerrule", []) return [self._to_balancer(balancer) for balancer in balancers]
[docs] def get_balancer(self, balancer_id): balancer = self._sync_request( command="listLoadBalancerRules", params={"id": balancer_id}, method="GET" ) balancer = balancer.get("loadbalancerrule", []) if not balancer: raise Exception("no such load balancer: " + str(balancer_id)) return self._to_balancer(balancer[0])
[docs] def create_balancer( self, name, members, protocol="http", port=80, algorithm=DEFAULT_ALGORITHM, location=None, private_port=None, network_id=None, vpc_id=None, ): """ @inherits: :class:`Driver.create_balancer` :param location: Location :type location: :class:`NodeLocation` :param private_port: Private port :type private_port: ``int`` :param network_id: The guest network this rule will be created for. :type network_id: ``str`` """ args = {} ip_args = {} if location is None: locations = self._sync_request(command="listZones", method="GET") location = locations["zone"][0]["id"] else: location = location.id if private_port is None: private_port = port if network_id is not None: args["networkid"] = network_id ip_args["networkid"] = network_id if vpc_id is not None: ip_args["vpcid"] = vpc_id ip_args.update({"zoneid": location, "networkid": network_id, "vpc_id": vpc_id}) result = self._async_request(command="associateIpAddress", params=ip_args, method="GET") public_ip = result["ipaddress"] args.update( { "algorithm": self._ALGORITHM_TO_VALUE_MAP[algorithm], "name": name, "privateport": private_port, "publicport": port, "publicipid": public_ip["id"], } ) result = self._sync_request(command="createLoadBalancerRule", params=args, method="GET") listbalancers = self._sync_request( command="listLoadBalancerRules", params=args, method="GET" ) listbalancers = [ rule for rule in listbalancers["loadbalancerrule"] if rule["id"] == result["id"] ] if len(listbalancers) != 1: return None balancer = self._to_balancer(listbalancers[0]) for member in members: balancer.attach_member(member) return balancer
[docs] def destroy_balancer(self, balancer): self._async_request( command="deleteLoadBalancerRule", params={"id": balancer.id}, method="GET" ) self._async_request( command="disassociateIpAddress", params={"id": balancer.ex_public_ip_id}, method="GET", )
[docs] def balancer_attach_member(self, balancer, member): member.port = balancer.ex_private_port self._async_request( command="assignToLoadBalancerRule", params={"id": balancer.id, "virtualmachineids": member.id}, method="GET", ) return True
[docs] def balancer_detach_member(self, balancer, member): self._async_request( command="removeFromLoadBalancerRule", params={"id": balancer.id, "virtualmachineids": member.id}, method="GET", ) return True
[docs] def balancer_list_members(self, balancer): members = self._sync_request( command="listLoadBalancerRuleInstances", params={"id": balancer.id}, method="GET", ) members = members["loadbalancerruleinstance"] return [self._to_member(m, balancer.ex_private_port, balancer) for m in members]
def _to_balancer(self, obj): balancer = LoadBalancer( id=obj["id"], name=obj["name"], state=self.LB_STATE_MAP.get(obj["state"], State.UNKNOWN), ip=obj["publicip"], port=obj["publicport"], driver=self.connection.driver, ) balancer.ex_private_port = obj["privateport"] balancer.ex_public_ip_id = obj["publicipid"] return balancer def _to_member(self, obj, port, balancer): return Member(id=obj["id"], ip=obj["nic"][0]["ipaddress"], port=port, balancer=balancer)