Remove client code, now in its own tree
Change-Id: Id476b2f8e04babf46359cf219d350ac36b1b7d98
This commit is contained in:
4
README
4
README
@@ -7,10 +7,6 @@ environment.
|
|||||||
Tools
|
Tools
|
||||||
-----
|
-----
|
||||||
|
|
||||||
* libra_client
|
|
||||||
|
|
||||||
Python utility designed to communicate with Atlas API based LBaaS systems.
|
|
||||||
|
|
||||||
* libra_pool_mgm
|
* libra_pool_mgm
|
||||||
|
|
||||||
Python daemon that manages a pool of Nova instances.
|
Python daemon that manages a pool of Nova instances.
|
||||||
|
@@ -1,237 +0,0 @@
|
|||||||
Libra Client
|
|
||||||
============
|
|
||||||
|
|
||||||
Synopsis
|
|
||||||
--------
|
|
||||||
|
|
||||||
:program:`libra_client` [:ref:`GENERAL OPTIONS <libra_client-options>`] [:ref:`COMMAND <libra_client-commands>`] [*COMMAND_OPTIONS*]
|
|
||||||
|
|
||||||
Description
|
|
||||||
-----------
|
|
||||||
|
|
||||||
:program:`libra_client` is a utility designed to communicate with Atlas API
|
|
||||||
based Load Balancer as a Service systems.
|
|
||||||
|
|
||||||
.. _libra_client-options:
|
|
||||||
|
|
||||||
Global Options
|
|
||||||
--------------
|
|
||||||
|
|
||||||
.. program:: libra_client
|
|
||||||
|
|
||||||
.. option:: --help, -h
|
|
||||||
|
|
||||||
Show help message and exit
|
|
||||||
|
|
||||||
.. option:: --debug
|
|
||||||
|
|
||||||
Turn on HTTP debugging for requests
|
|
||||||
|
|
||||||
.. option:: --insecure
|
|
||||||
|
|
||||||
Don't validate SSL certs
|
|
||||||
|
|
||||||
.. option:: --bypass_url <bypass-url>
|
|
||||||
|
|
||||||
URL to use as an endpoint instead of the one specified by the Service
|
|
||||||
Catalog
|
|
||||||
|
|
||||||
.. option:: --os_auth_url <auth-url>
|
|
||||||
|
|
||||||
The OpenStack authentication URL
|
|
||||||
|
|
||||||
.. option:: --os_username <auth-user-name>
|
|
||||||
|
|
||||||
The user name to use for authentication
|
|
||||||
|
|
||||||
.. option:: --os_password <auth-password>
|
|
||||||
|
|
||||||
The password to use for authentication
|
|
||||||
|
|
||||||
.. option:: --os_tenant_name <auth-tenant-name>
|
|
||||||
|
|
||||||
The tenant to authenticate to
|
|
||||||
|
|
||||||
.. option:: --os_region_name <region-name>
|
|
||||||
|
|
||||||
The region the load balancer is located
|
|
||||||
|
|
||||||
.. _libra_client-commands:
|
|
||||||
|
|
||||||
Client Commands
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. program:: libra_client create
|
|
||||||
|
|
||||||
create
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
Create a load balancer
|
|
||||||
|
|
||||||
.. option:: --name <name>
|
|
||||||
|
|
||||||
The name of the node to be created
|
|
||||||
|
|
||||||
.. option:: --port <port>
|
|
||||||
|
|
||||||
The port the load balancer will listen on
|
|
||||||
|
|
||||||
.. option:: --protocol <protocol>
|
|
||||||
|
|
||||||
The protocol type for the load balancer (HTTP or TCP)
|
|
||||||
|
|
||||||
.. option:: --node <ip:port>
|
|
||||||
|
|
||||||
The IP and port for a load balancer node (can be used multiple times to add multiple nodes)
|
|
||||||
|
|
||||||
.. option:: --vip <vip>
|
|
||||||
|
|
||||||
The virtual IP ID of an existing load balancer to attach to
|
|
||||||
|
|
||||||
.. program:: libra_client modify
|
|
||||||
|
|
||||||
modify
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
Update a load balancer's configuration
|
|
||||||
|
|
||||||
.. option:: --id <id>
|
|
||||||
|
|
||||||
The ID of the load balancer
|
|
||||||
|
|
||||||
.. option:: --name <name>
|
|
||||||
|
|
||||||
A new name for the load balancer
|
|
||||||
|
|
||||||
.. option:: --algorithm <algorithm>
|
|
||||||
|
|
||||||
A new algorithm for the load balancer
|
|
||||||
|
|
||||||
.. program:: libra_client list
|
|
||||||
|
|
||||||
list
|
|
||||||
^^^^
|
|
||||||
|
|
||||||
List all load balancers
|
|
||||||
|
|
||||||
.. option:: --deleted
|
|
||||||
|
|
||||||
Show deleted load balancers
|
|
||||||
|
|
||||||
.. program:: libra_client limits
|
|
||||||
|
|
||||||
limits
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
Show the API limits for the user
|
|
||||||
|
|
||||||
.. program:: libra_client algorithms
|
|
||||||
|
|
||||||
algorithms
|
|
||||||
^^^^^^^^^^
|
|
||||||
|
|
||||||
Gets a list of supported algorithms
|
|
||||||
|
|
||||||
.. program:: libra_client protocols
|
|
||||||
|
|
||||||
protocols
|
|
||||||
^^^^^^^^^
|
|
||||||
|
|
||||||
Gets a list of supported protocols
|
|
||||||
|
|
||||||
.. program:: libra_client status
|
|
||||||
|
|
||||||
status
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
Get the status of a single load balancer
|
|
||||||
|
|
||||||
.. option:: --id <id>
|
|
||||||
|
|
||||||
The ID of the load balancer
|
|
||||||
|
|
||||||
.. program:: libra_client delete
|
|
||||||
|
|
||||||
delete
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
Delete a load balancer
|
|
||||||
|
|
||||||
.. option:: --id <id>
|
|
||||||
|
|
||||||
The ID of the load balancer
|
|
||||||
|
|
||||||
.. program:: libra_client node-list
|
|
||||||
|
|
||||||
node-list
|
|
||||||
^^^^^^^^^
|
|
||||||
|
|
||||||
List the nodes in a load balancer
|
|
||||||
|
|
||||||
.. option:: --id <id>
|
|
||||||
|
|
||||||
The ID of the load balancer
|
|
||||||
|
|
||||||
.. program:: libra_client node-delete
|
|
||||||
|
|
||||||
node-delete
|
|
||||||
^^^^^^^^^^^
|
|
||||||
|
|
||||||
Delete a node from the load balancer
|
|
||||||
|
|
||||||
.. option:: --id <id>
|
|
||||||
|
|
||||||
The ID of the load balancer
|
|
||||||
|
|
||||||
.. option:: --nodeid <nodeid>
|
|
||||||
|
|
||||||
The ID of the node to be removed
|
|
||||||
|
|
||||||
.. program:: libra_client node-add
|
|
||||||
|
|
||||||
node-add
|
|
||||||
^^^^^^^^
|
|
||||||
|
|
||||||
Add a node to a load balancer
|
|
||||||
|
|
||||||
.. option:: --id <id>
|
|
||||||
|
|
||||||
The ID of the load balancer
|
|
||||||
|
|
||||||
.. option:: --node <ip:port>
|
|
||||||
|
|
||||||
The node address in ip:port format (can be used multiple times to add multiple nodes)
|
|
||||||
|
|
||||||
.. program:: libra_client node-modify
|
|
||||||
|
|
||||||
node-modify
|
|
||||||
^^^^^^^^^^^
|
|
||||||
|
|
||||||
Modify a node's state in a load balancer
|
|
||||||
|
|
||||||
.. option:: --id <id>
|
|
||||||
|
|
||||||
The ID of the load balancer
|
|
||||||
|
|
||||||
.. option:: --nodeid <nodeid>
|
|
||||||
|
|
||||||
The ID of the node to be modified
|
|
||||||
|
|
||||||
.. option:: --condition <condition>
|
|
||||||
|
|
||||||
The new state of the node (either ENABLED or DISABLED)
|
|
||||||
|
|
||||||
.. program:: libra_client node-status
|
|
||||||
|
|
||||||
node-status
|
|
||||||
^^^^^^^^^^^
|
|
||||||
|
|
||||||
Get the status of a node in a load balancer
|
|
||||||
|
|
||||||
.. option:: --id <id>
|
|
||||||
|
|
||||||
The ID of the load balancer
|
|
||||||
|
|
||||||
.. option:: --nodeid <nodeid>
|
|
||||||
|
|
||||||
The ID of the node in the load balancer
|
|
@@ -1,7 +0,0 @@
|
|||||||
Libra Command Line Client
|
|
||||||
=========================
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
command
|
|
@@ -5,7 +5,6 @@ Load Balancer as a Service Device Tools
|
|||||||
:maxdepth: 3
|
:maxdepth: 3
|
||||||
|
|
||||||
introduction
|
introduction
|
||||||
client/index
|
|
||||||
worker/index
|
worker/index
|
||||||
pool_mgm/index
|
pool_mgm/index
|
||||||
config
|
config
|
||||||
|
@@ -5,7 +5,6 @@ Libra is a Load Balancer as a Service (LBaaS) system originally designed by
|
|||||||
Hewlett-Packard Cloud Services. It consists of three of the core components
|
Hewlett-Packard Cloud Services. It consists of three of the core components
|
||||||
required to get LBaaS working:
|
required to get LBaaS working:
|
||||||
|
|
||||||
* A command line client
|
|
||||||
* A node pool manager to keep a warm spare pool of load balancers ready
|
* A node pool manager to keep a warm spare pool of load balancers ready
|
||||||
* A node worker to asyncronusly communicate to the API server
|
* A node worker to asyncronusly communicate to the API server
|
||||||
|
|
||||||
|
@@ -1,36 +0,0 @@
|
|||||||
# Copyright 2012 Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# Licensed 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 libraapi import LibraAPI
|
|
||||||
from clientoptions import ClientOptions
|
|
||||||
from novaclient import exceptions
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
options = ClientOptions()
|
|
||||||
args = options.run()
|
|
||||||
|
|
||||||
api = LibraAPI(args.os_username, args.os_password, args.os_tenant_name,
|
|
||||||
args.os_auth_url, args.os_region_name, args.insecure,
|
|
||||||
args.debug, args.bypass_url)
|
|
||||||
|
|
||||||
cmd = args.command.replace('-', '_')
|
|
||||||
method = getattr(api, '{cmd}_lb'.format(cmd=cmd))
|
|
||||||
|
|
||||||
try:
|
|
||||||
method(args)
|
|
||||||
except exceptions.ClientException as exc:
|
|
||||||
print exc
|
|
||||||
|
|
||||||
return 0
|
|
@@ -1,154 +0,0 @@
|
|||||||
# Copyright 2012 Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# Licensed 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 argparse
|
|
||||||
|
|
||||||
|
|
||||||
class ClientOptions(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.options = argparse.ArgumentParser('Libra command line client')
|
|
||||||
|
|
||||||
def _generate(self):
|
|
||||||
self.options.add_argument(
|
|
||||||
'--os_auth_url',
|
|
||||||
metavar='<auth-url>',
|
|
||||||
required=True,
|
|
||||||
help='Authentication URL'
|
|
||||||
)
|
|
||||||
self.options.add_argument(
|
|
||||||
'--os_username',
|
|
||||||
metavar='<auth-user-name>',
|
|
||||||
required=True,
|
|
||||||
help='Authentication username'
|
|
||||||
)
|
|
||||||
self.options.add_argument(
|
|
||||||
'--os_password',
|
|
||||||
metavar='<auth-password>',
|
|
||||||
required=True,
|
|
||||||
help='Authentication password'
|
|
||||||
)
|
|
||||||
self.options.add_argument(
|
|
||||||
'--os_tenant_name',
|
|
||||||
metavar='<auth-tenant-name>',
|
|
||||||
required=True,
|
|
||||||
help='Authentication tenant'
|
|
||||||
)
|
|
||||||
self.options.add_argument(
|
|
||||||
'--os_region_name',
|
|
||||||
metavar='<region-name>',
|
|
||||||
required=True,
|
|
||||||
help='Authentication region'
|
|
||||||
)
|
|
||||||
self.options.add_argument(
|
|
||||||
'--debug',
|
|
||||||
action='store_true',
|
|
||||||
help='Debug network messages'
|
|
||||||
)
|
|
||||||
self.options.add_argument(
|
|
||||||
'--insecure',
|
|
||||||
action='store_true',
|
|
||||||
help='Don\'t verify SSL cert'
|
|
||||||
)
|
|
||||||
self.options.add_argument(
|
|
||||||
'--bypass_url',
|
|
||||||
help='Use this API endpoint instead of the Service Catalog'
|
|
||||||
)
|
|
||||||
subparsers = self.options.add_subparsers(
|
|
||||||
metavar='<subcommand>', dest='command'
|
|
||||||
)
|
|
||||||
subparsers.add_parser(
|
|
||||||
'limits', help='get account API usage limits'
|
|
||||||
)
|
|
||||||
subparsers.add_parser(
|
|
||||||
'algorithms', help='get a list of supported algorithms'
|
|
||||||
)
|
|
||||||
subparsers.add_parser(
|
|
||||||
'protocols', help='get a list of supported protocols and ports'
|
|
||||||
)
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'list', help='list load balancers'
|
|
||||||
)
|
|
||||||
sp.add_argument(
|
|
||||||
'--deleted', help='list deleted load balancers',
|
|
||||||
action='store_true'
|
|
||||||
)
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'delete', help='delete a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--id', help='load balancer ID', required=True)
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'create', help='create a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--name', help='name for the load balancer',
|
|
||||||
required=True)
|
|
||||||
sp.add_argument('--port',
|
|
||||||
help='port for the load balancer, 80 is default')
|
|
||||||
sp.add_argument('--protocol',
|
|
||||||
help='protocol for the load balancer, HTTP is default',
|
|
||||||
choices=['HTTP', 'TCP'])
|
|
||||||
sp.add_argument('--algorithm',
|
|
||||||
help='algorithm for the load balancer,'
|
|
||||||
' ROUND_ROBIN is default',
|
|
||||||
choices=['LEAST_CONNECTIONS', 'ROUND_ROBIN'])
|
|
||||||
sp.add_argument('--node',
|
|
||||||
help='a node for the load balancer in ip:port format',
|
|
||||||
action='append', required=True)
|
|
||||||
sp.add_argument('--vip',
|
|
||||||
help='the virtual IP to attach the load balancer to')
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'modify', help='modify a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--id', help='load balancer ID', required=True)
|
|
||||||
sp.add_argument('--name', help='new name for the load balancer')
|
|
||||||
sp.add_argument('--algorithm',
|
|
||||||
help='new algorithm for the load balancer',
|
|
||||||
choices=['LEAST_CONNECTIONS', 'ROUND_ROBIN'])
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'status', help='get status of a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--id', help='load balancer ID', required=True)
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'node-list', help='list nodes in a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--id', help='load balancer ID', required=True)
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'node-delete', help='delete node from a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--id', help='load balancer ID', required=True)
|
|
||||||
sp.add_argument('--nodeid',
|
|
||||||
help='node ID to remove from load balancer',
|
|
||||||
required=True)
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'node-add', help='add node to a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--id', help='load balancer ID', required=True)
|
|
||||||
sp.add_argument('--node', help='node to add in ip:port form',
|
|
||||||
required=True, action='append')
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'node-modify', help='modify node in a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--id', help='load balancer ID', required=True)
|
|
||||||
sp.add_argument('--nodeid', help='node ID to modify', required=True)
|
|
||||||
sp.add_argument('--condition', help='the new state for the node',
|
|
||||||
choices=['ENABLED', 'DISABLED'], required=True)
|
|
||||||
sp = subparsers.add_parser(
|
|
||||||
'node-status', help='get status of a node in a load balancer'
|
|
||||||
)
|
|
||||||
sp.add_argument('--id', help='load balancer ID', required=True)
|
|
||||||
sp.add_argument('--nodeid', help='node ID to get status from',
|
|
||||||
required=True)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self._generate()
|
|
||||||
return self.options.parse_args()
|
|
@@ -1,217 +0,0 @@
|
|||||||
# Copyright 2012 Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# Licensed 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 prettytable
|
|
||||||
import novaclient
|
|
||||||
|
|
||||||
from novaclient import client
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE(LinuxJedi): Override novaclient's error handler as we send messages in
|
|
||||||
# a slightly different format which causes novaclient's to throw an exception
|
|
||||||
|
|
||||||
def from_response(response, body):
|
|
||||||
"""
|
|
||||||
Return an instance of an ClientException or subclass
|
|
||||||
based on an httplib2 response.
|
|
||||||
|
|
||||||
Usage::
|
|
||||||
|
|
||||||
resp, body = http.request(...)
|
|
||||||
if resp.status != 200:
|
|
||||||
raise exception_from_response(resp, body)
|
|
||||||
"""
|
|
||||||
cls = novaclient.exceptions._code_map.get(
|
|
||||||
response.status, novaclient.exceptions.ClientException
|
|
||||||
)
|
|
||||||
request_id = response.get('x-compute-request-id')
|
|
||||||
if body:
|
|
||||||
message = "n/a"
|
|
||||||
details = "n/a"
|
|
||||||
if hasattr(body, 'keys'):
|
|
||||||
message = body.get('message', None)
|
|
||||||
details = body.get('details', None)
|
|
||||||
return cls(code=response.status, message=message, details=details,
|
|
||||||
request_id=request_id)
|
|
||||||
else:
|
|
||||||
return cls(code=response.status, request_id=request_id)
|
|
||||||
|
|
||||||
novaclient.exceptions.from_response = from_response
|
|
||||||
|
|
||||||
|
|
||||||
class LibraAPI(object):
|
|
||||||
def __init__(self, username, password, tenant, auth_url, region,
|
|
||||||
insecure, debug, bypass_url):
|
|
||||||
self.nova = client.HTTPClient(
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
tenant,
|
|
||||||
auth_url,
|
|
||||||
region_name=region,
|
|
||||||
service_type='compute',
|
|
||||||
http_log_debug=debug,
|
|
||||||
insecure=insecure,
|
|
||||||
bypass_url=bypass_url
|
|
||||||
)
|
|
||||||
|
|
||||||
def limits_lb(self, args):
|
|
||||||
resp, body = self._get('/limits')
|
|
||||||
column_names = ['Verb', 'Value', 'Remaining', 'Unit', 'Next Available']
|
|
||||||
columns = ['verb', 'value', 'remaining', 'unit', 'next-available']
|
|
||||||
self._render_list(column_names, columns,
|
|
||||||
body['limits']['rate']['values']['limit'])
|
|
||||||
column_names = ['Values']
|
|
||||||
columns = ['values']
|
|
||||||
self._render_dict(column_names, columns, body['limits']['absolute'])
|
|
||||||
|
|
||||||
def protocols_lb(self, args):
|
|
||||||
resp, body = self._get('/protocols')
|
|
||||||
column_names = ['Name', 'Port']
|
|
||||||
columns = ['name', 'port']
|
|
||||||
self._render_list(column_names, columns, body['protocols'])
|
|
||||||
|
|
||||||
def algorithms_lb(self, args):
|
|
||||||
resp, body = self._get('/algorithms')
|
|
||||||
column_names = ['Name']
|
|
||||||
columns = ['name']
|
|
||||||
self._render_list(column_names, columns, body['algorithms'])
|
|
||||||
|
|
||||||
def list_lb(self, args):
|
|
||||||
if args.deleted:
|
|
||||||
resp, body = self._get('/loadbalancers?status=DELETED')
|
|
||||||
else:
|
|
||||||
resp, body = self._get('/loadbalancers')
|
|
||||||
column_names = ['Name', 'ID', 'Protocol', 'Port', 'Algorithm',
|
|
||||||
'Status', 'Created', 'Updated']
|
|
||||||
columns = ['name', 'id', 'protocol', 'port', 'algorithm', 'status',
|
|
||||||
'created', 'updated']
|
|
||||||
self._render_list(column_names, columns, body['loadBalancers'])
|
|
||||||
|
|
||||||
def status_lb(self, args):
|
|
||||||
resp, body = self._get('/loadbalancers/{0}'.format(args.id))
|
|
||||||
column_names = ['ID', 'Name', 'Protocol', 'Port', 'Algorithm',
|
|
||||||
'Status', 'Created', 'Updated', 'IPs', 'Nodes',
|
|
||||||
'Persistence Type', 'Connection Throttle']
|
|
||||||
columns = ['id', 'name', 'protocol', 'port', 'algorithm', 'status',
|
|
||||||
'created', 'updated', 'virtualIps', 'nodes',
|
|
||||||
'sessionPersistence', 'connectionThrottle']
|
|
||||||
if 'sessionPersistence' not in body:
|
|
||||||
body['sessionPersistence'] = 'None'
|
|
||||||
if 'connectionThrottle' not in body:
|
|
||||||
body['connectionThrottle'] = 'None'
|
|
||||||
self._render_dict(column_names, columns, body)
|
|
||||||
|
|
||||||
def delete_lb(self, args):
|
|
||||||
self._delete('/loadbalancers/{0}'.format(args.id))
|
|
||||||
|
|
||||||
def create_lb(self, args):
|
|
||||||
data = {}
|
|
||||||
nodes = []
|
|
||||||
data['name'] = args.name
|
|
||||||
if args.port is not None:
|
|
||||||
data['port'] = args.port
|
|
||||||
if args.protocol is not None:
|
|
||||||
data['protocol'] = args.protocol
|
|
||||||
if args.algorithm is not None:
|
|
||||||
data['algorithm'] = args.algorithm
|
|
||||||
for node in args.node:
|
|
||||||
addr = node.split(':')
|
|
||||||
nodes.append({'address': addr[0], 'port': addr[1],
|
|
||||||
'condition': 'ENABLED'})
|
|
||||||
data['nodes'] = nodes
|
|
||||||
if args.vip is not None:
|
|
||||||
data['virtualIps'] = [{'id': args.vip}]
|
|
||||||
|
|
||||||
resp, body = self._post('/loadbalancers', body=data)
|
|
||||||
column_names = ['ID', 'Name', 'Protocol', 'Port', 'Algorithm',
|
|
||||||
'Status', 'Created', 'Updated', 'IPs', 'Nodes']
|
|
||||||
columns = ['id', 'name', 'protocol', 'port', 'algorithm', 'status',
|
|
||||||
'created', 'updated', 'virtualIps', 'nodes']
|
|
||||||
self._render_dict(column_names, columns, body)
|
|
||||||
|
|
||||||
def modify_lb(self, args):
|
|
||||||
data = {}
|
|
||||||
if args.name is not None:
|
|
||||||
data['name'] = args.name
|
|
||||||
if args.algorithm is not None:
|
|
||||||
data['algorithm'] = args.algorithm
|
|
||||||
self._put('/loadbalancers/{0}'.format(args.id), body=data)
|
|
||||||
|
|
||||||
def node_list_lb(self, args):
|
|
||||||
resp, body = self._get('/loadbalancers/{0}/nodes'.format(args.id))
|
|
||||||
column_names = ['ID', 'Address', 'Port', 'Condition', 'Status']
|
|
||||||
columns = ['id', 'address', 'port', 'condition', 'status']
|
|
||||||
self._render_list(column_names, columns, body['nodes'])
|
|
||||||
|
|
||||||
def node_delete_lb(self, args):
|
|
||||||
self._delete('/loadbalancers/{0}/nodes/{1}'
|
|
||||||
.format(args.id, args.nodeid))
|
|
||||||
|
|
||||||
def node_add_lb(self, args):
|
|
||||||
data = {}
|
|
||||||
nodes = []
|
|
||||||
|
|
||||||
for node in args.node:
|
|
||||||
addr = node.split(':')
|
|
||||||
nodes.append({'address': addr[0], 'port': addr[1],
|
|
||||||
'condition': 'ENABLED'})
|
|
||||||
data['nodes'] = nodes
|
|
||||||
resp, body = self._post('/loadbalancers/{0}/nodes'
|
|
||||||
.format(args.id), body=data)
|
|
||||||
column_names = ['ID', 'Address', 'Port', 'Condition', 'Status']
|
|
||||||
columns = ['id', 'address', 'port', 'condition', 'status']
|
|
||||||
self._render_list(column_names, columns, body['nodes'])
|
|
||||||
|
|
||||||
def node_modify_lb(self, args):
|
|
||||||
data = {'condition': args.condition}
|
|
||||||
self._put('/loadbalancers/{0}/nodes/{1}'
|
|
||||||
.format(args.id, args.nodeid), body=data)
|
|
||||||
|
|
||||||
def node_status_lb(self, args):
|
|
||||||
resp, body = self._get('/loadbalancers/{0}/nodes/{1}'
|
|
||||||
.format(args.id, args.nodeid))
|
|
||||||
column_names = ['ID', 'Address', 'Port', 'Condition', 'Status']
|
|
||||||
columns = ['id', 'address', 'port', 'condition', 'status']
|
|
||||||
self._render_dict(column_names, columns, body)
|
|
||||||
|
|
||||||
def _render_list(self, column_names, columns, data):
|
|
||||||
table = prettytable.PrettyTable(column_names)
|
|
||||||
for item in data:
|
|
||||||
row = []
|
|
||||||
for column in columns:
|
|
||||||
rdata = item[column]
|
|
||||||
row.append(rdata)
|
|
||||||
table.add_row(row)
|
|
||||||
print table
|
|
||||||
|
|
||||||
def _render_dict(self, column_names, columns, data):
|
|
||||||
table = prettytable.PrettyTable(column_names)
|
|
||||||
row = []
|
|
||||||
for column in columns:
|
|
||||||
rdata = data[column]
|
|
||||||
row.append(rdata)
|
|
||||||
table.add_row(row)
|
|
||||||
print table
|
|
||||||
|
|
||||||
def _get(self, url, **kwargs):
|
|
||||||
return self.nova.get(url, **kwargs)
|
|
||||||
|
|
||||||
def _post(self, url, **kwargs):
|
|
||||||
return self.nova.post(url, **kwargs)
|
|
||||||
|
|
||||||
def _put(self, url, **kwargs):
|
|
||||||
return self.nova.put(url, **kwargs)
|
|
||||||
|
|
||||||
def _delete(self, url, **kwargs):
|
|
||||||
return self.nova.delete(url, **kwargs)
|
|
1
setup.py
1
setup.py
@@ -61,7 +61,6 @@ setuptools.setup(
|
|||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
'libra_worker = libra.worker.main:main',
|
'libra_worker = libra.worker.main:main',
|
||||||
'libra_pool_mgm = libra.mgm.mgm:main',
|
'libra_pool_mgm = libra.mgm.mgm:main',
|
||||||
'libra_client = libra.client.client:main',
|
|
||||||
'libra_statsd = libra.statsd.main:main',
|
'libra_statsd = libra.statsd.main:main',
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@@ -1,330 +0,0 @@
|
|||||||
import json
|
|
||||||
import mock
|
|
||||||
import httplib2
|
|
||||||
import sys
|
|
||||||
import novaclient
|
|
||||||
import testtools
|
|
||||||
from StringIO import StringIO
|
|
||||||
from libra.client.libraapi import LibraAPI
|
|
||||||
|
|
||||||
class DummyArgs(object):
|
|
||||||
""" Fake argparse response """
|
|
||||||
def __init__(self):
|
|
||||||
self.id = 2000
|
|
||||||
self.deleted = False
|
|
||||||
|
|
||||||
class DummyCreateArgs(object):
|
|
||||||
""" Fake argparse response for Create function """
|
|
||||||
def __init__(self):
|
|
||||||
self.name = 'a-new-loadbalancer'
|
|
||||||
self.node = ['10.1.1.1:80', '10.1.1.2:81']
|
|
||||||
self.port = None
|
|
||||||
self.protocol = None
|
|
||||||
self.algorithm = None
|
|
||||||
self.vip = None
|
|
||||||
|
|
||||||
class DummyModifyArgs(object):
|
|
||||||
""" Fake argparse response for Modify function """
|
|
||||||
def __init__(self):
|
|
||||||
self.id = 2012
|
|
||||||
self.name = 'a-modified-loadbalancer'
|
|
||||||
self.algorithm = 'LEAST_CONNECTIONS'
|
|
||||||
|
|
||||||
class MockLibraAPI(LibraAPI):
|
|
||||||
""" Used to capture data that would be sent to the API server """
|
|
||||||
def __init__(self, username, password, tenant, auth_url, region):
|
|
||||||
self.postdata = None
|
|
||||||
self.putdata = None
|
|
||||||
return super(MockLibraAPI, self).__init__(username, password, tenant, auth_url, region, False, False, None)
|
|
||||||
def _post(self, url, **kwargs):
|
|
||||||
""" Store the post data and execute as normal """
|
|
||||||
self.postdata = kwargs['body']
|
|
||||||
return super(MockLibraAPI, self)._post(url, **kwargs)
|
|
||||||
def _put(self, url, **kwargs):
|
|
||||||
""" Store the put data, no need to execute the httplib """
|
|
||||||
self.putdata = kwargs['body']
|
|
||||||
|
|
||||||
class TestLBaaSClientLibraAPI(testtools.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
""" Fake a login with token """
|
|
||||||
super(TestLBaaSClientLibraAPI, self).setUp()
|
|
||||||
self.api = MockLibraAPI('username', 'password', 'tenant', 'auth_test', 'region')
|
|
||||||
self.api.nova.management_url = "http://example.com"
|
|
||||||
self.api.nova.auth_token = "token"
|
|
||||||
|
|
||||||
def testListLb(self):
|
|
||||||
""" Test the table generated from the LIST function """
|
|
||||||
fake_response = httplib2.Response({"status": '200'})
|
|
||||||
fake_body = json.dumps({
|
|
||||||
"loadBalancers":[
|
|
||||||
{
|
|
||||||
"name":"lb-site1",
|
|
||||||
"id":"71",
|
|
||||||
"protocol":"HTTP",
|
|
||||||
"port":"80",
|
|
||||||
"algorithm":"LEAST_CONNECTIONS",
|
|
||||||
"status":"ACTIVE",
|
|
||||||
"created":"2010-11-30T03:23:42Z",
|
|
||||||
"updated":"2010-11-30T03:23:44Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name":"lb-site2",
|
|
||||||
"id":"166",
|
|
||||||
"protocol":"TCP",
|
|
||||||
"port":"9123",
|
|
||||||
"algorithm":"ROUND_ROBIN",
|
|
||||||
"status":"ACTIVE",
|
|
||||||
"created":"2010-11-30T03:23:42Z",
|
|
||||||
"updated":"2010-11-30T03:23:44Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
mock_request = mock.Mock(return_value=(fake_response, fake_body))
|
|
||||||
|
|
||||||
with mock.patch.object(httplib2.Http, "request", mock_request):
|
|
||||||
with mock.patch('time.time', mock.Mock(return_value=1234)):
|
|
||||||
orig = sys.stdout
|
|
||||||
try:
|
|
||||||
out = StringIO()
|
|
||||||
sys.stdout = out
|
|
||||||
args = DummyArgs()
|
|
||||||
self.api.list_lb(args)
|
|
||||||
output = out.getvalue().strip()
|
|
||||||
self.assertRegexpMatches(output, 'lb-site1')
|
|
||||||
self.assertRegexpMatches(output, '71')
|
|
||||||
self.assertRegexpMatches(output, 'HTTP')
|
|
||||||
self.assertRegexpMatches(output, '80')
|
|
||||||
self.assertRegexpMatches(output, 'LEAST_CONNECTIONS')
|
|
||||||
self.assertRegexpMatches(output, 'ACTIVE')
|
|
||||||
self.assertRegexpMatches(output, '2010-11-30T03:23:42Z')
|
|
||||||
self.assertRegexpMatches(output, '2010-11-30T03:23:44Z')
|
|
||||||
finally:
|
|
||||||
sys.stdout = orig
|
|
||||||
|
|
||||||
def testGetLb(self):
|
|
||||||
""" Test the table generated from the STATUS function """
|
|
||||||
fake_response = httplib2.Response({"status": '200'})
|
|
||||||
fake_body = json.dumps({
|
|
||||||
"id": "2000",
|
|
||||||
"name":"sample-loadbalancer",
|
|
||||||
"protocol":"HTTP",
|
|
||||||
"port": "80",
|
|
||||||
"algorithm":"ROUND_ROBIN",
|
|
||||||
"status":"ACTIVE",
|
|
||||||
"created":"2010-11-30T03:23:42Z",
|
|
||||||
"updated":"2010-11-30T03:23:44Z",
|
|
||||||
"virtualIps":[
|
|
||||||
{
|
|
||||||
"id": "1000",
|
|
||||||
"address":"2001:cdba:0000:0000:0000:0000:3257:9652",
|
|
||||||
"type":"PUBLIC",
|
|
||||||
"ipVersion":"IPV6"
|
|
||||||
}],
|
|
||||||
"nodes": [
|
|
||||||
{
|
|
||||||
"id": "1041",
|
|
||||||
"address":"10.1.1.1",
|
|
||||||
"port": "80",
|
|
||||||
"condition":"ENABLED",
|
|
||||||
"status":"ONLINE"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "1411",
|
|
||||||
"address":"10.1.1.2",
|
|
||||||
"port": "80",
|
|
||||||
"condition":"ENABLED",
|
|
||||||
"status":"ONLINE"
|
|
||||||
}],
|
|
||||||
"sessionPersistence":{
|
|
||||||
"persistenceType":"HTTP_COOKIE"
|
|
||||||
},
|
|
||||||
"connectionThrottle":{
|
|
||||||
"maxRequestRate": "50",
|
|
||||||
"rateInterval": "60"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
mock_request = mock.Mock(return_value=(fake_response, fake_body))
|
|
||||||
with mock.patch.object(httplib2.Http, "request", mock_request):
|
|
||||||
with mock.patch('time.time', mock.Mock(return_value=1234)):
|
|
||||||
orig = sys.stdout
|
|
||||||
try:
|
|
||||||
out = StringIO()
|
|
||||||
sys.stdout = out
|
|
||||||
args = DummyArgs()
|
|
||||||
self.api.status_lb(args)
|
|
||||||
output = out.getvalue().strip()
|
|
||||||
self.assertRegexpMatches(output, 'HTTP_COOKIE')
|
|
||||||
finally:
|
|
||||||
sys.stdout = orig
|
|
||||||
|
|
||||||
def testDeleteFailLb(self):
|
|
||||||
"""
|
|
||||||
Test a failure of a DELETE function. We don't test a succeed yet
|
|
||||||
since that has no response so nothing to assert on
|
|
||||||
"""
|
|
||||||
fake_response = httplib2.Response({"status": '500'})
|
|
||||||
fake_body = ''
|
|
||||||
mock_request = mock.Mock(return_value=(fake_response, fake_body))
|
|
||||||
with mock.patch.object(httplib2.Http, "request", mock_request):
|
|
||||||
with mock.patch('time.time', mock.Mock(return_value=1234)):
|
|
||||||
args = DummyArgs()
|
|
||||||
self.assertRaises(novaclient.exceptions.ClientException,
|
|
||||||
self.api.delete_lb, args)
|
|
||||||
|
|
||||||
def testCreateLb(self):
|
|
||||||
"""
|
|
||||||
Tests the CREATE function, tests that:
|
|
||||||
1. We send the correct POST data
|
|
||||||
2. We create a table from the response correctly
|
|
||||||
"""
|
|
||||||
fake_response = httplib2.Response({"status": '202'})
|
|
||||||
fake_body = json.dumps({
|
|
||||||
'name': 'a-new-loadbalancer',
|
|
||||||
'id': '144',
|
|
||||||
'protocol': 'HTTP',
|
|
||||||
'port': '83',
|
|
||||||
'algorithm': 'ROUND_ROBIN',
|
|
||||||
'status': 'BUILD',
|
|
||||||
'created': '2011-04-13T14:18:07Z',
|
|
||||||
'updated': '2011-04-13T14:18:07Z',
|
|
||||||
'virtualIps': [
|
|
||||||
{
|
|
||||||
'address': '15.0.0.1',
|
|
||||||
'id': '39',
|
|
||||||
'type': 'PUBLIC',
|
|
||||||
'ipVersion': 'IPV4',
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'nodes': [
|
|
||||||
{
|
|
||||||
'address': '10.1.1.1',
|
|
||||||
'id': '653',
|
|
||||||
'port': '80',
|
|
||||||
'status': 'ONLINE',
|
|
||||||
'condition': 'ENABLED'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
# This is what the POST data should look like based on the args passed
|
|
||||||
post_compare = {
|
|
||||||
"name": "a-new-loadbalancer",
|
|
||||||
"nodes": [
|
|
||||||
{
|
|
||||||
"address": "10.1.1.1",
|
|
||||||
"condition": "ENABLED",
|
|
||||||
"port": "80"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"address": "10.1.1.2",
|
|
||||||
"condition": "ENABLED",
|
|
||||||
"port": "81"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
mock_request = mock.Mock(return_value=(fake_response, fake_body))
|
|
||||||
with mock.patch.object(httplib2.Http, "request", mock_request):
|
|
||||||
with mock.patch('time.time', mock.Mock(return_value=1234)):
|
|
||||||
orig = sys.stdout
|
|
||||||
try:
|
|
||||||
out = StringIO()
|
|
||||||
sys.stdout = out
|
|
||||||
args = DummyCreateArgs()
|
|
||||||
self.api.create_lb(args)
|
|
||||||
self.assertEquals(post_compare, self.api.postdata)
|
|
||||||
output = out.getvalue().strip()
|
|
||||||
# At some point we should possibly compare the complete
|
|
||||||
# table rendering somehow instead of basic field data
|
|
||||||
self.assertRegexpMatches(output, 'ROUND_ROBIN')
|
|
||||||
self.assertRegexpMatches(output, 'BUILD')
|
|
||||||
self.assertRegexpMatches(output, '144')
|
|
||||||
finally:
|
|
||||||
sys.stdout = orig
|
|
||||||
|
|
||||||
def testCreateAddLb(self):
|
|
||||||
"""
|
|
||||||
Tests the CREATE function as above but adding a load balancer to a
|
|
||||||
virtual IP
|
|
||||||
"""
|
|
||||||
fake_response = httplib2.Response({"status": '202'})
|
|
||||||
fake_body = json.dumps({
|
|
||||||
'name': 'a-new-loadbalancer',
|
|
||||||
'id': '144',
|
|
||||||
'protocol': 'HTTP',
|
|
||||||
'port': '83',
|
|
||||||
'algorithm': 'ROUND_ROBIN',
|
|
||||||
'status': 'BUILD',
|
|
||||||
'created': '2011-04-13T14:18:07Z',
|
|
||||||
'updated': '2011-04-13T14:18:07Z',
|
|
||||||
'virtualIps': [
|
|
||||||
{
|
|
||||||
'address': '15.0.0.1',
|
|
||||||
'id': '39',
|
|
||||||
'type': 'PUBLIC',
|
|
||||||
'ipVersion': 'IPV4',
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'nodes': [
|
|
||||||
{
|
|
||||||
'address': '10.1.1.1',
|
|
||||||
'id': '653',
|
|
||||||
'port': '80',
|
|
||||||
'status': 'ONLINE',
|
|
||||||
'condition': 'ENABLED'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
# This is what the POST data should look like based on the args passed
|
|
||||||
post_compare = {
|
|
||||||
"name": "a-new-loadbalancer",
|
|
||||||
"port": "83",
|
|
||||||
"protocol": "HTTP",
|
|
||||||
"virtualIps": [
|
|
||||||
{
|
|
||||||
"id": "39"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nodes": [
|
|
||||||
{
|
|
||||||
"address": "10.1.1.1",
|
|
||||||
"condition": "ENABLED",
|
|
||||||
"port": "80"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
mock_request = mock.Mock(return_value=(fake_response, fake_body))
|
|
||||||
with mock.patch.object(httplib2.Http, "request", mock_request):
|
|
||||||
with mock.patch('time.time', mock.Mock(return_value=1234)):
|
|
||||||
orig = sys.stdout
|
|
||||||
try:
|
|
||||||
out = StringIO()
|
|
||||||
sys.stdout = out
|
|
||||||
# Add args to add a LB to a VIP
|
|
||||||
args = DummyCreateArgs()
|
|
||||||
args.port = '83'
|
|
||||||
args.protocol = 'HTTP'
|
|
||||||
args.vip = '39'
|
|
||||||
args.node = ['10.1.1.1:80']
|
|
||||||
self.api.create_lb(args)
|
|
||||||
self.assertEquals(post_compare, self.api.postdata)
|
|
||||||
output = out.getvalue().strip()
|
|
||||||
# At some point we should possibly compare the complete
|
|
||||||
# table rendering somehow instead of basic field data
|
|
||||||
self.assertRegexpMatches(output, 'ROUND_ROBIN')
|
|
||||||
self.assertRegexpMatches(output, 'BUILD')
|
|
||||||
self.assertRegexpMatches(output, '144')
|
|
||||||
finally:
|
|
||||||
sys.stdout = orig
|
|
||||||
|
|
||||||
|
|
||||||
def testModifyLb(self):
|
|
||||||
"""
|
|
||||||
Tests the MODIFY function, no repsonse so we only test the PUT data
|
|
||||||
"""
|
|
||||||
# This is what the PUT data should look like based on the args passed
|
|
||||||
put_compare = {
|
|
||||||
"name": "a-modified-loadbalancer",
|
|
||||||
"algorithm": "LEAST_CONNECTIONS"
|
|
||||||
}
|
|
||||||
args = DummyModifyArgs()
|
|
||||||
self.api.modify_lb(args)
|
|
||||||
self.assertEquals(put_compare, self.api.putdata)
|
|
2
tox.ini
2
tox.ini
@@ -18,4 +18,4 @@ commands = pep8 --repeat --show-source --exclude=.venv,.tox,dist,doc,*openstack/
|
|||||||
|
|
||||||
[testenv:pyflakes]
|
[testenv:pyflakes]
|
||||||
deps = pyflakes
|
deps = pyflakes
|
||||||
commands = pyflakes libra/client libra/common libra/mgm libra/worker
|
commands = pyflakes libra/common libra/mgm libra/worker
|
||||||
|
Reference in New Issue
Block a user