Mini Shell
# 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.cloudstack import CloudStackDriverMixIn
from libcloud.loadbalancer.base import LoadBalancer, Member, Driver, Algorithm
from libcloud.loadbalancer.base import DEFAULT_ALGORITHM
from libcloud.loadbalancer.types import Provider
from libcloud.loadbalancer.types import State
from libcloud.utils.misc import reverse_dict
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(CloudStackLBDriver, self).__init__(key=key, secret=secret,
secure=secure,
host=host, port=port)
def list_protocols(self):
"""
We don't actually have any protocol awareness beyond TCP.
:rtype: ``list`` of ``str``
"""
return ['tcp']
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]
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])
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
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')
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
def balancer_detach_member(self, balancer, member):
self._async_request(command='removeFromLoadBalancerRule',
params={'id': balancer.id,
'virtualmachineids': member.id},
method='GET')
return True
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
)
Zerion Mini Shell 1.0