Skip to content

Commit 12310b8

Browse files
Merge pull request #1075 from acamacho82/1041
dedicatedhost cancel, cancel-guests, and list-guests commands
2 parents d7d392e + 2987fd9 commit 12310b8

File tree

8 files changed

+489
-0
lines changed

8 files changed

+489
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Cancel a dedicated host."""
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+
12+
13+
@click.command()
14+
@click.argument('identifier')
15+
@environment.pass_env
16+
def cli(env, identifier):
17+
"""Cancel a dedicated host server immediately"""
18+
19+
mgr = SoftLayer.DedicatedHostManager(env.client)
20+
21+
host_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'dedicated host')
22+
23+
if not (env.skip_confirmations or formatting.no_going_back(host_id)):
24+
raise exceptions.CLIAbort('Aborted')
25+
26+
mgr.cancel_host(host_id)
27+
28+
click.secho('Dedicated Host %s was cancelled' % host_id, fg='green')
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Cancel a dedicated host."""
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+
12+
13+
@click.command()
14+
@click.argument('identifier')
15+
@environment.pass_env
16+
def cli(env, identifier):
17+
"""Cancel all virtual guests of the dedicated host immediately.
18+
19+
Use the 'slcli vs cancel' command to cancel an specific guest
20+
"""
21+
22+
dh_mgr = SoftLayer.DedicatedHostManager(env.client)
23+
24+
host_id = helpers.resolve_id(dh_mgr.resolve_ids, identifier, 'dedicated host')
25+
26+
if not (env.skip_confirmations or formatting.no_going_back(host_id)):
27+
raise exceptions.CLIAbort('Aborted')
28+
29+
table = formatting.Table(['id', 'server name', 'status'])
30+
31+
result = dh_mgr.cancel_guests(host_id)
32+
33+
if result:
34+
for status in result:
35+
table.add_row([
36+
status['id'],
37+
status['fqdn'],
38+
status['status']
39+
])
40+
41+
env.fout(table)
42+
else:
43+
click.secho('There is not any guest into the dedicated host %s' % host_id, fg='red')
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""List guests which are in a dedicated host server."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
import SoftLayer
7+
from SoftLayer.CLI import columns as column_helper
8+
from SoftLayer.CLI import environment
9+
from SoftLayer.CLI import formatting
10+
from SoftLayer.CLI import helpers
11+
12+
COLUMNS = [
13+
column_helper.Column('guid', ('globalIdentifier',)),
14+
column_helper.Column('cpu', ('maxCpu',)),
15+
column_helper.Column('memory', ('maxMemory',)),
16+
column_helper.Column('datacenter', ('datacenter', 'name')),
17+
column_helper.Column('primary_ip', ('primaryIpAddress',)),
18+
column_helper.Column('backend_ip', ('primaryBackendIpAddress',)),
19+
column_helper.Column(
20+
'created_by',
21+
('billingItem', 'orderItem', 'order', 'userRecord', 'username')),
22+
column_helper.Column('power_state', ('powerState', 'name')),
23+
column_helper.Column(
24+
'tags',
25+
lambda server: formatting.tags(server.get('tagReferences')),
26+
mask="tagReferences.tag.name"),
27+
]
28+
29+
DEFAULT_COLUMNS = [
30+
'id',
31+
'hostname',
32+
'domain',
33+
'primary_ip',
34+
'backend_ip',
35+
'power_state'
36+
]
37+
38+
39+
@click.command()
40+
@click.argument('identifier')
41+
@click.option('--cpu', '-c', help='Number of CPU cores', type=click.INT)
42+
@click.option('--domain', '-D', help='Domain portion of the FQDN')
43+
@click.option('--hostname', '-H', help='Host portion of the FQDN')
44+
@click.option('--memory', '-m', help='Memory in mebibytes', type=click.INT)
45+
@helpers.multi_option('--tag', help='Filter by tags')
46+
@click.option('--sortby',
47+
help='Column to sort by',
48+
default='hostname',
49+
show_default=True)
50+
@click.option('--columns',
51+
callback=column_helper.get_formatter(COLUMNS),
52+
help='Columns to display. [options: %s]'
53+
% ', '.join(column.name for column in COLUMNS),
54+
default=','.join(DEFAULT_COLUMNS),
55+
show_default=True)
56+
@environment.pass_env
57+
def cli(env, identifier, sortby, cpu, domain, hostname, memory, tag, columns):
58+
"""List guests which are in a dedicated host server."""
59+
60+
mgr = SoftLayer.DedicatedHostManager(env.client)
61+
guests = mgr.list_guests(host_id=identifier,
62+
cpus=cpu,
63+
hostname=hostname,
64+
domain=domain,
65+
memory=memory,
66+
tags=tag,
67+
mask=columns.mask())
68+
69+
table = formatting.Table(columns.columns)
70+
table.sortby = sortby
71+
72+
for guest in guests:
73+
table.add_row([value or formatting.blank()
74+
for value in columns.row(guest)])
75+
76+
env.fout(table)

SoftLayer/CLI/routes.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
('dedicatedhost:create', 'SoftLayer.CLI.dedicatedhost.create:cli'),
3838
('dedicatedhost:create-options', 'SoftLayer.CLI.dedicatedhost.create_options:cli'),
3939
('dedicatedhost:detail', 'SoftLayer.CLI.dedicatedhost.detail:cli'),
40+
('dedicatedhost:cancel', 'SoftLayer.CLI.dedicatedhost.cancel:cli'),
41+
('dedicatedhost:cancel-guests', 'SoftLayer.CLI.dedicatedhost.cancel_guests:cli'),
42+
('dedicatedhost:list-guests', 'SoftLayer.CLI.dedicatedhost.list_guests:cli'),
4043

4144
('cdn', 'SoftLayer.CLI.cdn'),
4245
('cdn:detail', 'SoftLayer.CLI.cdn.detail:cli'),

SoftLayer/fixtures/SoftLayer_Virtual_DedicatedHost.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,59 @@
7676
'id': 12345,
7777
'createDate': '2017-11-02T11:40:56-07:00'
7878
}
79+
80+
deleteObject = True
81+
82+
getGuests = [{
83+
'id': 200,
84+
'hostname': 'vs-test1',
85+
'domain': 'test.sftlyr.ws',
86+
'fullyQualifiedDomainName': 'vs-test1.test.sftlyr.ws',
87+
'status': {'keyName': 'ACTIVE', 'name': 'Active'},
88+
'datacenter': {'id': 50, 'name': 'TEST00',
89+
'description': 'Test Data Center'},
90+
'powerState': {'keyName': 'RUNNING', 'name': 'Running'},
91+
'maxCpu': 2,
92+
'maxMemory': 1024,
93+
'primaryIpAddress': '172.16.240.2',
94+
'globalIdentifier': '1a2b3c-1701',
95+
'primaryBackendIpAddress': '10.45.19.37',
96+
'hourlyBillingFlag': False,
97+
'billingItem': {
98+
'id': 6327,
99+
'recurringFee': 1.54,
100+
'orderItem': {
101+
'order': {
102+
'userRecord': {
103+
'username': 'chechu',
104+
}
105+
}
106+
}
107+
},
108+
}, {
109+
'id': 202,
110+
'hostname': 'vs-test2',
111+
'domain': 'test.sftlyr.ws',
112+
'fullyQualifiedDomainName': 'vs-test2.test.sftlyr.ws',
113+
'status': {'keyName': 'ACTIVE', 'name': 'Active'},
114+
'datacenter': {'id': 50, 'name': 'TEST00',
115+
'description': 'Test Data Center'},
116+
'powerState': {'keyName': 'RUNNING', 'name': 'Running'},
117+
'maxCpu': 4,
118+
'maxMemory': 4096,
119+
'primaryIpAddress': '172.16.240.7',
120+
'globalIdentifier': '05a8ac-6abf0',
121+
'primaryBackendIpAddress': '10.45.19.35',
122+
'hourlyBillingFlag': True,
123+
'billingItem': {
124+
'id': 6327,
125+
'recurringFee': 1.54,
126+
'orderItem': {
127+
'order': {
128+
'userRecord': {
129+
'username': 'chechu',
130+
}
131+
}
132+
}
133+
}
134+
}]

SoftLayer/managers/dedicated_host.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,144 @@ def __init__(self, client, ordering_manager=None):
3333
self.client = client
3434
self.account = client['Account']
3535
self.host = client['Virtual_DedicatedHost']
36+
self.guest = client['Virtual_Guest']
3637

3738
if ordering_manager is None:
3839
self.ordering_manager = ordering.OrderingManager(client)
3940

41+
def cancel_host(self, host_id):
42+
"""Cancel a dedicated host immediately, it fails if there are still guests in the host.
43+
44+
:param host_id: The ID of the dedicated host to be cancelled.
45+
:return: True on success or an exception
46+
47+
Example::
48+
# Cancels dedicated host id 12345
49+
result = mgr.cancel_host(12345)
50+
51+
"""
52+
return self.host.deleteObject(id=host_id)
53+
54+
def cancel_guests(self, host_id):
55+
"""Cancel all guests into the dedicated host immediately.
56+
57+
To cancel an specified guest use the method VSManager.cancel_instance()
58+
59+
:param host_id: The ID of the dedicated host.
60+
:return: The id, fqdn and status of all guests into a dictionary. The status
61+
could be 'Cancelled' or an exception message, The dictionary is empty
62+
if there isn't any guest in the dedicated host.
63+
64+
Example::
65+
# Cancel guests of dedicated host id 12345
66+
result = mgr.cancel_guests(12345)
67+
"""
68+
result = []
69+
70+
guests = self.host.getGuests(id=host_id, mask='id,fullyQualifiedDomainName')
71+
72+
if guests:
73+
for vs in guests:
74+
status_info = {
75+
'id': vs['id'],
76+
'fqdn': vs['fullyQualifiedDomainName'],
77+
'status': self._delete_guest(vs['id'])
78+
}
79+
result.append(status_info)
80+
81+
return result
82+
83+
def list_guests(self, host_id, tags=None, cpus=None, memory=None, hostname=None,
84+
domain=None, local_disk=None, nic_speed=None, public_ip=None,
85+
private_ip=None, **kwargs):
86+
"""Retrieve a list of all virtual servers on the dedicated host.
87+
88+
Example::
89+
90+
# Print out a list of instances with 4 cpu cores in the host id 12345.
91+
92+
for vsi in mgr.list_guests(host_id=12345, cpus=4):
93+
print vsi['fullyQualifiedDomainName'], vsi['primaryIpAddress']
94+
95+
# Using a custom object-mask. Will get ONLY what is specified
96+
object_mask = "mask[hostname,monitoringRobot[robotStatus]]"
97+
for vsi in mgr.list_guests(mask=object_mask,cpus=4):
98+
print vsi
99+
100+
:param integer host_id: the identifier of dedicated host
101+
:param list tags: filter based on list of tags
102+
:param integer cpus: filter based on number of CPUS
103+
:param integer memory: filter based on amount of memory
104+
:param string hostname: filter based on hostname
105+
:param string domain: filter based on domain
106+
:param string local_disk: filter based on local_disk
107+
:param integer nic_speed: filter based on network speed (in MBPS)
108+
:param string public_ip: filter based on public ip address
109+
:param string private_ip: filter based on private ip address
110+
:param dict \\*\\*kwargs: response-level options (mask, limit, etc.)
111+
:returns: Returns a list of dictionaries representing the matching
112+
virtual servers
113+
"""
114+
if 'mask' not in kwargs:
115+
items = [
116+
'id',
117+
'globalIdentifier',
118+
'hostname',
119+
'domain',
120+
'fullyQualifiedDomainName',
121+
'primaryBackendIpAddress',
122+
'primaryIpAddress',
123+
'lastKnownPowerState.name',
124+
'hourlyBillingFlag',
125+
'powerState',
126+
'maxCpu',
127+
'maxMemory',
128+
'datacenter',
129+
'activeTransaction.transactionStatus[friendlyName,name]',
130+
'status',
131+
]
132+
kwargs['mask'] = "mask[%s]" % ','.join(items)
133+
134+
_filter = utils.NestedDict(kwargs.get('filter') or {})
135+
136+
if tags:
137+
_filter['guests']['tagReferences']['tag']['name'] = {
138+
'operation': 'in',
139+
'options': [{'name': 'data', 'value': tags}],
140+
}
141+
142+
if cpus:
143+
_filter['guests']['maxCpu'] = utils.query_filter(cpus)
144+
145+
if memory:
146+
_filter['guests']['maxMemory'] = utils.query_filter(memory)
147+
148+
if hostname:
149+
_filter['guests']['hostname'] = utils.query_filter(hostname)
150+
151+
if domain:
152+
_filter['guests']['domain'] = utils.query_filter(domain)
153+
154+
if local_disk is not None:
155+
_filter['guests']['localDiskFlag'] = (
156+
utils.query_filter(bool(local_disk)))
157+
158+
if nic_speed:
159+
_filter['guests']['networkComponents']['maxSpeed'] = (
160+
utils.query_filter(nic_speed))
161+
162+
if public_ip:
163+
_filter['guests']['primaryIpAddress'] = (
164+
utils.query_filter(public_ip))
165+
166+
if private_ip:
167+
_filter['guests']['primaryBackendIpAddress'] = (
168+
utils.query_filter(private_ip))
169+
170+
kwargs['filter'] = _filter.to_dict()
171+
kwargs['iter'] = True
172+
return self.host.getGuests(id=host_id, **kwargs)
173+
40174
def list_instances(self, tags=None, cpus=None, memory=None, hostname=None,
41175
disk=None, datacenter=None, **kwargs):
42176
"""Retrieve a list of all dedicated hosts on the account
@@ -384,3 +518,13 @@ def get_router_options(self, datacenter=None, flavor=None):
384518
item = self._get_item(package, flavor)
385519

386520
return self._get_backend_router(location['location']['locationPackageDetails'], item)
521+
522+
def _delete_guest(self, guest_id):
523+
"""Deletes a guest and returns 'Cancelled' or and Exception message"""
524+
msg = 'Cancelled'
525+
try:
526+
self.guest.deleteObject(id=guest_id)
527+
except SoftLayer.SoftLayerAPIError as e:
528+
msg = 'Exception: ' + e.faultString
529+
530+
return msg

0 commit comments

Comments
 (0)