From 04ebe0853d1f59b8a18fcb8c8afffbc23dd0efc4 Mon Sep 17 00:00:00 2001
From: Stephen Finucane <stephenfin@redhat.com>
Date: Wed, 7 Aug 2024 13:17:05 +0100
Subject: [PATCH] compute: Add 'uuid' column to aggregate list

Change-Id: I15d4a2d5980c1ba3e00f7d1bd09f11d0f42564e1
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
Closes-bug: #2073542
---
 openstackclient/compute/v2/aggregate.py       |  52 ++++----
 .../tests/unit/compute/v2/test_aggregate.py   | 112 +++++++++++-------
 ...ate-list-uuid-column-808a0d051006a5ef.yaml |   5 +
 3 files changed, 104 insertions(+), 65 deletions(-)
 create mode 100644 releasenotes/notes/aggregate-list-uuid-column-808a0d051006a5ef.yaml

diff --git a/openstackclient/compute/v2/aggregate.py b/openstackclient/compute/v2/aggregate.py
index 967eec02cd..4cbce3c814 100644
--- a/openstackclient/compute/v2/aggregate.py
+++ b/openstackclient/compute/v2/aggregate.py
@@ -192,40 +192,46 @@ class ListAggregate(command.Lister):
 
         aggregates = list(compute_client.aggregates())
 
+        if sdk_utils.supports_microversion(compute_client, '2.41'):
+            column_headers = ("ID", "UUID")
+            columns = ("id", "uuid")
+        else:
+            column_headers = ("ID",)
+            columns = ("id",)
+
+        column_headers += (
+            "Name",
+            "Availability Zone",
+        )
+        columns += (
+            "name",
+            "availability_zone",
+        )
+
         if parsed_args.long:
             # Remove availability_zone from metadata because Nova doesn't
             for aggregate in aggregates:
                 if 'availability_zone' in aggregate.metadata:
                     aggregate.metadata.pop('availability_zone')
-            # This is the easiest way to change column headers
-            column_headers = (
-                "ID",
-                "Name",
-                "Availability Zone",
+
+            column_headers += (
                 "Properties",
                 "Hosts",
             )
-            columns = (
-                "ID",
-                "Name",
-                "Availability Zone",
-                "Metadata",
-                "Hosts",
-            )
-        else:
-            column_headers = columns = (
-                "ID",
-                "Name",
-                "Availability Zone",
+            columns += (
+                "metadata",
+                "hosts",
             )
 
-        data = (
-            utils.get_item_properties(
-                s, columns, formatters=_aggregate_formatters
-            )
-            for s in aggregates
+        return (
+            column_headers,
+            (
+                utils.get_item_properties(
+                    s, columns, formatters=_aggregate_formatters
+                )
+                for s in aggregates
+            ),
         )
-        return (column_headers, data)
 
 
 class RemoveAggregateHost(command.ShowOne):
diff --git a/openstackclient/tests/unit/compute/v2/test_aggregate.py b/openstackclient/tests/unit/compute/v2/test_aggregate.py
index 6cfe5bc79a..933344e8c4 100644
--- a/openstackclient/tests/unit/compute/v2/test_aggregate.py
+++ b/openstackclient/tests/unit/compute/v2/test_aggregate.py
@@ -227,44 +227,6 @@ class TestAggregateDelete(TestAggregate):
 
 
 class TestAggregateList(TestAggregate):
-    list_columns = (
-        "ID",
-        "Name",
-        "Availability Zone",
-    )
-
-    list_columns_long = (
-        "ID",
-        "Name",
-        "Availability Zone",
-        "Properties",
-        "Hosts",
-    )
-
-    list_data = (
-        (
-            TestAggregate.fake_ag.id,
-            TestAggregate.fake_ag.name,
-            TestAggregate.fake_ag.availability_zone,
-        ),
-    )
-
-    list_data_long = (
-        (
-            TestAggregate.fake_ag.id,
-            TestAggregate.fake_ag.name,
-            TestAggregate.fake_ag.availability_zone,
-            format_columns.DictColumn(
-                {
-                    key: value
-                    for key, value in TestAggregate.fake_ag.metadata.items()
-                    if key != 'availability_zone'
-                }
-            ),
-            format_columns.ListColumn(TestAggregate.fake_ag.hosts),
-        ),
-    )
-
     def setUp(self):
         super().setUp()
 
@@ -272,13 +234,54 @@ class TestAggregateList(TestAggregate):
         self.cmd = aggregate.ListAggregate(self.app, None)
 
     def test_aggregate_list(self):
+        self.set_compute_api_version('2.41')
+
         parsed_args = self.check_parser(self.cmd, [], [])
         columns, data = self.cmd.take_action(parsed_args)
 
-        self.assertEqual(self.list_columns, columns)
-        self.assertCountEqual(self.list_data, tuple(data))
+        expected_columns = (
+            "ID",
+            "UUID",
+            "Name",
+            "Availability Zone",
+        )
+        expected_data = (
+            (
+                self.fake_ag.id,
+                self.fake_ag.uuid,
+                self.fake_ag.name,
+                self.fake_ag.availability_zone,
+            ),
+        )
+
+        self.assertEqual(expected_columns, columns)
+        self.assertCountEqual(expected_data, tuple(data))
+
+    def test_aggregate_list_pre_v241(self):
+        self.set_compute_api_version('2.40')
+
+        parsed_args = self.check_parser(self.cmd, [], [])
+        columns, data = self.cmd.take_action(parsed_args)
+
+        expected_columns = (
+            "ID",
+            "Name",
+            "Availability Zone",
+        )
+        expected_data = (
+            (
+                self.fake_ag.id,
+                self.fake_ag.name,
+                self.fake_ag.availability_zone,
+            ),
+        )
+
+        self.assertEqual(expected_columns, columns)
+        self.assertCountEqual(expected_data, tuple(data))
 
     def test_aggregate_list_with_long(self):
+        self.set_compute_api_version('2.41')
+
         arglist = [
             '--long',
         ]
@@ -288,8 +291,33 @@ class TestAggregateList(TestAggregate):
         parsed_args = self.check_parser(self.cmd, arglist, vertifylist)
         columns, data = self.cmd.take_action(parsed_args)
 
-        self.assertEqual(self.list_columns_long, columns)
-        self.assertCountEqual(self.list_data_long, tuple(data))
+        expected_columns = (
+            "ID",
+            "UUID",
+            "Name",
+            "Availability Zone",
+            "Properties",
+            "Hosts",
+        )
+        expected_data = (
+            (
+                self.fake_ag.id,
+                self.fake_ag.uuid,
+                self.fake_ag.name,
+                self.fake_ag.availability_zone,
+                format_columns.DictColumn(
+                    {
+                        key: value
+                        for key, value in self.fake_ag.metadata.items()
+                        if key != 'availability_zone'
+                    }
+                ),
+                format_columns.ListColumn(self.fake_ag.hosts),
+            ),
+        )
+
+        self.assertEqual(expected_columns, columns)
+        self.assertCountEqual(expected_data, tuple(data))
 
 
 class TestAggregateRemoveHost(TestAggregate):
diff --git a/releasenotes/notes/aggregate-list-uuid-column-808a0d051006a5ef.yaml b/releasenotes/notes/aggregate-list-uuid-column-808a0d051006a5ef.yaml
new file mode 100644
index 0000000000..49e9e557d4
--- /dev/null
+++ b/releasenotes/notes/aggregate-list-uuid-column-808a0d051006a5ef.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    The ``aggregate list`` command will now include the UUIDs of the aggregates
+    when the cloud supports it.