This is an automated email from the ASF dual-hosted git repository.

cmcfarlen pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/10.1.x by this push:
     new 58dda60c57 traffic_ctl - Set the appropriate error exit code. (#12308) 
(#12327)
58dda60c57 is described below

commit 58dda60c57c1525a08be3b6dd96895c51671feb5
Author: Damian Meden <[email protected]>
AuthorDate: Wed Jul 2 16:51:07 2025 +0200

    traffic_ctl - Set the appropriate error exit code. (#12308) (#12327)
    
    Beside errors in the logic which was already covered this also marks the
    return code to error when the RPC sends back a response with some sort
    of failure.
    With this change traffic_ctl callers can now validate the exit code also 
considering the RPC errors/failures.
    
    (cherry picked from commit 5e334de06b0a64d5416b582ccef648e9093b10b3)
---
 src/traffic_ctl/CtrlCommands.cc                    |  3 +++
 src/traffic_ctl/CtrlPrinters.cc                    |  9 +++++--
 src/traffic_ctl/CtrlPrinters.h                     |  2 ++
 src/traffic_ctl/TrafficCtlStatus.h                 | 28 ++++++++++++++++++++++
 src/traffic_ctl/traffic_ctl.cc                     | 15 +++++-------
 .../traffic_ctl/traffic_ctl_config_output.test.py  |  3 +++
 .../traffic_ctl/traffic_ctl_test_utils.py          | 24 +++++++++++++++++--
 7 files changed, 71 insertions(+), 13 deletions(-)

diff --git a/src/traffic_ctl/CtrlCommands.cc b/src/traffic_ctl/CtrlCommands.cc
index 7a94ad067c..31fb78cf82 100644
--- a/src/traffic_ctl/CtrlCommands.cc
+++ b/src/traffic_ctl/CtrlCommands.cc
@@ -34,6 +34,7 @@
 #include "jsonrpc/CtrlRPCRequests.h"
 #include "jsonrpc/ctrl_yaml_codecs.h"
 
+#include "TrafficCtlStatus.h"
 namespace
 {
 /// We use yamlcpp as codec implementation.
@@ -498,6 +499,7 @@ DirectRPCCommand::from_file_request()
       }
 
     } catch (std::exception const &ex) {
+      App_Exit_Status_Code = CTRL_EX_ERROR;
       _printer->write_output(swoc::bwprint(text, "Error found: {}\n", 
ex.what()));
     }
   }
@@ -529,6 +531,7 @@ DirectRPCCommand::read_from_input()
     _printer->write_output("--> Request sent.\n");
     _printer->write_output(swoc::bwprint(text, "\n<-- {}\n", response));
   } catch (std::exception const &ex) {
+    App_Exit_Status_Code = CTRL_EX_ERROR;
     _printer->write_output(swoc::bwprint(text, "Error found: {}\n", 
ex.what()));
   }
 }
diff --git a/src/traffic_ctl/CtrlPrinters.cc b/src/traffic_ctl/CtrlPrinters.cc
index caf0f09b82..40fc02971e 100644
--- a/src/traffic_ctl/CtrlPrinters.cc
+++ b/src/traffic_ctl/CtrlPrinters.cc
@@ -29,6 +29,8 @@
 #include "jsonrpc/ctrl_yaml_codecs.h"
 #include "PrintUtils.h"
 
+#include "TrafficCtlStatus.h"
+
 swoc::BufferWriter &
 bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, FloatDate const 
&wrap)
 {
@@ -43,6 +45,7 @@ void
 
print_record_error_list(std::vector<shared::rpc::RecordLookUpResponse::RecordError>
 const &errors)
 {
   if (auto iter = std::begin(errors); iter != std::end(errors)) {
+    App_Exit_Status_Code = CTRL_EX_ERROR; // Set the exit code to error, so we 
can return it later.
     std::cout << "------------ Errors ----------\n";
     std::cout << *iter;
     ++iter;
@@ -64,8 +67,10 @@ BasePrinter::write_output(shared::rpc::JSONRPCResponse const 
&response)
   }
 
   if (response.is_error()) {
-    // If an error is present, then as per the specs we can ignore the 
jsonrpc.result field, so we print the error and we are done
-    // here!
+    App_Exit_Status_Code = CTRL_EX_ERROR; // Set the exit code to error, so we 
can return it later.
+
+    // If an error is present, then as per the specs we can ignore the 
jsonrpc.result field,
+    // so we print the error and we are done here!
     std::cout << response.error.as<shared::rpc::JSONRPCError>(); // Already 
formatted.
     return;
   }
diff --git a/src/traffic_ctl/CtrlPrinters.h b/src/traffic_ctl/CtrlPrinters.h
index 844a364d26..33c2241055 100644
--- a/src/traffic_ctl/CtrlPrinters.h
+++ b/src/traffic_ctl/CtrlPrinters.h
@@ -90,6 +90,8 @@ public:
   /// be called.
   /// @param response the  server response.
   ///
+  /// @note If there is an error, App_Exit_Status_Code will be set to 
CTRL_EX_ERROR.
+  ///
   void write_output(shared::rpc::JSONRPCResponse const &response);
 
   ///
diff --git a/src/traffic_ctl/TrafficCtlStatus.h 
b/src/traffic_ctl/TrafficCtlStatus.h
new file mode 100644
index 0000000000..b7d758fd25
--- /dev/null
+++ b/src/traffic_ctl/TrafficCtlStatus.h
@@ -0,0 +1,28 @@
+
+/**
+@section license License
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#pragma once
+
+constexpr int CTRL_EX_OK = 0;
+// EXIT_FAILURE can also be used.
+constexpr int CTRL_EX_ERROR         = 2;
+constexpr int CTRL_EX_UNIMPLEMENTED = 3;
+
+extern int App_Exit_Status_Code; //!< Global variable to store the exit status 
code of the application.
diff --git a/src/traffic_ctl/traffic_ctl.cc b/src/traffic_ctl/traffic_ctl.cc
index 37299f39ad..28e64f0ab3 100644
--- a/src/traffic_ctl/traffic_ctl.cc
+++ b/src/traffic_ctl/traffic_ctl.cc
@@ -32,13 +32,10 @@
 
 #include "CtrlCommands.h"
 #include "FileConfigCommand.h"
+#include "TrafficCtlStatus.h"
 
-constexpr int CTRL_EX_OK            = 0;
-constexpr int CTRL_EX_ERROR         = 2;
-constexpr int CTRL_EX_UNIMPLEMENTED = 3;
-
-int status_code{CTRL_EX_OK};
-
+// Define the global variable
+int App_Exit_Status_Code = CTRL_EX_OK; // Initialize it to a default value
 namespace
 {
 void
@@ -70,7 +67,7 @@ main([[maybe_unused]] int argc, const char **argv)
 
   auto CtrlUnimplementedCommand = [](std::string_view cmd) {
     std::cout << "Command " << cmd << " unimplemented.\n";
-    status_code = CTRL_EX_UNIMPLEMENTED;
+    App_Exit_Status_Code = CTRL_EX_UNIMPLEMENTED;
   };
 
   parser.add_description("Apache Traffic Server RPC CLI");
@@ -242,9 +239,9 @@ main([[maybe_unused]] int argc, const char **argv)
     // Execute
     args.invoke();
   } catch (std::exception const &ex) {
-    status_code = CTRL_EX_ERROR;
+    App_Exit_Status_Code = CTRL_EX_ERROR;
     std::cerr << "Error found:\n" << ex.what() << '\n';
   }
 
-  return status_code;
+  return App_Exit_Status_Code;
 }
diff --git a/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py 
b/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py
index d4643527db..ecf30a924e 100644
--- a/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py
+++ b/tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py
@@ -76,3 +76,6 @@ 
traffic_ctl.config().diff().as_records().validate_with_goldfile("diff_yaml.gold"
 ##### CONFIG DESCRIBE
 # don't really care about values, but just output and that the command 
actually went through
 
traffic_ctl.config().describe("proxy.config.http.server_ports").validate_with_goldfile("describe.gold")
+
+# Make sure that the command returns an exit code of 2
+traffic_ctl.config().get("invalid.should.set.the.exit.code.to.2").validate_with_exit_code(2)
diff --git a/tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py 
b/tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
index c8a2d57576..caf74825d6 100644
--- a/tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
+++ b/tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
@@ -54,12 +54,31 @@ def MakeGoldFileWithText(content, dir, test_number, 
add_new_line=True):
     return gold_filepath
 
 
-class Config():
+class Common():
+    """
+        Handy class to map common traffic_ctl test options.
+    """
+
+    def __init__(self, tr, finish_callback):
+        self._tr = tr
+        self._finish_callback = finish_callback
+
+    def validate_with_exit_code(self, exit_code: int):
+        """
+            Sets the exit code for the test.
+        """
+        self._tr.Processes.Default.ReturnCode = exit_code
+        self._finish_callback(self)
+        return self
+
+
+class Config(Common):
     """
         Handy class to map traffic_ctl config options.
     """
 
     def __init__(self, dir, tr, tn):
+        super().__init__(tr, lambda x: self.__finish())
         self._cmd = "traffic_ctl config "
         self._tr = tr
         self._dir = dir
@@ -105,12 +124,13 @@ class Config():
         self.__finish()
 
 
-class Server():
+class Server(Common):
     """
         Handy class to map traffic_ctl server options.
     """
 
     def __init__(self, dir, tr, tn):
+        super().__init__(tr, lambda x: self.__finish())
         self._cmd = "traffic_ctl server "
         self._tr = tr
         self._dir = dir

Reply via email to