From 4698f1f64253ae33b6b9a223a522aa3a2fab3d25 Mon Sep 17 00:00:00 2001
From: Tim Burke <tim.burke@gmail.com>
Date: Wed, 6 Jul 2022 22:50:45 -0700
Subject: [PATCH] shell: Print friendly account byte quotas

This gives us an opportunity to give it more human-friendly units
when doing a `stat --lh`.

Change-Id: I01c02ffcba94d89ae03f87c1c64afca4d491a895
---
 swiftclient/command_helpers.py | 17 +++++++++++++++--
 test/unit/test_shell.py        | 28 ++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/swiftclient/command_helpers.py b/swiftclient/command_helpers.py
index f37040f8..20310886 100644
--- a/swiftclient/command_helpers.py
+++ b/swiftclient/command_helpers.py
@@ -15,6 +15,7 @@ from swiftclient.utils import prt_bytes, split_request_headers
 
 
 POLICY_HEADER_PREFIX = 'x-account-storage-policy-'
+PER_POLICY_QUOTA_HEADER_PREFIX = 'x-account-quota-bytes-policy-'
 
 
 def stat_account(conn, options):
@@ -38,6 +39,10 @@ def stat_account(conn, options):
         ('Objects', object_count),
         ('Bytes', bytes_used),
     ])
+    if headers.get('x-account-meta-quota-bytes'):
+        quota_bytes = prt_bytes(headers.get('x-account-meta-quota-bytes'),
+                                options['human']).lstrip()
+        items.append(('Quota Bytes', quota_bytes))
 
     policies = set()
     for header_key, header_value in headers.items():
@@ -68,6 +73,10 @@ def stat_account(conn, options):
                  options['human']
              ).lstrip()),
         ))
+        policy_quota = headers.get(PER_POLICY_QUOTA_HEADER_PREFIX + policy)
+        if policy_quota:
+            items.append(('Quota Bytes for policy "' + policy + '"',
+                          prt_bytes(policy_quota, options['human']).lstrip()))
 
     return items, headers
 
@@ -75,7 +84,10 @@ def stat_account(conn, options):
 def print_account_stats(items, headers, output_manager):
     exclude_policy_headers = []
     for header_key, header_value in headers.items():
-        if header_key.lower().startswith(POLICY_HEADER_PREFIX):
+        if header_key.lower().startswith((
+                POLICY_HEADER_PREFIX,
+                PER_POLICY_QUOTA_HEADER_PREFIX,
+        )):
             exclude_policy_headers.append(header_key)
 
     items.extend(headers_to_items(
@@ -84,7 +96,8 @@ def print_account_stats(items, headers, output_manager):
             'content-length', 'date',
             'x-account-container-count',
             'x-account-object-count',
-            'x-account-bytes-used'] + exclude_policy_headers)))
+            'x-account-bytes-used',
+            'x-account-meta-quota-bytes'] + exclude_policy_headers)))
 
     # line up the items nicely
     offset = max(len(item) for item, value in items)
diff --git a/test/unit/test_shell.py b/test/unit/test_shell.py
index eedbc4be..3575ee22 100644
--- a/test/unit/test_shell.py
+++ b/test/unit/test_shell.py
@@ -159,6 +159,34 @@ class TestShell(unittest.TestCase):
                              '   Objects: 2\n'
                              '     Bytes: 3\n')
 
+    @mock.patch('swiftclient.service.Connection')
+    def test_stat_account_with_quota(self, connection):
+        argv = ["", "stat", "--lh"]
+        return_headers = {
+            'x-account-container-count': '2000',
+            'x-account-object-count': '3000',
+            'x-account-bytes-used': '4000000',
+            'x-account-storage-policy-gold-bytes-used': '4000',
+            'x-account-meta-quota-bytes': '5000000',
+            'x-account-quota-bytes-policy-gold': '5000',
+            'content-length': 0,
+            'date': ''}
+        connection.return_value.head_account.return_value = return_headers
+        connection.return_value.url = 'http://127.0.0.1/v1/AUTH_account'
+        with CaptureOutput() as output:
+            swiftclient.shell.main(argv)
+
+            self.assertEqual(
+                output.out,
+                '                      Account: AUTH_account\n'
+                '                   Containers: 2000\n'
+                '                      Objects: 2.9K\n'
+                '                        Bytes: 3.8M\n'
+                '                  Quota Bytes: 4.8M\n'
+                '     Objects in policy "gold": 0\n'
+                '       Bytes in policy "gold": 3.9K\n'
+                'Quota Bytes for policy "gold": 4.9K\n')
+
     @mock.patch('swiftclient.service.Connection')
     def test_stat_account_with_headers(self, connection):
         argv = ["", "stat", "-H", "Skip-Middleware: Test"]