Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
MVD CP-52334 multi-version driver API/CLI - incremental update
When scanning a host for drivers, don't remove and re-create them but
instead update an entry if it already exists.

Signed-off-by: Christian Lindig <[email protected]>
  • Loading branch information
Christian Lindig committed Jan 21, 2025
commit f38cb666b93ad0093c668e49730fea432a15ac9a
2 changes: 1 addition & 1 deletion doc/content/toolstack/features/MVD/index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'++
+++
title = "Multi-version drivers"
+++

Expand Down
4 changes: 1 addition & 3 deletions ocaml/idl/datamodel_driver_variant.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ open Datamodel_types
open Datamodel_common
open Datamodel_roles

(** This is pure data with no methods *)

let select =
call ~name:"select" ~in_oss_since:None ~lifecycle:[]
~doc:
Expand Down Expand Up @@ -45,7 +43,7 @@ let t =
; field ~lifecycle:[] ~qualifier:DynamicRO ~ty:(Ref _host_driver) "driver"
"Driver this variant is a part of"
; field ~lifecycle:[] ~qualifier:DynamicRO ~ty:String "version"
"Unique versions of this driver variant"
"Unique version of this driver variant"
; field ~lifecycle:[] ~qualifier:DynamicRO ~ty:Bool "hardware_present"
"True if the hardware for this variant is present on the host"
; field ~lifecycle:[] ~qualifier:DynamicRO ~ty:Float "priority"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not mentioned in the markdown doc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True; the role of priority is not clear at the moment; we are not actively using it except to order presentation. The value is reported by the lower level.

Expand Down
2 changes: 1 addition & 1 deletion ocaml/idl/datamodel_lifecycle.ml
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ let prototyped_of_message = function
| "Driver_variant", "select" ->
Some "24.39.0"
| "Host_driver", "rescan" ->
Some "24.39.0-next"
Some "24.40.0"
| "Host_driver", "deselect" ->
Some "24.35.0"
| "Host_driver", "select" ->
Expand Down
2 changes: 1 addition & 1 deletion ocaml/idl/schematest.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ let hash x = Digest.string x |> Digest.to_hex
(* BEWARE: if this changes, check that schema has been bumped accordingly in
ocaml/idl/datamodel_common.ml, usually schema_minor_vsn *)

let last_known_schema_hash = "863c257bad0d20800297cf968c294e4e"
let last_known_schema_hash = "36cb241822399344b119cce654162d3f"

let current_schema_hash : string =
let open Datamodel_types in
Expand Down
4 changes: 2 additions & 2 deletions ocaml/xapi-cli-server/cli_operations.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ open Records

let failwith str = raise (Cli_util.Cli_failure str)

let failwith' fmt = Printf.ksprintf failwith fmt
let failwithfmt fmt = Printf.ksprintf failwith fmt

exception ExitWithError of int

Expand Down Expand Up @@ -8012,7 +8012,7 @@ module Host_driver = struct

match List.find_opt by_name variants with
| None ->
failwith' "%s does not identify a variant of this driver" name
failwithfmt "%s does not identify a variant of this driver" name
| Some (variant, _) ->
Client.Host_driver.select ~rpc ~session_id ~self:driver ~variant

Expand Down
9 changes: 5 additions & 4 deletions ocaml/xapi/message_forwarding.ml
Original file line number Diff line number Diff line change
Expand Up @@ -6610,7 +6610,8 @@ functor
module Host_driver = struct
(** select needs to be executed on the host of the driver *)
let select ~__context ~self ~variant =
info "%s" __FUNCTION__ ;
info "Host_driver.select %s %s" (Ref.string_of self)
(Ref.string_of variant) ;
let host = Db.Host_driver.get_host ~__context ~self in
let local_fn = Local.Host_driver.select ~self ~variant in
do_op_on ~__context ~local_fn ~host (fun session_id rpc ->
Expand All @@ -6619,15 +6620,15 @@ functor

(** deselect needs to be executed on the host of the driver *)
let deselect ~__context ~self =
info "%s" __FUNCTION__ ;
info "Host_driver.deselect %s" (Ref.string_of self) ;
let host = Db.Host_driver.get_host ~__context ~self in
let local_fn = Local.Host_driver.deselect ~self in
do_op_on ~__context ~local_fn ~host (fun session_id rpc ->
Client.Host_driver.deselect ~rpc ~session_id ~self
)

let rescan ~__context ~host =
info "%s" __FUNCTION__ ;
info "Host_driver.rescan %s" (Ref.string_of host) ;
let local_fn = Local.Host_driver.rescan ~host in
do_op_on ~__context ~local_fn ~host (fun session_id rpc ->
Client.Host_driver.rescan ~rpc ~session_id ~host
Expand All @@ -6636,7 +6637,7 @@ functor

module Driver_variant = struct
let select ~__context ~self =
info "%s" __FUNCTION__ ;
info "Driver_variant.select %s" (Ref.string_of self) ;
let drv = Db.Driver_variant.get_driver ~__context ~self in
let host = Db.Host_driver.get_host ~__context ~self:drv in
let local_fn = Local.Driver_variant.select ~self in
Expand Down
119 changes: 53 additions & 66 deletions ocaml/xapi/xapi_host_driver.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,11 @@ module D = Debug.Make (struct let name = __MODULE__ end)

open D
module Unixext = Xapi_stdext_unix.Unixext

(*
module DriverMap = Map.Make (String)
module DriverSet = Set.Make (String)
*)
module T = Xapi_host_driver_tool
module Tool = Xapi_host_driver_tool

let invalid_value field value =
raise Api_errors.(Server_error (invalid_value, [field; value]))

let internal_error fmt =
Printf.ksprintf
(fun msg ->
error "%s" msg ;
raise Api_errors.(Server_error (internal_error, [msg]))
)
fmt

let drivertool args =
let path = !Xapi_globs.driver_tool in
try
let stdout, _stderr = Forkhelpers.execute_command_get_output path args in
debug "%s: executed %s %s" __FUNCTION__ path (String.concat " " args) ;
stdout
with e ->
internal_error "%s: failed to run %s %s: %s" __FUNCTION__ path
(String.concat " " args) (Printexc.to_string e)

module Variant = struct
let create ~__context ~name ~version ~driver ~hw_present ~priority ~dev_status
=
Expand All @@ -55,7 +32,7 @@ module Variant = struct
ref

let destroy ~__context ~self =
debug "Destroying driver variant %s" (Ref.string_of self) ;
debug "%s: destroying driver variant %s" __FUNCTION__ (Ref.string_of self) ;
Db.Driver_variant.destroy ~__context ~self

(** create' is like create but updates an exisiting entry if it
Expand Down Expand Up @@ -92,7 +69,7 @@ module Variant = struct
let d = Db.Host_driver.get_record ~__context ~self:drv in
let v = Db.Driver_variant.get_record ~__context ~self in
let stdout =
drivertool ["select"; d.API.host_driver_name; v.API.driver_variant_name]
Tool.call ["select"; d.API.host_driver_name; v.API.driver_variant_name]
in
info "%s: %s" __FUNCTION__ stdout ;
Db.Host_driver.set_selected_variant ~__context ~self:drv ~value:self
Expand Down Expand Up @@ -126,15 +103,16 @@ let create' ~__context ~host ~name ~friendly_name ~_type ~description ~info:inf
match Db.Host_driver.get_refs_where ~__context ~expr with
| [] ->
(* no such entry exists - create it *)
create ~__context ~host ~name ~friendly_name ~info:inf
~active_variant:null ~selected_variant:null ~description ~_type
create ~__context ~host ~name ~friendly_name ~info:inf ~active_variant
~selected_variant ~description ~_type
| [self] ->
(* one existing entry - update it *)
info "%s: updating host driver %s" __FUNCTION__ name ;
Db.Host_driver.set_friendly_name ~__context ~self ~value:name ;
Db.Host_driver.set_info ~__context ~self ~value:inf ;
Db.Host_driver.set_active_variant ~__context ~self ~value:null ;
Db.Host_driver.set_selected_variant ~__context ~self ~value:null ;
Db.Host_driver.set_active_variant ~__context ~self ~value:active_variant ;
Db.Host_driver.set_selected_variant ~__context ~self
~value:selected_variant ;
Db.Host_driver.set_description ~__context ~self ~value:description ;
Db.Host_driver.set_type ~__context ~self ~value:_type ;
self
Expand All @@ -156,7 +134,7 @@ let select ~__context ~self ~variant =
let d = Db.Host_driver.get_record ~__context ~self in
let v = Db.Driver_variant.get_record ~__context ~self:variant in
let stdout =
drivertool ["select"; d.API.host_driver_name; v.API.driver_variant_name]
Tool.call ["select"; d.API.host_driver_name; v.API.driver_variant_name]
in
info "%s: %s" __FUNCTION__ stdout ;
Db.Host_driver.set_selected_variant ~__context ~self ~value:variant
Expand All @@ -168,51 +146,60 @@ let select ~__context ~self ~variant =
let deselect ~__context ~self =
D.debug "%s driver %s" __FUNCTION__ (Ref.string_of self) ;
let d = Db.Host_driver.get_record ~__context ~self in
let stdout = drivertool ["deselect"; d.API.host_driver_name] in
let stdout = Tool.call ["deselect"; d.API.host_driver_name] in
info "%s: %s" __FUNCTION__ stdout ;
Db.Host_driver.set_active_variant ~__context ~self ~value:Ref.null ;
Db.Host_driver.set_selected_variant ~__context ~self ~value:Ref.null

(** remove all host driver entries for this host *)
let reset ~__context ~host =
(** remove all host driver entries that are not in [except]. We exepect
any list to be short *)
let remove ~__context ~host ~except =
D.debug "%s" __FUNCTION__ ;
let open Xapi_database.Db_filter_types in
let expr = Eq (Field "host", Literal (Ref.string_of host)) in
let drivers = Db.Host_driver.get_refs_where ~__context ~expr in
drivers |> List.iter (fun self -> destroy ~__context ~self)
Db.Host_driver.get_refs_where ~__context ~expr
|> List.filter (fun driver -> not @@ List.mem driver except)
|> List.iter (fun self -> destroy ~__context ~self)

(** Runs on [host] *)
(** Runs on [host]. We update or create an entry for each driver
reported by drivertool and remove any extra driver that is in xapi. *)
let scan ~__context ~host =
T.Mock.install () ;
Tool.Mock.install () ;
let null = Ref.null in
drivertool ["list"]
|> T.parse
|> List.iter @@ fun (_name, driver) ->
let driver_ref =
create' ~__context ~host ~name:driver.T.name ~friendly_name:driver.T.name
~info:driver.T.info ~active_variant:null ~selected_variant:null
~description:driver.T.descr ~_type:driver.T.ty
in
driver.T.variants
|> List.iter @@ fun (name, v) ->
let var_ref =
Variant.create' ~__context ~name ~version:v.T.version
~driver:driver_ref ~hw_present:v.T.hw_present ~priority:v.T.priority
~dev_status:v.T.dev_status
in
( match driver.T.selected with
| Some v when v = name ->
Db.Host_driver.set_selected_variant ~__context ~self:driver_ref
~value:var_ref
| _ ->
()
) ;
match driver.T.active with
| Some v when v = name ->
Db.Host_driver.set_active_variant ~__context ~self:driver_ref
~value:var_ref
| _ ->
()
let drivers (* on this host *) =
Tool.call ["list"]
|> Tool.parse
|> List.map @@ fun (_name, driver) ->
let driver_ref =
create' ~__context ~host ~name:driver.Tool.name
~friendly_name:driver.Tool.name ~info:driver.Tool.info
~active_variant:null ~selected_variant:null
~description:driver.Tool.descr ~_type:driver.Tool.ty
in
(driver.Tool.variants
|> List.iter @@ fun (name, v) ->
let var_ref =
Variant.create' ~__context ~name ~version:v.Tool.version
~driver:driver_ref ~hw_present:v.Tool.hw_present
~priority:v.Tool.priority ~dev_status:v.Tool.dev_status
in
( match driver.Tool.selected with
| Some v when v = name ->
Db.Host_driver.set_selected_variant ~__context ~self:driver_ref
~value:var_ref
| _ ->
()
) ;
match driver.Tool.active with
| Some v when v = name ->
Db.Host_driver.set_active_variant ~__context ~self:driver_ref
~value:var_ref
| _ ->
()
) ;
driver_ref
in
remove ~__context ~host ~except:drivers

(** Runs on [host] *)
let rescan ~__context ~host = debug "%s" __FUNCTION__ ; scan ~__context ~host
14 changes: 11 additions & 3 deletions ocaml/xapi/xapi_host_driver_tool.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
host-driver-tool that manages multi-version drivers and reports
the state of them in JSON *)

module D = Debug.Make (struct let name = __MODULE__ end)

open D
open Debug.Make (struct let name = __MODULE__ end)

let internal_error fmt =
Printf.ksprintf
Expand Down Expand Up @@ -234,6 +232,16 @@ let read path =
| exception e ->
raise e

let call args =
let path = !Xapi_globs.driver_tool in
try
let stdout, _stderr = Forkhelpers.execute_command_get_output path args in
debug "%s: executed %s %s" __FUNCTION__ path (String.concat " " args) ;
stdout
with e ->
internal_error "%s: failed to run %s %s: %s" __FUNCTION__ path
(String.concat " " args) (Printexc.to_string e)

module Mock = struct
let drivertool_sh =
{|#!/usr/bin/env bash
Expand Down
3 changes: 3 additions & 0 deletions ocaml/xapi/xapi_host_driver_tool.mli
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ val parse : string -> (string * driver) list
val read : string -> (string * driver) list
(** read from a file whose path is provided *)

val call : string list -> string
(** invoke drivertool with argumtns and return stdout *)

(** install a mock drivertool.sh *)
module Mock : sig
val install : unit -> unit
Expand Down
4 changes: 1 addition & 3 deletions quality-gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ verify-cert () {
}

mli-files () {
<<<<<<< HEAD
N=496
N=499
N=498
X="ocaml/tests"
X+="|ocaml/quicktest"
X+="|ocaml/message-switch/core_test"
Expand Down