Skip to content

Commit da2273e

Browse files
#1590 added docs and unit tests
1 parent 377387b commit da2273e

File tree

3 files changed

+151
-39
lines changed

3 files changed

+151
-39
lines changed
Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
1-
"""Metric Utilities"""
2-
import datetime
3-
import itertools
4-
import sys
5-
1+
"""Report on Resources in closing datacenters"""
62
import click
73

84
from SoftLayer.CLI import environment
95
from SoftLayer.CLI import formatting
106
from SoftLayer import utils
117

128

13-
from pprint import pprint as pp
14-
159
@click.command(short_help="""Report on Resources in closing datacenters""")
1610
@environment.pass_env
1711
def cli(env):
1812
"""Report on Resources in closing datacenters
1913
20-
Displays a list of Datacenters soon to be shutdown, and any resources on the account
14+
Displays a list of Datacenters soon to be shutdown, and any resources on the account
2115
in those locations
2216
"""
2317

@@ -33,7 +27,7 @@ def cli(env):
3327
}
3428
mask = """mask[name, datacenterLongName, frontendRouterId, capabilities, datacenterId, backendRouterId,
3529
backendRouterName, frontendRouterName]"""
36-
closing_pods = env.client.call('SoftLayer_Network_Pod', 'getAllObjects', mask=mask)
30+
closing_pods = env.client.call('SoftLayer_Network_Pod', 'getAllObjects', mask=mask, filter=closing_filter)
3731
# Find all VLANs in the POD that is going to close.
3832
search = "_objectType:SoftLayer_Network_Vlan primaryRouter.hostname: \"{}\" || primaryRouter.hostname: \"{}\""
3933
resource_mask = """mask[
@@ -54,16 +48,17 @@ def cli(env):
5448
for pod in closing_pods:
5549
resources = {'hardware': {}, 'virtual': {}, 'firewall': {}, 'gateway': {}}
5650
vlans = env.client.call('SoftLayer_Search', 'advancedSearch',
57-
search.format(pod.get('backendRouterName'), pod.get('frontendRouterName')),
58-
iter=True, mask=resource_mask)
51+
search.format(pod.get('backendRouterName'), pod.get('frontendRouterName')),
52+
iter=True, mask=resource_mask)
53+
# Go through the vlans and coalate the resources into a data structure that is easy to print out
5954
for vlan in vlans:
6055
resources = process_vlan(vlan.get('resource', {}), resources)
61-
62-
for resource_type in resources.keys():
63-
64-
for resource_object in resources[resource_type].values():
56+
57+
# Go through each resource and add it to the table
58+
for resource_type, resource_values in resources.items():
59+
for resource_id, resource_object in resource_values.items():
6560
resource_table.add_row([
66-
resource_object['id'],
61+
resource_id,
6762
resource_object['name'],
6863
resource_object['vlan'].get('PUBLIC', '-'),
6964
resource_object['vlan'].get('PRIVATE', '-'),
@@ -72,46 +67,51 @@ def cli(env):
7267
pod.get('backendRouterName'),
7368
resource_object['cancelDate']
7469
])
75-
70+
7671
env.fout(resource_table)
7772

7873

7974
# returns a Table Row for a given resource
8075
def process_vlan(vlan, resources=None):
76+
"""Takes in a vlan object and pulls out the needed resources"""
8177
if resources is None:
8278
resources = {'hardware': {}, 'virtual': {}, 'firewall': {}, 'gateway': {}}
8379

8480
type_x = "virtual"
85-
for x in vlan.get('virtualGuests', {}):
86-
existing = resources[type_x].get(x.get('id'))
87-
resources[type_x][x['id']] = build_resource_object('fullyQualifiedDomainName', vlan, x, existing)
81+
for obj_x in vlan.get('virtualGuests', {}):
82+
existing = resources[type_x].get(obj_x.get('id'))
83+
resources[type_x][obj_x['id']] = build_resource_object('fullyQualifiedDomainName', vlan, obj_x, existing)
8884

8985
type_x = 'hardware'
90-
for x in vlan.get('hardware', {}):
91-
existing = resources[type_x].get(x.get('id'))
92-
resources[type_x][x['id']] = build_resource_object('fullyQualifiedDomainName', vlan, x, existing)
86+
for obj_x in vlan.get('hardware', {}):
87+
existing = resources[type_x].get(obj_x.get('id'))
88+
resources[type_x][obj_x['id']] = build_resource_object('fullyQualifiedDomainName', vlan, obj_x, existing)
9389

9490
type_x = 'firewall'
95-
for x in vlan.get('networkVlanFirewall', {}):
96-
existing = resources[type_x].get(x.get('id'))
97-
resources[type_x][x['id']] = build_resource_object('primaryIpAddress', vlan, x, existing)
91+
for obj_x in vlan.get('networkVlanFirewall', {}):
92+
existing = resources[type_x].get(obj_x.get('id'))
93+
resources[type_x][obj_x['id']] = build_resource_object('primaryIpAddress', vlan, obj_x, existing)
9894

9995
type_x = 'gateway'
100-
for x in vlan.get('privateNetworkGateways', {}):
101-
existing = resources[type_x].get(x.get('id'))
102-
resources[type_x][x['id']] = build_resource_object('name', vlan, x, existing)
103-
for x in vlan.get('publicNetworkGateways', {}):
104-
existing = resources[type_x].get(x.get('id'))
105-
resources[type_x][x['id']] = build_resource_object('name', vlan, x, existing)
96+
for obj_x in vlan.get('privateNetworkGateways', {}):
97+
existing = resources[type_x].get(obj_x.get('id'))
98+
resources[type_x][obj_x['id']] = build_resource_object('name', vlan, obj_x, existing)
99+
for obj_x in vlan.get('publicNetworkGateways', {}):
100+
existing = resources[type_x].get(obj_x.get('id'))
101+
resources[type_x][obj_x['id']] = build_resource_object('name', vlan, obj_x, existing)
106102

107103
return resources
108104

109-
# name_property is what property to use as the name from resource
110-
# vlan is the vlan object
111-
# resource has the data we want
112-
# entry is for any existing data
105+
113106
def build_resource_object(name_property, vlan, resource, entry):
114-
new_entry = {
107+
"""builds out a resource object and puts the required values in the right place.
108+
109+
:param: name_property is what property to use as the name from resource
110+
:param: vlan is the vlan object
111+
:param: resource has the data we want
112+
:param: entry is for any existing data
113+
"""
114+
new_entry = {
115115
'id': resource.get('id'),
116116
'name': resource.get(name_property),
117117
'vlan': {vlan.get('networkSpace'): vlan.get('vlanNumber')},
@@ -122,4 +122,4 @@ def build_resource_object(name_property, vlan, resource, entry):
122122
else:
123123
entry = new_entry
124124

125-
return entry
125+
return entry

docs/cli/reports.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,14 @@ A list of datacenters, and how many servers, VSI, vlans, subnets and public_ips
1414

1515
.. click:: SoftLayer.CLI.report.bandwidth:cli
1616
:prog: report bandwidth
17-
:show-nested:
17+
:show-nested:
18+
19+
20+
.. click:: SoftLayer.CLI.report.dc_closures:cli
21+
:prog: report datacenter-closures
22+
:show-nested:
23+
24+
Displays some basic information about the Servers and other resources that are in Datacenters scheduled to be
25+
decommissioned in the near future.
26+
See `IBM Cloud Datacenter Consolidation <https://cloud.ibm.com/docs/get-support?topic=get-support-dc-closure>`_ for
27+
more information

tests/CLI/modules/report_tests.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from SoftLayer import testing
88

99
import json
10+
from unittest import mock as mock
1011

1112
from pprint import pprint as pp
1213

@@ -295,3 +296,104 @@ def test_server_bandwidth_report(self):
295296
300,
296297
)
297298
self.assertEqual(expected_args, call.args)
299+
300+
def test_dc_closure_report(self):
301+
search_mock = self.set_mock('SoftLayer_Search', 'advancedSearch')
302+
search_mock.side_effect = [_advanced_search(), [], [], []]
303+
result = self.run_command(['report', 'datacenter-closures'])
304+
305+
self.assert_no_fail(result)
306+
self.assert_called_with('SoftLayer_Network_Pod', 'getAllObjects', filter=mock.ANY, mask=mock.ANY)
307+
self.assert_called_with('SoftLayer_Search', 'advancedSearch')
308+
json_output = json.loads(result.output)
309+
pp(json_output)
310+
self.assertEqual(5, len(json_output))
311+
self.assertEqual('bcr01a.ams01', json_output[0]['POD'])
312+
313+
314+
def _advanced_search():
315+
results = [{'matchedTerms': ['primaryRouter.hostname:|fcr01a.mex01|'],
316+
'relevanceScore': '5.4415264',
317+
'resource': {'fullyQualifiedName': 'mex01.fcr01.858',
318+
'hardware': [{'billingItem': {'cancellationDate': None},
319+
'fullyQualifiedDomainName': 'testpooling2.ibmtest.com',
320+
'id': 1676221},
321+
{'billingItem': {'cancellationDate': '2022-03-03T23:59:59-06:00'},
322+
'fullyQualifiedDomainName': 'testpooling.ibmtest.com',
323+
'id': 1534033}],
324+
'id': 1133383,
325+
'name': 'Mex-BM-Public',
326+
'networkSpace': 'PUBLIC',
327+
'privateNetworkGateways': [],
328+
'publicNetworkGateways': [],
329+
'virtualGuests': [],
330+
'vlanNumber': 858},
331+
'resourceType': 'SoftLayer_Network_Vlan'},
332+
{'matchedTerms': ['primaryRouter.hostname:|fcr01a.mex01|'],
333+
'relevanceScore': '5.4415264',
334+
'resource': {'fullyQualifiedName': 'mex01.fcr01.1257',
335+
'hardware': [],
336+
'id': 2912280,
337+
'networkSpace': 'PUBLIC',
338+
'privateNetworkGateways': [],
339+
'publicNetworkGateways': [],
340+
'virtualGuests': [{'billingItem': {'cancellationDate': None},
341+
'fullyQualifiedDomainName': 'imageTest.ibmtest.com',
342+
'id': 127270182},
343+
{'billingItem': {'cancellationDate': None},
344+
'fullyQualifiedDomainName': 'test.deleteme.com',
345+
'id': 106291032},
346+
{'billingItem': {'cancellationDate': None},
347+
'fullyQualifiedDomainName': 'testslack.test.com',
348+
'id': 127889958}],
349+
'vlanNumber': 1257},
350+
'resourceType': 'SoftLayer_Network_Vlan'},
351+
{'matchedTerms': ['primaryRouter.hostname:|bcr01a.mex01|'],
352+
'relevanceScore': '5.003179',
353+
'resource': {'fullyQualifiedName': 'mex01.bcr01.1472',
354+
'hardware': [],
355+
'id': 2912282,
356+
'networkSpace': 'PRIVATE',
357+
'privateNetworkGateways': [],
358+
'publicNetworkGateways': [],
359+
'virtualGuests': [{'billingItem': {'cancellationDate': None},
360+
'fullyQualifiedDomainName': 'imageTest.ibmtest.com',
361+
'id': 127270182},
362+
{'billingItem': {'cancellationDate': None},
363+
'fullyQualifiedDomainName': 'test.deleteme.com',
364+
'id': 106291032},
365+
{'billingItem': {'cancellationDate': None},
366+
'fullyQualifiedDomainName': 'testslack.test.com',
367+
'id': 127889958}],
368+
'vlanNumber': 1472},
369+
'resourceType': 'SoftLayer_Network_Vlan'},
370+
{'matchedTerms': ['primaryRouter.hostname:|bcr01a.mex01|'],
371+
'relevanceScore': '4.9517627',
372+
'resource': {'fullyQualifiedName': 'mex01.bcr01.1664',
373+
'hardware': [{'billingItem': {'cancellationDate': '2022-03-03T23:59:59-06:00'},
374+
'fullyQualifiedDomainName': 'testpooling.ibmtest.com',
375+
'id': 1534033},
376+
{'billingItem': {'cancellationDate': None},
377+
'fullyQualifiedDomainName': 'testpooling2.ibmtest.com',
378+
'id': 1676221}],
379+
'id': 3111644,
380+
'name': 'testmex',
381+
'networkSpace': 'PRIVATE',
382+
'privateNetworkGateways': [],
383+
'publicNetworkGateways': [],
384+
'virtualGuests': [],
385+
'vlanNumber': 1664},
386+
'resourceType': 'SoftLayer_Network_Vlan'},
387+
{'matchedTerms': ['primaryRouter.hostname:|bcr01a.mex01|'],
388+
'relevanceScore': '4.9517627',
389+
'resource': {'fullyQualifiedName': 'mex01.bcr01.1414',
390+
'hardware': [],
391+
'id': 2933662,
392+
'name': 'test-for-trunks',
393+
'networkSpace': 'PRIVATE',
394+
'privateNetworkGateways': [],
395+
'publicNetworkGateways': [],
396+
'virtualGuests': [],
397+
'vlanNumber': 1414},
398+
'resourceType': 'SoftLayer_Network_Vlan'}]
399+
return results

0 commit comments

Comments
 (0)