Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions SoftLayer/CLI/dedicatedhost/cancel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Cancel a dedicated host."""
# :license: MIT, see LICENSE for more details.

import click

import SoftLayer
from SoftLayer.CLI import environment
from SoftLayer.CLI import exceptions
from SoftLayer.CLI import formatting
from SoftLayer.CLI import helpers


@click.command()
@click.argument('identifier')
@environment.pass_env
def cli(env, identifier):
"""Cancel a dedicated host server immediately"""

mgr = SoftLayer.DedicatedHostManager(env.client)

host_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'dedicated host')

if not (env.skip_confirmations or formatting.no_going_back(host_id)):
raise exceptions.CLIAbort('Aborted')

mgr.cancel_host(host_id)

click.secho('Dedicated Host %s was cancelled' % host_id, fg='green')
43 changes: 43 additions & 0 deletions SoftLayer/CLI/dedicatedhost/cancel_guests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Cancel a dedicated host."""
# :license: MIT, see LICENSE for more details.

import click

import SoftLayer
from SoftLayer.CLI import environment
from SoftLayer.CLI import exceptions
from SoftLayer.CLI import formatting
from SoftLayer.CLI import helpers


@click.command()
@click.argument('identifier')
@environment.pass_env
def cli(env, identifier):
"""Cancel all virtual guests of the dedicated host immediately.

Use the 'slcli vs cancel' command to cancel an specific guest
"""

dh_mgr = SoftLayer.DedicatedHostManager(env.client)

host_id = helpers.resolve_id(dh_mgr.resolve_ids, identifier, 'dedicated host')

if not (env.skip_confirmations or formatting.no_going_back(host_id)):
raise exceptions.CLIAbort('Aborted')

table = formatting.Table(['id', 'server name', 'status'])

result = dh_mgr.cancel_guests(host_id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After updated the manager function, just add a way to print out a nice table with the results of each guests' cancelation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. It prints a table like below

$ slcli --really dh cancel-guests 33333
:..........:...........................:..................................................................:
:    id    :        server name        :                              status                              :
:..........:...........................:..................................................................:
: 1111111  :    foobar.softlayer.com   :                            Cancelled                             :
: 2222222  :    wombat.softlayer.com   : Exception: A billing item is required to process a cancellation. :
:..........:...........................:..................................................................:


if result:
for status in result:
table.add_row([
status['id'],
status['fqdn'],
status['status']
])

env.fout(table)
else:
click.secho('There is not any guest into the dedicated host %s' % host_id, fg='red')
76 changes: 76 additions & 0 deletions SoftLayer/CLI/dedicatedhost/list_guests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""List guests which are in a dedicated host server."""
# :license: MIT, see LICENSE for more details.

import click

import SoftLayer
from SoftLayer.CLI import columns as column_helper
from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.CLI import helpers

COLUMNS = [
column_helper.Column('guid', ('globalIdentifier',)),
column_helper.Column('cpu', ('maxCpu',)),
column_helper.Column('memory', ('maxMemory',)),
column_helper.Column('datacenter', ('datacenter', 'name')),
column_helper.Column('primary_ip', ('primaryIpAddress',)),
column_helper.Column('backend_ip', ('primaryBackendIpAddress',)),
column_helper.Column(
'created_by',
('billingItem', 'orderItem', 'order', 'userRecord', 'username')),
column_helper.Column('power_state', ('powerState', 'name')),
column_helper.Column(
'tags',
lambda server: formatting.tags(server.get('tagReferences')),
mask="tagReferences.tag.name"),
]

DEFAULT_COLUMNS = [
'id',
'hostname',
'domain',
'primary_ip',
'backend_ip',
'power_state'
]


@click.command()
@click.argument('identifier')
@click.option('--cpu', '-c', help='Number of CPU cores', type=click.INT)
@click.option('--domain', '-D', help='Domain portion of the FQDN')
@click.option('--hostname', '-H', help='Host portion of the FQDN')
@click.option('--memory', '-m', help='Memory in mebibytes', type=click.INT)
@helpers.multi_option('--tag', help='Filter by tags')
@click.option('--sortby',
help='Column to sort by',
default='hostname',
show_default=True)
@click.option('--columns',
callback=column_helper.get_formatter(COLUMNS),
help='Columns to display. [options: %s]'
% ', '.join(column.name for column in COLUMNS),
default=','.join(DEFAULT_COLUMNS),
show_default=True)
@environment.pass_env
def cli(env, identifier, sortby, cpu, domain, hostname, memory, tag, columns):
"""List guests which are in a dedicated host server."""

mgr = SoftLayer.DedicatedHostManager(env.client)
guests = mgr.list_guests(host_id=identifier,
cpus=cpu,
hostname=hostname,
domain=domain,
memory=memory,
tags=tag,
mask=columns.mask())

table = formatting.Table(columns.columns)
table.sortby = sortby

for guest in guests:
table.add_row([value or formatting.blank()
for value in columns.row(guest)])

env.fout(table)
3 changes: 3 additions & 0 deletions SoftLayer/CLI/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
('dedicatedhost:create', 'SoftLayer.CLI.dedicatedhost.create:cli'),
('dedicatedhost:create-options', 'SoftLayer.CLI.dedicatedhost.create_options:cli'),
('dedicatedhost:detail', 'SoftLayer.CLI.dedicatedhost.detail:cli'),
('dedicatedhost:cancel', 'SoftLayer.CLI.dedicatedhost.cancel:cli'),
('dedicatedhost:cancel-guests', 'SoftLayer.CLI.dedicatedhost.cancel_guests:cli'),
('dedicatedhost:list-guests', 'SoftLayer.CLI.dedicatedhost.list_guests:cli'),

('cdn', 'SoftLayer.CLI.cdn'),
('cdn:detail', 'SoftLayer.CLI.cdn.detail:cli'),
Expand Down
56 changes: 56 additions & 0 deletions SoftLayer/fixtures/SoftLayer_Virtual_DedicatedHost.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,59 @@
'id': 12345,
'createDate': '2017-11-02T11:40:56-07:00'
}

deleteObject = True

getGuests = [{
'id': 200,
'hostname': 'vs-test1',
'domain': 'test.sftlyr.ws',
'fullyQualifiedDomainName': 'vs-test1.test.sftlyr.ws',
'status': {'keyName': 'ACTIVE', 'name': 'Active'},
'datacenter': {'id': 50, 'name': 'TEST00',
'description': 'Test Data Center'},
'powerState': {'keyName': 'RUNNING', 'name': 'Running'},
'maxCpu': 2,
'maxMemory': 1024,
'primaryIpAddress': '172.16.240.2',
'globalIdentifier': '1a2b3c-1701',
'primaryBackendIpAddress': '10.45.19.37',
'hourlyBillingFlag': False,
'billingItem': {
'id': 6327,
'recurringFee': 1.54,
'orderItem': {
'order': {
'userRecord': {
'username': 'chechu',
}
}
}
},
}, {
'id': 202,
'hostname': 'vs-test2',
'domain': 'test.sftlyr.ws',
'fullyQualifiedDomainName': 'vs-test2.test.sftlyr.ws',
'status': {'keyName': 'ACTIVE', 'name': 'Active'},
'datacenter': {'id': 50, 'name': 'TEST00',
'description': 'Test Data Center'},
'powerState': {'keyName': 'RUNNING', 'name': 'Running'},
'maxCpu': 4,
'maxMemory': 4096,
'primaryIpAddress': '172.16.240.7',
'globalIdentifier': '05a8ac-6abf0',
'primaryBackendIpAddress': '10.45.19.35',
'hourlyBillingFlag': True,
'billingItem': {
'id': 6327,
'recurringFee': 1.54,
'orderItem': {
'order': {
'userRecord': {
'username': 'chechu',
}
}
}
}
}]
144 changes: 144 additions & 0 deletions SoftLayer/managers/dedicated_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,144 @@ def __init__(self, client, ordering_manager=None):
self.client = client
self.account = client['Account']
self.host = client['Virtual_DedicatedHost']
self.guest = client['Virtual_Guest']

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

def cancel_host(self, host_id):
"""Cancel a dedicated host immediately, it fails if there are still guests in the host.

:param host_id: The ID of the dedicated host to be cancelled.
:return: True on success or an exception

Example::
# Cancels dedicated host id 12345
result = mgr.cancel_host(12345)

"""
return self.host.deleteObject(id=host_id)

def cancel_guests(self, host_id):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this function, I'd like it to be able to return a structure that has a bit more information about what guests were canceled so the slcli can print out a receipt.

Ideally id, FQDN, and whether the guest was canceled or got an error

return  = [
    {'id': 1234, 'fqdn': 'test01.test.com', 'status': 'canceled' },
    {'id': 1235, 'fqdn': 'test02.test.com', 'status': 'Exception: Running Transaction or something' },
]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, it returns a dictionary and it is empty if there isn't any guest in the dedicated host. The slcli prints a table or a message in case the dict is empty.

"""Cancel all guests into the dedicated host immediately.

To cancel an specified guest use the method VSManager.cancel_instance()

:param host_id: The ID of the dedicated host.
:return: The id, fqdn and status of all guests into a dictionary. The status
could be 'Cancelled' or an exception message, The dictionary is empty
if there isn't any guest in the dedicated host.

Example::
# Cancel guests of dedicated host id 12345
result = mgr.cancel_guests(12345)
"""
result = []

guests = self.host.getGuests(id=host_id, mask='id,fullyQualifiedDomainName')

if guests:
for vs in guests:
status_info = {
'id': vs['id'],
'fqdn': vs['fullyQualifiedDomainName'],
'status': self._delete_guest(vs['id'])
}
result.append(status_info)

return result

def list_guests(self, host_id, tags=None, cpus=None, memory=None, hostname=None,
domain=None, local_disk=None, nic_speed=None, public_ip=None,
private_ip=None, **kwargs):
"""Retrieve a list of all virtual servers on the dedicated host.

Example::

# Print out a list of instances with 4 cpu cores in the host id 12345.

for vsi in mgr.list_guests(host_id=12345, cpus=4):
print vsi['fullyQualifiedDomainName'], vsi['primaryIpAddress']

# Using a custom object-mask. Will get ONLY what is specified
object_mask = "mask[hostname,monitoringRobot[robotStatus]]"
for vsi in mgr.list_guests(mask=object_mask,cpus=4):
print vsi

:param integer host_id: the identifier of dedicated host
:param list tags: filter based on list of tags
:param integer cpus: filter based on number of CPUS
:param integer memory: filter based on amount of memory
:param string hostname: filter based on hostname
:param string domain: filter based on domain
:param string local_disk: filter based on local_disk
:param integer nic_speed: filter based on network speed (in MBPS)
:param string public_ip: filter based on public ip address
:param string private_ip: filter based on private ip address
:param dict \\*\\*kwargs: response-level options (mask, limit, etc.)
:returns: Returns a list of dictionaries representing the matching
virtual servers
"""
if 'mask' not in kwargs:
items = [
'id',
'globalIdentifier',
'hostname',
'domain',
'fullyQualifiedDomainName',
'primaryBackendIpAddress',
'primaryIpAddress',
'lastKnownPowerState.name',
'hourlyBillingFlag',
'powerState',
'maxCpu',
'maxMemory',
'datacenter',
'activeTransaction.transactionStatus[friendlyName,name]',
'status',
]
kwargs['mask'] = "mask[%s]" % ','.join(items)

_filter = utils.NestedDict(kwargs.get('filter') or {})

if tags:
_filter['guests']['tagReferences']['tag']['name'] = {
'operation': 'in',
'options': [{'name': 'data', 'value': tags}],
}

if cpus:
_filter['guests']['maxCpu'] = utils.query_filter(cpus)

if memory:
_filter['guests']['maxMemory'] = utils.query_filter(memory)

if hostname:
_filter['guests']['hostname'] = utils.query_filter(hostname)

if domain:
_filter['guests']['domain'] = utils.query_filter(domain)

if local_disk is not None:
_filter['guests']['localDiskFlag'] = (
utils.query_filter(bool(local_disk)))

if nic_speed:
_filter['guests']['networkComponents']['maxSpeed'] = (
utils.query_filter(nic_speed))

if public_ip:
_filter['guests']['primaryIpAddress'] = (
utils.query_filter(public_ip))

if private_ip:
_filter['guests']['primaryBackendIpAddress'] = (
utils.query_filter(private_ip))

kwargs['filter'] = _filter.to_dict()
kwargs['iter'] = True
return self.host.getGuests(id=host_id, **kwargs)

def list_instances(self, tags=None, cpus=None, memory=None, hostname=None,
disk=None, datacenter=None, **kwargs):
"""Retrieve a list of all dedicated hosts on the account
Expand Down Expand Up @@ -384,3 +518,13 @@ def get_router_options(self, datacenter=None, flavor=None):
item = self._get_item(package, flavor)

return self._get_backend_router(location['location']['locationPackageDetails'], item)

def _delete_guest(self, guest_id):
"""Deletes a guest and returns 'Cancelled' or and Exception message"""
msg = 'Cancelled'
try:
self.guest.deleteObject(id=guest_id)
except SoftLayer.SoftLayerAPIError as e:
msg = 'Exception: ' + e.faultString

return msg
Loading