Skip to content

Commit 5b429d7

Browse files
Merge pull request #1592 from allmightyspiff/issues1590
Datacenter closure report
2 parents eaae689 + da2273e commit 5b429d7

File tree

4 files changed

+239
-1
lines changed

4 files changed

+239
-1
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""Report on Resources in closing datacenters"""
2+
import click
3+
4+
from SoftLayer.CLI import environment
5+
from SoftLayer.CLI import formatting
6+
from SoftLayer import utils
7+
8+
9+
@click.command(short_help="""Report on Resources in closing datacenters""")
10+
@environment.pass_env
11+
def cli(env):
12+
"""Report on Resources in closing datacenters
13+
14+
Displays a list of Datacenters soon to be shutdown, and any resources on the account
15+
in those locations
16+
"""
17+
18+
closing_filter = {
19+
'capabilities': {
20+
'operation': 'in',
21+
'options': [{'name': 'data', 'value': ['CLOSURE_ANNOUNCED']}]
22+
},
23+
'name': {
24+
'operation': 'orderBy',
25+
'options': [{'name': 'sort', 'value': ['DESC']}]
26+
}
27+
}
28+
mask = """mask[name, datacenterLongName, frontendRouterId, capabilities, datacenterId, backendRouterId,
29+
backendRouterName, frontendRouterName]"""
30+
closing_pods = env.client.call('SoftLayer_Network_Pod', 'getAllObjects', mask=mask, filter=closing_filter)
31+
# Find all VLANs in the POD that is going to close.
32+
search = "_objectType:SoftLayer_Network_Vlan primaryRouter.hostname: \"{}\" || primaryRouter.hostname: \"{}\""
33+
resource_mask = """mask[
34+
resource(SoftLayer_Network_Vlan)[
35+
id,fullyQualifiedName,name,note,vlanNumber,networkSpace,
36+
virtualGuests[id,fullyQualifiedDomainName,billingItem[cancellationDate]],
37+
hardware[id,fullyQualifiedDomainName,billingItem[cancellationDate]],
38+
networkVlanFirewall[id,primaryIpAddress,billingItem[cancellationDate]],
39+
privateNetworkGateways[id,name,networkSpace],
40+
publicNetworkGateways[id,name,networkSpace]
41+
]
42+
]
43+
"""
44+
table_title = "Resources in closing datacenters"
45+
resource_table = formatting.Table(["Id", "Name", "Public VLAN", "Private VLAN", "Type", "Datacenter",
46+
"POD", "Cancellation Date"], title=table_title)
47+
resource_table.align = 'l'
48+
for pod in closing_pods:
49+
resources = {'hardware': {}, 'virtual': {}, 'firewall': {}, 'gateway': {}}
50+
vlans = env.client.call('SoftLayer_Search', 'advancedSearch',
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
54+
for vlan in vlans:
55+
resources = process_vlan(vlan.get('resource', {}), resources)
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():
60+
resource_table.add_row([
61+
resource_id,
62+
resource_object['name'],
63+
resource_object['vlan'].get('PUBLIC', '-'),
64+
resource_object['vlan'].get('PRIVATE', '-'),
65+
resource_type,
66+
pod.get('datacenterLongName'),
67+
pod.get('backendRouterName'),
68+
resource_object['cancelDate']
69+
])
70+
71+
env.fout(resource_table)
72+
73+
74+
# returns a Table Row for a given resource
75+
def process_vlan(vlan, resources=None):
76+
"""Takes in a vlan object and pulls out the needed resources"""
77+
if resources is None:
78+
resources = {'hardware': {}, 'virtual': {}, 'firewall': {}, 'gateway': {}}
79+
80+
type_x = "virtual"
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)
84+
85+
type_x = 'hardware'
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)
89+
90+
type_x = 'firewall'
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)
94+
95+
type_x = 'gateway'
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)
102+
103+
return resources
104+
105+
106+
def build_resource_object(name_property, vlan, resource, 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 = {
115+
'id': resource.get('id'),
116+
'name': resource.get(name_property),
117+
'vlan': {vlan.get('networkSpace'): vlan.get('vlanNumber')},
118+
'cancelDate': utils.clean_time(utils.lookup(resource, 'billingItem', 'cancellationDate'))
119+
}
120+
if entry:
121+
entry['vlan'][vlan.get('networkSpace')] = vlan.get('vlanNumber')
122+
else:
123+
entry = new_entry
124+
125+
return entry

SoftLayer/CLI/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@
366366

367367
('report', 'SoftLayer.CLI.report'),
368368
('report:bandwidth', 'SoftLayer.CLI.report.bandwidth:cli'),
369+
('report:datacenter-closures', 'SoftLayer.CLI.report.dc_closures:cli'),
369370

370371
('autoscale', 'SoftLayer.CLI.autoscale'),
371372
('autoscale:list', 'SoftLayer.CLI.autoscale.list:cli'),

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)