All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 00/10] Configurable policy for handling deprecated interfaces
@ 2021-03-12 15:32 Markus Armbruster
  2021-03-12 15:32 ` [PATCH v6 01/10] qemu-options: New -compat to set policy for " Markus Armbruster
                   ` (10 more replies)
  0 siblings, 11 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Lukáš Doktor, Kevin Wolf, Peter Krempa,
	Daniel P . Berrange, libvir-list, mdroth, marcandre.lureau,
	libguestfs

New option -compat lets you configure what to do when deprecated
interfaces get used.  This is intended for testing users of the
management interfaces.  It is experimental.

-compat deprecated-input=<in-policy> configures what to do when
deprecated input is received.  Available policies:

* accept: Accept deprecated commands and arguments (default)
* reject: Reject them
* crash: Crash

-compat deprecated-output=<out-policy> configures what to do when
deprecated output is sent.  Available output policies:

* accept: Emit deprecated command results and events (default)
* hide: Suppress them

For now, -compat covers only deprecated syntactic aspects of QMP.  We
may want to extend it to cover semantic aspects, CLI, and experimental
features.

v6:
* Rebased, with straightforward conflicts
* PATCH 1: More verbose commit message, explaining intent, and the
  lack of introspection [Peter], comments updated for 6.0, Eric's R-by
  kept anyway
* PATCH 5+6: Split old PATCH 5 [Eric], Eric's R-by lept anyway
* PATCH 7: New, correcting a latent issue so it doesn't break PATCH 8
* PATCH 10: Doc fix [Eric]

v5:
* Old PATCH 01-26 merged in commit f57587c7d47.
* Rebased, non-trivial conflicts in PATCH 1 due to Meson, and in PATCH
  7 due to visitor changes
* PATCH 1: Comments updated for 5.2 [Eric]
* PATCH 2: Harmless missing initialization fixed [Eric]
* PATCH 3+4: Harmless missing has_FOO = true fixed [Eric]
* PATCH 6+7: Commit message tweaked

v4:
* PATCH 05+07: Temporary memory leak plugged [Marc-André]
* PATCH 23: Rewritten [Marc-André]
* PATCH 24: Comment typo [Marc-André]
* PATCH 30: Memory leaks plugged

v3:
* Rebased, non-trivial conflicts in PATCH 01+26+27+34 due to RST
  conversion and code motion
* PATCH 28-29: Old PATCH 28 split up to ease review
* PATCH 30-31: New
* PATCH 32-33: Old PATCH 29 split up to ease review

Comparison to RFC (24 Oct 2019):
* Cover arguments and results in addition to commands and events
* Half-baked "[RFC PATCH 18/19] qapi: Include a warning in the
  response to a deprecated command" dropped

See also last item of
    Subject: Minutes of KVM Forum BoF on deprecating stuff
    Date: Fri, 26 Oct 2018 16:03:51 +0200
    Message-ID: <87mur0ls8o.fsf@dusky.pond.sub.org>
    https://lists.nongnu.org/archive/html/qemu-devel/2018-10/msg05828.html

Cc: Lukáš Doktor <ldoktor@redhat.com>
Cc: libguestfs@redhat.com
Cc: libvir-list@redhat.com
Cc: Daniel P. Berrange <berrange@redhat.com>
Cc: Peter Krempa <pkrempa@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>

Markus Armbruster (10):
  qemu-options: New -compat to set policy for deprecated interfaces
  qapi: Implement deprecated-output=hide for QMP command results
  qapi: Implement deprecated-output=hide for QMP events
  qapi: Implement deprecated-output=hide for QMP event data
  monitor: Drop query-qmp-schema 'gen': false hack
  qapi: Implement deprecated-output=hide for QMP introspection
  test-util-sockets: Add stub for monitor_set_cur()
  qapi: Implement deprecated-input=reject for QMP commands
  qapi: Implement deprecated-input=reject for QMP command arguments
  qapi: New -compat deprecated-input=crash

 qapi/compat.json                        |  52 ++++++++++++
 qapi/introspect.json                    |   2 +-
 qapi/qapi-schema.json                   |   1 +
 include/qapi/compat-policy.h            |  20 +++++
 include/qapi/qmp/dispatch.h             |   1 +
 include/qapi/qobject-input-visitor.h    |   9 +++
 include/qapi/qobject-output-visitor.h   |   9 +++
 include/qapi/visitor-impl.h             |   6 ++
 include/qapi/visitor.h                  |  18 +++++
 monitor/monitor-internal.h              |   3 -
 monitor/misc.c                          |   2 -
 monitor/qmp-cmds-control.c              | 100 +++++++++++++++++++++---
 qapi/qapi-visit-core.c                  |  18 +++++
 qapi/qmp-dispatch.c                     |  17 ++++
 qapi/qobject-input-visitor.c            |  29 +++++++
 qapi/qobject-output-visitor.c           |  19 +++++
 softmmu/vl.c                            |  17 ++++
 storage-daemon/qemu-storage-daemon.c    |   2 -
 tests/test-qmp-cmds.c                   |  91 +++++++++++++++++++--
 tests/test-qmp-event.c                  |  41 ++++++++++
 tests/test-util-sockets.c               |   1 +
 qapi/meson.build                        |   1 +
 qapi/trace-events                       |   2 +
 qemu-options.hx                         |  22 ++++++
 scripts/qapi/commands.py                |  14 ++--
 scripts/qapi/events.py                  |  20 ++++-
 scripts/qapi/visit.py                   |  15 ++++
 tests/qapi-schema/qapi-schema-test.json |  20 +++--
 tests/qapi-schema/qapi-schema-test.out  |  20 ++---
 29 files changed, 522 insertions(+), 50 deletions(-)
 create mode 100644 qapi/compat.json
 create mode 100644 include/qapi/compat-policy.h

-- 
2.26.2



^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v6 01/10] qemu-options: New -compat to set policy for deprecated interfaces
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-15 15:41   ` Eric Blake
  2021-03-12 15:32 ` [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results Markus Armbruster
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

New option -compat lets you configure what to do when deprecated
interfaces get used.  This is intended for testing users of the
management interfaces.  It is experimental.

-compat deprecated-input=<input-policy> configures what to do when
deprecated input is received.  Input policy can be "accept" (accept
silently), or "reject" (reject the request with an error).

-compat deprecated-output=<out-policy> configures what to do when
deprecated output is sent.  Output policy can be "accept" (pass on
unchanged), or "hide" (filter out the deprecated parts).

Default is "accept".  Policies other than "accept" are implemented
later in this series.

For now, -compat covers only syntactic aspects of QMP, i.e. stuff
tagged with feature 'deprecated'.  We may want to extend it to cover
semantic aspects, CLI, and experimental features.

Note that there is no good way for management application to detect
presence of -compat: it's not visible output of query-qmp-schema or
query-command-line-options.  Tolerable, because it's meant for
testing.  If running with -compat fails, skip the test.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 qapi/compat.json             | 51 ++++++++++++++++++++++++++++++++++++
 qapi/qapi-schema.json        |  1 +
 include/qapi/compat-policy.h | 20 ++++++++++++++
 qapi/qmp-dispatch.c          |  3 +++
 softmmu/vl.c                 | 17 ++++++++++++
 qapi/meson.build             |  1 +
 qemu-options.hx              | 20 ++++++++++++++
 7 files changed, 113 insertions(+)
 create mode 100644 qapi/compat.json
 create mode 100644 include/qapi/compat-policy.h

diff --git a/qapi/compat.json b/qapi/compat.json
new file mode 100644
index 0000000000..d2c02a21aa
--- /dev/null
+++ b/qapi/compat.json
@@ -0,0 +1,51 @@
+# -*- Mode: Python -*-
+
+##
+# = Compatibility policy
+##
+
+##
+# @CompatPolicyInput:
+#
+# Policy for handling "funny" input.
+#
+# @accept: Accept silently
+# @reject: Reject with an error
+#
+# Since: 5.2
+##
+{ 'enum': 'CompatPolicyInput',
+  'data': [ 'accept', 'reject' ] }
+
+##
+# @CompatPolicyOutput:
+#
+# Policy for handling "funny" output.
+#
+# @accept: Pass on unchanged
+# @hide: Filter out
+#
+# Since: 5.2
+##
+{ 'enum': 'CompatPolicyOutput',
+  'data': [ 'accept', 'hide' ] }
+
+##
+# @CompatPolicy:
+#
+# Policy for handling deprecated management interfaces.
+#
+# This is intended for testing users of the management interfaces.
+#
+# Limitation: covers only syntactic aspects of QMP, i.e. stuff tagged
+# with feature 'deprecated'.  We may want to extend it to cover
+# semantic aspects, CLI, and experimental features.
+#
+# @deprecated-input: how to handle deprecated input (default 'accept')
+# @deprecated-output: how to handle deprecated output (default 'accept')
+#
+# Since: 5.2
+##
+{ 'struct': 'CompatPolicy',
+  'data': { '*deprecated-input': 'CompatPolicyInput',
+            '*deprecated-output': 'CompatPolicyOutput' } }
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index 3441c9a9ae..4912b9744e 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -79,6 +79,7 @@
 { 'include': 'migration.json' }
 { 'include': 'transaction.json' }
 { 'include': 'trace.json' }
+{ 'include': 'compat.json' }
 { 'include': 'control.json' }
 { 'include': 'introspect.json' }
 { 'include': 'qom.json' }
diff --git a/include/qapi/compat-policy.h b/include/qapi/compat-policy.h
new file mode 100644
index 0000000000..b8c6638156
--- /dev/null
+++ b/include/qapi/compat-policy.h
@@ -0,0 +1,20 @@
+/*
+ * Policy for handling "funny" management interfaces
+ *
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <armbru@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
+ */
+
+#ifndef QAPI_COMPAT_POLICY_H
+#define QAPI_COMPAT_POLICY_H
+
+#include "qapi/qapi-types-compat.h"
+
+extern CompatPolicy compat_policy;
+
+#endif
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 0a2b20a4e4..45090f881a 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -14,6 +14,7 @@
 #include "qemu/osdep.h"
 
 #include "block/aio.h"
+#include "qapi/compat-policy.h"
 #include "qapi/error.h"
 #include "qapi/qmp/dispatch.h"
 #include "qapi/qmp/qdict.h"
@@ -23,6 +24,8 @@
 #include "qemu/coroutine.h"
 #include "qemu/main-loop.h"
 
+CompatPolicy compat_policy;
+
 static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
                                      Error **errp)
 {
diff --git a/softmmu/vl.c b/softmmu/vl.c
index b7673b9613..4c53b2940c 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -29,6 +29,7 @@
 #include "exec/cpu-common.h"
 #include "hw/boards.h"
 #include "hw/qdev-properties.h"
+#include "qapi/compat-policy.h"
 #include "qapi/error.h"
 #include "qapi/qmp/qdict.h"
 #include "qemu-version.h"
@@ -113,6 +114,7 @@
 #include "sysemu/replay.h"
 #include "qapi/qapi-events-run-state.h"
 #include "qapi/qapi-visit-block-core.h"
+#include "qapi/qapi-visit-compat.h"
 #include "qapi/qapi-visit-ui.h"
 #include "qapi/qapi-commands-block-core.h"
 #include "qapi/qapi-commands-migration.h"
@@ -3413,6 +3415,21 @@ void qemu_init(int argc, char **argv, char **envp)
                 enable_mlock = qemu_opt_get_bool(opts, "mem-lock", false);
                 enable_cpu_pm = qemu_opt_get_bool(opts, "cpu-pm", false);
                 break;
+            case QEMU_OPTION_compat:
+                {
+                    CompatPolicy *opts;
+                    Visitor *v;
+
+                    v = qobject_input_visitor_new_str(optarg, NULL,
+                                                      &error_fatal);
+
+                    visit_type_CompatPolicy(v, NULL, &opts, &error_fatal);
+                    QAPI_CLONE_MEMBERS(CompatPolicy, &compat_policy, opts);
+
+                    qapi_free_CompatPolicy(opts);
+                    visit_free(v);
+                    break;
+                }
             case QEMU_OPTION_msg:
                 opts = qemu_opts_parse_noisily(qemu_find_opts("msg"), optarg,
                                                false);
diff --git a/qapi/meson.build b/qapi/meson.build
index fcb15a78f1..376f4ceafe 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -24,6 +24,7 @@ qapi_all_modules = [
   'block-export',
   'char',
   'common',
+  'compat',
   'control',
   'crypto',
   'dump',
diff --git a/qemu-options.hx b/qemu-options.hx
index 90801286c6..2be2feed32 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3470,6 +3470,26 @@ DEFHEADING()
 
 DEFHEADING(Debug/Expert options:)
 
+DEF("compat", HAS_ARG, QEMU_OPTION_compat,
+    "-compat [deprecated-input=accept|reject][,deprecated-output=accept|hide]\n"
+    "                Policy for handling deprecated management interfaces\n",
+    QEMU_ARCH_ALL)
+SRST
+``-compat [deprecated-input=@var{input-policy}][,deprecated-output=@var{output-policy}]``
+    Set policy for handling deprecated management interfaces (experimental):
+
+    ``deprecated-input=accept`` (default)
+        Accept deprecated commands and arguments
+    ``deprecated-input=reject``
+        Reject deprecated commands and arguments
+    ``deprecated-output=accept`` (default)
+        Emit deprecated command results and events
+    ``deprecated-output=hide``
+        Suppress deprecated command results and events
+
+    Limitation: covers only syntactic aspects of QMP.
+ERST
+
 DEF("fw_cfg", HAS_ARG, QEMU_OPTION_fwcfg,
     "-fw_cfg [name=]<name>,file=<file>\n"
     "                add named fw_cfg entry with contents from file\n"
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
  2021-03-12 15:32 ` [PATCH v6 01/10] qemu-options: New -compat to set policy for " Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-15 15:45   ` Eric Blake
  2021-03-18 13:36   ` Markus Armbruster
  2021-03-12 15:32 ` [PATCH v6 03/10] qapi: Implement deprecated-output=hide for QMP events Markus Armbruster
                   ` (8 subsequent siblings)
  10 siblings, 2 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

This policy suppresses deprecated bits in output, and thus permits
"testing the future".  Implement it for QMP command results.  Example:
when QEMU is run with -compat deprecated-output=hide, then

    {"execute": "query-cpus-fast"}

yields

    {"return": [{"thread-id": 9805, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}

instead of

    {"return": [{"arch": "x86", "thread-id": 22436, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}

Note the suppression of deprecated member "arch".

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 include/qapi/qobject-output-visitor.h   |  9 ++++++
 include/qapi/visitor-impl.h             |  3 ++
 include/qapi/visitor.h                  |  9 ++++++
 qapi/qapi-visit-core.c                  |  9 ++++++
 qapi/qobject-output-visitor.c           | 19 +++++++++++
 tests/test-qmp-cmds.c                   | 42 ++++++++++++++++++++++---
 qapi/trace-events                       |  1 +
 scripts/qapi/commands.py                |  2 +-
 scripts/qapi/visit.py                   | 12 +++++++
 tests/qapi-schema/qapi-schema-test.json | 17 +++++-----
 tests/qapi-schema/qapi-schema-test.out  | 18 +++++------
 11 files changed, 118 insertions(+), 23 deletions(-)

diff --git a/include/qapi/qobject-output-visitor.h b/include/qapi/qobject-output-visitor.h
index 2b1726baf5..29f4ea6aad 100644
--- a/include/qapi/qobject-output-visitor.h
+++ b/include/qapi/qobject-output-visitor.h
@@ -53,4 +53,13 @@ typedef struct QObjectOutputVisitor QObjectOutputVisitor;
  */
 Visitor *qobject_output_visitor_new(QObject **result);
 
+/*
+ * Create a QObject output visitor for @obj for use with QMP
+ *
+ * This is like qobject_output_visitor_new(), except it obeys the
+ * policy for handling deprecated management interfaces set with
+ * -compat.
+ */
+Visitor *qobject_output_visitor_new_qmp(QObject **result);
+
 #endif
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 7362c043be..2d853255a3 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -113,6 +113,9 @@ struct Visitor
        The core takes care of the return type in the public interface. */
     void (*optional)(Visitor *v, const char *name, bool *present);
 
+    /* Optional */
+    bool (*deprecated)(Visitor *v, const char *name);
+
     /* Must be set */
     VisitorType type;
 
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index ebc19ede7f..4d23b59853 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -459,6 +459,15 @@ void visit_end_alternate(Visitor *v, void **obj);
  */
 bool visit_optional(Visitor *v, const char *name, bool *present);
 
+/*
+ * Should we visit deprecated member @name?
+ *
+ * @name must not be NULL.  This function is only useful between
+ * visit_start_struct() and visit_end_struct(), since only objects
+ * have deprecated members.
+ */
+bool visit_deprecated(Visitor *v, const char *name);
+
 /*
  * Visit an enum value.
  *
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 7e5f40e7f0..d9726ecaa1 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -135,6 +135,15 @@ bool visit_optional(Visitor *v, const char *name, bool *present)
     return *present;
 }
 
+bool visit_deprecated(Visitor *v, const char *name)
+{
+    trace_visit_deprecated(v, name);
+    if (v->deprecated) {
+        return v->deprecated(v, name);
+    }
+    return true;
+}
+
 bool visit_is_input(Visitor *v)
 {
     return v->type == VISITOR_INPUT;
diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c
index ba6f6ac8a7..5c4aa0f64d 100644
--- a/qapi/qobject-output-visitor.c
+++ b/qapi/qobject-output-visitor.c
@@ -13,6 +13,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qapi/compat-policy.h"
 #include "qapi/qobject-output-visitor.h"
 #include "qapi/visitor-impl.h"
 #include "qemu/queue.h"
@@ -31,6 +32,8 @@ typedef struct QStackEntry {
 
 struct QObjectOutputVisitor {
     Visitor visitor;
+    CompatPolicyOutput deprecated_policy;
+
     QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */
     QObject *root; /* Root of the output visit */
     QObject **result; /* User's storage location for result */
@@ -207,6 +210,13 @@ static bool qobject_output_type_null(Visitor *v, const char *name,
     return true;
 }
 
+static bool qobject_output_deprecated(Visitor *v, const char *name)
+{
+    QObjectOutputVisitor *qov = to_qov(v);
+
+    return qov->deprecated_policy != COMPAT_POLICY_OUTPUT_HIDE;
+}
+
 /* Finish building, and return the root object.
  * The root object is never null. The caller becomes the object's
  * owner, and should use qobject_unref() when done with it.  */
@@ -256,6 +266,7 @@ Visitor *qobject_output_visitor_new(QObject **result)
     v->visitor.type_number = qobject_output_type_number;
     v->visitor.type_any = qobject_output_type_any;
     v->visitor.type_null = qobject_output_type_null;
+    v->visitor.deprecated = qobject_output_deprecated;
     v->visitor.complete = qobject_output_complete;
     v->visitor.free = qobject_output_free;
 
@@ -264,3 +275,11 @@ Visitor *qobject_output_visitor_new(QObject **result)
 
     return &v->visitor;
 }
+
+Visitor *qobject_output_visitor_new_qmp(QObject **result)
+{
+    QObjectOutputVisitor *v = to_qov(qobject_output_visitor_new(result));
+
+    v->deprecated_policy = compat_policy.deprecated_output;
+    return &v->visitor;
+}
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index d3413bfef0..1079d35122 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -1,4 +1,5 @@
 #include "qemu/osdep.h"
+#include "qapi/compat-policy.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
 #include "qapi/qmp/qnum.h"
@@ -49,12 +50,17 @@ void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
 {
 }
 
-void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
-                       FeatureStruct2 *fs2, FeatureStruct3 *fs3,
-                       FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1,
-                       CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3,
-                       Error **errp)
+FeatureStruct1 *qmp_test_features0(bool has_fs0, FeatureStruct0 *fs0,
+                                   bool has_fs1, FeatureStruct1 *fs1,
+                                   bool has_fs2, FeatureStruct2 *fs2,
+                                   bool has_fs3, FeatureStruct3 *fs3,
+                                   bool has_fs4, FeatureStruct4 *fs4,
+                                   bool has_cfs1, CondFeatureStruct1 *cfs1,
+                                   bool has_cfs2, CondFeatureStruct2 *cfs2,
+                                   bool has_cfs3, CondFeatureStruct3 *cfs3,
+                                   Error **errp)
 {
+    return g_new0(FeatureStruct1, 1);
 }
 
 void qmp_test_command_features1(Error **errp)
@@ -275,6 +281,30 @@ static void test_dispatch_cmd_io(void)
     qobject_unref(ret3);
 }
 
+static void test_dispatch_cmd_ret_deprecated(void)
+{
+    const char *cmd = "{ 'execute': 'test-features0' }";
+    QDict *ret;
+
+    memset(&compat_policy, 0, sizeof(compat_policy));
+
+    /* default accept */
+    ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+    assert(ret && qdict_size(ret) == 1);
+    qobject_unref(ret);
+
+    compat_policy.has_deprecated_output = true;
+    compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_ACCEPT;
+    ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+    assert(ret && qdict_size(ret) == 1);
+    qobject_unref(ret);
+
+    compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE;
+    ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+    assert(ret && qdict_size(ret) == 0);
+    qobject_unref(ret);
+}
+
 /* test generated dealloc functions for generated types */
 static void test_dealloc_types(void)
 {
@@ -349,6 +379,8 @@ int main(int argc, char **argv)
     g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
     g_test_add_func("/qmp/dispatch_cmd_success_response",
                     test_dispatch_cmd_success_response);
+    g_test_add_func("/qmp/dispatch_cmd_ret_deprecated",
+                    test_dispatch_cmd_ret_deprecated);
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
     g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial);
 
diff --git a/qapi/trace-events b/qapi/trace-events
index 5eb4afa110..eff1fbd199 100644
--- a/qapi/trace-events
+++ b/qapi/trace-events
@@ -17,6 +17,7 @@ visit_start_alternate(void *v, const char *name, void *obj, size_t size) "v=%p n
 visit_end_alternate(void *v, void *obj) "v=%p obj=%p"
 
 visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p"
+visit_deprecated(void *v, const char *name) "v=%p name=%s"
 
 visit_type_enum(void *v, const char *name, int *obj) "v=%p name=%s obj=%p"
 visit_type_int(void *v, const char *name, int64_t *obj) "v=%p name=%s obj=%p"
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 0a75a9371b..7adeda917b 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -96,7 +96,7 @@ def gen_marshal_output(ret_type: QAPISchemaType) -> str:
 {
     Visitor *v;
 
-    v = qobject_output_visitor_new(ret_out);
+    v = qobject_output_visitor_new_qmp(ret_out);
     if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) {
         visit_complete(v, ret_out);
     }
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 9aa0b1e11e..9d83bf650f 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -77,6 +77,7 @@ def gen_visit_object_members(name: str,
                      c_type=base.c_name())
 
     for memb in members:
+        deprecated = 'deprecated' in [f.name for f in memb.features]
         ret += gen_if(memb.ifcond)
         if memb.optional:
             ret += mcgen('''
@@ -84,6 +85,12 @@ def gen_visit_object_members(name: str,
 ''',
                          name=memb.name, c_name=c_name(memb.name))
             indent.increase()
+        if deprecated:
+            ret += mcgen('''
+    if (visit_deprecated(v, "%(name)s")) {
+''',
+                         name=memb.name)
+            indent.increase()
         ret += mcgen('''
     if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) {
         return false;
@@ -91,6 +98,11 @@ def gen_visit_object_members(name: str,
 ''',
                      c_type=memb.type.c_name(), name=memb.name,
                      c_name=c_name(memb.name))
+        if deprecated:
+            indent.decrease()
+            ret += mcgen('''
+    }
+''')
         if memb.optional:
             indent.decrease()
             ret += mcgen('''
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 63f92adf68..48a0adabae 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -299,14 +299,15 @@
   'features': [ 'feature1' ] }
 
 { 'command': 'test-features0',
-  'data': { 'fs0': 'FeatureStruct0',
-            'fs1': 'FeatureStruct1',
-            'fs2': 'FeatureStruct2',
-            'fs3': 'FeatureStruct3',
-            'fs4': 'FeatureStruct4',
-            'cfs1': 'CondFeatureStruct1',
-            'cfs2': 'CondFeatureStruct2',
-            'cfs3': 'CondFeatureStruct3' },
+  'data': { '*fs0': 'FeatureStruct0',
+            '*fs1': 'FeatureStruct1',
+            '*fs2': 'FeatureStruct2',
+            '*fs3': 'FeatureStruct3',
+            '*fs4': 'FeatureStruct4',
+            '*cfs1': 'CondFeatureStruct1',
+            '*cfs2': 'CondFeatureStruct2',
+            '*cfs3': 'CondFeatureStruct3' },
+  'returns': 'FeatureStruct1',
   'features': [] }
 
 { 'command': 'test-command-features1',
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 3b1387d9f1..776d737891 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -409,15 +409,15 @@ alternate FeatureAlternate1
     case eins: FeatureStruct1
     feature feature1
 object q_obj_test-features0-arg
-    member fs0: FeatureStruct0 optional=False
-    member fs1: FeatureStruct1 optional=False
-    member fs2: FeatureStruct2 optional=False
-    member fs3: FeatureStruct3 optional=False
-    member fs4: FeatureStruct4 optional=False
-    member cfs1: CondFeatureStruct1 optional=False
-    member cfs2: CondFeatureStruct2 optional=False
-    member cfs3: CondFeatureStruct3 optional=False
-command test-features0 q_obj_test-features0-arg -> None
+    member fs0: FeatureStruct0 optional=True
+    member fs1: FeatureStruct1 optional=True
+    member fs2: FeatureStruct2 optional=True
+    member fs3: FeatureStruct3 optional=True
+    member fs4: FeatureStruct4 optional=True
+    member cfs1: CondFeatureStruct1 optional=True
+    member cfs2: CondFeatureStruct2 optional=True
+    member cfs3: CondFeatureStruct3 optional=True
+command test-features0 q_obj_test-features0-arg -> FeatureStruct1
     gen=True success_response=True boxed=False oob=False preconfig=False
 command test-command-features1 None -> None
     gen=True success_response=True boxed=False oob=False preconfig=False
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 03/10] qapi: Implement deprecated-output=hide for QMP events
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
  2021-03-12 15:32 ` [PATCH v6 01/10] qemu-options: New -compat to set policy for " Markus Armbruster
  2021-03-12 15:32 ` [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-12 15:32 ` [PATCH v6 04/10] qapi: Implement deprecated-output=hide for QMP event data Markus Armbruster
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

This policy suppresses deprecated bits in output, and thus permits
"testing the future".  Implement it for QMP events: suppress
deprecated ones.

No QMP event is deprecated right now.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 tests/test-qmp-event.c | 20 ++++++++++++++++++++
 scripts/qapi/events.py | 12 +++++++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c
index 7dd0053190..ab059fb5c2 100644
--- a/tests/test-qmp-event.c
+++ b/tests/test-qmp-event.c
@@ -14,6 +14,7 @@
 #include "qemu/osdep.h"
 
 #include "qemu-common.h"
+#include "qapi/compat-policy.h"
 #include "qapi/error.h"
 #include "qapi/qmp/qbool.h"
 #include "qapi/qmp/qdict.h"
@@ -140,6 +141,24 @@ static void test_event_d(TestEventData *data,
     qobject_unref(data->expect);
 }
 
+static void test_event_deprecated(TestEventData *data, const void *unused)
+{
+    data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES1' }");
+
+    memset(&compat_policy, 0, sizeof(compat_policy));
+
+    qapi_event_send_test_event_features1();
+    g_assert(data->emitted);
+
+    compat_policy.has_deprecated_output = true;
+    compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE;
+    data->emitted = false;
+    qapi_event_send_test_event_features1();
+    g_assert(!data->emitted);
+
+    qobject_unref(data->expect);
+}
+
 int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
@@ -148,6 +167,7 @@ int main(int argc, char **argv)
     event_test_add("/event/event_b", test_event_b);
     event_test_add("/event/event_c", test_event_c);
     event_test_add("/event/event_d", test_event_d);
+    event_test_add("/event/deprecated", test_event_deprecated);
     g_test_run();
 
     return 0;
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index 90d2f6156d..f6e1e76f64 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -79,6 +79,7 @@ def gen_param_var(typ: QAPISchemaObjectType) -> str:
 
 def gen_event_send(name: str,
                    arg_type: Optional[QAPISchemaObjectType],
+                   features: List[QAPISchemaFeature],
                    boxed: bool,
                    event_enum_name: str,
                    event_emit: str) -> str:
@@ -107,6 +108,14 @@ def gen_event_send(name: str,
         if not boxed:
             ret += gen_param_var(arg_type)
 
+    if 'deprecated' in [f.name for f in features]:
+        ret += mcgen('''
+
+    if (compat_policy.deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) {
+        return;
+    }
+''')
+
     ret += mcgen('''
 
     qmp = qmp_event_build_dict("%(name)s");
@@ -176,6 +185,7 @@ def _begin_user_module(self, name: str) -> None:
 #include "%(prefix)sqapi-emit-events.h"
 #include "%(events)s.h"
 #include "%(visit)s.h"
+#include "qapi/compat-policy.h"
 #include "qapi/error.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qobject-output-visitor.h"
@@ -220,7 +230,7 @@ def visit_event(self,
                     boxed: bool) -> None:
         with ifcontext(ifcond, self._genh, self._genc):
             self._genh.add(gen_event_send_decl(name, arg_type, boxed))
-            self._genc.add(gen_event_send(name, arg_type, boxed,
+            self._genc.add(gen_event_send(name, arg_type, features, boxed,
                                           self._event_enum_name,
                                           self._event_emit_name))
         # Note: we generate the enum member regardless of @ifcond, to
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 04/10] qapi: Implement deprecated-output=hide for QMP event data
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
                   ` (2 preceding siblings ...)
  2021-03-12 15:32 ` [PATCH v6 03/10] qapi: Implement deprecated-output=hide for QMP events Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-12 15:32 ` [PATCH v6 05/10] monitor: Drop query-qmp-schema 'gen': false hack Markus Armbruster
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

This policy suppresses deprecated bits in output, and thus permits
"testing the future".  Implement it for QMP event data: suppress
deprecated members.

No QMP event data is deprecated right now.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 tests/test-qmp-event.c                  | 21 +++++++++++++++++++++
 scripts/qapi/events.py                  |  8 ++++++--
 tests/qapi-schema/qapi-schema-test.json |  3 +++
 tests/qapi-schema/qapi-schema-test.out  |  2 ++
 4 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c
index ab059fb5c2..047f44ff9a 100644
--- a/tests/test-qmp-event.c
+++ b/tests/test-qmp-event.c
@@ -159,6 +159,26 @@ static void test_event_deprecated(TestEventData *data, const void *unused)
     qobject_unref(data->expect);
 }
 
+static void test_event_deprecated_data(TestEventData *data, const void *unused)
+{
+    memset(&compat_policy, 0, sizeof(compat_policy));
+
+    data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES0',"
+                                           " 'data': { 'foo': 42 } }");
+    qapi_event_send_test_event_features0(42);
+    g_assert(data->emitted);
+
+    qobject_unref(data->expect);
+
+    compat_policy.has_deprecated_output = true;
+    compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE;
+    data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES0' }");
+    qapi_event_send_test_event_features0(42);
+    g_assert(data->emitted);
+
+    qobject_unref(data->expect);
+}
+
 int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
@@ -168,6 +188,7 @@ int main(int argc, char **argv)
     event_test_add("/event/event_c", test_event_c);
     event_test_add("/event/event_d", test_event_d);
     event_test_add("/event/deprecated", test_event_deprecated);
+    event_test_add("/event/deprecated_data", test_event_deprecated_data);
     g_test_run();
 
     return 0;
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index f6e1e76f64..8335c2bdfc 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -126,7 +126,7 @@ def gen_event_send(name: str,
     if have_args:
         assert arg_type is not None
         ret += mcgen('''
-    v = qobject_output_visitor_new(&obj);
+    v = qobject_output_visitor_new_qmp(&obj);
 ''')
         if not arg_type.is_implicit():
             ret += mcgen('''
@@ -145,7 +145,11 @@ def gen_event_send(name: str,
         ret += mcgen('''
 
     visit_complete(v, &obj);
-    qdict_put_obj(qmp, "data", obj);
+    if (qdict_size(qobject_to(QDict, obj))) {
+        qdict_put_obj(qmp, "data", obj);
+    } else {
+        qobject_unref(obj);
+    }
 ''')
 
     ret += mcgen('''
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 48a0adabae..12ec588b52 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -324,5 +324,8 @@
   'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
                                               'defined(TEST_IF_COND_2)'] } ] }
 
+{ 'event': 'TEST-EVENT-FEATURES0',
+  'data': 'FeatureStruct1' }
+
 { 'event': 'TEST-EVENT-FEATURES1',
   'features': [ 'deprecated' ] }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 776d737891..f5741df97f 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -440,6 +440,8 @@ command test-command-cond-features3 None -> None
     gen=True success_response=True boxed=False oob=False preconfig=False
     feature feature1
         if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
+event TEST-EVENT-FEATURES0 FeatureStruct1
+    boxed=False
 event TEST-EVENT-FEATURES1 None
     boxed=False
     feature deprecated
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 05/10] monitor: Drop query-qmp-schema 'gen': false hack
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
                   ` (3 preceding siblings ...)
  2021-03-12 15:32 ` [PATCH v6 04/10] qapi: Implement deprecated-output=hide for QMP event data Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-15 16:10   ` Eric Blake
  2021-03-12 15:32 ` [PATCH v6 06/10] qapi: Implement deprecated-output=hide for QMP introspection Markus Armbruster
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

QMP commands return their response as a generated QAPI type, which the
monitor core converts to JSON via QObject.

query-qmp-schema's response is the generated introspection data.  This
is a QLitObject since commit 7d0f982bfb "qapi: generate a literal
qobject for introspection", v2.12).  Before, it was a string.  Instead
of converting QLitObject / string -> QObject -> QAPI type
SchemaInfoList -> QObject -> JSON, we take a shortcut: the command is
'gen': false, so it can return the QObject instead of the QAPI type.
Slightly simpler and more efficient.

The next commit will filter the response for output policy, and this
is easier in the SchemaInfoList representation.  Drop the shortcut.

This replaces the manual command registration by a generated one.  The
manual registration makes the commnd available before the machine is
built by passing flag QCO_ALLOW_PRECONFIG.  To keep it available
there, we need need to add 'allow-preconfig': true to its definition
in the schema.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 qapi/introspect.json                 |  2 +-
 monitor/monitor-internal.h           |  3 ---
 monitor/misc.c                       |  2 --
 monitor/qmp-cmds-control.c           | 29 ++++++++++++++++------------
 storage-daemon/qemu-storage-daemon.c |  2 --
 5 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/qapi/introspect.json b/qapi/introspect.json
index 944bb87a20..39bd303778 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -49,7 +49,7 @@
 ##
 { 'command': 'query-qmp-schema',
   'returns': [ 'SchemaInfo' ],
-  'gen': false }                # just to simplify qmp_query_json()
+  'allow-preconfig': true }
 
 ##
 # @SchemaMetaType:
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 40903d6386..9c3a09cb01 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -183,7 +183,4 @@ void help_cmd(Monitor *mon, const char *name);
 void handle_hmp_command(MonitorHMP *mon, const char *cmdline);
 int hmp_compare_cmd(const char *name, const char *list);
 
-void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
-                                 Error **errp);
-
 #endif
diff --git a/monitor/misc.c b/monitor/misc.c
index a7650ed747..0b46006e42 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -231,8 +231,6 @@ static void monitor_init_qmp_commands(void)
 
     qmp_init_marshal(&qmp_commands);
 
-    qmp_register_command(&qmp_commands, "query-qmp-schema",
-                         qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
     qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
                          QCO_NO_OPTIONS);
     qmp_register_command(&qmp_commands, "object-add", qmp_object_add,
diff --git a/monitor/qmp-cmds-control.c b/monitor/qmp-cmds-control.c
index 509ae870bd..25afd0867f 100644
--- a/monitor/qmp-cmds-control.c
+++ b/monitor/qmp-cmds-control.c
@@ -26,10 +26,14 @@
 
 #include "monitor-internal.h"
 #include "qemu-version.h"
+#include "qapi/compat-policy.h"
 #include "qapi/error.h"
 #include "qapi/qapi-commands-control.h"
+#include "qapi/qapi-commands-introspect.h"
 #include "qapi/qapi-emit-events.h"
 #include "qapi/qapi-introspect.h"
+#include "qapi/qapi-visit-introspect.h"
+#include "qapi/qobject-input-visitor.h"
 
 /*
  * Accept QMP capabilities in @list for @mon.
@@ -154,17 +158,18 @@ EventInfoList *qmp_query_events(Error **errp)
     return ev_list;
 }
 
-/*
- * Minor hack: generated marshalling suppressed for this command
- * ('gen': false in the schema) so we can parse the JSON string
- * directly into QObject instead of first parsing it with
- * visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it
- * to QObject with generated output marshallers, every time.  Instead,
- * we do it in test-qobject-input-visitor.c, just to make sure
- * qapi-gen.py's output actually conforms to the schema.
- */
-void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
-                                 Error **errp)
+SchemaInfoList *qmp_query_qmp_schema(Error **errp)
 {
-    *ret_data = qobject_from_qlit(&qmp_schema_qlit);
+    QObject *obj = qobject_from_qlit(&qmp_schema_qlit);
+    Visitor *v = qobject_input_visitor_new(obj);
+    SchemaInfoList *schema = NULL;
+
+    /* test_visitor_in_qmp_introspect() ensures this can't fail */
+    visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
+    g_assert(schema);
+
+    qobject_unref(obj);
+    visit_free(v);
+
+    return schema;
 }
diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c
index 23756fc8e5..02afdbeafc 100644
--- a/storage-daemon/qemu-storage-daemon.c
+++ b/storage-daemon/qemu-storage-daemon.c
@@ -146,8 +146,6 @@ static QemuOptsList qemu_object_opts = {
 static void init_qmp_commands(void)
 {
     qmp_init_marshal(&qmp_commands);
-    qmp_register_command(&qmp_commands, "query-qmp-schema",
-                         qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
     qmp_register_command(&qmp_commands, "object-add", qmp_object_add,
                          QCO_NO_OPTIONS);
 
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 06/10] qapi: Implement deprecated-output=hide for QMP introspection
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
                   ` (4 preceding siblings ...)
  2021-03-12 15:32 ` [PATCH v6 05/10] monitor: Drop query-qmp-schema 'gen': false hack Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-15 16:13   ` Eric Blake
  2021-03-12 15:32 ` [PATCH v6 07/10] test-util-sockets: Add stub for monitor_set_cur() Markus Armbruster
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

This policy suppresses deprecated bits in output, and thus permits
"testing the future".  Implement it for QMP command query-qmp-schema:
suppress information on deprecated commands, events and object type
members, i.e. anything that has the special feature flag "deprecated".

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 monitor/qmp-cmds-control.c | 71 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/monitor/qmp-cmds-control.c b/monitor/qmp-cmds-control.c
index 25afd0867f..bcfccc4ac4 100644
--- a/monitor/qmp-cmds-control.c
+++ b/monitor/qmp-cmds-control.c
@@ -158,6 +158,74 @@ EventInfoList *qmp_query_events(Error **errp)
     return ev_list;
 }
 
+static void *split_off_generic_list(void *list,
+                                    bool (*splitp)(void *elt),
+                                    void **part)
+{
+    GenericList *keep = NULL, **keep_tailp = &keep;
+    GenericList *split = NULL, **split_tailp = &split;
+    GenericList *tail;
+
+    for (tail = list; tail; tail = tail->next) {
+        if (splitp(tail)) {
+            *split_tailp = tail;
+            split_tailp = &tail->next;
+        } else {
+            *keep_tailp = tail;
+            keep_tailp = &tail->next;
+        }
+    }
+
+    *keep_tailp = *split_tailp = NULL;
+    *part = split;
+    return keep;
+}
+
+static bool is_in(const char *s, strList *list)
+{
+    strList *tail;
+
+    for (tail = list; tail; tail = tail->next) {
+        if (!strcmp(tail->value, s)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static bool is_entity_deprecated(void *link)
+{
+    return is_in("deprecated", ((SchemaInfoList *)link)->value->features);
+}
+
+static bool is_member_deprecated(void *link)
+{
+    return is_in("deprecated",
+                 ((SchemaInfoObjectMemberList *)link)->value->features);
+}
+
+static SchemaInfoList *zap_deprecated(SchemaInfoList *schema)
+{
+    void *to_zap;
+    SchemaInfoList *tail;
+    SchemaInfo *ent;
+
+    schema = split_off_generic_list(schema, is_entity_deprecated, &to_zap);
+    qapi_free_SchemaInfoList(to_zap);
+
+    for (tail = schema; tail; tail = tail->next) {
+        ent = tail->value;
+        if (ent->meta_type == SCHEMA_META_TYPE_OBJECT) {
+            ent->u.object.members
+                = split_off_generic_list(ent->u.object.members,
+                                         is_member_deprecated, &to_zap);
+            qapi_free_SchemaInfoObjectMemberList(to_zap);
+        }
+    }
+
+    return schema;
+}
+
 SchemaInfoList *qmp_query_qmp_schema(Error **errp)
 {
     QObject *obj = qobject_from_qlit(&qmp_schema_qlit);
@@ -171,5 +239,8 @@ SchemaInfoList *qmp_query_qmp_schema(Error **errp)
     qobject_unref(obj);
     visit_free(v);
 
+    if (compat_policy.deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) {
+        return zap_deprecated(schema);
+    }
     return schema;
 }
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 07/10] test-util-sockets: Add stub for monitor_set_cur()
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
                   ` (5 preceding siblings ...)
  2021-03-12 15:32 ` [PATCH v6 06/10] qapi: Implement deprecated-output=hide for QMP introspection Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-15 16:14   ` Eric Blake
  2021-03-12 15:32 ` [PATCH v6 08/10] qapi: Implement deprecated-input=reject for QMP commands Markus Armbruster
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, marcandre.lureau, mdroth

Without this stub, the next commit fails to link.  I suspect the real
cause is 947e47448d "monitor: Use getter/setter functions for
cur_mon".

Cc: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/test-util-sockets.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c
index 67486055ed..72b9246529 100644
--- a/tests/test-util-sockets.c
+++ b/tests/test-util-sockets.c
@@ -73,6 +73,7 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
  * otherwise we get duplicate syms at link time.
  */
 Monitor *monitor_cur(void) { return cur_mon; }
+Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); }
 int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); }
 
 #ifndef _WIN32
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 08/10] qapi: Implement deprecated-input=reject for QMP commands
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
                   ` (6 preceding siblings ...)
  2021-03-12 15:32 ` [PATCH v6 07/10] test-util-sockets: Add stub for monitor_set_cur() Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-15 16:16   ` Eric Blake
  2021-03-12 15:32 ` [PATCH v6 09/10] qapi: Implement deprecated-input=reject for QMP command arguments Markus Armbruster
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

This policy rejects deprecated input, and thus permits "testing the
future".  Implement it for QMP commands: make deprecated ones fail.
Example: when QEMU is run with -compat deprecated-input=reject, then

    {"execute": "query-cpus"}

fails like this

    {"error": {"class": "CommandNotFound", "desc": "Deprecated command query-cpus disabled by policy"}}

When the deprecated command is removed, the error will change to

    {"error": {"class": "CommandNotFound", "desc": "The command query-cpus has not been found"}}

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 include/qapi/qmp/dispatch.h |  1 +
 qapi/qmp-dispatch.c         | 13 +++++++++++++
 tests/test-qmp-cmds.c       | 24 ++++++++++++++++++++++++
 scripts/qapi/commands.py    | 10 +++++++---
 4 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 1486cac3ef..8b974b570e 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -26,6 +26,7 @@ typedef enum QmpCommandOptions
     QCO_ALLOW_OOB             =  (1U << 1),
     QCO_ALLOW_PRECONFIG       =  (1U << 2),
     QCO_COROUTINE             =  (1U << 3),
+    QCO_DEPRECATED            =  (1U << 4),
 } QmpCommandOptions;
 
 typedef struct QmpCommand
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 45090f881a..cbc4452341 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -158,6 +158,19 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
                   "The command %s has not been found", command);
         goto out;
     }
+    if (cmd->options & QCO_DEPRECATED) {
+        switch (compat_policy.deprecated_input) {
+        case COMPAT_POLICY_INPUT_ACCEPT:
+            break;
+        case COMPAT_POLICY_INPUT_REJECT:
+            error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
+                      "Deprecated command %s disabled by policy",
+                      command);
+            goto out;
+        default:
+            abort();
+        }
+    }
     if (!cmd->enabled) {
         error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
                   "The command %s has been disabled for this instance",
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 1079d35122..cba982154b 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -281,6 +281,28 @@ static void test_dispatch_cmd_io(void)
     qobject_unref(ret3);
 }
 
+static void test_dispatch_cmd_deprecated(void)
+{
+    const char *cmd = "{ 'execute': 'test-command-features1' }";
+    QDict *ret;
+
+    memset(&compat_policy, 0, sizeof(compat_policy));
+
+    /* accept */
+    ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+    assert(ret && qdict_size(ret) == 0);
+    qobject_unref(ret);
+
+    compat_policy.has_deprecated_input = true;
+    compat_policy.deprecated_input = COMPAT_POLICY_INPUT_ACCEPT;
+    ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+    assert(ret && qdict_size(ret) == 0);
+    qobject_unref(ret);
+
+    compat_policy.deprecated_input = COMPAT_POLICY_INPUT_REJECT;
+    do_qmp_dispatch_error(false, ERROR_CLASS_COMMAND_NOT_FOUND, cmd);
+}
+
 static void test_dispatch_cmd_ret_deprecated(void)
 {
     const char *cmd = "{ 'execute': 'test-features0' }";
@@ -379,6 +401,8 @@ int main(int argc, char **argv)
     g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
     g_test_add_func("/qmp/dispatch_cmd_success_response",
                     test_dispatch_cmd_success_response);
+    g_test_add_func("/qmp/dispatch_cmd_deprecated",
+                    test_dispatch_cmd_deprecated);
     g_test_add_func("/qmp/dispatch_cmd_ret_deprecated",
                     test_dispatch_cmd_ret_deprecated);
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 7adeda917b..f5d97454af 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -210,12 +210,16 @@ def gen_marshal(name: str,
 
 
 def gen_register_command(name: str,
+                         features: List[QAPISchemaFeature],
                          success_response: bool,
                          allow_oob: bool,
                          allow_preconfig: bool,
                          coroutine: bool) -> str:
     options = []
 
+    if 'deprecated' in [f.name for f in features]:
+        options += ['QCO_DEPRECATED']
+
     if not success_response:
         options += ['QCO_NO_SUCCESS_RESP']
     if allow_oob:
@@ -326,9 +330,9 @@ def visit_command(self,
             self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
         with self._temp_module('./init'):
             with ifcontext(ifcond, self._genh, self._genc):
-                self._genc.add(gen_register_command(name, success_response,
-                                                    allow_oob, allow_preconfig,
-                                                    coroutine))
+                self._genc.add(gen_register_command(
+                    name, features, success_response, allow_oob,
+                    allow_preconfig, coroutine))
 
 
 def gen_commands(schema: QAPISchema,
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 09/10] qapi: Implement deprecated-input=reject for QMP command arguments
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
                   ` (7 preceding siblings ...)
  2021-03-12 15:32 ` [PATCH v6 08/10] qapi: Implement deprecated-input=reject for QMP commands Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-12 15:32 ` [PATCH v6 10/10] qapi: New -compat deprecated-input=crash Markus Armbruster
  2021-03-18 15:08 ` [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
  10 siblings, 0 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

This policy rejects deprecated input, and thus permits "testing the
future".  Implement it for QMP command arguments: reject commands with
deprecated ones.  Example: when QEMU is run with -compat
deprecated-input=reject, then

    {"execute": "eject", "arguments": {"device": "cd"}}

fails like this

    {"error": {"class": "GenericError", "desc": "Deprecated parameter 'device' disabled by policy"}}

When the deprecated parameter is removed, the error will change to

    {"error": {"class": "GenericError", "desc": "Parameter 'device' is unexpected"}}

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 include/qapi/qobject-input-visitor.h |  9 +++++++++
 include/qapi/visitor-impl.h          |  3 +++
 include/qapi/visitor.h               |  9 +++++++++
 qapi/qapi-visit-core.c               |  9 +++++++++
 qapi/qobject-input-visitor.c         | 28 ++++++++++++++++++++++++++++
 tests/test-qmp-cmds.c                | 25 +++++++++++++++++++++++++
 qapi/trace-events                    |  1 +
 scripts/qapi/commands.py             |  2 +-
 scripts/qapi/visit.py                |  3 +++
 9 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/include/qapi/qobject-input-visitor.h b/include/qapi/qobject-input-visitor.h
index 95985e25e5..cbc54de4ac 100644
--- a/include/qapi/qobject-input-visitor.h
+++ b/include/qapi/qobject-input-visitor.h
@@ -58,6 +58,15 @@ typedef struct QObjectInputVisitor QObjectInputVisitor;
  */
 Visitor *qobject_input_visitor_new(QObject *obj);
 
+/*
+ * Create a QObject input visitor for @obj for use with QMP
+ *
+ * This is like qobject_input_visitor_new(), except it obeys the
+ * policy for handling deprecated management interfaces set with
+ * -compat.
+ */
+Visitor *qobject_input_visitor_new_qmp(QObject *obj);
+
 /*
  * Create a QObject input visitor for @obj for use with keyval_parse()
  *
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 2d853255a3..3b950f6e3d 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -113,6 +113,9 @@ struct Visitor
        The core takes care of the return type in the public interface. */
     void (*optional)(Visitor *v, const char *name, bool *present);
 
+    /* Optional */
+    bool (*deprecated_accept)(Visitor *v, const char *name, Error **errp);
+
     /* Optional */
     bool (*deprecated)(Visitor *v, const char *name);
 
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 4d23b59853..b3c9ef7a81 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -459,6 +459,15 @@ void visit_end_alternate(Visitor *v, void **obj);
  */
 bool visit_optional(Visitor *v, const char *name, bool *present);
 
+/*
+ * Should we reject deprecated member @name?
+ *
+ * @name must not be NULL.  This function is only useful between
+ * visit_start_struct() and visit_end_struct(), since only objects
+ * have deprecated members.
+ */
+bool visit_deprecated_accept(Visitor *v, const char *name, Error **errp);
+
 /*
  * Should we visit deprecated member @name?
  *
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index d9726ecaa1..a641adec51 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -135,6 +135,15 @@ bool visit_optional(Visitor *v, const char *name, bool *present)
     return *present;
 }
 
+bool visit_deprecated_accept(Visitor *v, const char *name, Error **errp)
+{
+    trace_visit_deprecated_accept(v, name);
+    if (v->deprecated_accept) {
+        return v->deprecated_accept(v, name, errp);
+    }
+    return true;
+}
+
 bool visit_deprecated(Visitor *v, const char *name)
 {
     trace_visit_deprecated(v, name);
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index 23843b242e..1b8fa1f2f6 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -14,6 +14,7 @@
 
 #include "qemu/osdep.h"
 #include <math.h>
+#include "qapi/compat-policy.h"
 #include "qapi/error.h"
 #include "qapi/qobject-input-visitor.h"
 #include "qapi/visitor-impl.h"
@@ -43,6 +44,7 @@ typedef struct StackObject {
 
 struct QObjectInputVisitor {
     Visitor visitor;
+    CompatPolicyInput deprecated_policy;
 
     /* Root of visit at visitor creation. */
     QObject *root;
@@ -662,6 +664,23 @@ static void qobject_input_optional(Visitor *v, const char *name, bool *present)
     *present = true;
 }
 
+static bool qobject_input_deprecated_accept(Visitor *v, const char *name,
+                                            Error **errp)
+{
+    QObjectInputVisitor *qiv = to_qiv(v);
+
+    switch (qiv->deprecated_policy) {
+    case COMPAT_POLICY_INPUT_ACCEPT:
+        return true;
+    case COMPAT_POLICY_INPUT_REJECT:
+        error_setg(errp, "Deprecated parameter '%s' disabled by policy",
+                   name);
+        return false;
+    default:
+        abort();
+    }
+}
+
 static void qobject_input_free(Visitor *v)
 {
     QObjectInputVisitor *qiv = to_qiv(v);
@@ -696,6 +715,7 @@ static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
     v->visitor.end_list = qobject_input_end_list;
     v->visitor.start_alternate = qobject_input_start_alternate;
     v->visitor.optional = qobject_input_optional;
+    v->visitor.deprecated_accept = qobject_input_deprecated_accept;
     v->visitor.free = qobject_input_free;
 
     v->root = qobject_ref(obj);
@@ -718,6 +738,14 @@ Visitor *qobject_input_visitor_new(QObject *obj)
     return &v->visitor;
 }
 
+Visitor *qobject_input_visitor_new_qmp(QObject *obj)
+{
+    QObjectInputVisitor *v = to_qiv(qobject_input_visitor_new(obj));
+
+    v->deprecated_policy = compat_policy.deprecated_input;
+    return &v->visitor;
+}
+
 Visitor *qobject_input_visitor_new_keyval(QObject *obj)
 {
     QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index cba982154b..266db074b4 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -303,6 +303,29 @@ static void test_dispatch_cmd_deprecated(void)
     do_qmp_dispatch_error(false, ERROR_CLASS_COMMAND_NOT_FOUND, cmd);
 }
 
+static void test_dispatch_cmd_arg_deprecated(void)
+{
+    const char *cmd = "{ 'execute': 'test-features0',"
+        " 'arguments': { 'fs1': { 'foo': 42 } } }";
+    QDict *ret;
+
+    memset(&compat_policy, 0, sizeof(compat_policy));
+
+    /* accept */
+    ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+    assert(ret && qdict_size(ret) == 1);
+    qobject_unref(ret);
+
+    compat_policy.has_deprecated_input = true;
+    compat_policy.deprecated_input = COMPAT_POLICY_INPUT_ACCEPT;
+    ret = qobject_to(QDict, do_qmp_dispatch(false, cmd));
+    assert(ret && qdict_size(ret) == 1);
+    qobject_unref(ret);
+
+    compat_policy.deprecated_input = COMPAT_POLICY_INPUT_REJECT;
+    do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR, cmd);
+}
+
 static void test_dispatch_cmd_ret_deprecated(void)
 {
     const char *cmd = "{ 'execute': 'test-features0' }";
@@ -403,6 +426,8 @@ int main(int argc, char **argv)
                     test_dispatch_cmd_success_response);
     g_test_add_func("/qmp/dispatch_cmd_deprecated",
                     test_dispatch_cmd_deprecated);
+    g_test_add_func("/qmp/dispatch_cmd_arg_deprecated",
+                    test_dispatch_cmd_arg_deprecated);
     g_test_add_func("/qmp/dispatch_cmd_ret_deprecated",
                     test_dispatch_cmd_ret_deprecated);
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
diff --git a/qapi/trace-events b/qapi/trace-events
index eff1fbd199..3cabe912ae 100644
--- a/qapi/trace-events
+++ b/qapi/trace-events
@@ -17,6 +17,7 @@ visit_start_alternate(void *v, const char *name, void *obj, size_t size) "v=%p n
 visit_end_alternate(void *v, void *obj) "v=%p obj=%p"
 
 visit_optional(void *v, const char *name, bool *present) "v=%p name=%s present=%p"
+visit_deprecated_accept(void *v, const char *name) "v=%p name=%s"
 visit_deprecated(void *v, const char *name) "v=%p name=%s"
 
 visit_type_enum(void *v, const char *name, int *obj) "v=%p name=%s obj=%p"
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index f5d97454af..8ccd1d9224 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -154,7 +154,7 @@ def gen_marshal(name: str,
 
     ret += mcgen('''
 
-    v = qobject_input_visitor_new(QOBJECT(args));
+    v = qobject_input_visitor_new_qmp(QOBJECT(args));
     if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
         goto out;
     }
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 9d83bf650f..9e96f3c566 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -87,6 +87,9 @@ def gen_visit_object_members(name: str,
             indent.increase()
         if deprecated:
             ret += mcgen('''
+    if (!visit_deprecated_accept(v, "%(name)s", errp)) {
+        return false;
+    }
     if (visit_deprecated(v, "%(name)s")) {
 ''',
                          name=memb.name)
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v6 10/10] qapi: New -compat deprecated-input=crash
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
                   ` (8 preceding siblings ...)
  2021-03-12 15:32 ` [PATCH v6 09/10] qapi: Implement deprecated-input=reject for QMP command arguments Markus Armbruster
@ 2021-03-12 15:32 ` Markus Armbruster
  2021-03-15 16:19   ` Eric Blake
  2021-03-18 15:08 ` [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
  10 siblings, 1 reply; 23+ messages in thread
From: Markus Armbruster @ 2021-03-12 15:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

Policy "crash" calls abort() when deprecated input is received.

Bugs in integration tests may mask the error from policy "reject".
Provide a larger hammer: crash outright.  Masking that seems unlikely.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 qapi/compat.json             | 9 +++++----
 qapi/qmp-dispatch.c          | 1 +
 qapi/qobject-input-visitor.c | 1 +
 qemu-options.hx              | 4 +++-
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/qapi/compat.json b/qapi/compat.json
index d2c02a21aa..ae3afc22df 100644
--- a/qapi/compat.json
+++ b/qapi/compat.json
@@ -11,11 +11,12 @@
 #
 # @accept: Accept silently
 # @reject: Reject with an error
+# @crash: abort() the process
 #
-# Since: 5.2
+# Since: 6.0
 ##
 { 'enum': 'CompatPolicyInput',
-  'data': [ 'accept', 'reject' ] }
+  'data': [ 'accept', 'reject', 'crash' ] }
 
 ##
 # @CompatPolicyOutput:
@@ -25,7 +26,7 @@
 # @accept: Pass on unchanged
 # @hide: Filter out
 #
-# Since: 5.2
+# Since: 6.0
 ##
 { 'enum': 'CompatPolicyOutput',
   'data': [ 'accept', 'hide' ] }
@@ -44,7 +45,7 @@
 # @deprecated-input: how to handle deprecated input (default 'accept')
 # @deprecated-output: how to handle deprecated output (default 'accept')
 #
-# Since: 5.2
+# Since: 6.0
 ##
 { 'struct': 'CompatPolicy',
   'data': { '*deprecated-input': 'CompatPolicyInput',
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index cbc4452341..12657d635e 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -167,6 +167,7 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
                       "Deprecated command %s disabled by policy",
                       command);
             goto out;
+        case COMPAT_POLICY_INPUT_CRASH:
         default:
             abort();
         }
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index 1b8fa1f2f6..baad0dcd3c 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -676,6 +676,7 @@ static bool qobject_input_deprecated_accept(Visitor *v, const char *name,
         error_setg(errp, "Deprecated parameter '%s' disabled by policy",
                    name);
         return false;
+    case COMPAT_POLICY_INPUT_CRASH:
     default:
         abort();
     }
diff --git a/qemu-options.hx b/qemu-options.hx
index 2be2feed32..165fa048e9 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3471,7 +3471,7 @@ DEFHEADING()
 DEFHEADING(Debug/Expert options:)
 
 DEF("compat", HAS_ARG, QEMU_OPTION_compat,
-    "-compat [deprecated-input=accept|reject][,deprecated-output=accept|hide]\n"
+    "-compat [deprecated-input=accept|reject|crash][,deprecated-output=accept|hide]\n"
     "                Policy for handling deprecated management interfaces\n",
     QEMU_ARCH_ALL)
 SRST
@@ -3482,6 +3482,8 @@ SRST
         Accept deprecated commands and arguments
     ``deprecated-input=reject``
         Reject deprecated commands and arguments
+    ``deprecated-input=crash``
+        Crash on deprecated commands and arguments
     ``deprecated-output=accept`` (default)
         Emit deprecated command results and events
     ``deprecated-output=hide``
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 01/10] qemu-options: New -compat to set policy for deprecated interfaces
  2021-03-12 15:32 ` [PATCH v6 01/10] qemu-options: New -compat to set policy for " Markus Armbruster
@ 2021-03-15 15:41   ` Eric Blake
  2021-03-15 16:29     ` Markus Armbruster
  0 siblings, 1 reply; 23+ messages in thread
From: Eric Blake @ 2021-03-15 15:41 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

On 3/12/21 9:32 AM, Markus Armbruster wrote:
> New option -compat lets you configure what to do when deprecated
> interfaces get used.  This is intended for testing users of the
> management interfaces.  It is experimental.
> 
> -compat deprecated-input=<input-policy> configures what to do when
> deprecated input is received.  Input policy can be "accept" (accept
> silently), or "reject" (reject the request with an error).
> 
> -compat deprecated-output=<out-policy> configures what to do when
> deprecated output is sent.  Output policy can be "accept" (pass on
> unchanged), or "hide" (filter out the deprecated parts).
> 
> Default is "accept".  Policies other than "accept" are implemented
> later in this series.
> 
> For now, -compat covers only syntactic aspects of QMP, i.e. stuff
> tagged with feature 'deprecated'.  We may want to extend it to cover
> semantic aspects, CLI, and experimental features.
> 
> Note that there is no good way for management application to detect
> presence of -compat: it's not visible output of query-qmp-schema or
> query-command-line-options.  Tolerable, because it's meant for
> testing.  If running with -compat fails, skip the test.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---

> +++ b/qapi/compat.json
> @@ -0,0 +1,51 @@
> +# -*- Mode: Python -*-
> +
> +##
> +# = Compatibility policy
> +##
> +
> +##
> +# @CompatPolicyInput:
> +#
> +# Policy for handling "funny" input.
> +#
> +# @accept: Accept silently
> +# @reject: Reject with an error
> +#
> +# Since: 5.2

6.0

> +##
> +{ 'enum': 'CompatPolicyInput',
> +  'data': [ 'accept', 'reject' ] }
> +
> +##
> +# @CompatPolicyOutput:
> +#
> +# Policy for handling "funny" output.
> +#
> +# @accept: Pass on unchanged
> +# @hide: Filter out
> +#
> +# Since: 5.2

and here

> +##
> +{ 'enum': 'CompatPolicyOutput',
> +  'data': [ 'accept', 'hide' ] }
> +
> +##
> +# @CompatPolicy:
> +#
> +# Policy for handling deprecated management interfaces.
> +#
> +# This is intended for testing users of the management interfaces.
> +#
> +# Limitation: covers only syntactic aspects of QMP, i.e. stuff tagged
> +# with feature 'deprecated'.  We may want to extend it to cover
> +# semantic aspects, CLI, and experimental features.
> +#
> +# @deprecated-input: how to handle deprecated input (default 'accept')
> +# @deprecated-output: how to handle deprecated output (default 'accept')
> +#
> +# Since: 5.2

and here

> +##
> +{ 'struct': 'CompatPolicy',
> +  'data': { '*deprecated-input': 'CompatPolicyInput',
> +            '*deprecated-output': 'CompatPolicyOutput' } }
> diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
> index 3441c9a9ae..4912b9744e 100644

R-b still stands once you make the necessary tweaks.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results
  2021-03-12 15:32 ` [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results Markus Armbruster
@ 2021-03-15 15:45   ` Eric Blake
  2021-03-15 16:33     ` Markus Armbruster
  2021-03-18 13:36   ` Markus Armbruster
  1 sibling, 1 reply; 23+ messages in thread
From: Eric Blake @ 2021-03-15 15:45 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel
  Cc: Daniel P. Berrangé, marcandre.lureau, mdroth

On 3/12/21 9:32 AM, Markus Armbruster wrote:
> This policy suppresses deprecated bits in output, and thus permits
> "testing the future".  Implement it for QMP command results.  Example:
> when QEMU is run with -compat deprecated-output=hide, then
> 
>     {"execute": "query-cpus-fast"}
> 
> yields
> 
>     {"return": [{"thread-id": 9805, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}
> 
> instead of
> 
>     {"return": [{"arch": "x86", "thread-id": 22436, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}

Example may not be relevant much longer, given Dan's patch [1] to make
this permanent since we've already passed the deprecation wait.  Up to
you if you want to choose a different example.

https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg07564.html

> 
> Note the suppression of deprecated member "arch".
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---

R-b still stands.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 05/10] monitor: Drop query-qmp-schema 'gen': false hack
  2021-03-12 15:32 ` [PATCH v6 05/10] monitor: Drop query-qmp-schema 'gen': false hack Markus Armbruster
@ 2021-03-15 16:10   ` Eric Blake
  2021-03-15 16:34     ` Markus Armbruster
  0 siblings, 1 reply; 23+ messages in thread
From: Eric Blake @ 2021-03-15 16:10 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

On 3/12/21 9:32 AM, Markus Armbruster wrote:
> QMP commands return their response as a generated QAPI type, which the
> monitor core converts to JSON via QObject.
> 
> query-qmp-schema's response is the generated introspection data.  This
> is a QLitObject since commit 7d0f982bfb "qapi: generate a literal
> qobject for introspection", v2.12).  Before, it was a string.  Instead
> of converting QLitObject / string -> QObject -> QAPI type
> SchemaInfoList -> QObject -> JSON, we take a shortcut: the command is
> 'gen': false, so it can return the QObject instead of the QAPI type.
> Slightly simpler and more efficient.
> 
> The next commit will filter the response for output policy, and this
> is easier in the SchemaInfoList representation.  Drop the shortcut.
> 
> This replaces the manual command registration by a generated one.  The
> manual registration makes the commnd available before the machine is

command

> built by passing flag QCO_ALLOW_PRECONFIG.  To keep it available
> there, we need need to add 'allow-preconfig': true to its definition
> in the schema.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  qapi/introspect.json                 |  2 +-
>  monitor/monitor-internal.h           |  3 ---
>  monitor/misc.c                       |  2 --
>  monitor/qmp-cmds-control.c           | 29 ++++++++++++++++------------
>  storage-daemon/qemu-storage-daemon.c |  2 --
>  5 files changed, 18 insertions(+), 20 deletions(-)
> 

R-b still stands.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 06/10] qapi: Implement deprecated-output=hide for QMP introspection
  2021-03-12 15:32 ` [PATCH v6 06/10] qapi: Implement deprecated-output=hide for QMP introspection Markus Armbruster
@ 2021-03-15 16:13   ` Eric Blake
  0 siblings, 0 replies; 23+ messages in thread
From: Eric Blake @ 2021-03-15 16:13 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

On 3/12/21 9:32 AM, Markus Armbruster wrote:
> This policy suppresses deprecated bits in output, and thus permits
> "testing the future".  Implement it for QMP command query-qmp-schema:
> suppress information on deprecated commands, events and object type
> members, i.e. anything that has the special feature flag "deprecated".
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  monitor/qmp-cmds-control.c | 71 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
> 
> diff --git a/monitor/qmp-cmds-control.c b/monitor/qmp-cmds-control.c
> index 25afd0867f..bcfccc4ac4 100644
> --- a/monitor/qmp-cmds-control.c
> +++ b/monitor/qmp-cmds-control.c
> @@ -158,6 +158,74 @@ EventInfoList *qmp_query_events(Error **errp)
>      return ev_list;
>  }
>  
> +static void *split_off_generic_list(void *list,
> +                                    bool (*splitp)(void *elt),
> +                                    void **part)
> +{
> +    GenericList *keep = NULL, **keep_tailp = &keep;
> +    GenericList *split = NULL, **split_tailp = &split;
> +    GenericList *tail;
> +
> +    for (tail = list; tail; tail = tail->next) {
> +        if (splitp(tail)) {
> +            *split_tailp = tail;
> +            split_tailp = &tail->next;
> +        } else {
> +            *keep_tailp = tail;
> +            keep_tailp = &tail->next;
> +        }
> +    }

At first glance, I wondered if QAPI_LIST_APPEND would be better than
open coding, but with a bit more thought, I agree that this particular
case is best written as presented (you are manipulating two tail
pointers in one iteration, which is different semantics than
QAPI_LIST_APPEND advancing a single tail pointer).

R-b still stands.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 07/10] test-util-sockets: Add stub for monitor_set_cur()
  2021-03-12 15:32 ` [PATCH v6 07/10] test-util-sockets: Add stub for monitor_set_cur() Markus Armbruster
@ 2021-03-15 16:14   ` Eric Blake
  0 siblings, 0 replies; 23+ messages in thread
From: Eric Blake @ 2021-03-15 16:14 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: Kevin Wolf, marcandre.lureau, mdroth

On 3/12/21 9:32 AM, Markus Armbruster wrote:
> Without this stub, the next commit fails to link.  I suspect the real
> cause is 947e47448d "monitor: Use getter/setter functions for
> cur_mon".
> 
> Cc: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  tests/test-util-sockets.c | 1 +
>  1 file changed, 1 insertion(+)

We may be able to clean this up later, but in the interest of getting
this series into soft freeze,

Reviewed-by: Eric Blake <eblake@redhat.com>

> 
> diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c
> index 67486055ed..72b9246529 100644
> --- a/tests/test-util-sockets.c
> +++ b/tests/test-util-sockets.c
> @@ -73,6 +73,7 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
>   * otherwise we get duplicate syms at link time.
>   */
>  Monitor *monitor_cur(void) { return cur_mon; }
> +Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); }
>  int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); }
>  
>  #ifndef _WIN32
> 

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 08/10] qapi: Implement deprecated-input=reject for QMP commands
  2021-03-12 15:32 ` [PATCH v6 08/10] qapi: Implement deprecated-input=reject for QMP commands Markus Armbruster
@ 2021-03-15 16:16   ` Eric Blake
  0 siblings, 0 replies; 23+ messages in thread
From: Eric Blake @ 2021-03-15 16:16 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

On 3/12/21 9:32 AM, Markus Armbruster wrote:
> This policy rejects deprecated input, and thus permits "testing the
> future".  Implement it for QMP commands: make deprecated ones fail.
> Example: when QEMU is run with -compat deprecated-input=reject, then
> 
>     {"execute": "query-cpus"}
> 
> fails like this
> 
>     {"error": {"class": "CommandNotFound", "desc": "Deprecated command query-cpus disabled by policy"}}
> 
> When the deprecated command is removed, the error will change to
> 
>     {"error": {"class": "CommandNotFound", "desc": "The command query-cpus has not been found"}}

Again, Dan's patch changes this permanently:
https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg07566.html

Up to you if you want to tweak the example, but the concept of the patch
is still fine, so my R-b still stands.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 10/10] qapi: New -compat deprecated-input=crash
  2021-03-12 15:32 ` [PATCH v6 10/10] qapi: New -compat deprecated-input=crash Markus Armbruster
@ 2021-03-15 16:19   ` Eric Blake
  0 siblings, 0 replies; 23+ messages in thread
From: Eric Blake @ 2021-03-15 16:19 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

On 3/12/21 9:32 AM, Markus Armbruster wrote:
> Policy "crash" calls abort() when deprecated input is received.
> 
> Bugs in integration tests may mask the error from policy "reject".
> Provide a larger hammer: crash outright.  Masking that seems unlikely.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  qapi/compat.json             | 9 +++++----
>  qapi/qmp-dispatch.c          | 1 +
>  qapi/qobject-input-visitor.c | 1 +
>  qemu-options.hx              | 4 +++-
>  4 files changed, 10 insertions(+), 5 deletions(-)
> 
> diff --git a/qapi/compat.json b/qapi/compat.json
> index d2c02a21aa..ae3afc22df 100644
> --- a/qapi/compat.json
> +++ b/qapi/compat.json
> @@ -11,11 +11,12 @@
>  #
>  # @accept: Accept silently
>  # @reject: Reject with an error
> +# @crash: abort() the process
>  #
> -# Since: 5.2
> +# Since: 6.0

Rebase churn once you fix this earlier in the series.

R-b still stands.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 01/10] qemu-options: New -compat to set policy for deprecated interfaces
  2021-03-15 15:41   ` Eric Blake
@ 2021-03-15 16:29     ` Markus Armbruster
  0 siblings, 0 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-15 16:29 UTC (permalink / raw)
  To: Eric Blake; +Cc: marcandre.lureau, qemu-devel, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 3/12/21 9:32 AM, Markus Armbruster wrote:
>> New option -compat lets you configure what to do when deprecated
>> interfaces get used.  This is intended for testing users of the
>> management interfaces.  It is experimental.
>> 
>> -compat deprecated-input=<input-policy> configures what to do when
>> deprecated input is received.  Input policy can be "accept" (accept
>> silently), or "reject" (reject the request with an error).
>> 
>> -compat deprecated-output=<out-policy> configures what to do when
>> deprecated output is sent.  Output policy can be "accept" (pass on
>> unchanged), or "hide" (filter out the deprecated parts).
>> 
>> Default is "accept".  Policies other than "accept" are implemented
>> later in this series.
>> 
>> For now, -compat covers only syntactic aspects of QMP, i.e. stuff
>> tagged with feature 'deprecated'.  We may want to extend it to cover
>> semantic aspects, CLI, and experimental features.
>> 
>> Note that there is no good way for management application to detect
>> presence of -compat: it's not visible output of query-qmp-schema or
>> query-command-line-options.  Tolerable, because it's meant for
>> testing.  If running with -compat fails, skip the test.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> ---
>
>> +++ b/qapi/compat.json
>> @@ -0,0 +1,51 @@
>> +# -*- Mode: Python -*-
>> +
>> +##
>> +# = Compatibility policy
>> +##
>> +
>> +##
>> +# @CompatPolicyInput:
>> +#
>> +# Policy for handling "funny" input.
>> +#
>> +# @accept: Accept silently
>> +# @reject: Reject with an error
>> +#
>> +# Since: 5.2
>
> 6.0
>
>> +##
>> +{ 'enum': 'CompatPolicyInput',
>> +  'data': [ 'accept', 'reject' ] }
>> +
>> +##
>> +# @CompatPolicyOutput:
>> +#
>> +# Policy for handling "funny" output.
>> +#
>> +# @accept: Pass on unchanged
>> +# @hide: Filter out
>> +#
>> +# Since: 5.2
>
> and here
>
>> +##
>> +{ 'enum': 'CompatPolicyOutput',
>> +  'data': [ 'accept', 'hide' ] }
>> +
>> +##
>> +# @CompatPolicy:
>> +#
>> +# Policy for handling deprecated management interfaces.
>> +#
>> +# This is intended for testing users of the management interfaces.
>> +#
>> +# Limitation: covers only syntactic aspects of QMP, i.e. stuff tagged
>> +# with feature 'deprecated'.  We may want to extend it to cover
>> +# semantic aspects, CLI, and experimental features.
>> +#
>> +# @deprecated-input: how to handle deprecated input (default 'accept')
>> +# @deprecated-output: how to handle deprecated output (default 'accept')
>> +#
>> +# Since: 5.2
>
> and here
>
>> +##
>> +{ 'struct': 'CompatPolicy',
>> +  'data': { '*deprecated-input': 'CompatPolicyInput',
>> +            '*deprecated-output': 'CompatPolicyOutput' } }
>> diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
>> index 3441c9a9ae..4912b9744e 100644
>
> R-b still stands once you make the necessary tweaks.

I thought I had updated these...  Thanks for catching my mistake!



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results
  2021-03-15 15:45   ` Eric Blake
@ 2021-03-15 16:33     ` Markus Armbruster
  0 siblings, 0 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-15 16:33 UTC (permalink / raw)
  To: Eric Blake; +Cc: marcandre.lureau, Daniel P. Berrangé, qemu-devel, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 3/12/21 9:32 AM, Markus Armbruster wrote:
>> This policy suppresses deprecated bits in output, and thus permits
>> "testing the future".  Implement it for QMP command results.  Example:
>> when QEMU is run with -compat deprecated-output=hide, then
>> 
>>     {"execute": "query-cpus-fast"}
>> 
>> yields
>> 
>>     {"return": [{"thread-id": 9805, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}
>> 
>> instead of
>> 
>>     {"return": [{"arch": "x86", "thread-id": 22436, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}
>
> Example may not be relevant much longer, given Dan's patch [1] to make
> this permanent since we've already passed the deprecation wait.  Up to
> you if you want to choose a different example.
>
> https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg07564.html

I think I'll keep this one just to save me some time.  Even a slightly
outdated example should serve okay as illustration.

>
>> 
>> Note the suppression of deprecated member "arch".
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> ---
>
> R-b still stands.

Thanks!



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 05/10] monitor: Drop query-qmp-schema 'gen': false hack
  2021-03-15 16:10   ` Eric Blake
@ 2021-03-15 16:34     ` Markus Armbruster
  0 siblings, 0 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-15 16:34 UTC (permalink / raw)
  To: Eric Blake; +Cc: mdroth, marcandre.lureau, Markus Armbruster, qemu-devel

Eric Blake <eblake@redhat.com> writes:

> On 3/12/21 9:32 AM, Markus Armbruster wrote:
>> QMP commands return their response as a generated QAPI type, which the
>> monitor core converts to JSON via QObject.
>> 
>> query-qmp-schema's response is the generated introspection data.  This
>> is a QLitObject since commit 7d0f982bfb "qapi: generate a literal
>> qobject for introspection", v2.12).  Before, it was a string.  Instead
>> of converting QLitObject / string -> QObject -> QAPI type
>> SchemaInfoList -> QObject -> JSON, we take a shortcut: the command is
>> 'gen': false, so it can return the QObject instead of the QAPI type.
>> Slightly simpler and more efficient.
>> 
>> The next commit will filter the response for output policy, and this
>> is easier in the SchemaInfoList representation.  Drop the shortcut.
>> 
>> This replaces the manual command registration by a generated one.  The
>> manual registration makes the commnd available before the machine is
>
> command

Fixing...

>> built by passing flag QCO_ALLOW_PRECONFIG.  To keep it available
>> there, we need need to add 'allow-preconfig': true to its definition
>> in the schema.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> ---
>>  qapi/introspect.json                 |  2 +-
>>  monitor/monitor-internal.h           |  3 ---
>>  monitor/misc.c                       |  2 --
>>  monitor/qmp-cmds-control.c           | 29 ++++++++++++++++------------
>>  storage-daemon/qemu-storage-daemon.c |  2 --
>>  5 files changed, 18 insertions(+), 20 deletions(-)
>> 
>
> R-b still stands.

Thanks!



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results
  2021-03-12 15:32 ` [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results Markus Armbruster
  2021-03-15 15:45   ` Eric Blake
@ 2021-03-18 13:36   ` Markus Armbruster
  1 sibling, 0 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-18 13:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, mdroth

Markus Armbruster <armbru@redhat.com> writes:

> This policy suppresses deprecated bits in output, and thus permits
> "testing the future".  Implement it for QMP command results.  Example:
> when QEMU is run with -compat deprecated-output=hide, then
>
>     {"execute": "query-cpus-fast"}
>
> yields
>
>     {"return": [{"thread-id": 9805, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}
>
> instead of
>
>     {"return": [{"arch": "x86", "thread-id": 22436, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]}
>
> Note the suppression of deprecated member "arch".
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
[...]
> diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c
> index ba6f6ac8a7..5c4aa0f64d 100644
> --- a/qapi/qobject-output-visitor.c
> +++ b/qapi/qobject-output-visitor.c
[...]
> @@ -264,3 +275,11 @@ Visitor *qobject_output_visitor_new(QObject **result)
>  
>      return &v->visitor;
>  }
> +
> +Visitor *qobject_output_visitor_new_qmp(QObject **result)
> +{
> +    QObjectOutputVisitor *v = to_qov(qobject_output_visitor_new(result));
> +
> +    v->deprecated_policy = compat_policy.deprecated_output;
> +    return &v->visitor;
> +}

Linking fail when we link qapi/qobject-output-visitor.o (which uses
@compat_policy), but not qapi/qmp-dispatch.o (which defines it).

Fails for me when I configure --disable-system --disable-tools.

Minimally invasive fix: move the function to qmp-dispatch.c.

Same for qobject_input_visitor_new_qmp() in PATCH 09.

[...]



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v6 00/10] Configurable policy for handling deprecated interfaces
  2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
                   ` (9 preceding siblings ...)
  2021-03-12 15:32 ` [PATCH v6 10/10] qapi: New -compat deprecated-input=crash Markus Armbruster
@ 2021-03-18 15:08 ` Markus Armbruster
  10 siblings, 0 replies; 23+ messages in thread
From: Markus Armbruster @ 2021-03-18 15:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Lukáš Doktor, Kevin Wolf, Peter Krempa,
	Daniel P . Berrange, libvir-list, mdroth, marcandre.lureau,
	libguestfs

This series needs fixups to not break --disable-system --disable-tools
builds.  It's not much (see appended diff), but enough to make me respin
it as v7.  I'll respin the pull request, too.


diff --git a/include/qapi/compat-policy.h b/include/qapi/compat-policy.h
index b8c6638156..1083f95122 100644
--- a/include/qapi/compat-policy.h
+++ b/include/qapi/compat-policy.h
@@ -17,4 +17,22 @@
 
 extern CompatPolicy compat_policy;
 
+/*
+ * Create a QObject input visitor for @obj for use with QMP
+ *
+ * This is like qobject_input_visitor_new(), except it obeys the
+ * policy for handling deprecated management interfaces set with
+ * -compat.
+ */
+Visitor *qobject_input_visitor_new_qmp(QObject *obj);
+
+/*
+ * Create a QObject output visitor for @obj for use with QMP
+ *
+ * This is like qobject_output_visitor_new(), except it obeys the
+ * policy for handling deprecated management interfaces set with
+ * -compat.
+ */
+Visitor *qobject_output_visitor_new_qmp(QObject **result);
+
 #endif
diff --git a/include/qapi/qobject-input-visitor.h b/include/qapi/qobject-input-visitor.h
index cbc54de4ac..8d69388810 100644
--- a/include/qapi/qobject-input-visitor.h
+++ b/include/qapi/qobject-input-visitor.h
@@ -15,6 +15,7 @@
 #ifndef QOBJECT_INPUT_VISITOR_H
 #define QOBJECT_INPUT_VISITOR_H
 
+#include "qapi/qapi-types-compat.h"
 #include "qapi/visitor.h"
 
 typedef struct QObjectInputVisitor QObjectInputVisitor;
@@ -58,14 +59,8 @@ typedef struct QObjectInputVisitor QObjectInputVisitor;
  */
 Visitor *qobject_input_visitor_new(QObject *obj);
 
-/*
- * Create a QObject input visitor for @obj for use with QMP
- *
- * This is like qobject_input_visitor_new(), except it obeys the
- * policy for handling deprecated management interfaces set with
- * -compat.
- */
-Visitor *qobject_input_visitor_new_qmp(QObject *obj);
+void qobject_input_visitor_set_policy(Visitor *v,
+                                      CompatPolicyInput deprecated);
 
 /*
  * Create a QObject input visitor for @obj for use with keyval_parse()
diff --git a/include/qapi/qobject-output-visitor.h b/include/qapi/qobject-output-visitor.h
index 29f4ea6aad..f2a2f92a00 100644
--- a/include/qapi/qobject-output-visitor.h
+++ b/include/qapi/qobject-output-visitor.h
@@ -15,6 +15,7 @@
 #define QOBJECT_OUTPUT_VISITOR_H
 
 #include "qapi/visitor.h"
+#include "qapi/qapi-types-compat.h"
 
 typedef struct QObjectOutputVisitor QObjectOutputVisitor;
 
@@ -53,13 +54,7 @@ typedef struct QObjectOutputVisitor QObjectOutputVisitor;
  */
 Visitor *qobject_output_visitor_new(QObject **result);
 
-/*
- * Create a QObject output visitor for @obj for use with QMP
- *
- * This is like qobject_output_visitor_new(), except it obeys the
- * policy for handling deprecated management interfaces set with
- * -compat.
- */
-Visitor *qobject_output_visitor_new_qmp(QObject **result);
+void qobject_output_visitor_set_policy(Visitor *v,
+                                       CompatPolicyOutput deprecated);
 
 #endif
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 12657d635e..0f7e2e48fa 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -19,6 +19,8 @@
 #include "qapi/qmp/dispatch.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
 #include "sysemu/runstate.h"
 #include "qapi/qmp/qbool.h"
 #include "qemu/coroutine.h"
@@ -26,6 +28,22 @@
 
 CompatPolicy compat_policy;
 
+Visitor *qobject_input_visitor_new_qmp(QObject *obj)
+{
+    Visitor *v = qobject_input_visitor_new(obj);
+
+    qobject_input_visitor_set_policy(v, compat_policy.deprecated_input);
+    return v;
+}
+
+Visitor *qobject_output_visitor_new_qmp(QObject **result)
+{
+    Visitor *v = qobject_output_visitor_new(result);
+
+    qobject_output_visitor_set_policy(v, compat_policy.deprecated_output);
+    return v;
+}
+
 static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
                                      Error **errp)
 {
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index baad0dcd3c..04b790412e 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -739,12 +739,12 @@ Visitor *qobject_input_visitor_new(QObject *obj)
     return &v->visitor;
 }
 
-Visitor *qobject_input_visitor_new_qmp(QObject *obj)
+void qobject_input_visitor_set_policy(Visitor *v,
+                                       CompatPolicyInput deprecated)
 {
-    QObjectInputVisitor *v = to_qiv(qobject_input_visitor_new(obj));
+    QObjectInputVisitor *qiv = to_qiv(v);
 
-    v->deprecated_policy = compat_policy.deprecated_input;
-    return &v->visitor;
+    qiv->deprecated_policy = deprecated;
 }
 
 Visitor *qobject_input_visitor_new_keyval(QObject *obj)
diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c
index 5c4aa0f64d..e4873308d4 100644
--- a/qapi/qobject-output-visitor.c
+++ b/qapi/qobject-output-visitor.c
@@ -276,10 +276,10 @@ Visitor *qobject_output_visitor_new(QObject **result)
     return &v->visitor;
 }
 
-Visitor *qobject_output_visitor_new_qmp(QObject **result)
+void qobject_output_visitor_set_policy(Visitor *v,
+                                       CompatPolicyOutput deprecated)
 {
-    QObjectOutputVisitor *v = to_qov(qobject_output_visitor_new(result));
+    QObjectOutputVisitor *qov = to_qov(v);
 
-    v->deprecated_policy = compat_policy.deprecated_output;
-    return &v->visitor;
+    qov->deprecated_policy = deprecated;
 }
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 8ccd1d9224..0e13d51054 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -255,10 +255,9 @@ def _begin_user_module(self, name: str) -> None:
         visit = self._module_basename('qapi-visit', name)
         self._genc.add(mcgen('''
 #include "qemu/osdep.h"
+#include "qapi/compat-policy.h"
 #include "qapi/visitor.h"
 #include "qapi/qmp/qdict.h"
-#include "qapi/qobject-output-visitor.h"
-#include "qapi/qobject-input-visitor.h"
 #include "qapi/dealloc-visitor.h"
 #include "qapi/error.h"
 #include "%(visit)s.h"
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index 8335c2bdfc..fee8c671e7 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -192,7 +192,6 @@ def _begin_user_module(self, name: str) -> None:
 #include "qapi/compat-policy.h"
 #include "qapi/error.h"
 #include "qapi/qmp/qdict.h"
-#include "qapi/qobject-output-visitor.h"
 #include "qapi/qmp-event.h"
 
 ''',



^ permalink raw reply related	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2021-03-18 15:12 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-12 15:32 [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster
2021-03-12 15:32 ` [PATCH v6 01/10] qemu-options: New -compat to set policy for " Markus Armbruster
2021-03-15 15:41   ` Eric Blake
2021-03-15 16:29     ` Markus Armbruster
2021-03-12 15:32 ` [PATCH v6 02/10] qapi: Implement deprecated-output=hide for QMP command results Markus Armbruster
2021-03-15 15:45   ` Eric Blake
2021-03-15 16:33     ` Markus Armbruster
2021-03-18 13:36   ` Markus Armbruster
2021-03-12 15:32 ` [PATCH v6 03/10] qapi: Implement deprecated-output=hide for QMP events Markus Armbruster
2021-03-12 15:32 ` [PATCH v6 04/10] qapi: Implement deprecated-output=hide for QMP event data Markus Armbruster
2021-03-12 15:32 ` [PATCH v6 05/10] monitor: Drop query-qmp-schema 'gen': false hack Markus Armbruster
2021-03-15 16:10   ` Eric Blake
2021-03-15 16:34     ` Markus Armbruster
2021-03-12 15:32 ` [PATCH v6 06/10] qapi: Implement deprecated-output=hide for QMP introspection Markus Armbruster
2021-03-15 16:13   ` Eric Blake
2021-03-12 15:32 ` [PATCH v6 07/10] test-util-sockets: Add stub for monitor_set_cur() Markus Armbruster
2021-03-15 16:14   ` Eric Blake
2021-03-12 15:32 ` [PATCH v6 08/10] qapi: Implement deprecated-input=reject for QMP commands Markus Armbruster
2021-03-15 16:16   ` Eric Blake
2021-03-12 15:32 ` [PATCH v6 09/10] qapi: Implement deprecated-input=reject for QMP command arguments Markus Armbruster
2021-03-12 15:32 ` [PATCH v6 10/10] qapi: New -compat deprecated-input=crash Markus Armbruster
2021-03-15 16:19   ` Eric Blake
2021-03-18 15:08 ` [PATCH v6 00/10] Configurable policy for handling deprecated interfaces Markus Armbruster

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.