Skip to content

Commit d6ef561

Browse files
caberoscaberos
authored andcommitted
slcli autoscale create
1 parent 51b594e commit d6ef561

9 files changed

Lines changed: 319 additions & 1 deletion

File tree

SoftLayer/CLI/autoscale/create.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
"""Order/create a dedicated server."""
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 exceptions
9+
from SoftLayer.CLI import formatting
10+
from SoftLayer.CLI import helpers
11+
from SoftLayer.managers.autoscale import AutoScaleManager
12+
13+
14+
@click.command()
15+
@click.option('--name', help="Scale group's name.")
16+
@click.option('--cooldown', type=click.INT,
17+
help="The number of seconds this group will wait after lastActionDate before performing another action.")
18+
@click.option('--min', 'minimum', type=click.INT, help="Set the minimum number of guests")
19+
@click.option('--max', 'maximum', type=click.INT, help="Set the maximum number of guests")
20+
@click.option('--regional', type=click.INT,
21+
help="The identifier of the regional group this scaling group is assigned to.")
22+
@click.option('--postinstall', '-i', help="Post-install script to download")
23+
@click.option('--os', '-o', help="OS install code. Tip: you can specify <OS>_LATEST")
24+
@click.option('--datacenter', '-d', required=True, prompt=True, help="Datacenter shortname")
25+
@click.option('--hostname', '-H', required=True, prompt=True, help="Host portion of the FQDN")
26+
@click.option('--domain', '-D', required=True, prompt=True, help="Domain portion of the FQDN")
27+
@click.option('--cpu', type=click.INT, help="Number of CPUs for new guests (existing not effected")
28+
@click.option('--memory', type=click.INT, help="RAM in MB or GB for new guests (existing not effected")
29+
@click.option('--policy-relative', help="The type of scale to perform(ABSOLUTE, PERCENT, RELATIVE).")
30+
@click.option('--termination-policy',
31+
help="The termination policy for the group(CLOSEST_TO_NEXT_CHARGE=1, NEWEST=2, OLDEST=3).")
32+
@click.option('--policy-name', help="Collection of policies for this group. This can be empty.")
33+
@click.option('--policy-amount', help="The number to scale by. This number has different meanings based on type.")
34+
@click.option('--userdata', help="User defined metadata string")
35+
@helpers.multi_option('--key', '-k', help="SSH keys to add to the root user")
36+
@helpers.multi_option('--disk', help="Disk sizes")
37+
@environment.pass_env
38+
def cli(env, **args):
39+
"""Order/create autoscale."""
40+
scale = AutoScaleManager(env.client)
41+
network = SoftLayer.NetworkManager(env.client)
42+
43+
pods = network.get_closed_pods()
44+
closure = []
45+
46+
datacenter = network.get_datacenter(args.get('datacenter'))
47+
48+
ssh_keys = []
49+
for key in args.get('key'):
50+
resolver = SoftLayer.SshKeyManager(env.client).resolve_ids
51+
key_id = helpers.resolve_id(resolver, key, 'SshKey')
52+
ssh_keys.append(key_id)
53+
scale_actions = [
54+
{
55+
"amount": args['policy_amount'],
56+
"scaleType": args['policy_relative']
57+
}
58+
]
59+
policy_template = {
60+
'name': args['policy_name'],
61+
'policies': scale_actions
62+
63+
}
64+
policies = []
65+
66+
block = []
67+
number_disk = 0
68+
for guest_disk in args['disk']:
69+
disks = {'diskImage': {'capacity': guest_disk}, 'device': number_disk}
70+
block.append(disks)
71+
number_disk += 1
72+
73+
virt_template = {
74+
'localDiskFlag': False,
75+
'domain': args['domain'],
76+
'hostname': args['hostname'],
77+
'sshKeys': ssh_keys,
78+
'postInstallScriptUri': args.get('postinstall'),
79+
'operatingSystemReferenceCode': args['os'],
80+
'maxMemory': args.get('memory'),
81+
'datacenter': {'id': datacenter[0]['id']},
82+
'startCpus': args.get('cpu'),
83+
'blockDevices': block,
84+
'hourlyBillingFlag': True,
85+
'privateNetworkOnlyFlag': False,
86+
'networkComponents': [{'maxSpeed': 100}],
87+
'typeId': 1,
88+
'userData': [{
89+
'value': args.get('userdata')
90+
}],
91+
'networkVlans': [],
92+
93+
}
94+
95+
order = {
96+
'name': args['name'],
97+
'cooldown': args['cooldown'],
98+
'maximumMemberCount': args['maximum'],
99+
'minimumMemberCount': args['minimum'],
100+
'regionalGroupId': args['regional'],
101+
'suspendedFlag': False,
102+
'balancedTerminationFlag': False,
103+
'virtualGuestMemberTemplate': virt_template,
104+
'virtualGuestMemberCount': 0,
105+
'policies': policies.append(clean_dict(policy_template)),
106+
'terminationPolicyId': args['termination_policy']
107+
}
108+
109+
# print(virt_template)
110+
111+
for pod in pods:
112+
if args.get('datacenter') in str(pod['name']):
113+
closure.append(pod['name'])
114+
click.secho(click.style('Warning: Closed soon: %s' % (', '.join(closure)), fg='yellow'))
115+
if not (env.skip_confirmations or formatting.confirm(
116+
"This action will incur charges on your account. Continue?")):
117+
raise exceptions.CLIAbort('Aborting scale group order.')
118+
else:
119+
result = scale.create(order)
120+
121+
table = formatting.KeyValueTable(['name', 'value'])
122+
table.align['name'] = 'r'
123+
table.align['value'] = 'l'
124+
table.add_row(['Id', result['id']])
125+
table.add_row(['Created', result['createDate']])
126+
table.add_row(['Name', result['name']])
127+
table.add_row(['Virtual Guest Id', result['virtualGuestMembers'][0]['virtualGuest']['id']])
128+
table.add_row(['Virtual Guest domain', result['virtualGuestMembers'][0]['virtualGuest']['domain']])
129+
table.add_row(['Virtual Guest hostname', result['virtualGuestMembers'][0]['virtualGuest']['hostname']])
130+
output = table
131+
132+
env.fout(output)
133+
134+
135+
def clean_dict(dictionary):
136+
"""Removes any `None` entires from the dictionary"""
137+
return {k: v for k, v in dictionary.items() if v}

SoftLayer/CLI/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@
372372

373373
('autoscale', 'SoftLayer.CLI.autoscale'),
374374
('autoscale:list', 'SoftLayer.CLI.autoscale.list:cli'),
375+
('autoscale:create', 'SoftLayer.CLI.autoscale.create:cli'),
375376
('autoscale:detail', 'SoftLayer.CLI.autoscale.detail:cli'),
376377
('autoscale:scale', 'SoftLayer.CLI.autoscale.scale:cli'),
377378
('autoscale:logs', 'SoftLayer.CLI.autoscale.logs:cli'),

SoftLayer/fixtures/SoftLayer_Scale_Group.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,79 @@
455455
]
456456

457457
editObject = True
458+
459+
createObject = {
460+
"accountId": 307608,
461+
"cooldown": 3600,
462+
"createDate": "2022-04-22T13:45:24-06:00",
463+
"id": 5446140,
464+
"lastActionDate": "2022-04-22T13:45:29-06:00",
465+
"maximumMemberCount": 5,
466+
"minimumMemberCount": 1,
467+
"name": "test22042022",
468+
"regionalGroupId": 4568,
469+
"suspendedFlag": False,
470+
"terminationPolicyId": 2,
471+
"virtualGuestMemberTemplate": {
472+
"accountId": 307608,
473+
"domain": "test.com",
474+
"hostname": "testvs",
475+
"maxMemory": 2048,
476+
"startCpus": 2,
477+
"blockDevices": [
478+
{
479+
"diskImage": {
480+
"capacity": 100,
481+
}
482+
}
483+
],
484+
"hourlyBillingFlag": True,
485+
"localDiskFlag": True,
486+
"networkComponents": [
487+
{
488+
"maxSpeed": 100,
489+
}
490+
],
491+
"operatingSystemReferenceCode": "CENTOS_7_64",
492+
"userData": [
493+
{
494+
"value": "the userData"
495+
}
496+
]
497+
},
498+
"virtualGuestMemberCount": 0,
499+
"networkVlans": [],
500+
"policies": [],
501+
"status": {
502+
"id": 1,
503+
"keyName": "ACTIVE",
504+
"name": "Active"
505+
},
506+
"virtualGuestAssets": [],
507+
"virtualGuestMembers": [
508+
{
509+
"createDate": "2022-04-22T13:45:29-06:00",
510+
"id": 123456,
511+
"scaleGroupId": 5446140,
512+
"virtualGuest": {
513+
"createDate": "2022-04-22T13:45:28-06:00",
514+
"deviceStatusId": 3,
515+
"domain": "test.com",
516+
"fullyQualifiedDomainName": "testvs-97e7.test.com",
517+
"hostname": "testvs-97e7",
518+
"id": 129911702,
519+
"maxCpu": 2,
520+
"maxCpuUnits": "CORE",
521+
"maxMemory": 2048,
522+
"startCpus": 2,
523+
"statusId": 1001,
524+
"typeId": 1,
525+
"uuid": "46e55f99-b412-4287-95b5-b8182b2fc924",
526+
"status": {
527+
"keyName": "ACTIVE",
528+
"name": "Active"
529+
}
530+
}
531+
}
532+
]
533+
}

SoftLayer/managers/autoscale.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,14 @@ def edit(self, identifier, template):
116116
.. _SoftLayer_Scale_Group: https://sldn.softlayer.com/reference/datatypes/SoftLayer_Scale_Group/
117117
"""
118118
return self.client.call('SoftLayer_Scale_Group', 'editObject', template, id=identifier)
119+
120+
def create(self, template):
121+
"""Calls `SoftLayer_Scale_Group::createObject()`_
122+
123+
:param template: `SoftLayer_Scale_Group`_
124+
125+
.. _SoftLayer_Scale_Group::createObject():
126+
https://sldn.softlayer.com/reference/services/SoftLayer_Scale_Group/createObject/
127+
.. _SoftLayer_Scale_Group: https://sldn.softlayer.com/reference/datatypes/SoftLayer_Scale_Group/
128+
"""
129+
return self.client.call('SoftLayer_Scale_Group', 'createObject', template)

SoftLayer/managers/network.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,3 +824,15 @@ def get_closed_pods(self):
824824
mask = """mask[name, datacenterLongName, frontendRouterId, capabilities, datacenterId, backendRouterId,
825825
backendRouterName, frontendRouterName]"""
826826
return self.client.call('SoftLayer_Network_Pod', 'getAllObjects', mask=mask, filter=closing_filter)
827+
828+
def get_datacenter(self, _filter=None, datacenter=None):
829+
"""Calls SoftLayer_Location::getDatacenters()
830+
831+
returns datacenter list.
832+
"""
833+
_filter = None
834+
835+
if datacenter:
836+
_filter = {"name": {"operation": datacenter}}
837+
838+
return self.client.call('SoftLayer_Location', 'getDatacenters', filter=_filter, limit=1)

docs/cli/autoscale.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,9 @@ For making changes to the triggers or the autoscale group itself, see the `Autos
3434
:prog: autoscale edit
3535
:show-nested:
3636

37+
.. click:: SoftLayer.CLI.autoscale.create:cli
38+
:prog: autoscale create
39+
:show-nested:
40+
3741

3842
.. _Autoscale Portal: https://cloud.ibm.com/classic/autoscale

tests/CLI/modules/autoscale_tests.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def test_autoscale_edit_userdata(self, manager):
7777
@mock.patch('SoftLayer.managers.autoscale.AutoScaleManager.edit')
7878
def test_autoscale_edit_userfile(self, manager):
7979
# On windows, python cannot edit a NamedTemporaryFile.
80-
if(sys.platform.startswith("win")):
80+
if (sys.platform.startswith("win")):
8181
self.skipTest("Test doesn't work in Windows")
8282
group = fixtures.SoftLayer_Scale_Group.getObject
8383
template = {
@@ -89,3 +89,25 @@ def test_autoscale_edit_userfile(self, manager):
8989
result = self.run_command(['autoscale', 'edit', '12345', '--userfile', userfile.name])
9090
self.assert_no_fail(result)
9191
manager.assert_called_with('12345', template)
92+
93+
@mock.patch('SoftLayer.CLI.formatting.confirm')
94+
def test_autoscale_create(self, confirm_mock):
95+
confirm_mock.return_value = True
96+
result = self.run_command(['autoscale', 'create',
97+
'--name=test',
98+
'--cooldown=3600',
99+
'--min=1',
100+
'--max=3',
101+
'-o=CENTOS_7_64',
102+
'--datacenter=ams01',
103+
'--termination-policy=2',
104+
'-H=testvs',
105+
'-D=test.com',
106+
'--cpu=2',
107+
'--memory=1024',
108+
'--policy-relative=absolute',
109+
'--policy-amount=3',
110+
'--regional=102',
111+
'--disk=25'])
112+
self.assert_no_fail(result)
113+
self.assertEqual(result.exit_code, 0)

tests/managers/autoscale_tests.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,54 @@ def test_edit_object(self):
123123
'editObject',
124124
args=(template,),
125125
identifier=12345)
126+
127+
def test_create_object(self):
128+
template = {
129+
'name': 'test',
130+
'cooldown': 3600,
131+
'maximumMemberCount': 5,
132+
'minimumMemberCount': 1,
133+
'regionalGroupId': 4568,
134+
'suspendedFlag': False,
135+
'balancedTerminationFlag': False,
136+
'virtualGuestMemberTemplate': {
137+
'domain': 'test.com',
138+
'hostname': 'testvs',
139+
'operatingSystemReferenceCode': 'CENTOS_7_64',
140+
'maxMemory': 2048,
141+
'datacenter': {
142+
'id': 265592
143+
},
144+
'startCpus': 2,
145+
'blockDevices': [
146+
{
147+
'diskImage': {
148+
'capacity': '100'
149+
},
150+
'device': 0
151+
}
152+
],
153+
'hourlyBillingFlag': True,
154+
'networkComponents': [
155+
{
156+
'maxSpeed': 100
157+
}
158+
],
159+
'localDiskFlag': True,
160+
'typeId': 1,
161+
'userData': [
162+
{
163+
'value': 'the userData'
164+
}
165+
]
166+
},
167+
'virtualGuestMemberCount': 0,
168+
169+
'terminationPolicyId': '2',
170+
}
171+
172+
self.autoscale.create(template)
173+
self.assert_called_with(
174+
'SoftLayer_Scale_Group',
175+
'createObject',
176+
args=(template,))

tests/managers/network_tests.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,3 +628,7 @@ def test_vlan_edit(self):
628628
def test_get_all_pods(self):
629629
self.network.get_pods()
630630
self.assert_called_with('SoftLayer_Network_Pod', 'getAllObjects')
631+
632+
def test_get_all_datacenter(self):
633+
self.network.get_datacenter()
634+
self.assert_called_with('SoftLayer_Location', 'getDatacenters')

0 commit comments

Comments
 (0)