Repository: softlayer/softlayer-python
Pull request #1264 (2020-04-28 16:26:16)

Add Account planned, unplanned and announcement events.
Add Account planned, unplanned and announcement events https://github.com/softlayer/softlayer-python/issues/1260.


Patch:
diff --git a/SoftLayer/CLI/account/events.py b/SoftLayer/CLI/account/events.py
index 5cc91144..b5d8960c 100644
--- a/SoftLayer/CLI/account/events.py
+++ b/SoftLayer/CLI/account/events.py
@@ -16,39 +16,90 @@ def cli(env, ack_all):
     """Summary and acknowledgement of upcoming and ongoing maintenance events"""
 
     manager = AccountManager(env.client)
-    events = manager.get_upcoming_events()
+    planned_events = manager.get_upcoming_events("PLANNED")
+    unplanned_events = manager.get_upcoming_events("UNPLANNED_INCIDENT")
+    announcement_events = manager.get_upcoming_events("ANNOUNCEMENT")
 
+    add_ack_flag(planned_events, manager, ack_all)
+    env.fout(planned_event_table(planned_events))
+
+    add_ack_flag(unplanned_events, manager, ack_all)
+    env.fout(unplanned_event_table(unplanned_events))
+
+    add_ack_flag(announcement_events, manager, ack_all)
+    env.fout(announcement_event_table(announcement_events))
+
+
+def add_ack_flag(events, manager, ack_all):
+    """Add acknowledgedFlag to the event"""
     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):
+def planned_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'
+    planned_table = formatting.Table(['Event Data', 'Id', 'Event ID', 'Subject', 'Status', 'Items', 'Start Date',
+                                      'End Date', 'Acknowledged', 'Updates'], title="Planned Events")
+    planned_table.align['Subject'] = 'l'
+    planned_table.align['Impacted Resources'] = 'l'
     for event in events:
-        table.add_row([
+        planned_table.add_row([
+            utils.clean_time(event.get('startDate')),
             event.get('id'),
+            event.get('systemTicketId'),
+            # Some subjects can have \r\n for some reason.
+            utils.clean_splitlines(event.get('subject')),
+            utils.lookup(event, 'statusCode', 'name'),
+            event.get('impactedResourceCount'),
             utils.clean_time(event.get('startDate')),
             utils.clean_time(event.get('endDate')),
+            event.get('acknowledgedFlag'),
+            event.get('updateCount'),
+
+        ])
+    return planned_table
+
+
+def unplanned_event_table(events):
+    """Formats a table for events"""
+    unplanned_table = formatting.Table(['Id', 'Event ID', 'Subject', 'Status', 'Items', 'Start Date',
+                                        'Last Updated', 'Acknowledged', 'Updates'], title="Unplanned Events")
+    unplanned_table.align['Subject'] = 'l'
+    unplanned_table.align['Impacted Resources'] = 'l'
+    for event in events:
+        print(event.get('modifyDate'))
+        unplanned_table.add_row([
+            event.get('id'),
+            event.get('systemTicketId'),
             # Some subjects can have \r\n for some reason.
             utils.clean_splitlines(event.get('subject')),
             utils.lookup(event, 'statusCode', 'name'),
+            event.get('impactedResourceCount'),
+            utils.clean_time(event.get('startDate')),
+            utils.clean_time(event.get('modifyDate')),
             event.get('acknowledgedFlag'),
             event.get('updateCount'),
-            event.get('impactedResourceCount')
         ])
-    return table
+    return unplanned_table
+
+
+def announcement_event_table(events):
+    """Formats a table for events"""
+    announcement_table = formatting.Table(
+        ['Id', 'Event ID', 'Subject', 'Status', 'Items', 'Acknowledged', 'Updates'], title="Announcement Events")
+    announcement_table.align['Subject'] = 'l'
+    announcement_table.align['Impacted Resources'] = 'l'
+    for event in events:
+        announcement_table.add_row([
+            event.get('id'),
+            event.get('systemTicketId'),
+            # Some subjects can have \r\n for some reason.
+            utils.clean_splitlines(event.get('subject')),
+            utils.lookup(event, 'statusCode', 'name'),
+            event.get('impactedResourceCount'),
+            event.get('acknowledgedFlag'),
+            event.get('updateCount')
+        ])
+    return announcement_table
diff --git a/SoftLayer/CLI/formatting.py b/SoftLayer/CLI/formatting.py
index b88fe056..b591f814 100644
--- a/SoftLayer/CLI/formatting.py
+++ b/SoftLayer/CLI/formatting.py
@@ -416,13 +416,11 @@ def _format_list(result):
     if not result:
         return result
 
-    new_result = [item for item in result if item]
-
-    if isinstance(new_result[0], dict):
-        return _format_list_objects(new_result)
+    if isinstance(result[0], dict):
+        return _format_list_objects(result)
 
     table = Table(['value'])
-    for item in new_result:
+    for item in result:
         table.add_row([iter_to_table(item)])
     return table
 
@@ -432,15 +430,12 @@ def _format_list_objects(result):
 
     all_keys = set()
     for item in result:
-        if isinstance(item, dict):
-            all_keys = all_keys.union(item.keys())
+        all_keys = all_keys.union(item.keys())
 
     all_keys = sorted(all_keys)
     table = Table(all_keys)
 
     for item in result:
-        if not item:
-            continue
         values = []
         for key in all_keys:
             value = iter_to_table(item.get(key))
diff --git a/SoftLayer/managers/account.py b/SoftLayer/managers/account.py
index 4269bc7a..56f951c2 100644
--- a/SoftLayer/managers/account.py
+++ b/SoftLayer/managers/account.py
@@ -47,25 +47,61 @@ def get_summary(self):
         """
         return self.client.call('Account', 'getObject', mask=mask)
 
-    def get_upcoming_events(self):
-        """Retreives a list of Notification_Occurrence_Events that have not ended yet
+    def get_upcoming_events(self, event_type):
+        """Retrieves a list of Notification_Occurrence_Events that have not ended yet
 
+        :param: String event_type: notification event type.
         :return: SoftLayer_Notification_Occurrence_Event
         """
-        mask = "mask[id, subject, startDate, endDate, statusCode, acknowledgedFlag, impactedResourceCount, updateCount]"
+        mask = "mask[id, subject, startDate, endDate, modifyDate, statusCode, acknowledgedFlag, " \
+               "impactedResourceCount, updateCount, systemTicketId, notificationOccurrenceEventType[keyName]]"
+
         _filter = {
-            'endDate': {
-                'operation': '> sysdate'
-            },
-            'startDate': {
+            'notificationOccurrenceEventType': {
+                'keyName': {
+                    'operation': event_type
+                }
+            }
+        }
+
+        self.add_event_filter(_filter, event_type)
+
+        return self.client.call('Notification_Occurrence_Event', 'getAllObjects', filter=_filter, mask=mask, iter=True)
+
+    @staticmethod
+    def add_event_filter(_filter, event_type):
+        """Add data to the object filter.
+
+        :param: _filter: event filter.
+        :param: string event_type: event type.
+        """
+        if event_type == 'PLANNED':
+            _filter['endDate'] = {
+                'operation': '> sysdate - 2'
+            }
+            _filter['startDate'] = {
                 'operation': 'orderBy',
                 'options': [{
                     'name': 'sort',
-                    'value': ['ASC']
+                    'value': ['DESC']
                 }]
             }
-        }
-        return self.client.call('Notification_Occurrence_Event', 'getAllObjects', filter=_filter, mask=mask, iter=True)
+
+        if event_type == 'UNPLANNED_INCIDENT':
+            _filter['modifyDate'] = {
+                'operation': '> sysdate - 2'
+            }
+
+        if event_type == 'ANNOUNCEMENT':
+            _filter['statusCode'] = {
+                'keyName': {
+                    'operation': 'in',
+                    'options': [{
+                        'name': 'data',
+                        'value': ['PUBLISHED']
+                    }]
+                }
+            }
 
     def ack_event(self, event_id):
         """Acknowledge an event. This mostly prevents it from appearing as a notification in the control portal.


Test patch:
diff --git a/tests/CLI/helper_tests.py b/tests/CLI/helper_tests.py
index c22278c3..5c6656c2 100644
--- a/tests/CLI/helper_tests.py
+++ b/tests/CLI/helper_tests.py
@@ -439,10 +439,11 @@ def test_template_options(self):
 class TestExportToTemplate(testing.TestCase):
 
     def test_export_to_template(self):
-        if (sys.platform.startswith("win")):
+        if(sys.platform.startswith("win")):
             self.skipTest("Test doesn't work in Windows")
         # Tempfile creation is wonky on windows
         with tempfile.NamedTemporaryFile() as tmp:
+
             template.export_to_template(tmp.name, {
                 'os': None,
                 'datacenter': 'ams01',
@@ -486,9 +487,3 @@ def test_format_api_list_non_objects(self):
         self.assertIsInstance(result, formatting.Table)
         self.assertEqual(result.columns, ['value'])
         self.assertEqual(result.rows, [['a'], ['b'], ['c']])
-
-    def test_format_api_list_with_none_value(self):
-        result = formatting._format_list([{'key': [None, 'value']}, None])
-
-        self.assertIsInstance(result, formatting.Table)
-        self.assertEqual(result.columns, ['key'])
diff --git a/tests/managers/account_tests.py b/tests/managers/account_tests.py
index 513aa44f..b47ec6ab 100644
--- a/tests/managers/account_tests.py
+++ b/tests/managers/account_tests.py
@@ -18,10 +18,51 @@ def test_get_summary(self):
         self.manager.get_summary()
         self.assert_called_with('SoftLayer_Account', 'getObject')
 
-    def test_get_upcoming_events(self):
-        self.manager.get_upcoming_events()
+    def test_get_planned_upcoming_events(self):
+        self.manager.get_upcoming_events("PLANNED")
         self.assert_called_with(self.SLNOE, 'getAllObjects')
 
+    def test_get_unplanned_upcoming_events(self):
+        self.manager.get_upcoming_events("UNPLANNED_INCIDENT")
+        self.assert_called_with(self.SLNOE, 'getAllObjects')
+
+    def test_get_announcement_upcoming_events(self):
+        self.manager.get_upcoming_events("ANNOUNCEMENT")
+        self.assert_called_with(self.SLNOE, 'getAllObjects')
+
+    def test_add_planned_event_filter(self):
+        event_type = 'PLANNED'
+        _filter = {
+            'notificationOccurrenceEventType': {
+                'keyName': {
+                    'operation': event_type
+                }
+            }
+        }
+        self.manager.add_event_filter(_filter, event_type)
+
+    def test_add_unplanned_event_filter(self):
+        event_type = 'UNPLANNED_INCIDENT'
+        _filter = {
+            'notificationOccurrenceEventType': {
+                'keyName': {
+                    'operation': event_type
+                }
+            }
+        }
+        self.manager.add_event_filter(_filter, event_type)
+
+    def test_add_announcement_event_filter(self):
+        event_type = 'ANNOUNCEMENT'
+        _filter = {
+            'notificationOccurrenceEventType': {
+                'keyName': {
+                    'operation': event_type
+                }
+            }
+        }
+        self.manager.add_event_filter(_filter, event_type)
+
     def test_ack_event(self):
         self.manager.ack_event(12345)
         self.assert_called_with(self.SLNOE, 'acknowledgeNotification', identifier=12345)