Browse Source

Raise specific errors during create configdocs

Currently shipyard raises same error for 2 scenarios-
    - Collection empty or resulted in no revision (Error code - 400)
    - Buffer is either not empty or the collection already
      exists in buffer (Error code - 409)

This PS enables shipyard to raise specific errors for the above
given scenarios which would equip consumers of Shipyard API client
to handle the exception gracefully.

Change-Id: I10860ca60f4fde4088cbb146283a2db305418320
changes/78/624178/7
Nishant Kumar 7 months ago
parent
commit
30950202b3

+ 6
- 0
src/bin/shipyard_client/shipyard_client/api_client/base_client.py View File

@@ -23,6 +23,8 @@ import requests
23 23
 from shipyard_client.api_client.client_error import ClientError
24 24
 from shipyard_client.api_client.client_error import UnauthenticatedClientError
25 25
 from shipyard_client.api_client.client_error import UnauthorizedClientError
26
+from shipyard_client.api_client.client_error import ShipyardBufferError
27
+from shipyard_client.api_client.client_error import InvalidCollectionError
26 28
 
27 29
 
28 30
 class BaseClient(metaclass=abc.ABCMeta):
@@ -99,6 +101,10 @@ class BaseClient(metaclass=abc.ABCMeta):
99 101
                 raise UnauthenticatedClientError()
100 102
             if response.status_code == 403:
101 103
                 raise UnauthorizedClientError()
104
+            if response.status_code == 400:
105
+                raise InvalidCollectionError(response.text)
106
+            if response.status_code == 409:
107
+                raise ShipyardBufferError(response.text)
102 108
             return response
103 109
         except requests.exceptions.RequestException as e:
104 110
             self.error(str(e))

+ 8
- 0
src/bin/shipyard_client/shipyard_client/api_client/client_error.py View File

@@ -23,3 +23,11 @@ class UnauthorizedClientError(ClientError):
23 23
 
24 24
 class UnauthenticatedClientError(ClientError):
25 25
     pass
26
+
27
+
28
+class ShipyardBufferError(ClientError):
29
+    pass
30
+
31
+
32
+class InvalidCollectionError(ClientError):
33
+    pass

+ 6
- 0
src/bin/shipyard_client/shipyard_client/cli/action.py View File

@@ -19,6 +19,8 @@ import logging
19 19
 from shipyard_client.api_client.client_error import ClientError
20 20
 from shipyard_client.api_client.client_error import UnauthenticatedClientError
21 21
 from shipyard_client.api_client.client_error import UnauthorizedClientError
22
+from shipyard_client.api_client.client_error import ShipyardBufferError
23
+from shipyard_client.api_client.client_error import InvalidCollectionError
22 24
 from shipyard_client.api_client.shipyard_api_client import ShipyardClient
23 25
 from shipyard_client.api_client.shipyardclient_context import \
24 26
     ShipyardClientContext
@@ -134,6 +136,10 @@ class CliAction(AbstractCliAction):
134 136
                              "Check credential values")
135 137
         except UnauthorizedClientError:
136 138
             self.resp_txt = "Error: Unauthorized to perform this action."
139
+        except ShipyardBufferError as ex:
140
+            self.resp_txt = format_utils.cli_format_exception_handler(ex)
141
+        except InvalidCollectionError as ex:
142
+            self.resp_txt = format_utils.cli_format_exception_handler(ex)
137 143
         except ClientError as ex:
138 144
             self.resp_txt = "Error: Client Error: {}".format(str(ex))
139 145
         except Exception as ex:

+ 57
- 37
src/bin/shipyard_client/shipyard_client/cli/format_utils.py View File

@@ -47,11 +47,7 @@ def cli_format_status_handler(response, is_error=False):
47 47
         standard error format
48 48
     :is_error: toggles the use of status or error verbiage
49 49
     :returns: a generically formatted error response formulated from the
50
-        client_repsonse.  The response will be in the format:
51
-
52
-    [Error|Status]: {{message}}
53
-    Reason: {{Reason}}
54
-    Additional: {{details message list messages}}
50
+        client_repsonse.
55 51
     ...
56 52
     """
57 53
     formatted = "Error: {}\nReason: {}" if is_error \
@@ -59,44 +55,68 @@ def cli_format_status_handler(response, is_error=False):
59 55
     try:
60 56
         if response.text:
61 57
             resp_j = response.json()
62
-            resp = formatted.format(resp_j.get('message', 'Not specified'),
63
-                                    resp_j.get('reason', 'Not specified'))
64
-            # lvl_counts must have a matching number of values as the
65
-            # _LEVEL_KEYS below + 1 for sentinel.
66
-            lvl_counts = [0, 0, 0, 0]
67
-            if resp_j.get('details'):
68
-                mlist = resp_j['details'].get('messageList', [])
69
-                # Decorate messages with level number and sortkey
70
-                for message in mlist:
71
-                    message['lnum'], message['sortkey'] = _lvl_key(
72
-                        message.get('level'),
73
-                        message.get('error', False)
74
-                    )
75
-                # Sort and formulate the messages
76
-                for message in sorted(mlist, key=lambda m: m['sortkey']):
77
-                    lnum = message['lnum']
78
-                    lvl_counts[lnum] = lvl_counts[lnum] + 1
79
-                    if message.get('kind') == 'ValidationMessage':
80
-                        resp = resp + _format_validation_message(message)
81
-                    else:
82
-                        resp = resp + _format_basic_message(message)
83
-                    if message.get('source'):
84
-                        resp = resp + "\n{}Source: {}".format(
85
-                            _INDENT,
86
-                            message['source']
87
-                        )
88
-                # Append a count summary
89
-                resp = resp + ("\n\n####  Errors: {},"
90
-                               " Warnings: {},"
91
-                               " Infos: {},"
92
-                               " Other: {}  ####".format(*lvl_counts))
93
-            return resp
58
+            return cli_format_response(formatted, resp_j)
94 59
         else:
95 60
             return ''
96 61
     except ValueError:
97 62
         return "Error: Unable to decode response. Value: {}".format(
98 63
             response.text)
99 64
 
65
+def cli_format_exception_handler(exc_msg):
66
+    """ Formatter for custom error raised by Shipyard """
67
+    try:
68
+        formatted = "Error: {}\nReason: {}"
69
+        # Convert exception message to dict from string
70
+        exc_dict = json.loads(str(exc_msg))
71
+        return cli_format_response(formatted, exc_dict)
72
+    except Exception:
73
+        return "Error: Unable to decode response. Value: {}".format(
74
+            exc_msg)
75
+
76
+def cli_format_response(formatted, response):
77
+    """ Handler for Shipyard status and error responses
78
+
79
+    :param formatted: structure to be used for response
80
+    :param response: client response to be formatted
81
+
82
+    The response will be in the format:
83
+    [Error|Status]: {{message}}
84
+    Reason: {{Reason}}
85
+    Additional: {{details message list messages}}
86
+    """
87
+    resp = formatted.format(response.get('message', 'Not specified'),
88
+                            response.get('reason', 'Not specified'))
89
+    # lvl_counts must have a matching number of values as the
90
+    # _LEVEL_KEYS below + 1 for sentinel.
91
+    lvl_counts = [0, 0, 0, 0]
92
+    if response.get('details'):
93
+        mlist = response['details'].get('messageList', [])
94
+        # Decorate messages with level number and sortkey
95
+        for message in mlist:
96
+            message['lnum'], message['sortkey'] = _lvl_key(
97
+                message.get('level'),
98
+                message.get('error', False)
99
+            )
100
+        # Sort and formulate the messages
101
+        for message in sorted(mlist, key=lambda m: m['sortkey']):
102
+            lnum = message['lnum']
103
+            lvl_counts[lnum] = lvl_counts[lnum] + 1
104
+            if message.get('kind') == 'ValidationMessage':
105
+                resp = resp + _format_validation_message(message)
106
+            else:
107
+                resp = resp + _format_basic_message(message)
108
+            if message.get('source'):
109
+                resp = resp + "\n{}Source: {}".format(
110
+                    _INDENT,
111
+                    message['source']
112
+                )
113
+        # Append a count summary
114
+        resp = resp + ("\n\n####  Errors: {},"
115
+                       " Warnings: {},"
116
+                       " Infos: {},"
117
+                       " Other: {}  ####".format(*lvl_counts))
118
+    return resp
119
+
100 120
 
101 121
 # Map of levels by severity. Extra values are included in this map but valid
102 122
 # values are defined here:

Loading…
Cancel
Save