Skip to content
1 change: 1 addition & 0 deletions SoftLayer/CLI/account/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Account commands"""
73 changes: 73 additions & 0 deletions SoftLayer/CLI/account/event_detail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Details of a specific event, and ability to acknowledge event."""
# :license: MIT, see LICENSE for more details.

import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers.account import AccountManager as AccountManager
from SoftLayer import utils


@click.command()
@click.argument('identifier')
@click.option('--ack', is_flag=True, default=False,
help="Acknowledge Event. Doing so will turn off the popup in the control portal")
@environment.pass_env
def cli(env, identifier, ack):
"""Details of a specific event, and ability to acknowledge event."""

# Print a list of all on going maintenance
manager = AccountManager(env.client)
event = manager.get_event(identifier)

if ack:
manager.ack_event(identifier)

env.fout(basic_event_table(event))
env.fout(impacted_table(event))
env.fout(update_table(event))


def basic_event_table(event):
"""Formats a basic event table"""
table = formatting.Table(["Id", "Status", "Type", "Start", "End"],
title=utils.clean_splitlines(event.get('subject')))

table.add_row([
event.get('id'),
utils.lookup(event, 'statusCode', 'name'),
utils.lookup(event, 'notificationOccurrenceEventType', 'keyName'),
utils.clean_time(event.get('startDate')),
utils.clean_time(event.get('endDate'))
])

return table


def impacted_table(event):
"""Formats a basic impacted resources table"""
table = formatting.Table([
"Type", "Id", "Hostname", "PrivateIp", "Label"
])
for item in event.get('impactedResources', []):
table.add_row([
item.get('resourceType'),
item.get('resourceTableId'),
item.get('hostname'),
item.get('privateIp'),
item.get('filterLabel')
])
return table


def update_table(event):
"""Formats a basic event update table"""
update_number = 0
for update in event.get('updates', []):
header = "======= Update #%s on %s =======" % (update_number, utils.clean_time(update.get('startDate')))
click.secho(header, fg='green')
update_number = update_number + 1
text = update.get('contents')
# deals with all the \r\n from the API
click.secho(utils.clean_splitlines(text))
54 changes: 54 additions & 0 deletions SoftLayer/CLI/account/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Summary and acknowledgement of upcoming and ongoing maintenance events"""
# :license: MIT, see LICENSE for more details.
import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers.account import AccountManager as AccountManager
from SoftLayer import utils


@click.command()
@click.option('--ack-all', is_flag=True, default=False,
help="Acknowledge every upcoming event. Doing so will turn off the popup in the control portal")
@environment.pass_env
def cli(env, ack_all):
"""Summary and acknowledgement of upcoming and ongoing maintenance events"""

manager = AccountManager(env.client)
events = manager.get_upcoming_events()

if ack_all:
for event in events:
result = manager.ack_event(event['id'])
event['acknowledgedFlag'] = result
env.fout(event_table(events))


def event_table(events):
"""Formats a table for events"""
table = formatting.Table([
"Id",
"Start Date",
"End Date",
"Subject",
"Status",
"Acknowledged",
"Updates",
"Impacted Resources"
], title="Upcoming Events")
table.align['Subject'] = 'l'
table.align['Impacted Resources'] = 'l'
for event in events:
table.add_row([
event.get('id'),
utils.clean_time(event.get('startDate')),
utils.clean_time(event.get('endDate')),
# Some subjects can have \r\n for some reason.
utils.clean_splitlines(event.get('subject')),
utils.lookup(event, 'statusCode', 'name'),
event.get('acknowledgedFlag'),
event.get('updateCount'),
event.get('impactedResourceCount')
])
return table
61 changes: 61 additions & 0 deletions SoftLayer/CLI/account/invoice_detail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Invoice details"""
# :license: MIT, see LICENSE for more details.

import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers.account import AccountManager as AccountManager
from SoftLayer import utils


@click.command()
@click.argument('identifier')
@click.option('--details', is_flag=True, default=False, show_default=True,
help="Shows a very detailed list of charges")
@environment.pass_env
def cli(env, identifier, details):
"""Invoices and all that mess"""

manager = AccountManager(env.client)
top_items = manager.get_billing_items(identifier)

title = "Invoice %s" % identifier
table = formatting.Table(["Item Id", "Category", "Description", "Single",
"Monthly", "Create Date", "Location"], title=title)
table.align['category'] = 'l'
table.align['description'] = 'l'
for item in top_items:
fqdn = "%s.%s" % (item.get('hostName', ''), item.get('domainName', ''))
# category id=2046, ram_usage doesn't have a name...
category = utils.lookup(item, 'category', 'name') or item.get('categoryCode')
description = nice_string(item.get('description'))
if fqdn != '.':
description = "%s (%s)" % (item.get('description'), fqdn)
table.add_row([
item.get('id'),
category,
nice_string(description),
"$%.2f" % float(item.get('oneTimeAfterTaxAmount')),
"$%.2f" % float(item.get('recurringAfterTaxAmount')),
utils.clean_time(item.get('createDate'), out_format="%Y-%m-%d"),
utils.lookup(item, 'location', 'name')
])
if details:
for child in item.get('children', []):
table.add_row([
'>>>',
utils.lookup(child, 'category', 'name'),
nice_string(child.get('description')),
"$%.2f" % float(child.get('oneTimeAfterTaxAmount')),
"$%.2f" % float(child.get('recurringAfterTaxAmount')),
'---',
'---'
])

env.fout(table)


def nice_string(ugly_string, limit=100):
"""Format and trims strings"""
return (ugly_string[:limit] + '..') if len(ugly_string) > limit else ugly_string
46 changes: 46 additions & 0 deletions SoftLayer/CLI/account/invoices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Invoice listing"""
# :license: MIT, see LICENSE for more details.

import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers.account import AccountManager as AccountManager
from SoftLayer import utils


@click.command()
@click.option('--limit', default=50, show_default=True,
help="How many invoices to get back.")
@click.option('--closed', is_flag=True, default=False, show_default=True,
help="Include invoices with a CLOSED status.")
@click.option('--all', 'get_all', is_flag=True, default=False, show_default=True,
help="Return ALL invoices. There may be a lot of these.")
@environment.pass_env
def cli(env, limit, closed=False, get_all=False):
"""Invoices and all that mess"""

manager = AccountManager(env.client)
invoices = manager.get_invoices(limit, closed, get_all)

table = formatting.Table([
"Id", "Created", "Type", "Status", "Starting Balance", "Ending Balance", "Invoice Amount", "Items"
])
table.align['Starting Balance'] = 'l'
table.align['Ending Balance'] = 'l'
table.align['Invoice Amount'] = 'l'
table.align['Items'] = 'l'
if isinstance(invoices, dict):
invoices = [invoices]
for invoice in invoices:
table.add_row([
invoice.get('id'),
utils.clean_time(invoice.get('createDate'), out_format="%Y-%m-%d"),
invoice.get('typeCode'),
invoice.get('statusCode'),
invoice.get('startingBalance'),
invoice.get('endingBalance'),
invoice.get('invoiceTotalAmount'),
invoice.get('itemCount')
])
env.fout(table)
39 changes: 39 additions & 0 deletions SoftLayer/CLI/account/summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Account Summary page"""
# :license: MIT, see LICENSE for more details.
import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers.account import AccountManager as AccountManager
from SoftLayer import utils


@click.command()
@environment.pass_env
def cli(env):
"""Prints some various bits of information about an account"""

manager = AccountManager(env.client)
summary = manager.get_summary()
env.fout(get_snapshot_table(summary))


def get_snapshot_table(account):
"""Generates a table for printing account summary data"""
table = formatting.KeyValueTable(["Name", "Value"], title="Account Snapshot")
table.align['Name'] = 'r'
table.align['Value'] = 'l'
table.add_row(['Company Name', account.get('companyName', '-')])
table.add_row(['Balance', utils.lookup(account, 'pendingInvoice', 'startingBalance')])
table.add_row(['Upcoming Invoice', utils.lookup(account, 'pendingInvoice', 'invoiceTotalAmount')])
table.add_row(['Image Templates', account.get('blockDeviceTemplateGroupCount', '-')])
table.add_row(['Dedicated Hosts', account.get('dedicatedHostCount', '-')])
table.add_row(['Hardware', account.get('hardwareCount', '-')])
table.add_row(['Virtual Guests', account.get('virtualGuestCount', '-')])
table.add_row(['Domains', account.get('domainCount', '-')])
table.add_row(['Network Storage Volumes', account.get('networkStorageCount', '-')])
table.add_row(['Open Tickets', account.get('openTicketCount', '-')])
table.add_row(['Network Vlans', account.get('networkVlanCount', '-')])
table.add_row(['Subnets', account.get('subnetCount', '-')])
table.add_row(['Users', account.get('userCount', '-')])
return table
7 changes: 7 additions & 0 deletions SoftLayer/CLI/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@

('call-api', 'SoftLayer.CLI.call_api:cli'),

('account', 'SoftLayer.CLI.account'),
('account:invoice-detail', 'SoftLayer.CLI.account.invoice_detail:cli'),
('account:invoices', 'SoftLayer.CLI.account.invoices:cli'),
('account:events', 'SoftLayer.CLI.account.events:cli'),
('account:event-detail', 'SoftLayer.CLI.account.event_detail:cli'),
('account:summary', 'SoftLayer.CLI.account.summary:cli'),

('virtual', 'SoftLayer.CLI.virt'),
('virtual:cancel', 'SoftLayer.CLI.virt.cancel:cli'),
('virtual:capture', 'SoftLayer.CLI.virt.capture:cli'),
Expand Down
24 changes: 24 additions & 0 deletions SoftLayer/fixtures/SoftLayer_Account.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,3 +662,27 @@
"name": "SPREAD"
}
}]

getInvoices = [
{
'id': 33816665,
'modifyDate': '2019-03-04T00:17:42-06:00',
'createDate': '2019-03-04T00:17:42-06:00',
'startingBalance': '129251.73',
'statusCode': 'OPEN',
'typeCode': 'RECURRING',
'itemCount': 3317,
'invoiceTotalAmount': '6230.66'
},
{
'id': 12345667,
'modifyDate': '2019-03-05T00:17:42-06:00',
'createDate': '2019-03-04T00:17:42-06:00',
'startingBalance': '129251.73',
'statusCode': 'OPEN',
'typeCode': 'RECURRING',
'itemCount': 12,
'invoiceTotalAmount': '6230.66',
'endingBalance': '12345.55'
}
]
23 changes: 23 additions & 0 deletions SoftLayer/fixtures/SoftLayer_Billing_Invoice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
getInvoiceTopLevelItems = [
{
'categoryCode': 'sov_sec_ip_addresses_priv',
'createDate': '2018-04-04T23:15:20-06:00',
'description': '64 Portable Private IP Addresses',
'id': 724951323,
'oneTimeAfterTaxAmount': '0',
'recurringAfterTaxAmount': '0',
'hostName': 'bleg',
'domainName': 'beh.com',
'category': {'name': 'Private (only) Secondary VLAN IP Addresses'},
'children': [
{
'id': 12345,
'category': {'name': 'Fake Child Category'},
'description': 'Blah',
'oneTimeAfterTaxAmount': 55.50,
'recurringAfterTaxAmount': 0.10
}
],
'location': {'name': 'fra02'}
}
]
31 changes: 31 additions & 0 deletions SoftLayer/fixtures/SoftLayer_Notification_Occurrence_Event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
getObject = {
'endDate': '2019-03-18T17:00:00-06:00',
'id': 1234,
'lastImpactedUserCount': 417756,
'modifyDate': '2019-03-12T15:32:48-06:00',
'recoveryTime': None,
'startDate': '2019-03-18T16:00:00-06:00',
'subject': 'Public Website Maintenance',
'summary': 'Blah Blah Blah',
'systemTicketId': 76057381,
'acknowledgedFlag': False,
'attachments': [],
'impactedResources': [{
'resourceType': 'Server',
'resourceTableId': 12345,
'hostname': 'test',
'privateIp': '10.0.0.1',
'filterLable': 'Server'
}],
'notificationOccurrenceEventType': {'keyName': 'PLANNED'},
'statusCode': {'keyName': 'PUBLISHED', 'name': 'Published'},
'updates': [{
'contents': 'More Blah Blah',
'createDate': '2019-03-12T13:07:22-06:00',
'endDate': None, 'startDate': '2019-03-12T13:07:22-06:00'
}]
}

getAllObjects = [getObject]

acknowledgeNotification = True
Loading