1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
"""Order and Cancel LBaaS instances."""
import click
import SoftLayer
from SoftLayer.CLI import environment
from SoftLayer.CLI import exceptions
from SoftLayer.CLI import formatting
from SoftLayer.exceptions import SoftLayerAPIError
from SoftLayer import utils
# pylint: disable=unused-argument
def parse_proto(ctx, param, value):
"""Parses the frontend and backend cli options"""
proto = {'protocol': 'HTTP', 'port': 80}
splitout = value.split(':')
if len(splitout) != 2:
raise exceptions.ArgumentError(f"{param}={value} is not properly formatted.")
proto['protocol'] = splitout[0]
proto['port'] = int(splitout[1])
return proto
@click.command(cls=SoftLayer.CLI.command.SLCommand, )
@click.option('--name', '-n', help='Label for this loadbalancer.', required=True)
@click.option('--datacenter', '-d', help='Datacenter shortname (dal13).', required=True)
@click.option('--label', '-l', help='A descriptive label for this loadbalancer.')
@click.option('--frontend', '-f', required=True, default='HTTP:80', show_default=True, callback=parse_proto,
help='PROTOCOL:PORT string for incoming internet connections.')
@click.option('--backend', '-b', required=True, default='HTTP:80', show_default=True, callback=parse_proto,
help='PROTOCOL:PORT string for connecting to backend servers.')
@click.option('--method', '-m', help="Balancing Method.", default='ROUNDROBIN', show_default=True,
type=click.Choice(['ROUNDROBIN', 'LEASTCONNECTION', 'WEIGHTED_RR']))
@click.option('--subnet', '-s', required=True,
help="Private subnet Id to order the LB on. See `slcli lb order-options`")
@click.option('--public', is_flag=True, default=False, show_default=True, help="Use a Public to Public loadbalancer.")
@click.option('--verify', is_flag=True, default=False, show_default=True,
help="Only verify an order, dont actually create one.")
@environment.pass_env
def order(env, **args):
"""Creates a LB. Protocols supported are TCP, HTTP, and HTTPS."""
mgr = SoftLayer.LoadBalancerManager(env.client)
network = SoftLayer.NetworkManager(env.client)
datacenter = network.get_datacenter(datacenter=args.get('datacenter'))
if datacenter:
location = {'id': datacenter[0]['id']}
else:
raise exceptions.CLIHalt(f'Datacenter {datacenter} was not found')
name = args.get('name')
description = args.get('label', None)
backend = args.get('backend')
frontend = args.get('frontend')
protocols = [
{
"backendPort": backend.get('port'),
"backendProtocol": backend.get('protocol'),
"frontendPort": frontend.get('port'),
"frontendProtocol": frontend.get('protocol'),
"loadBalancingMethod": args.get('method'),
"maxConn": 1000
}
]
# remove verify=True to place the order
receipt = mgr.order_lbaas(location, name, description, protocols, args.get('subnet'),
public=args.get('public'), verify=args.get('verify'))
table = parse_receipt(receipt)
env.fout(table)
def parse_receipt(receipt):
"""Takes an order receipt and nicely formats it for cli output"""
table = formatting.KeyValueTable(['Item', 'Cost'], title=f"Order: {receipt.get('orderId', 'Quote')}")
if receipt.get('prices'):
for price in receipt.get('prices'):
table.add_row([price['item']['description'], price['hourlyRecurringFee']])
elif receipt.get('orderDetails'):
for price in receipt['orderDetails']['prices']:
table.add_row([price['item']['description'], price['hourlyRecurringFee']])
return table
@click.command(cls=SoftLayer.CLI.command.SLCommand, )
@click.option('--datacenter', '-d', help="Show only selected datacenter, use shortname (dal13) format.")
@environment.pass_env
def order_options(env, datacenter):
"""Prints options for order a LBaaS"""
print("Prints options for ordering")
mgr = SoftLayer.LoadBalancerManager(env.client)
net_mgr = SoftLayer.NetworkManager(env.client)
package = mgr.lbaas_order_options()
if not datacenter:
data_table = formatting.KeyValueTable(['Datacenters', 'City'])
for region in package['regions']:
data_table.add_row([region['description'].split('-')[0], region['description'].split('-')[1]])
# print(region)
env.fout(data_table)
click.secho("Use `slcli lb order-options --datacenter <DC>` "
"to find pricing information and private subnets for that specific site.")
else:
for region in package['regions']:
dc_name = utils.lookup(region, 'location', 'location', 'name')
# Skip locations if they are not the one requested.
if datacenter and dc_name != datacenter.lower():
continue
l_groups = []
for group in region['location']['location']['groups']:
l_groups.append(group.get('id'))
# Price lookups
prices = []
price_table = formatting.KeyValueTable(['KeyName', 'Cost'], title='Prices')
for item in package['items']:
i_price = {'keyName': item['keyName']}
for price in item.get('prices', []):
if not price.get('locationGroupId'):
i_price['default_price'] = price.get('hourlyRecurringFee')
elif price.get('locationGroupId') in l_groups:
i_price['region_price'] = price.get('hourlyRecurringFee')
prices.append(i_price)
for price in prices:
if price.get('region_price'):
price_table.add_row([price.get('keyName'), price.get('region_price')])
else:
price_table.add_row([price.get('keyName'), price.get('default_price')])
# Vlan/Subnet Lookups
mask = "mask[networkVlan,podName,addressSpace]"
subnets = net_mgr.list_subnets(datacenter=dc_name, network_space='PRIVATE', mask=mask)
subnet_table = formatting.Table(['Id', 'Subnet', 'Vlan'], title='Private subnet')
for subnet in subnets:
# Only show these types, easier to filter here than in an API call.
if subnet.get('subnetType') != 'PRIMARY' and \
subnet.get('subnetType') != 'ADDITIONAL_PRIMARY':
continue
space = f"{subnet.get('networkIdentifier')}/{subnet.get('cidr')}"
vlan = f"{subnet['podName']}.{subnet['networkVlan']['vlanNumber']}"
subnet_table.add_row([subnet.get('id'), space, vlan])
env.fout(price_table)
env.fout(subnet_table)
@click.command(cls=SoftLayer.CLI.command.SLCommand, )
@click.argument('identifier')
@click.option('--force', default=False, is_flag=True, help="Force cancel LBaaS Instance without confirmation")
@environment.pass_env
def cancel(env, identifier, force):
"""Cancels a LBaaS instance"""
mgr = SoftLayer.LoadBalancerManager(env.client)
uuid, _ = mgr.get_lbaas_uuid_id(identifier)
if not force:
if not (env.skip_confirmations or
formatting.confirm("This will cancel the LBaaS Instance and cannot be undone. Continue?")):
raise exceptions.CLIAbort('Aborted')
try:
mgr.cancel_lbaas(uuid)
click.secho(f"LB {identifier} canceled succesfully.", fg='green')
except SoftLayerAPIError as exception:
click.secho(f"ERROR: {exception.faultString}", fg='red')
|