Skip to content

Commit 3bffd7a

Browse files
Merge branch 'master' into issue_1241
2 parents 788b7a0 + f4f403c commit 3bffd7a

38 files changed

+1090
-89
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: softlayer
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
matrix:
13+
python-version: [3.8]
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- name: Set up Python ${{ matrix.python-version }}
18+
uses: actions/setup-python@v1
19+
with:
20+
python-version: ${{ matrix.python-version }}
21+
- name: Install dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install -r tools/test-requirements.txt
25+
- name: Documentation Checks
26+
run: |
27+
python docCheck.py

CHANGELOG.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
# Change Log
22

3-
4-
## [5.8.5] - 2012-01-29
3+
## [5.8.7] - 2020-03-26
4+
https://github.com/softlayer/softlayer-python/compare/v5.8.5...v5.8.7
5+
6+
- #1222 Get load balancer (LBaaS) by name
7+
- #1221 Added version checker
8+
- #1227 Updated unit test suite for TravisCI to run properly
9+
- #1225 Add note about using multiple colon symbols not working when setting tags.
10+
- #1228 Support ordering [Dependent Duplicate Volumes](https://cloud.ibm.com/docs/BlockStorage?topic=BlockStorage-dependentduplicate)
11+
- #1233 Refactored File/Block managers to reduce duplicated code.
12+
- #1231 Added Refresh functions for Dependent Duplicate Volumes
13+
- #801 Added support for JSON styled parameters and object filters
14+
- #1234 Added ability to change which datacenters an image template was stored in
15+
16+
## [5.8.6] - Skipped
17+
18+
## [5.8.5] - 2020-01-29
519
https://github.com/softlayer/softlayer-python/compare/v5.8.4...v5.8.5
620

721
- #1195 Fixed an issue with `slcli vs dns-sync --ptr`. Added `slcli hw dns-sync`
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""Lists all active billing items on this account. See https://cloud.ibm.com/billing/billing-items"""
2+
# :license: MIT, see LICENSE for more details.
3+
import click
4+
5+
from SoftLayer.CLI import environment
6+
from SoftLayer.CLI import formatting
7+
from SoftLayer.managers.account import AccountManager as AccountManager
8+
from SoftLayer import utils
9+
10+
11+
@click.command()
12+
@environment.pass_env
13+
def cli(env):
14+
"""Lists billing items with some other useful information.
15+
16+
Similiar to https://cloud.ibm.com/billing/billing-items
17+
"""
18+
19+
manager = AccountManager(env.client)
20+
items = manager.get_account_billing_items()
21+
table = item_table(items)
22+
23+
env.fout(table)
24+
25+
26+
def item_table(items):
27+
"""Formats a table for billing items"""
28+
table = formatting.Table([
29+
"Id",
30+
"Create Date",
31+
"Cost",
32+
"Category Code",
33+
"Ordered By",
34+
"Description",
35+
"Notes"
36+
], title="Billing Items")
37+
table.align['Description'] = 'l'
38+
table.align['Category Code'] = 'l'
39+
for item in items:
40+
description = item.get('description')
41+
fqdn = "{}.{}".format(item.get('hostName', ''), item.get('domainName', ''))
42+
if fqdn != ".":
43+
description = fqdn
44+
user = utils.lookup(item, 'orderItem', 'order', 'userRecord')
45+
ordered_by = "IBM"
46+
create_date = utils.clean_time(item.get('createDate'), in_format='%Y-%m-%d', out_format='%Y-%m-%d')
47+
if user:
48+
# ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name'))
49+
ordered_by = user.get('displayName')
50+
51+
table.add_row([
52+
item.get('id'),
53+
create_date,
54+
item.get('nextInvoiceTotalRecurringAmount'),
55+
item.get('categoryCode'),
56+
ordered_by,
57+
utils.trim_to(description, 50),
58+
utils.trim_to(item.get('notes', 'None'), 40),
59+
])
60+
return table
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Cancels a billing item."""
2+
# :license: MIT, see LICENSE for more details.
3+
import click
4+
5+
from SoftLayer.CLI import environment
6+
from SoftLayer.managers.account import AccountManager as AccountManager
7+
8+
9+
@click.command()
10+
@click.argument('identifier')
11+
@environment.pass_env
12+
def cli(env, identifier):
13+
"""Cancels a billing item."""
14+
15+
manager = AccountManager(env.client)
16+
item = manager.cancel_item(identifier)
17+
18+
env.fout(item)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""Gets some details about a specific billing item."""
2+
# :license: MIT, see LICENSE for more details.
3+
import click
4+
5+
from SoftLayer.CLI import environment
6+
from SoftLayer.CLI import formatting
7+
from SoftLayer.managers.account import AccountManager as AccountManager
8+
from SoftLayer import utils
9+
10+
11+
@click.command()
12+
@click.argument('identifier')
13+
@environment.pass_env
14+
def cli(env, identifier):
15+
"""Gets detailed information about a billing item."""
16+
manager = AccountManager(env.client)
17+
item = manager.get_billing_item(identifier)
18+
env.fout(item_table(item))
19+
20+
21+
def item_table(item):
22+
"""Formats a table for billing items"""
23+
24+
date_format = '%Y-%m-%d'
25+
table = formatting.KeyValueTable(["Key", "Value"], title="{}".format(item.get('description', 'Billing Item')))
26+
table.add_row(['createDate', utils.clean_time(item.get('createDate'), date_format, date_format)])
27+
table.add_row(['cycleStartDate', utils.clean_time(item.get('cycleStartDate'), date_format, date_format)])
28+
table.add_row(['cancellationDate', utils.clean_time(item.get('cancellationDate'), date_format, date_format)])
29+
table.add_row(['description', item.get('description')])
30+
fqdn = "{}.{}".format(item.get('hostName'), item.get('domain'))
31+
if fqdn != ".":
32+
table.add_row(['FQDN', fqdn])
33+
34+
if item.get('hourlyFlag', False):
35+
table.add_row(['hourlyRecurringFee', item.get('hourlyRecurringFee')])
36+
table.add_row(['hoursUsed', item.get('hoursUsed')])
37+
table.add_row(['currentHourlyCharge', item.get('currentHourlyCharge')])
38+
else:
39+
table.add_row(['recurringFee', item.get('recurringFee')])
40+
41+
ordered_by = "IBM"
42+
user = utils.lookup(item, 'orderItem', 'order', 'userRecord')
43+
if user:
44+
ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name'))
45+
table.add_row(['Ordered By', ordered_by])
46+
table.add_row(['Notes', item.get('notes')])
47+
table.add_row(['Location', utils.lookup(item, 'location', 'name')])
48+
if item.get('children'):
49+
for child in item.get('children'):
50+
table.add_row([child.get('categoryCode'), child.get('description')])
51+
52+
return table

SoftLayer/CLI/hardware/billing.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""Get billing for a hardware device."""
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.CLI import helpers
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 billing for a hardware device."""
18+
hardware = SoftLayer.HardwareManager(env.client)
19+
20+
hardware_id = helpers.resolve_id(hardware.resolve_ids, identifier, 'hardware')
21+
result = hardware.get_hardware(hardware_id)
22+
table = formatting.KeyValueTable(['name', 'value'])
23+
table.align['name'] = 'r'
24+
table.align['value'] = 'l'
25+
26+
table.add_row(['Id', identifier])
27+
28+
table.add_row(['Billing Item Id', utils.lookup(result, 'billingItem', 'id')])
29+
table.add_row(['Recurring Fee', utils.lookup(result, 'billingItem', 'recurringFee')])
30+
table.add_row(['Total', utils.lookup(result, 'billingItem', 'nextInvoiceTotalRecurringAmount')])
31+
table.add_row(['Provision Date', utils.lookup(result, 'billingItem', 'provisionDate')])
32+
33+
price_table = formatting.Table(['Item', 'Recurring Price'])
34+
for item in utils.lookup(result, 'billingItem', 'children') or []:
35+
price_table.add_row([item['description'], item['nextInvoiceTotalRecurringAmount']])
36+
37+
table.add_row(['prices', price_table])
38+
env.fout(table)

SoftLayer/CLI/routes.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@
1717
('account:events', 'SoftLayer.CLI.account.events:cli'),
1818
('account:event-detail', 'SoftLayer.CLI.account.event_detail:cli'),
1919
('account:summary', 'SoftLayer.CLI.account.summary:cli'),
20+
('account:billing-items', 'SoftLayer.CLI.account.billing_items:cli'),
21+
('account:item-detail', 'SoftLayer.CLI.account.item_detail:cli'),
22+
('account:cancel-item', 'SoftLayer.CLI.account.cancel_item:cli'),
2023

2124
('virtual', 'SoftLayer.CLI.virt'),
2225
('virtual:bandwidth', 'SoftLayer.CLI.virt.bandwidth:cli'),
26+
('virtual:billing', 'SoftLayer.CLI.virt.billing:cli'),
2327
('virtual:cancel', 'SoftLayer.CLI.virt.cancel:cli'),
2428
('virtual:capture', 'SoftLayer.CLI.virt.capture:cli'),
2529
('virtual:create', 'SoftLayer.CLI.virt.create:cli'),
@@ -192,11 +196,9 @@
192196
('loadbal:order-options', 'SoftLayer.CLI.loadbal.order:order_options'),
193197
('loadbal:cancel', 'SoftLayer.CLI.loadbal.order:cancel'),
194198

195-
196199
('loadbal:ns-detail', 'SoftLayer.CLI.loadbal.ns_detail:cli'),
197200
('loadbal:ns-list', 'SoftLayer.CLI.loadbal.ns_list:cli'),
198201

199-
200202
('metadata', 'SoftLayer.CLI.metadata:cli'),
201203

202204
('nas', 'SoftLayer.CLI.nas'),
@@ -232,6 +234,7 @@
232234
('hardware:create', 'SoftLayer.CLI.hardware.create:cli'),
233235
('hardware:create-options', 'SoftLayer.CLI.hardware.create_options:cli'),
234236
('hardware:detail', 'SoftLayer.CLI.hardware.detail:cli'),
237+
('hardware:billing', 'SoftLayer.CLI.hardware.billing:cli'),
235238
('hardware:edit', 'SoftLayer.CLI.hardware.edit:cli'),
236239
('hardware:list', 'SoftLayer.CLI.hardware.list:cli'),
237240
('hardware:power-cycle', 'SoftLayer.CLI.hardware.power:power_cycle'),
@@ -306,6 +309,8 @@
306309
('user:edit-details', 'SoftLayer.CLI.user.edit_details:cli'),
307310
('user:create', 'SoftLayer.CLI.user.create:cli'),
308311
('user:delete', 'SoftLayer.CLI.user.delete:cli'),
312+
('user:vpn-manual', 'SoftLayer.CLI.user.vpn_manual:cli'),
313+
('user:vpn-subnet', 'SoftLayer.CLI.user.vpn_subnet:cli'),
309314

310315
('vlan', 'SoftLayer.CLI.vlan'),
311316
('vlan:detail', 'SoftLayer.CLI.vlan.detail:cli'),

SoftLayer/CLI/user/vpn_manual.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Enable or Disable vpn subnets manual config for a user."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
5+
import click
6+
7+
import SoftLayer
8+
from SoftLayer.CLI import environment
9+
from SoftLayer.CLI import helpers
10+
11+
12+
@click.command()
13+
@click.argument('user')
14+
@click.option('--enable/--disable', default=True,
15+
help="Enable or disable vpn subnets manual config.")
16+
@environment.pass_env
17+
def cli(env, user, enable):
18+
"""Enable or disable user vpn subnets manual config"""
19+
mgr = SoftLayer.UserManager(env.client)
20+
user_id = helpers.resolve_id(mgr.resolve_ids, user, 'username')
21+
22+
result = mgr.vpn_manual(user_id, enable)
23+
message = "{} vpn manual config {}".format(user, 'enable' if enable else 'disable')
24+
25+
if result:
26+
click.secho(message, fg='green')
27+
else:
28+
click.secho("Failed to update {}".format(user), fg='red')

SoftLayer/CLI/user/vpn_subnet.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Add or remove specific subnets access for a user."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
5+
import click
6+
7+
import SoftLayer
8+
from SoftLayer.CLI import environment
9+
from SoftLayer.CLI import helpers
10+
11+
12+
@click.command()
13+
@click.option('--add/--remove', default=True,
14+
help="Add or remove access to subnets.")
15+
@click.argument('user', nargs=1, required=True)
16+
@click.argument('subnet', nargs=-1, required=True)
17+
@environment.pass_env
18+
def cli(env, user, add, subnet):
19+
"""Add or remove subnets access for a user."""
20+
mgr = SoftLayer.UserManager(env.client)
21+
user_id = helpers.resolve_id(mgr.resolve_ids, user, 'username')
22+
if add:
23+
result = mgr.vpn_subnet_add(user_id, subnet)
24+
else:
25+
result = mgr.vpn_subnet_remove(user_id, subnet)
26+
27+
if result:
28+
click.secho("%s updated successfully" % (user), fg='green')
29+
else:
30+
click.secho("Failed to update %s" % (user), fg='red')

SoftLayer/CLI/virt/billing.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""Get billing for a virtual device."""
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.CLI import helpers
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 billing for a virtual device."""
18+
virtual = SoftLayer.VSManager(env.client)
19+
20+
virtual_id = helpers.resolve_id(virtual.resolve_ids, identifier, 'virtual')
21+
result = virtual.get_instance(virtual_id)
22+
table = formatting.KeyValueTable(['name', 'value'])
23+
table.align['name'] = 'r'
24+
table.align['value'] = 'l'
25+
26+
table.add_row(['Id', identifier])
27+
28+
table.add_row(['Billing Item Id', utils.lookup(result, 'billingItem', 'id')])
29+
table.add_row(['Recurring Fee', utils.lookup(result, 'billingItem', 'recurringFee')])
30+
table.add_row(['Total', utils.lookup(result, 'billingItem', 'nextInvoiceTotalRecurringAmount')])
31+
table.add_row(['Provision Date', utils.lookup(result, 'billingItem', 'provisionDate')])
32+
33+
price_table = formatting.Table(['Recurring Price'])
34+
for item in utils.lookup(result, 'billingItem', 'children') or []:
35+
price_table.add_row([item['nextInvoiceTotalRecurringAmount']])
36+
37+
table.add_row(['prices', price_table])
38+
env.fout(table)

0 commit comments

Comments
 (0)