]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlinkctl: add --graceful= option for optionally marking some errors as successes
authorLennart Poettering <lennart@poettering.net>
Mon, 27 May 2024 20:32:51 +0000 (22:32 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 20 Jun 2024 16:20:09 +0000 (18:20 +0200)
This is generally useful, but in some cases particularly: when
implementing enumeration calls that use the "more" flag to return
multiple replies then for the first reply we need to return an error in
case the list of objects to enumerate is empty, usually so form of
"NoSuchXYZ" error. In many cases this shouldn't really be treated as
error, as an empty list probably more than not is as valid as a list
with one, two or more entries.

man/varlinkctl.xml
src/varlinkctl/varlinkctl.c

index f21e513cb0fcf16cf1373c4ce2b445898864c0b1..2e8207cbcb3c5fdc76a9fdb4bd83e60fd6742f67 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--graceful=</option></term>
+
+        <listitem>
+          <para>Takes a qualified Varlink error name (i.e. an interface name, suffixed by an error name,
+          separated by a dot; e.g. <literal>org.varlink.service.InvalidParameter</literal>). Ensures that if
+          a method call fails with the specified error this will be treated as success, i.e. will cause the
+          <command>varlinkctl</command> invocation to exit with a zero exit status. This option may be used more
+          than once in order to treat multiple different errors as successes.</para>
+
+          <xi:include href="version-info.xml" xpointer="v257"/>
+        </listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="no-pager" />
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
index 02caf218e790c7c560f2cd50a6a9d929b5398f75..f4e5cc2cbff63c5b3a41eebf0f9ee70201886768 100644 (file)
@@ -22,6 +22,9 @@ static PagerFlags arg_pager_flags = 0;
 static VarlinkMethodFlags arg_method_flags = 0;
 static bool arg_collect = false;
 static bool arg_quiet = false;
+static char **arg_graceful = NULL;
+
+STATIC_DESTRUCTOR_REGISTER(arg_graceful, strv_freep);
 
 static int help(void) {
         _cleanup_free_ char *link = NULL;
@@ -58,6 +61,7 @@ static int help(void) {
                "     --json=MODE         Output as JSON\n"
                "  -j                     Same as --json=pretty on tty, --json=short otherwise\n"
                "  -q --quiet             Do not output method reply\n"
+               "     --graceful=ERROR    Treat specified Varlink error as success\n"
                "\nSee the %2$s for details.\n",
                program_invocation_short_name,
                link,
@@ -82,6 +86,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_ONEWAY,
                 ARG_JSON,
                 ARG_COLLECT,
+                ARG_GRACEFUL,
         };
 
         static const struct option options[] = {
@@ -93,6 +98,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "json",     required_argument, NULL, ARG_JSON     },
                 { "collect",  no_argument,       NULL, ARG_COLLECT  },
                 { "quiet",    no_argument,       NULL, 'q'          },
+                { "graceful", required_argument, NULL, ARG_GRACEFUL },
                 {},
         };
 
@@ -142,6 +148,18 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_quiet = true;
                         break;
 
+                case ARG_GRACEFUL:
+                        r = varlink_idl_qualified_symbol_name_is_valid(optarg);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to validate Varlink error name '%s': %m", optarg);
+                        if (r == 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid Varlink error name: %s", optarg);
+
+                        if (strv_extend(&arg_graceful, optarg) < 0)
+                                return log_oom();
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -153,6 +171,8 @@ static int parse_argv(int argc, char *argv[]) {
         if (FLAGS_SET(arg_method_flags, VARLINK_METHOD_MORE))
                 arg_json_format_flags |= SD_JSON_FORMAT_SEQ;
 
+        strv_sort_uniq(arg_graceful);
+
         return 1;
 }
 
@@ -438,7 +458,13 @@ static int reply_callback(
                 /* Propagate the error we received via sd_notify() */
                 (void) sd_notifyf(/* unset_environment= */ false, "VARLINKERROR=%s", error);
 
-                r = *ret = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call failed: %s", error);
+                if (strv_contains(arg_graceful, error)) {
+                        log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
+                                 "Method call returned expected error: %s", error);
+
+                        r = 0;
+                } else
+                        r = *ret = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call failed: %s", error);
         } else
                 r = 0;
 
@@ -505,7 +531,13 @@ static int verb_call(int argc, char *argv[], void *userdata) {
                         /* Propagate the error we received via sd_notify() */
                         (void) sd_notifyf(/* unset_environment= */ false, "VARLINKERROR=%s", error);
 
-                        r = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call %s() failed: %s", method, error);
+                        if (strv_contains(arg_graceful, error)) {
+                                log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
+                                         "Method call %s() returned expected error: %s", method, error);
+
+                                r = 0;
+                        } else
+                                r = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call %s() failed: %s", method, error);
                 } else
                         r = 0;
 
@@ -570,7 +602,13 @@ static int verb_call(int argc, char *argv[], void *userdata) {
                         /* Propagate the error we received via sd_notify() */
                         (void) sd_notifyf(/* unset_environment= */ false, "VARLINKERROR=%s", error);
 
-                        r = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call %s() failed: %s", method, error);
+                        if (strv_contains(arg_graceful, error)) {
+                                log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
+                                         "Method call %s() returned expected error: %s", method, error);
+
+                                r = 0;
+                        } else
+                                r = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call %s() failed: %s", method, error);
                 } else
                         r = 0;