Skip to content

Commit 189244b

Browse files
Merge pull request #1177 from softlayer/autoscale
Autoscale
2 parents 95e7236 + daeaff4 commit 189244b

File tree

17 files changed

+1280
-1
lines changed

17 files changed

+1280
-1
lines changed

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ For the CLI, just use the -vvv option. If you are using the REST endpoint, this
9494
9595
If you are using the library directly in python, you can do something like this.
9696

97-
.. code-bock:: python
97+
.. code-block:: python
9898
9999
import SoftLayer
100100
import logging

SoftLayer/CLI/autoscale/__init__.py

Whitespace-only changes.

SoftLayer/CLI/autoscale/detail.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""Get details of an Autoscale groups."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
import SoftLayer
7+
from SoftLayer.CLI import environment
8+
from SoftLayer.CLI import formatting
9+
from SoftLayer.managers.autoscale import AutoScaleManager
10+
from SoftLayer import utils
11+
12+
13+
@click.command()
14+
@click.argument('identifier')
15+
@environment.pass_env
16+
def cli(env, identifier):
17+
"""Get details of an Autoscale groups."""
18+
19+
autoscale = AutoScaleManager(env.client)
20+
group = autoscale.details(identifier)
21+
22+
# Group Config Table
23+
table = formatting.KeyValueTable(["Group", "Value"])
24+
table.align['Group'] = 'l'
25+
table.align['Value'] = 'l'
26+
27+
table.add_row(['Id', group.get('id')])
28+
# Ideally we would use regionalGroup->preferredDatacenter, but that generates an error.
29+
table.add_row(['Datacenter', group['regionalGroup']['locations'][0]['longName']])
30+
table.add_row(['Termination', utils.lookup(group, 'terminationPolicy', 'name')])
31+
table.add_row(['Minimum Members', group.get('minimumMemberCount')])
32+
table.add_row(['Maximum Members', group.get('maximumMemberCount')])
33+
table.add_row(['Current Members', group.get('virtualGuestMemberCount')])
34+
table.add_row(['Cooldown', "{} seconds".format(group.get('cooldown'))])
35+
table.add_row(['Last Action', utils.clean_time(group.get('lastActionDate'))])
36+
37+
for network in group.get('networkVlans', []):
38+
network_type = utils.lookup(network, 'networkVlan', 'networkSpace')
39+
router = utils.lookup(network, 'networkVlan', 'primaryRouter', 'hostname')
40+
vlan_number = utils.lookup(network, 'networkVlan', 'vlanNumber')
41+
vlan_name = "{}.{}".format(router, vlan_number)
42+
table.add_row([network_type, vlan_name])
43+
44+
env.fout(table)
45+
46+
# Template Config Table
47+
config_table = formatting.KeyValueTable(["Template", "Value"])
48+
config_table.align['Template'] = 'l'
49+
config_table.align['Value'] = 'l'
50+
51+
template = group.get('virtualGuestMemberTemplate')
52+
53+
config_table.add_row(['Hostname', template.get('hostname')])
54+
config_table.add_row(['Domain', template.get('domain')])
55+
config_table.add_row(['Core', template.get('startCpus')])
56+
config_table.add_row(['Ram', template.get('maxMemory')])
57+
network = template.get('networkComponents')
58+
config_table.add_row(['Network', network[0]['maxSpeed'] if network else 'Default'])
59+
ssh_keys = template.get('sshKeys', [])
60+
ssh_manager = SoftLayer.SshKeyManager(env.client)
61+
for key in ssh_keys:
62+
# Label isn't included when retrieved from the AutoScale group...
63+
ssh_key = ssh_manager.get_key(key.get('id'))
64+
config_table.add_row(['SSH Key {}'.format(ssh_key.get('id')), ssh_key.get('label')])
65+
disks = template.get('blockDevices', [])
66+
disk_type = "Local" if template.get('localDiskFlag') else "SAN"
67+
68+
for disk in disks:
69+
disk_image = disk.get('diskImage')
70+
config_table.add_row(['{} Disk {}'.format(disk_type, disk.get('device')), disk_image.get('capacity')])
71+
config_table.add_row(['OS', template.get('operatingSystemReferenceCode')])
72+
config_table.add_row(['Post Install', template.get('postInstallScriptUri') or 'None'])
73+
74+
env.fout(config_table)
75+
76+
# Policy Config Table
77+
policy_table = formatting.KeyValueTable(["Policy", "Cooldown"])
78+
policies = group.get('policies', [])
79+
for policy in policies:
80+
policy_table.add_row([policy.get('name'), policy.get('cooldown') or group.get('cooldown')])
81+
82+
env.fout(policy_table)
83+
84+
# Active Guests
85+
member_table = formatting.Table(['Id', 'Hostname', 'Created'], title="Active Guests")
86+
guests = group.get('virtualGuestMembers', [])
87+
for guest in guests:
88+
real_guest = guest.get('virtualGuest')
89+
member_table.add_row([
90+
real_guest.get('id'), real_guest.get('hostname'), utils.clean_time(real_guest.get('provisionDate'))
91+
])
92+
env.fout(member_table)

SoftLayer/CLI/autoscale/edit.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""Edits an Autoscale group."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.managers.autoscale import AutoScaleManager
8+
9+
10+
@click.command()
11+
@click.argument('identifier')
12+
@click.option('--name', help="Scale group's name.")
13+
@click.option('--min', 'minimum', type=click.INT, help="Set the minimum number of guests")
14+
@click.option('--max', 'maximum', type=click.INT, help="Set the maximum number of guests")
15+
@click.option('--userdata', help="User defined metadata string")
16+
@click.option('--userfile', '-F', help="Read userdata from a file",
17+
type=click.Path(exists=True, readable=True, resolve_path=True))
18+
@click.option('--cpu', type=click.INT, help="Number of CPUs for new guests (existing not effected")
19+
@click.option('--memory', type=click.INT, help="RAM in MB or GB for new guests (existing not effected")
20+
@environment.pass_env
21+
def cli(env, identifier, name, minimum, maximum, userdata, userfile, cpu, memory):
22+
"""Edits an Autoscale group."""
23+
24+
template = {}
25+
autoscale = AutoScaleManager(env.client)
26+
group = autoscale.details(identifier)
27+
28+
template['name'] = name
29+
template['minimumMemberCount'] = minimum
30+
template['maximumMemberCount'] = maximum
31+
virt_template = {}
32+
if userdata:
33+
virt_template['userData'] = [{"value": userdata}]
34+
elif userfile:
35+
with open(userfile, 'r') as userfile_obj:
36+
virt_template['userData'] = [{"value": userfile_obj.read()}]
37+
virt_template['startCpus'] = cpu
38+
virt_template['maxMemory'] = memory
39+
40+
# Remove any entries that are `None` as the API will complain about them.
41+
template['virtualGuestMemberTemplate'] = clean_dict(virt_template)
42+
clean_template = clean_dict(template)
43+
44+
# If there are any values edited in the template, we need to get the OLD template values and replace them.
45+
if template['virtualGuestMemberTemplate']:
46+
# Update old template with new values
47+
for key, value in clean_template['virtualGuestMemberTemplate'].items():
48+
group['virtualGuestMemberTemplate'][key] = value
49+
clean_template['virtualGuestMemberTemplate'] = group['virtualGuestMemberTemplate']
50+
51+
autoscale.edit(identifier, clean_template)
52+
click.echo("Done")
53+
54+
55+
def clean_dict(dictionary):
56+
"""Removes any `None` entires from the dictionary"""
57+
return {k: v for k, v in dictionary.items() if v}

SoftLayer/CLI/autoscale/list.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""List Autoscale groups."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer.managers.autoscale import AutoScaleManager
9+
from SoftLayer import utils
10+
11+
12+
@click.command()
13+
@environment.pass_env
14+
def cli(env):
15+
"""List AutoScale Groups."""
16+
17+
autoscale = AutoScaleManager(env.client)
18+
groups = autoscale.list()
19+
20+
table = formatting.Table(["Id", "Name", "Status", "Min/Max", "Running"])
21+
table.align['Name'] = 'l'
22+
for group in groups:
23+
status = utils.lookup(group, 'status', 'name')
24+
min_max = "{}/{}".format(group.get('minimumMemberCount'), group.get('maximumMemberCount'))
25+
table.add_row([
26+
group.get('id'), group.get('name'), status, min_max, group.get('virtualGuestMemberCount')
27+
])
28+
29+
env.fout(table)

SoftLayer/CLI/autoscale/logs.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Retreive logs for an autoscale group"""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer.managers.autoscale import AutoScaleManager
9+
from SoftLayer import utils
10+
11+
12+
@click.command()
13+
@click.argument('identifier')
14+
@click.option('--date-min', '-d', 'date_min', type=click.DateTime(formats=["%Y-%m-%d", "%m/%d/%Y"]),
15+
help='Earliest date to retreive logs for.')
16+
@environment.pass_env
17+
def cli(env, identifier, date_min):
18+
"""Retreive logs for an autoscale group"""
19+
20+
autoscale = AutoScaleManager(env.client)
21+
22+
mask = "mask[id,createDate,description]"
23+
object_filter = {}
24+
if date_min:
25+
object_filter['logs'] = {
26+
'createDate': {
27+
'operation': 'greaterThanDate',
28+
'options': [{'name': 'date', 'value': [date_min.strftime("%m/%d/%Y")]}]
29+
}
30+
}
31+
32+
logs = autoscale.get_logs(identifier, mask=mask, object_filter=object_filter)
33+
table = formatting.Table(['Date', 'Entry'], title="Logs")
34+
table.align['Entry'] = 'l'
35+
for log in logs:
36+
table.add_row([utils.clean_time(log.get('createDate')), log.get('description')])
37+
env.fout(table)

SoftLayer/CLI/autoscale/scale.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""Scales an Autoscale group"""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer.managers.autoscale import AutoScaleManager
9+
from SoftLayer import utils
10+
11+
12+
@click.command()
13+
@click.argument('identifier')
14+
@click.option('--up/--down', 'scale_up', is_flag=True, default=True,
15+
help="'--up' adds guests, '--down' removes guests.")
16+
@click.option('--by/--to', 'scale_by', is_flag=True, required=True,
17+
help="'--by' will add/remove the specified number of guests."
18+
" '--to' will add/remove a number of guests to get the group's guest count to the specified number.")
19+
@click.option('--amount', required=True, type=click.INT, help="Number of guests for the scale action.")
20+
@environment.pass_env
21+
def cli(env, identifier, scale_up, scale_by, amount):
22+
"""Scales an Autoscale group. Bypasses a scale group's cooldown period."""
23+
24+
autoscale = AutoScaleManager(env.client)
25+
26+
# Scale By, and go down, need to use negative amount
27+
if not scale_up and scale_by:
28+
amount = amount * -1
29+
30+
result = []
31+
if scale_by:
32+
click.secho("Scaling group {} by {}".format(identifier, amount), fg='green')
33+
result = autoscale.scale(identifier, amount)
34+
else:
35+
click.secho("Scaling group {} to {}".format(identifier, amount), fg='green')
36+
result = autoscale.scale_to(identifier, amount)
37+
38+
try:
39+
# Check if the first guest has a cancellation date, assume we are removing guests if it is.
40+
cancel_date = result[0]['virtualGuest']['billingItem']['cancellationDate'] or False
41+
except (IndexError, KeyError, TypeError):
42+
cancel_date = False
43+
44+
if cancel_date:
45+
member_table = formatting.Table(['Id', 'Hostname', 'Created'], title="Cancelled Guests")
46+
else:
47+
member_table = formatting.Table(['Id', 'Hostname', 'Created'], title="Added Guests")
48+
49+
for guest in result:
50+
real_guest = guest.get('virtualGuest')
51+
member_table.add_row([
52+
guest.get('id'), real_guest.get('hostname'), utils.clean_time(real_guest.get('createDate'))
53+
])
54+
55+
env.fout(member_table)

SoftLayer/CLI/autoscale/tag.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Tags all guests in an autoscale group."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.managers.autoscale import AutoScaleManager
8+
from SoftLayer.managers.vs import VSManager
9+
10+
11+
@click.command()
12+
@click.argument('identifier')
13+
@click.option('--tags', '-g', help="Tags to set for each guest in this group. Existing tags are overwritten. "
14+
"An empty string will remove all tags")
15+
@environment.pass_env
16+
def cli(env, identifier, tags):
17+
"""Tags all guests in an autoscale group.
18+
19+
--tags "Use, quotes, if you, want whitespace"
20+
21+
--tags Otherwise,Just,commas
22+
"""
23+
24+
autoscale = AutoScaleManager(env.client)
25+
vsmanager = VSManager(env.client)
26+
mask = "mask[id,virtualGuestId,virtualGuest[tagReferences,id,hostname]]"
27+
guests = autoscale.get_virtual_guests(identifier, mask=mask)
28+
click.echo("New Tags: {}".format(tags))
29+
for guest in guests:
30+
real_guest = guest.get('virtualGuest')
31+
click.echo("Setting tags for {}".format(real_guest.get('hostname')))
32+
vsmanager.set_tags(tags, real_guest.get('id'),)
33+
click.echo("Done")

SoftLayer/CLI/routes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,14 @@
302302

303303
('report', 'SoftLayer.CLI.report'),
304304
('report:bandwidth', 'SoftLayer.CLI.report.bandwidth:cli'),
305+
306+
('autoscale', 'SoftLayer.CLI.autoscale'),
307+
('autoscale:list', 'SoftLayer.CLI.autoscale.list:cli'),
308+
('autoscale:detail', 'SoftLayer.CLI.autoscale.detail:cli'),
309+
('autoscale:scale', 'SoftLayer.CLI.autoscale.scale:cli'),
310+
('autoscale:logs', 'SoftLayer.CLI.autoscale.logs:cli'),
311+
('autoscale:tag', 'SoftLayer.CLI.autoscale.tag:cli'),
312+
('autoscale:edit', 'SoftLayer.CLI.autoscale.edit:cli')
305313
]
306314

307315
ALL_ALIASES = {

0 commit comments

Comments
 (0)