
Adds new options and updates documentation. Change-Id: I5d240d8633ddd0be448f92550e6f8031a46f8d56
289 lines
11 KiB
Python
289 lines
11 KiB
Python
# 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
|
|
import socket
|
|
|
|
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, url, method=None):
|
|
"""
|
|
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_code, novaclient.exceptions.ClientException
|
|
)
|
|
if response.headers:
|
|
request_id = response.headers.get('x-compute-request-id')
|
|
else:
|
|
request_id = None
|
|
if body:
|
|
message = "n/a"
|
|
details = "n/a"
|
|
if hasattr(body, 'keys'):
|
|
message = body.get('faultstring', None)
|
|
if not message:
|
|
message = body.get('message', None)
|
|
details = body.get('details', None)
|
|
return cls(code=response.status_code, message=message, details=details,
|
|
request_id=request_id, url=url, method=method)
|
|
else:
|
|
return cls(code=response.status_code, request_id=request_id, url=url,
|
|
method=method)
|
|
|
|
novaclient.exceptions.from_response = from_response
|
|
|
|
|
|
class LibraAPI(object):
|
|
def __init__(self, args):
|
|
self.nova = client.HTTPClient(
|
|
args.os_username,
|
|
args.os_password,
|
|
args.os_tenant_name,
|
|
args.os_auth_url,
|
|
region_name=args.os_region_name,
|
|
service_type=args.service_type,
|
|
http_log_debug=args.debug,
|
|
insecure=args.insecure,
|
|
bypass_url=args.bypass_url
|
|
)
|
|
|
|
def limits_lb(self, args):
|
|
resp, body = self._get('/limits')
|
|
# Work around the fact that limits is missing from HP's API server
|
|
if 'rate' in body['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', 'Node Count']
|
|
columns = ['name', 'id', 'protocol', 'port', 'algorithm', 'status',
|
|
'created', 'updated', 'nodeCount']
|
|
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', 'Status Description', 'Created', 'Updated',
|
|
'IPs', 'Nodes', 'Persistence Type',
|
|
'Connection Throttle', 'Node Count']
|
|
columns = ['id', 'name', 'protocol', 'port', 'algorithm', 'status',
|
|
'statusDescription', 'created', 'updated', 'virtualIps',
|
|
'nodes', 'sessionPersistence', 'connectionThrottle',
|
|
'nodeCount']
|
|
if 'sessionPersistence' not in body:
|
|
body['sessionPersistence'] = 'None'
|
|
if 'connectionThrottle' not in body:
|
|
body['connectionThrottle'] = 'None'
|
|
if 'statusDescription' in body:
|
|
body['statusDescription'] = body['statusDescription'].rstrip()
|
|
else:
|
|
body['statusDescription'] = 'None'
|
|
self._render_dict(column_names, columns, body)
|
|
|
|
def virtualips_lb(self, args):
|
|
resp, body = self._get('/loadbalancers/{0}/virtualips'.format(args.id))
|
|
column_names = ['ID', 'Address', 'Type', 'IP Version']
|
|
columns = ['id', 'address', 'type', 'ipVersion']
|
|
self._render_list(column_names, columns, body['virtualIps'])
|
|
|
|
def delete_lb(self, args):
|
|
self._delete('/loadbalancers/{0}'.format(args.id))
|
|
|
|
def create_lb(self, args):
|
|
data = {}
|
|
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
|
|
data['nodes'] = self._parse_nodes(args.node)
|
|
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 = {}
|
|
|
|
data['nodes'] = self._parse_nodes(args.node)
|
|
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 logs_lb(self, args):
|
|
data = {}
|
|
|
|
if args.storage:
|
|
data['objectStoreType'] = args.storage
|
|
if args.endpoint:
|
|
data['objectStoreEndpoint'] = args.endpoint
|
|
if args.basepath:
|
|
data['objectStoreBasePath'] = args.basepath
|
|
if args.token:
|
|
data['authToken'] = args.token
|
|
|
|
resp, body = self._post('/loadbalancers/{0}/logs'.format(args.id),
|
|
body=data)
|
|
|
|
def monitor_delete_lb(self, args):
|
|
resp, body = self._delete('/loadbalancers/{0}/healthmonitor'
|
|
.format(args.id))
|
|
|
|
def monitor_list_lb(self, args):
|
|
resp, body = self._get('/loadbalancers/{0}/healthmonitor'
|
|
.format(args.id))
|
|
column_names = ['Type', 'Delay', 'Timeout', 'Attempts', 'Path']
|
|
columns = ['type', 'delay', 'timeout', 'attemptsBeforeDeactivation',
|
|
'path']
|
|
self._render_dict(column_names, columns, body)
|
|
|
|
def monitor_modify_lb(self, args):
|
|
data = {}
|
|
data['type'] = args.type
|
|
data['delay'] = args.delay
|
|
data['timeout'] = args.timeout
|
|
data['attemptsBeforeDeactivation'] = args.attempts
|
|
if args.type.upper() != "CONNECT":
|
|
data['path'] = args.path
|
|
resp, body = self._put('/loadbalancers/{0}/healthmonitor'
|
|
.format(args.id), body=data)
|
|
|
|
def _render_list(self, column_names, columns, data):
|
|
table = prettytable.PrettyTable(column_names)
|
|
for item in data:
|
|
row = []
|
|
for column in columns:
|
|
if column in item:
|
|
rdata = item[column]
|
|
else:
|
|
rdata = ''
|
|
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:
|
|
if column in data:
|
|
rdata = data[column]
|
|
else:
|
|
rdata = ''
|
|
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)
|
|
|
|
def _parse_nodes(self, nodes):
|
|
out_nodes = []
|
|
try:
|
|
for node in nodes:
|
|
addr = node.split(':')
|
|
# Test IP valid
|
|
# TODO: change to pton when we want to support IPv6
|
|
socket.inet_aton(addr[0])
|
|
# Test port valid
|
|
if int(addr[1]) < 0 or int(addr[1]) > 65535:
|
|
raise
|
|
out_nodes.append({'address': addr[0], 'port': addr[1]})
|
|
except:
|
|
raise Exception("Invalid IP:port specified for --node")
|
|
return out_nodes
|