From 397de7ba7ced457ca00dab2f09a63d02fc37d713 Mon Sep 17 00:00:00 2001 From: Gang Ji Date: Thu, 4 Jul 2024 16:06:52 +0800 Subject: [PATCH] CP-46933: Expose XAPI API version in the output of HTTP API /updates XAPI API version is exposed from updateinfo.xml, to expose it in the output of HTTP API /updates, a new json field "xapi-api-version" is added in the json output only when XAPI API version is exposed from updateinfo.xml successfully, otherwise the returned json data keeps the original format. Signed-off-by: Gang Ji --- ocaml/tests/test_updateinfo.ml | 1277 ++++++++++++++++++-------------- ocaml/xapi/repository.ml | 23 +- ocaml/xapi/updateinfo.ml | 192 ++--- ocaml/xapi/updateinfo.mli | 10 +- 4 files changed, 851 insertions(+), 651 deletions(-) diff --git a/ocaml/tests/test_updateinfo.ml b/ocaml/tests/test_updateinfo.ml index 2adb7c9d2db..6df2f0b2fba 100644 --- a/ocaml/tests/test_updateinfo.ml +++ b/ocaml/tests/test_updateinfo.ml @@ -442,7 +442,11 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct module Io = struct type input_t = string - type output_t = ((string * UpdateInfo.t) list, exn) result + type output_t = + ( UpdateInfo.api_ver_t option * (UpdateInfo.id_t * UpdateInfo.t) list + , exn + ) + result let string_of_input_t s = s @@ -451,7 +455,10 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct str "%a" Dump.( result - ~ok:(list (pair string (record @@ fields_of_updateinfo))) + ~ok: + (pair (option string) + (list (pair string (record @@ fields_of_updateinfo))) + ) ~error:exn ) ) @@ -472,13 +479,22 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct , Error Api_errors.(Server_error (invalid_updateinfo_xml, [])) ) ; (* No update in updateinfo.xml *) - ({| + ( {| - |}, Ok []) + |} + , Ok (None, []) + ) + ; (* No update in updateinfo.xml, but with xapi-api-version *) + ( {| + + + |} + , Error Api_errors.(Server_error (invalid_updateinfo_xml, [])) + ) ; (* Missing update_type *) ( {| - + UPDATE-0000 title @@ -494,7 +510,7 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct ) ; (* Missing id *) ( {| - + title summary @@ -509,7 +525,7 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct ) ; (* Missing summary *) ( {| - + UPDATE-0000 title @@ -524,7 +540,7 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct ) ; (* Missing description *) ( {| - + UPDATE-0000 title @@ -537,35 +553,37 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "" - ; guidance= - [ - (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* Duplicate update ID *) ( {| - + UPDATE-0000 title @@ -588,7 +606,99 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Error Api_errors.(Server_error (invalid_updateinfo_xml, [])) ) + ; (* Single update, without xapi-api-version *) + ( {| + + + UPDATE-0000 + title + summary + description + special information + https://update.details.info + + + High + + + |} + , Ok + ( None + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" + ; severity= Severity.High + ; title= "title" + } + ) + ] + ) + ) ; (* Single update *) + ( {| + + + UPDATE-0000 + title + summary + description + special information + https://update.details.info + + + High + + + |} + , Ok + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" + ; severity= Severity.High + ; title= "title" + } + ) + ] + ) + ) + ; (* Two updates, without xapi-api-version *) ( {| @@ -602,39 +712,76 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct High + + UPDATE-0001 + title + summary + description + special information + https://update.details.info + + + None + |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= - Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" - ; severity= Severity.High - ; title= "title" - } - ) - ] + ( None + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" + ; severity= Severity.High + ; title= "title" + } + ) + ; ( "UPDATE-0001" + , UpdateInfo. + { + id= "UPDATE-0001" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:50Z" + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* Two updates *) ( {| - + UPDATE-0000 title @@ -660,60 +807,62 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= - Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" - ; severity= Severity.High - ; title= "title" - } - ) - ; ( "UPDATE-0001" - , UpdateInfo. - { - id= "UPDATE-0001" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= - Xapi_stdext_date.Date.of_string "2023-05-12T08:37:50Z" - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" + ; severity= Severity.High + ; title= "title" + } + ) + ; ( "UPDATE-0001" + , UpdateInfo. + { + id= "UPDATE-0001" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:50Z" + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* Single update with deprecated guidances only *) ( {| - + UPDATE-0000 title @@ -747,56 +896,58 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= - [ - Applicability. - { - name= "xsconsole" - ; arch= "x86_64" - ; inequality= Some Gte - ; epoch= None - ; version= "10.1.0" - ; release= "25" - } - ; Applicability. - { - name= "xsconsole" - ; arch= "x86_64" - ; inequality= Some Lt - ; epoch= None - ; version= "10.1.0" - ; release= "25" - } - ] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= - Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" - ; severity= Severity.High - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= + [ + Applicability. + { + name= "xsconsole" + ; arch= "x86_64" + ; inequality= Some Gte + ; epoch= None + ; version= "10.1.0" + ; release= "25" + } + ; Applicability. + { + name= "xsconsole" + ; arch= "x86_64" + ; inequality= Some Lt + ; epoch= None + ; version= "10.1.0" + ; release= "25" + } + ] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" + ; severity= Severity.High + ; title= "title" + } + ) + ] + ) ) ; (* Single update with unknown guidance *) ( {| - + UPDATE-0000 title @@ -842,56 +993,58 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Recommended, [RebootHost]) - ; (Full, [RebootHost; RestartVM]) - ; (Mandatory, [RebootHost]) - ; (Livepatch, []) - ] - ; guidance_applicabilities= - [ - Applicability. - { - name= "xsconsole" - ; arch= "x86_64" - ; inequality= Some Gte - ; epoch= None - ; version= "10.1.0" - ; release= "25" - } - ; Applicability. - { - name= "xsconsole" - ; arch= "x86_64" - ; inequality= Some Lt - ; epoch= None - ; version= "10.1.0" - ; release= "25" - } - ] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= - Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" - ; severity= Severity.High - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Recommended, [RebootHost]) + ; (Full, [RebootHost; RestartVM]) + ; (Mandatory, [RebootHost]) + ; (Livepatch, []) + ] + ; guidance_applicabilities= + [ + Applicability. + { + name= "xsconsole" + ; arch= "x86_64" + ; inequality= Some Gte + ; epoch= None + ; version= "10.1.0" + ; release= "25" + } + ; Applicability. + { + name= "xsconsole" + ; arch= "x86_64" + ; inequality= Some Lt + ; epoch= None + ; version= "10.1.0" + ; release= "25" + } + ] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" + ; severity= Severity.High + ; title= "title" + } + ) + ] + ) ) ; (* Single update with livepatches and livepatch guidance *) ( {| - + UPDATE-0000 title @@ -916,58 +1069,60 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Livepatch, [RestartToolstack]) - ; (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= - [ - LivePatch. - { - component= Kernel - ; base_build_id= - "8346194f2e98a228f5a595b13ecabd43a99fada0" - ; base_version= "4.19.19" - ; base_release= "8.0.19.xs8" - ; to_version= "4.19.19" - ; to_release= "8.0.21.xs8" - } - ; LivePatch. - { - component= Kernel - ; base_build_id= - "9346194f2e98a228f5a595b13ecabd43a99fada0" - ; base_version= "4.19.19" - ; base_release= "8.0.20.xs8" - ; to_version= "4.19.19" - ; to_release= "8.0.21.xs8" - } - ] - ; issued= - Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" - ; severity= Severity.High - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Livepatch, [RestartToolstack]) + ; (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= + [ + LivePatch. + { + component= Kernel + ; base_build_id= + "8346194f2e98a228f5a595b13ecabd43a99fada0" + ; base_version= "4.19.19" + ; base_release= "8.0.19.xs8" + ; to_version= "4.19.19" + ; to_release= "8.0.21.xs8" + } + ; LivePatch. + { + component= Kernel + ; base_build_id= + "9346194f2e98a228f5a595b13ecabd43a99fada0" + ; base_version= "4.19.19" + ; base_release= "8.0.20.xs8" + ; to_version= "4.19.19" + ; to_release= "8.0.21.xs8" + } + ] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" + ; severity= Severity.High + ; title= "title" + } + ) + ] + ) ) ; (* Single update with livepatches and unknown livepatch guidance *) ( {| - + UPDATE-0000 title @@ -992,58 +1147,60 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Livepatch, [RebootHost]) - ; (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= - [ - LivePatch. - { - component= Kernel - ; base_build_id= - "8346194f2e98a228f5a595b13ecabd43a99fada0" - ; base_version= "4.19.19" - ; base_release= "8.0.19.xs8" - ; to_version= "4.19.19" - ; to_release= "8.0.21.xs8" - } - ; LivePatch. - { - component= Kernel - ; base_build_id= - "9346194f2e98a228f5a595b13ecabd43a99fada0" - ; base_version= "4.19.19" - ; base_release= "8.0.20.xs8" - ; to_version= "4.19.19" - ; to_release= "8.0.21.xs8" - } - ] - ; issued= - Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" - ; severity= Severity.High - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Livepatch, [RebootHost]) + ; (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= + [ + LivePatch. + { + component= Kernel + ; base_build_id= + "8346194f2e98a228f5a595b13ecabd43a99fada0" + ; base_version= "4.19.19" + ; base_release= "8.0.19.xs8" + ; to_version= "4.19.19" + ; to_release= "8.0.21.xs8" + } + ; LivePatch. + { + component= Kernel + ; base_build_id= + "9346194f2e98a228f5a595b13ecabd43a99fada0" + ; base_version= "4.19.19" + ; base_release= "8.0.20.xs8" + ; to_version= "4.19.19" + ; to_release= "8.0.21.xs8" + } + ] + ; issued= + Xapi_stdext_date.Date.of_string "2023-05-12T08:37:49Z" + ; severity= Severity.High + ; title= "title" + } + ) + ] + ) ) ; (* Single update with livepatch guidance but empty livepatch *) ( {| - + UPDATE-0000 title @@ -1064,35 +1221,37 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Livepatch, [RestartDeviceModel]) - ; (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Livepatch, [RestartDeviceModel]) + ; (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* Single update with valid livepatches *) ( {| - + UPDATE-0000 title @@ -1115,47 +1274,49 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Livepatch, [RestartToolstack]) - ; (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= - [ - LivePatch. - { - component= Kernel - ; base_build_id= - "9346194f2e98a228f5a595b13ecabd43a99fada0" - ; base_version= "4.19.19" - ; base_release= "8.0.20.xs8" - ; to_version= "4.19.19" - ; to_release= "8.0.21.xs8" - } - ] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Livepatch, [RestartToolstack]) + ; (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= + [ + LivePatch. + { + component= Kernel + ; base_build_id= + "9346194f2e98a228f5a595b13ecabd43a99fada0" + ; base_version= "4.19.19" + ; base_release= "8.0.20.xs8" + ; to_version= "4.19.19" + ; to_release= "8.0.21.xs8" + } + ] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* Single update with invalid livepatches *) ( {| - + UPDATE-0000 title @@ -1178,35 +1339,37 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "description" - ; guidance= - [ - (Livepatch, [RestartToolstack]) - ; (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "description" + ; guidance= + [ + (Livepatch, [RestartToolstack]) + ; (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* guidance in new format: empty guidance *) ( {| - + UPDATE-0000 title @@ -1227,35 +1390,37 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "empty guidance" - ; guidance= - [ - (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "empty guidance" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* guidance in new format only: empty guidance *) ( {| - + UPDATE-0000 title @@ -1273,35 +1438,37 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "guidance in new format only: empty guidance" - ; guidance= - [ - (Mandatory, []) - ; (Recommended, []) - ; (Full, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "guidance in new format only: empty guidance" + ; guidance= + [ + (Mandatory, []) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* guidance in new format: empty mandatory and full *) ( {| - + UPDATE-0000 title @@ -1326,35 +1493,37 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "empty mandatory and full" - ; guidance= - [ - (Full, []) - ; (Mandatory, []) - ; (Recommended, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "empty mandatory and full" + ; guidance= + [ + (Full, []) + ; (Mandatory, []) + ; (Recommended, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* guidance in new format: mandatory only *) ( {| - + UPDATE-0000 title @@ -1381,37 +1550,39 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "mandatory only" - ; guidance= - [ - ( Mandatory - , [RestartDeviceModel; EvacuateHost; RestartToolstack] - ) - ; (Recommended, []) - ; (Full, []) - ; (Livepatch, []) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "mandatory only" + ; guidance= + [ + ( Mandatory + , [RestartDeviceModel; EvacuateHost; RestartToolstack] + ) + ; (Recommended, []) + ; (Full, []) + ; (Livepatch, []) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* guidance in new format: mandatory, recommended, full and livepatch *) ( {| - + UPDATE-0000 title @@ -1445,35 +1616,37 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "mandatory, recommended, full and livepatch" - ; guidance= - [ - (Full, [RebootHost]) - ; (Livepatch, [RestartDeviceModel]) - ; (Recommended, [EvacuateHost]) - ; (Mandatory, [RestartToolstack]) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "mandatory, recommended, full and livepatch" + ; guidance= + [ + (Full, [RebootHost]) + ; (Livepatch, [RestartDeviceModel]) + ; (Recommended, [EvacuateHost]) + ; (Mandatory, [RestartToolstack]) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ; (* guidance in new format: mandatory, recommended, full and livepatch *) ( {| - + UPDATE-0000 title @@ -1507,31 +1680,33 @@ module UpdateInfoOfXml = Generic.MakeStateless (struct |} , Ok - [ - ( "UPDATE-0000" - , UpdateInfo. - { - id= "UPDATE-0000" - ; summary= "summary" - ; description= "RestartVM in mandatory" - ; guidance= - [ - (Full, [RebootHost]) - ; (Livepatch, [RestartDeviceModel]) - ; (Recommended, [EvacuateHost]) - ; (Mandatory, [RestartVM]) - ] - ; guidance_applicabilities= [] - ; spec_info= "special information" - ; url= "https://update.details.info" - ; update_type= "security" - ; livepatches= [] - ; issued= Xapi_stdext_date.Date.epoch - ; severity= Severity.None - ; title= "title" - } - ) - ] + ( Some "2.23" + , [ + ( "UPDATE-0000" + , UpdateInfo. + { + id= "UPDATE-0000" + ; summary= "summary" + ; description= "RestartVM in mandatory" + ; guidance= + [ + (Full, [RebootHost]) + ; (Livepatch, [RestartDeviceModel]) + ; (Recommended, [EvacuateHost]) + ; (Mandatory, [RestartVM]) + ] + ; guidance_applicabilities= [] + ; spec_info= "special information" + ; url= "https://update.details.info" + ; update_type= "security" + ; livepatches= [] + ; issued= Xapi_stdext_date.Date.epoch + ; severity= Severity.None + ; title= "title" + } + ) + ] + ) ) ] end) diff --git a/ocaml/xapi/repository.ml b/ocaml/xapi/repository.ml index 95007999782..d798246d0b0 100644 --- a/ocaml/xapi/repository.ml +++ b/ocaml/xapi/repository.ml @@ -298,7 +298,7 @@ let get_applied_livepatches_of_host updates_of_host = let is_livepatchable ~__context repository applied_livepatches_of_host = let updates_info = - parse_updateinfo ~__context ~self:repository ~check:false + parse_updateinfo ~__context ~self:repository ~check:false |> snd in List.exists (fun lp -> @@ -562,7 +562,7 @@ let get_pool_updates_in_json ~__context ~hosts = set_available_updates ~__context |> ignore ; let repository_name = get_repository_name ~__context ~self:repository in - let updates_info = + let api_ver, updates_info = parse_updateinfo ~__context ~self:repository ~check:true in let updates_of_hosts, ids_of_updates = @@ -579,12 +579,17 @@ let get_pool_updates_in_json ~__context ~hosts = |> List.map (fun upd_id -> List.assoc upd_id updates_info) |> List.map (prune_updateinfo_for_livepatches lps) in - `Assoc - [ - ("hosts", `List (List.map HostUpdates.to_json updates_of_hosts)) - ; ("updates", `List (List.map UpdateInfo.to_json updateinfo_list)) - ; ("hash", `String (Db.Repository.get_hash ~__context ~self:repository)) - ] + let f x = + Option.fold ~none:x + ~some:(fun api_ver -> ("xapi-api-version", `String api_ver) :: x) + api_ver + in + [ + ("hosts", `List (List.map HostUpdates.to_json updates_of_hosts)) + ; ("updates", `List (List.map UpdateInfo.to_json updateinfo_list)) + ; ("hash", `String (Db.Repository.get_hash ~__context ~self:repository)) + ] + |> fun x -> `Assoc (f x) with | Api_errors.(Server_error (code, _)) as e when code <> Api_errors.internal_error -> @@ -787,7 +792,7 @@ let apply_updates ~__context ~host ~hash = raise Api_errors.(Server_error (updateinfo_hash_mismatch, [])) ; with_pool_repositories (fun () -> let updates_info = - parse_updateinfo ~__context ~self:repository ~check:true + parse_updateinfo ~__context ~self:repository ~check:true |> snd in let updates_of_hosts = if Helpers.is_pool_master ~__context ~host then ( diff --git a/ocaml/xapi/updateinfo.ml b/ocaml/xapi/updateinfo.ml index 092af683232..375604cfe78 100644 --- a/ocaml/xapi/updateinfo.ml +++ b/ocaml/xapi/updateinfo.ml @@ -531,8 +531,10 @@ end module UpdateInfo = struct (** The [guidance] deprecates [rec_guidance], [abs_guidance] and [livepatch_guidance] *) + type id_t = string + type t = { - id: string + id: id_t ; summary: string ; description: string ; guidance: GuidanceInUpdateInfo.t @@ -546,6 +548,8 @@ module UpdateInfo = struct ; title: string } + type api_ver_t = string + let guidance_to_string o = Option.value (Option.map Guidance.to_string o) ~default:"" @@ -605,94 +609,106 @@ module UpdateInfo = struct Option.value (List.assoc_opt kind updateinfo.guidance) ~default:[] let of_xml = function - | Xml.Element ("updates", _, children) -> - List.filter_map - (fun n -> - match n with - | Xml.Element ("update", attr, update_nodes) -> - let ty = - match List.assoc_opt "type" attr with - | Some ty -> - ty - | None -> - "" - in - let ui = - List.fold_left - (fun acc node -> - match node with - | Xml.Element ("id", _, [Xml.PCData v]) -> - {acc with id= v} - | Xml.Element ("url", _, [Xml.PCData v]) -> - {acc with url= v} - | Xml.Element ("special_info", _, [Xml.PCData v]) -> - {acc with spec_info= v} - | Xml.Element ("summary", _, [Xml.PCData v]) -> - {acc with summary= v} - | Xml.Element ("description", _, [Xml.PCData v]) -> - {acc with description= v} - | Xml.Element ("guidance", _, guidance_blocks) -> - { - acc with - guidance= - GuidanceInUpdateInfo.of_xml guidance_blocks - } - | Xml.Element ("guidance_applicabilities", _, apps) -> - { - acc with - guidance_applicabilities= - List.filter_map Applicability.of_xml apps - } - | Xml.Element ("livepatches", _, livepatches) -> - {acc with livepatches= LivePatch.of_xml livepatches} - | Xml.Element ("issued", attr, _) -> - let issued = - match List.assoc_opt "date" attr with - | Some date -> ( - try - Xapi_stdext_date.Date.of_string - (Scanf.sscanf date - "%04d-%02d-%02d %02d:%02d:%02d" - (fun y mon d h m s -> - Printf.sprintf - "%04i%02i%02iT%02i:%02i:%02iZ" y mon d - h m s - ) - ) - with e -> - (* The error should not block update. Ingore it - and set "issued" as epoch. *) - warn "%s" (ExnHelper.string_of_exn e) ; - Xapi_stdext_date.Date.epoch - ) - | None -> - Xapi_stdext_date.Date.epoch - in - {acc with issued} - | Xml.Element ("severity", _, [Xml.PCData v]) -> ( - try {acc with severity= Severity.of_string v} - with e -> - (* The error should not block update. Ingore it. *) - warn "%s" (ExnHelper.string_of_exn e) ; - acc + | Xml.Element ("updates", attrs, children) -> ( + let api_ver = List.assoc_opt "xapi-api-version" attrs in + let uis = + List.filter_map + (fun n -> + match n with + | Xml.Element ("update", attrs, update_nodes) -> + let ty = + match List.assoc_opt "type" attrs with + | Some ty -> + ty + | None -> + "" + in + let ui = + List.fold_left + (fun acc node -> + match node with + | Xml.Element ("id", _, [Xml.PCData v]) -> + {acc with id= v} + | Xml.Element ("url", _, [Xml.PCData v]) -> + {acc with url= v} + | Xml.Element ("special_info", _, [Xml.PCData v]) -> + {acc with spec_info= v} + | Xml.Element ("summary", _, [Xml.PCData v]) -> + {acc with summary= v} + | Xml.Element ("description", _, [Xml.PCData v]) -> + {acc with description= v} + | Xml.Element ("guidance", _, guidance_blocks) -> + { + acc with + guidance= + GuidanceInUpdateInfo.of_xml guidance_blocks + } + | Xml.Element ("guidance_applicabilities", _, apps) -> + { + acc with + guidance_applicabilities= + List.filter_map Applicability.of_xml apps + } + | Xml.Element ("livepatches", _, livepatches) -> + {acc with livepatches= LivePatch.of_xml livepatches} + | Xml.Element ("issued", attrs, _) -> + let issued = + match List.assoc_opt "date" attrs with + | Some date -> ( + try + Xapi_stdext_date.Date.of_string + (Scanf.sscanf date + "%04d-%02d-%02d %02d:%02d:%02d" + (fun y mon d h m s -> + Printf.sprintf + "%04i%02i%02iT%02i:%02i:%02iZ" y mon + d h m s + ) + ) + with e -> + (* The error should not block update. Ingore it + and set "issued" as epoch. *) + warn "%s" (ExnHelper.string_of_exn e) ; + Xapi_stdext_date.Date.epoch + ) + | None -> + Xapi_stdext_date.Date.epoch + in + {acc with issued} + | Xml.Element ("severity", _, [Xml.PCData v]) -> ( + try {acc with severity= Severity.of_string v} + with e -> + (* The error should not block update. Ingore it. *) + warn "%s" (ExnHelper.string_of_exn e) ; + acc + ) + | Xml.Element ("title", _, [Xml.PCData v]) -> + {acc with title= v} + | _ -> + acc ) - | Xml.Element ("title", _, [Xml.PCData v]) -> - {acc with title= v} - | _ -> - acc - ) - {default with update_type= ty} - update_nodes - |> assert_valid_updateinfo - in - debug "updateinfo: %s" (to_string ui) ; - Some ui - | _ -> - None - ) - children - |> assert_no_dup_update_id - |> List.map (fun updateinfo -> (updateinfo.id, updateinfo)) + {default with update_type= ty} + update_nodes + |> assert_valid_updateinfo + in + debug "updateinfo: %s" (to_string ui) ; + Some ui + | _ -> + None + ) + children + |> assert_no_dup_update_id + |> List.map (fun updateinfo -> (updateinfo.id, updateinfo)) + in + match (api_ver, uis) with + | Some v, [] -> + error + "Unexpected xapi-api-version: %s when there is no updates at all" + v ; + raise Api_errors.(Server_error (invalid_updateinfo_xml, [])) + | _, _ -> + (api_ver, uis) + ) | _ -> error "Failed to parse updateinfo.xml: missing " ; raise Api_errors.(Server_error (invalid_updateinfo_xml, [])) diff --git a/ocaml/xapi/updateinfo.mli b/ocaml/xapi/updateinfo.mli index 7a348db598c..8948d778d23 100644 --- a/ocaml/xapi/updateinfo.mli +++ b/ocaml/xapi/updateinfo.mli @@ -143,8 +143,10 @@ end (** The metadata of one update in updateinfo. *) module UpdateInfo : sig + type id_t = string + type t = { - id: string + id: id_t ; summary: string ; description: string ; guidance: GuidanceInUpdateInfo.t @@ -158,13 +160,15 @@ module UpdateInfo : sig ; title: string } + type api_ver_t = string + val to_json : t -> Yojson.Basic.t val guidance_to_string : Guidance.t option -> string - val of_xml : Xml.xml -> (string * t) list + val of_xml : Xml.xml -> api_ver_t option * (id_t * t) list - val of_xml_file : string -> (string * t) list + val of_xml_file : string -> api_ver_t option * (id_t * t) list val get_guidances_of_kind : kind:Guidance.kind -> t -> Guidance.t list end