RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.
Bug 2100126 - Make lvm JSON output conform to standard
Summary: Make lvm JSON output conform to standard
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 9
Classification: Red Hat
Component: lvm2
Version: 9.1
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: rc
: ---
Assignee: Peter Rajnoha
QA Contact: cluster-qe@redhat.com
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2022-06-22 13:51 UTC by Tony Asleson
Modified: 2023-05-09 10:37 UTC (History)
9 users (show)

Fixed In Version: lvm2-2.03.17-1.el9
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2023-05-09 08:23:40 UTC
Type: Bug
Target Upstream Version:
Embargoed:
pm-rhel: mirror+


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Issue Tracker CLUSTERQE-6164 0 None None None 2022-11-11 20:35:28 UTC
Red Hat Issue Tracker RHELPLAN-125991 0 None None None 2022-06-22 13:58:51 UTC
Red Hat Product Errata RHBA-2023:2544 0 None None None 2023-05-09 08:23:57 UTC

Description Tony Asleson 2022-06-22 13:51:25 UTC
Description of problem:

The lvm JSON output does not adhere to the standard.  This prevents standard
JSON parsers to parse the output as expected.  The JSON specification:

https://www.json.org/

The following items are known at this time.

1. Numeric values are double quoted and shouldn't be
2. lvm tags could be represented as an array of strings
   instead of a comma separated string
3. Empty numeric values would need to have a value,
   not be an empty string.

Version-Release number of selected component (if applicable):
NA

How reproducible:
100%


Steps to Reproduce:
Use JSON lvm output

Additional info:

I'll work on a golang wrapper around lvm with all the known lvm
fields to see what other things could be changed to make the
JSON output more standards compliant.

Comment 1 Peter Rajnoha 2022-06-23 10:16:05 UTC
(In reply to Tony Asleson from comment #0)
> Description of problem:
> 
> The lvm JSON output does not adhere to the standard.  This prevents standard
> JSON parsers to parse the output as expected.  The JSON specification:
> 
> https://www.json.org/
> 
> The following items are known at this time.
> 
> 1. Numeric values are double quoted and shouldn't be
> 2. lvm tags could be represented as an array of strings
>    instead of a comma separated string

OK, I think we could fix this quite easily, will try to patch (...but I need to recall that code a bit, I haven't seen that for a while). Though, we'd be changing the existing output someone may use already, but we can consider that as a "fix".

> 3. Empty numeric values would need to have a value,
>    not be an empty string.
> 

Checking with the JSON specs, can we just use 'null' for this?

> Additional info:
> 
> I'll work on a golang wrapper around lvm with all the known lvm
> fields to see what other things could be changed to make the
> JSON output more standards compliant.

OK, let me know... Thanks!

Comment 2 Tony Asleson 2022-06-24 18:28:55 UTC
(In reply to Peter Rajnoha from comment #1)
> (In reply to Tony Asleson from comment #0)
> > Description of problem:
> > 
> > The lvm JSON output does not adhere to the standard.  This prevents standard
> > JSON parsers to parse the output as expected.  The JSON specification:
> > 
> > https://www.json.org/
> > 
> > The following items are known at this time.
> > 
> > 1. Numeric values are double quoted and shouldn't be
> > 2. lvm tags could be represented as an array of strings
> >    instead of a comma separated string
> 
> OK, I think we could fix this quite easily, will try to patch (...but I need
> to recall that code a bit, I haven't seen that for a while). Though, we'd be
> changing the existing output someone may use already, but we can consider
> that as a "fix".

I think it would be better to have an option to turn on this fix as this could
break existing users.


> > 3. Empty numeric values would need to have a value,
> >    not be an empty string.
> > 
> 
> Checking with the JSON specs, can we just use 'null' for this?

I don't think so, but let me investigate some more.

> 
> > Additional info:
> > 
> > I'll work on a golang wrapper around lvm with all the known lvm
> > fields to see what other things could be changed to make the
> > JSON output more standards compliant.
> 
> OK, let me know... Thanks!

I'll post a link to the code when I get something put together, thanks.

Comment 3 Peter Rajnoha 2022-06-30 14:51:01 UTC
(In reply to Tony Asleson from comment #2)
> I think it would be better to have an option to turn on this fix as this
> could
> break existing users.
> 

OK, I can add a config for that...

> 
> > > 3. Empty numeric values would need to have a value,
> > >    not be an empty string.
> > > 
> > 
> > Checking with the JSON specs, can we just use 'null' for this?
> 
> I don't think so, but let me investigate some more.
> 

Looks that 'null' can be used for any type of value in JSON. So if it's possible, I'd rather use that 'null' than any "zero value", because for certain specific fields, the value is really not defined at all and giving a zero value would be a bit misleading (e.g. "lv_data_percent" which is related only to thin and cache). We don't output these undefined values in non-json output too - they're numeric fields mostly (== we don't give a zero value for such field, just blank field). For string values, we use "" for undefined.

I have the changes here in this branch so far (still need to add the config option to enable/disable the json arrays for array values): https://sourceware.org/git/?p=lvm2.git;a=shortlog;h=refs/heads/dev-prajnoha-report-strlist-tuning

Comment 4 Peter Rajnoha 2022-07-01 09:52:43 UTC
> (In reply to Tony Asleson from comment #2)
> > I think it would be better to have an option to turn on this fix as this
> > could
> > break existing users.

Looked into this a bit and there's one practical annoyance here. Thing is, the formatting, including JSON, is implemented right inside libdevmapper. The settings we can configure for report are:

  - a separator to use (this is directly a parameter for dm_report_init/dm_report_init_with_selection)

  - global report flags: 

    #define DM_REPORT_OUTPUT_MASK                   0x000000FF                                                                              
    #define DM_REPORT_OUTPUT_ALIGNED                0x00000001                                                                              
    #define DM_REPORT_OUTPUT_BUFFERED               0x00000002                                                                              
    #define DM_REPORT_OUTPUT_HEADINGS               0x00000004                                                                                                                                                                                                                                                                                                                                     
    #define DM_REPORT_OUTPUT_FIELD_NAME_PREFIX      0x00000008                                                                              
    #define DM_REPORT_OUTPUT_FIELD_UNQUOTED         0x00000010                                                                              
    #define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS        0x00000020                                                                              
    #define DM_REPORT_OUTPUT_MULTIPLE_TIMES         0x00000040   

So, right now, the only way I could set how JSON does formatting is by introducing a new flag like "DM_REPORT_OUTPUT_JSON_NUMERIC_FIELDS_WITHOUT_QUOTES", but that seems inadequate because those flags are used to change global settings, not granular ones such as how a concrete format (JSON) is going to behave in a very granular and concrete situation ("putting quotes around numeric values").

This possibly directs us to introducing a new API function to control such granular report settings, but I'm hesitating whether it's worth it - I'm not sure if there will ever be any more settings to configure. Maybe a few could appear in the future, but looks like an overkill right now.

Our options to deal with this are:

  1) just define DM_REPORT_OUTPUT_JSON_NUMERIC_FIELD_WITHOUT_QUOTES as global flag, not matter if it looks weird and inadequate and only applies to a very concrete thing
  2) add a new API function to control more granular settings for report (this looks as a huge overkill if we're not going to use it for more settings)
  3) add environment variable that libdm/report would see and change behaviour based on that (looks hacky and also inadequate)
  4) or we will simply hardcode the change in output and any possible current users of JSON would need to adapt in newer versions of libdm/lvm2 (looks bad in the eyes of users as we'll change the format)

What do you think?

Comment 5 Tony Asleson 2022-07-05 17:10:35 UTC
Playing around with using 'null' for values does work.  However, for languages
like golang when a numeric value is 'null' it defaults to its default value
which is typically 0 for numeric values.  Having fields only apply in certain contexts
is problematic.  So even in those cases, a consumer will likely require hand written
code to handle.


>   1) just define DM_REPORT_OUTPUT_JSON_NUMERIC_FIELD_WITHOUT_QUOTES as
> global flag, not matter if it looks weird and inadequate and only applies to
> a very concrete thing
>   2) add a new API function to control more granular settings for report
> (this looks as a huge overkill if we're not going to use it for more
> settings)
>   3) add environment variable that libdm/report would see and change
> behaviour based on that (looks hacky and also inadequate)
>   4) or we will simply hardcode the change in output and any possible
> current users of JSON would need to adapt in newer versions of libdm/lvm2
> (looks bad in the eyes of users as we'll change the format)
> 
> What do you think?

#4 is not an option IMHO.

#1 However what if the name is something like
DM_REPORT_JSON_STD_COMPLIANT so we can address everything we find?

Comment 6 Peter Rajnoha 2022-07-07 07:50:28 UTC
(In reply to Tony Asleson from comment #5)
> Playing around with using 'null' for values does work.  However, for
> languages
> like golang when a numeric value is 'null' it defaults to its default value
> which is typically 0 for numeric values.  Having fields only apply in
> certain contexts
> is problematic.  So even in those cases, a consumer will likely require hand
> written
> code to handle.

Yes, I understand, it's not ideal. But the fact is that LVs are heterogeneous and not all fields apply to all types. At the same time, we have the tabular output so certain cells in the output are really 'null' naturally. I could output some zero value instead, but I'm afraid that would be much more misleading than the 'null'. So I'd rather use the 'null' (if the format allows us to do that) even though it requires the possible reader to do an extra check.

Also, the output in JSON would deviate from output in standard format in case we used 'zero value' instead of 'null value'.

> #1 However what if the name is something like
> DM_REPORT_JSON_STD_COMPLIANT so we can address everything we find?

OK, I think we could do that as compromise... if it doesn't matter that it would also cover all sorts of fixes we find on the way in the future.

Comment 7 Peter Rajnoha 2022-07-28 12:32:48 UTC
(In reply to Tony Asleson from comment #5)
> #1 However what if the name is something like
> DM_REPORT_JSON_STD_COMPLIANT so we can address everything we find?

I've just chatted with Zdenek about all this and he has a good suggestion - we might as well define a new "format" specifier, say "--reportformat json_std_compliant". That would probably be the easiest way - we'd still keep the original "json" for existing users who expect the output as it is today, as well as the new "json_std_compliant" format.

(In reply to Tony Asleson from comment #5)
> Playing around with using 'null' for values does work.  However, for
> languages
> like golang when a numeric value is 'null' it defaults to its default value
> which is typically 0 for numeric values.  Having fields only apply in
> certain contexts
> is problematic.  So even in those cases, a consumer will likely require hand
> written
> code to handle.

The issue with reporting some zero value instead of 'null' is that then we lose possibility of detecting the difference between "undefined value" and "zero value". If using the 'null', is this just an issue with a concrete golang library for parsing JSON or can you choose a different one where the 'null' is handled better? I don't know what's the output from that golang parser - are they some structures that are filled in with values after parsing JSON?

If the 'null' is an issue, we could create a format called "--reportformat json_without_nulls", if we were to follow the logic with introducting a new format specifier.

Comment 8 Tony Asleson 2022-08-02 16:04:06 UTC
(In reply to Peter Rajnoha from comment #7)
> (In reply to Tony Asleson from comment #5)
> > #1 However what if the name is something like
> > DM_REPORT_JSON_STD_COMPLIANT so we can address everything we find?
> 
> I've just chatted with Zdenek about all this and he has a good suggestion -
> we might as well define a new "format" specifier, say "--reportformat
> json_std_compliant". That would probably be the easiest way - we'd still
> keep the original "json" for existing users who expect the output as it is
> today, as well as the new "json_std_compliant" format.

This seems like the best way

> (In reply to Tony Asleson from comment #5)
> > Playing around with using 'null' for values does work.  However, for
> > languages
> > like golang when a numeric value is 'null' it defaults to its default value
> > which is typically 0 for numeric values.  Having fields only apply in
> > certain contexts
> > is problematic.  So even in those cases, a consumer will likely require hand
> > written
> > code to handle.
> 
> The issue with reporting some zero value instead of 'null' is that then we
> lose possibility of detecting the difference between "undefined value" and
> "zero value". If using the 'null', is this just an issue with a concrete
> golang library for parsing JSON or can you choose a different one where the
> 'null' is handled better? I don't know what's the output from that golang
> parser - are they some structures that are filled in with values after
> parsing JSON?

Golang has the ability to serialize JSON to a structure or structure to JSON.
Having values that aren't applicable should likely use 'null', which in the
case of golang will be treated as the default value.  I don't see a good way
to not require custom serialization/de-serialization code for golang, so
lets stick to what makes the most sense for values which aren't applicable,
which seems like a 'null'.

Comment 9 Peter Rajnoha 2022-08-05 08:53:15 UTC
Updated patchset with new '--reportformat json_std' cmd line option and 'report/output_format = "json_std"' config file option: https://sourceware.org/git/?p=lvm2.git;a=shortlog;h=refs/heads/dev-prajnoha-json_std

Example output in all 3 formats ("basic" - no change, "json" - no change, "json_std" - new one):

❯  lvs -o name,vg_name,data_percent,lv_tags,lv_kernel_major
  LV    VG     Data%  LV Tags  KMaj
  root  fedora                  253
  swap  fedora                  253
  lvol1 vg     0.00   a,bc,def  253
  lvol2 vg                       -1
  pool  vg     0.00             253


❯  lvs -o name,vg_name,data_percent,lv_tags,lv_kernel_major --reportformat json
  {
      "report": [
          {
              "lv": [
                  {"lv_name":"root", "vg_name":"fedora", "data_percent":"", "lv_tags":"", "lv_kernel_major":"253"},
                  {"lv_name":"swap", "vg_name":"fedora", "data_percent":"", "lv_tags":"", "lv_kernel_major":"253"},
                  {"lv_name":"lvol1", "vg_name":"vg", "data_percent":"0.00", "lv_tags":"a,bc,def", "lv_kernel_major":"253"},
                  {"lv_name":"lvol2", "vg_name":"vg", "data_percent":"", "lv_tags":"", "lv_kernel_major":"-1"},
                  {"lv_name":"pool", "vg_name":"vg", "data_percent":"0.00", "lv_tags":"", "lv_kernel_major":"253"}
              ]
          }
      ]
  }

❯  lvs -o name,vg_name,data_percent,lv_tags,lv_kernel_major --reportformat json_std
  {
      "report": [
          {
              "lv": [
                  {"lv_name":"root", "vg_name":"fedora", "data_percent":null, "lv_tags":[], "lv_kernel_major":253},
                  {"lv_name":"swap", "vg_name":"fedora", "data_percent":null, "lv_tags":[], "lv_kernel_major":253},
                  {"lv_name":"lvol1", "vg_name":"vg", "data_percent":0.00, "lv_tags":["a","bc","def"], "lv_kernel_major":253},
                  {"lv_name":"lvol2", "vg_name":"vg", "data_percent":null, "lv_tags":[], "lv_kernel_major":-1},
                  {"lv_name":"pool", "vg_name":"vg", "data_percent":0.00, "lv_tags":[], "lv_kernel_major":253}
              ]
          }
      ]
  }

Comment 10 Peter Rajnoha 2022-08-11 11:09:07 UTC
Upstream commits 02f015990b2d077f304e19c9ff11728d4480bee8..12ffa753f64eeea946e5331e64ed9d561de98c6b

Comment 11 Peter Rajnoha 2022-08-16 11:38:28 UTC
+ additional upstream commit 1ab6d0d8d8d043a99cb44531de563c7aeb1f0f75

Comment 12 Peter Rajnoha 2022-08-24 10:28:13 UTC
+ upstream commit 800436d2affd4142b9d4b405112c4c30f1d31b5b

Comment 15 Corey Marthaler 2022-11-28 20:26:26 UTC
Marking Verified:Tested in the latest rpms.

kernel-5.14.0-176.el9    BUILT: Wed Oct 12 03:57:18 AM CDT 2022
lvm2-2.03.17-1.el9    BUILT: Thu Nov 10 10:02:16 AM CST 2022
lvm2-libs-2.03.17-1.el9    BUILT: Thu Nov 10 10:02:16 AM CST 2022


[root@hayes-03 ~]# lvs -o name,vg_name,data_percent,lv_tags,lv_kernel_major --reportformat json
  {
      "report": [
          {
              "lv": [
                  {"lv_name":"vdo_lv", "vg_name":"vdo_sanity", "data_percent":"0.00", "lv_tags":"", "lv_kernel_major":"253"},
                  {"lv_name":"vpool0", "vg_name":"vdo_sanity", "data_percent":"12.06", "lv_tags":"", "lv_kernel_major":"-1"}
              ]
          }
      ]
  }

[root@hayes-03 ~]# lvs -o name,vg_name,data_percent,lv_tags,lv_kernel_major --reportformat json_std
  {
      "report": [
          {
              "lv": [
                  {"lv_name":"vdo_lv", "vg_name":"vdo_sanity", "data_percent":0.00, "lv_tags":[], "lv_kernel_major":253},
                  {"lv_name":"vpool0", "vg_name":"vdo_sanity", "data_percent":12.06, "lv_tags":[], "lv_kernel_major":-1}
              ]
          }
      ]
  }

Comment 19 Corey Marthaler 2023-01-04 01:14:41 UTC
Marking VERIFIED in the latest rpms as well.

kernel-5.14.0-212.el9    BUILT: Tue Dec 13 03:37:26 PM CST 2022
lvm2-2.03.17-3.el9    BUILT: Wed Dec  7 10:41:40 AM CST 2022
lvm2-libs-2.03.17-3.el9    BUILT: Wed Dec  7 10:41:40 AM CST 2022


[root@hayes-03 ~]#  lvs -o name,vg_name,data_percent,lv_tags,lv_kernel_major --reportformat json
  {
      "report": [
          {
              "lv": [
                  {"lv_name":"pool", "vg_name":"vdo_sanity", "data_percent":"0.00", "lv_tags":"", "lv_kernel_major":"253"},
                  {"lv_name":"vdo_lv", "vg_name":"vdo_sanity", "data_percent":"0.00", "lv_tags":"", "lv_kernel_major":"253"},
                  {"lv_name":"vdo_pool", "vg_name":"vdo_sanity", "data_percent":"", "lv_tags":"", "lv_kernel_major":"253"}
              ]
          }
      ]
  }
[root@hayes-03 ~]# lvs -o name,vg_name,data_percent,lv_tags,lv_kernel_major --reportformat json_std
  {
      "report": [
          {
              "lv": [
                  {"lv_name":"pool", "vg_name":"vdo_sanity", "data_percent":0.00, "lv_tags":[], "lv_kernel_major":253},
                  {"lv_name":"vdo_lv", "vg_name":"vdo_sanity", "data_percent":0.00, "lv_tags":[], "lv_kernel_major":253},
                  {"lv_name":"vdo_pool", "vg_name":"vdo_sanity", "data_percent":null, "lv_tags":[], "lv_kernel_major":253}
              ]
          }
      ]
  }

Comment 21 errata-xmlrpc 2023-05-09 08:23:40 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (lvm2 bug fix and enhancement update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2023:2544


Note You need to log in before you can comment on or make changes to this bug.