File: order.py

package info (click to toggle)
python-softlayer 6.2.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 7,508 kB
  • sloc: python: 57,195; makefile: 133; xml: 97; sh: 59
file content (173 lines) | stat: -rw-r--r-- 7,648 bytes parent folder | download
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')