Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datacenter closure report #1592

Merged
merged 2 commits into from
Mar 7, 2022
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
125 changes: 125 additions & 0 deletions SoftLayer/CLI/report/dc_closures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""Report on Resources in closing datacenters"""
import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer import utils


@click.command(short_help="""Report on Resources in closing datacenters""")
@environment.pass_env
def cli(env):
"""Report on Resources in closing datacenters

Displays a list of Datacenters soon to be shutdown, and any resources on the account
in those locations
"""

closing_filter = {
'capabilities': {
'operation': 'in',
'options': [{'name': 'data', 'value': ['CLOSURE_ANNOUNCED']}]
},
'name': {
'operation': 'orderBy',
'options': [{'name': 'sort', 'value': ['DESC']}]
}
}
mask = """mask[name, datacenterLongName, frontendRouterId, capabilities, datacenterId, backendRouterId,
backendRouterName, frontendRouterName]"""
closing_pods = env.client.call('SoftLayer_Network_Pod', 'getAllObjects', mask=mask, filter=closing_filter)
# Find all VLANs in the POD that is going to close.
search = "_objectType:SoftLayer_Network_Vlan primaryRouter.hostname: \"{}\" || primaryRouter.hostname: \"{}\""
resource_mask = """mask[
resource(SoftLayer_Network_Vlan)[
id,fullyQualifiedName,name,note,vlanNumber,networkSpace,
virtualGuests[id,fullyQualifiedDomainName,billingItem[cancellationDate]],
hardware[id,fullyQualifiedDomainName,billingItem[cancellationDate]],
networkVlanFirewall[id,primaryIpAddress,billingItem[cancellationDate]],
privateNetworkGateways[id,name,networkSpace],
publicNetworkGateways[id,name,networkSpace]
]
]
"""
table_title = "Resources in closing datacenters"
resource_table = formatting.Table(["Id", "Name", "Public VLAN", "Private VLAN", "Type", "Datacenter",
"POD", "Cancellation Date"], title=table_title)
resource_table.align = 'l'
for pod in closing_pods:
resources = {'hardware': {}, 'virtual': {}, 'firewall': {}, 'gateway': {}}
vlans = env.client.call('SoftLayer_Search', 'advancedSearch',
search.format(pod.get('backendRouterName'), pod.get('frontendRouterName')),
iter=True, mask=resource_mask)
# Go through the vlans and coalate the resources into a data structure that is easy to print out
for vlan in vlans:
resources = process_vlan(vlan.get('resource', {}), resources)

# Go through each resource and add it to the table
for resource_type, resource_values in resources.items():
for resource_id, resource_object in resource_values.items():
resource_table.add_row([
resource_id,
resource_object['name'],
resource_object['vlan'].get('PUBLIC', '-'),
resource_object['vlan'].get('PRIVATE', '-'),
resource_type,
pod.get('datacenterLongName'),
pod.get('backendRouterName'),
resource_object['cancelDate']
])

env.fout(resource_table)


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

type_x = "virtual"
for obj_x in vlan.get('virtualGuests', {}):
existing = resources[type_x].get(obj_x.get('id'))
resources[type_x][obj_x['id']] = build_resource_object('fullyQualifiedDomainName', vlan, obj_x, existing)

type_x = 'hardware'
for obj_x in vlan.get('hardware', {}):
existing = resources[type_x].get(obj_x.get('id'))
resources[type_x][obj_x['id']] = build_resource_object('fullyQualifiedDomainName', vlan, obj_x, existing)

type_x = 'firewall'
for obj_x in vlan.get('networkVlanFirewall', {}):
existing = resources[type_x].get(obj_x.get('id'))
resources[type_x][obj_x['id']] = build_resource_object('primaryIpAddress', vlan, obj_x, existing)

type_x = 'gateway'
for obj_x in vlan.get('privateNetworkGateways', {}):
existing = resources[type_x].get(obj_x.get('id'))
resources[type_x][obj_x['id']] = build_resource_object('name', vlan, obj_x, existing)
for obj_x in vlan.get('publicNetworkGateways', {}):
existing = resources[type_x].get(obj_x.get('id'))
resources[type_x][obj_x['id']] = build_resource_object('name', vlan, obj_x, existing)

return resources


def build_resource_object(name_property, vlan, resource, entry):
"""builds out a resource object and puts the required values in the right place.

:param: name_property is what property to use as the name from resource
:param: vlan is the vlan object
:param: resource has the data we want
:param: entry is for any existing data
"""
new_entry = {
'id': resource.get('id'),
'name': resource.get(name_property),
'vlan': {vlan.get('networkSpace'): vlan.get('vlanNumber')},
'cancelDate': utils.clean_time(utils.lookup(resource, 'billingItem', 'cancellationDate'))
}
if entry:
entry['vlan'][vlan.get('networkSpace')] = vlan.get('vlanNumber')
else:
entry = new_entry

return entry
1 change: 1 addition & 0 deletions SoftLayer/CLI/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@

('report', 'SoftLayer.CLI.report'),
('report:bandwidth', 'SoftLayer.CLI.report.bandwidth:cli'),
('report:datacenter-closures', 'SoftLayer.CLI.report.dc_closures:cli'),

('autoscale', 'SoftLayer.CLI.autoscale'),
('autoscale:list', 'SoftLayer.CLI.autoscale.list:cli'),
Expand Down
12 changes: 11 additions & 1 deletion docs/cli/reports.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,14 @@ A list of datacenters, and how many servers, VSI, vlans, subnets and public_ips

.. click:: SoftLayer.CLI.report.bandwidth:cli
:prog: report bandwidth
:show-nested:
:show-nested:


.. click:: SoftLayer.CLI.report.dc_closures:cli
:prog: report datacenter-closures
:show-nested:

Displays some basic information about the Servers and other resources that are in Datacenters scheduled to be
decommissioned in the near future.
See `IBM Cloud Datacenter Consolidation <https://cloud.ibm.com/docs/get-support?topic=get-support-dc-closure>`_ for
more information
102 changes: 102 additions & 0 deletions tests/CLI/modules/report_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from SoftLayer import testing

import json
from unittest import mock as mock

from pprint import pprint as pp

Expand Down Expand Up @@ -295,3 +296,104 @@ def test_server_bandwidth_report(self):
300,
)
self.assertEqual(expected_args, call.args)

def test_dc_closure_report(self):
search_mock = self.set_mock('SoftLayer_Search', 'advancedSearch')
search_mock.side_effect = [_advanced_search(), [], [], []]
result = self.run_command(['report', 'datacenter-closures'])

self.assert_no_fail(result)
self.assert_called_with('SoftLayer_Network_Pod', 'getAllObjects', filter=mock.ANY, mask=mock.ANY)
self.assert_called_with('SoftLayer_Search', 'advancedSearch')
json_output = json.loads(result.output)
pp(json_output)
self.assertEqual(5, len(json_output))
self.assertEqual('bcr01a.ams01', json_output[0]['POD'])


def _advanced_search():
results = [{'matchedTerms': ['primaryRouter.hostname:|fcr01a.mex01|'],
'relevanceScore': '5.4415264',
'resource': {'fullyQualifiedName': 'mex01.fcr01.858',
'hardware': [{'billingItem': {'cancellationDate': None},
'fullyQualifiedDomainName': 'testpooling2.ibmtest.com',
'id': 1676221},
{'billingItem': {'cancellationDate': '2022-03-03T23:59:59-06:00'},
'fullyQualifiedDomainName': 'testpooling.ibmtest.com',
'id': 1534033}],
'id': 1133383,
'name': 'Mex-BM-Public',
'networkSpace': 'PUBLIC',
'privateNetworkGateways': [],
'publicNetworkGateways': [],
'virtualGuests': [],
'vlanNumber': 858},
'resourceType': 'SoftLayer_Network_Vlan'},
{'matchedTerms': ['primaryRouter.hostname:|fcr01a.mex01|'],
'relevanceScore': '5.4415264',
'resource': {'fullyQualifiedName': 'mex01.fcr01.1257',
'hardware': [],
'id': 2912280,
'networkSpace': 'PUBLIC',
'privateNetworkGateways': [],
'publicNetworkGateways': [],
'virtualGuests': [{'billingItem': {'cancellationDate': None},
'fullyQualifiedDomainName': 'imageTest.ibmtest.com',
'id': 127270182},
{'billingItem': {'cancellationDate': None},
'fullyQualifiedDomainName': 'test.deleteme.com',
'id': 106291032},
{'billingItem': {'cancellationDate': None},
'fullyQualifiedDomainName': 'testslack.test.com',
'id': 127889958}],
'vlanNumber': 1257},
'resourceType': 'SoftLayer_Network_Vlan'},
{'matchedTerms': ['primaryRouter.hostname:|bcr01a.mex01|'],
'relevanceScore': '5.003179',
'resource': {'fullyQualifiedName': 'mex01.bcr01.1472',
'hardware': [],
'id': 2912282,
'networkSpace': 'PRIVATE',
'privateNetworkGateways': [],
'publicNetworkGateways': [],
'virtualGuests': [{'billingItem': {'cancellationDate': None},
'fullyQualifiedDomainName': 'imageTest.ibmtest.com',
'id': 127270182},
{'billingItem': {'cancellationDate': None},
'fullyQualifiedDomainName': 'test.deleteme.com',
'id': 106291032},
{'billingItem': {'cancellationDate': None},
'fullyQualifiedDomainName': 'testslack.test.com',
'id': 127889958}],
'vlanNumber': 1472},
'resourceType': 'SoftLayer_Network_Vlan'},
{'matchedTerms': ['primaryRouter.hostname:|bcr01a.mex01|'],
'relevanceScore': '4.9517627',
'resource': {'fullyQualifiedName': 'mex01.bcr01.1664',
'hardware': [{'billingItem': {'cancellationDate': '2022-03-03T23:59:59-06:00'},
'fullyQualifiedDomainName': 'testpooling.ibmtest.com',
'id': 1534033},
{'billingItem': {'cancellationDate': None},
'fullyQualifiedDomainName': 'testpooling2.ibmtest.com',
'id': 1676221}],
'id': 3111644,
'name': 'testmex',
'networkSpace': 'PRIVATE',
'privateNetworkGateways': [],
'publicNetworkGateways': [],
'virtualGuests': [],
'vlanNumber': 1664},
'resourceType': 'SoftLayer_Network_Vlan'},
{'matchedTerms': ['primaryRouter.hostname:|bcr01a.mex01|'],
'relevanceScore': '4.9517627',
'resource': {'fullyQualifiedName': 'mex01.bcr01.1414',
'hardware': [],
'id': 2933662,
'name': 'test-for-trunks',
'networkSpace': 'PRIVATE',
'privateNetworkGateways': [],
'publicNetworkGateways': [],
'virtualGuests': [],
'vlanNumber': 1414},
'resourceType': 'SoftLayer_Network_Vlan'}]
return results