Skip to content

Commit 2c87860

Browse files
authored
CA-408048 remove SM plugins from DB if unavailable (#6401)
An SM plugin might become unavailable; we have to remove its record on xapi startup. The canonical case is an upgrade from XS8 to XS9.
2 parents 4b72ad9 + efc5b30 commit 2c87860

File tree

6 files changed

+205
-3
lines changed

6 files changed

+205
-3
lines changed

ocaml/xapi-aux/dune

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(library
22
(name xapi_aux)
33
(modes best)
4+
(modules :standard \ version_test)
45
(libraries
56
astring
67
clock
@@ -21,3 +22,11 @@
2122
(wrapped false)
2223
)
2324

25+
; to run this test: dune exec ./version_test.exe
26+
(tests
27+
(names version_test)
28+
(modes (best exe))
29+
(modules version_test)
30+
(package xapi)
31+
(libraries
32+
xapi_aux alcotest))

ocaml/xapi-aux/version.ml

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
(*
2+
Copyright (c) Cloud Software Group, Inc.
3+
4+
This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published
6+
by the Free Software Foundation; version 2.1 only. with the special
7+
exception on linking described in file LICENSE.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
*)
14+
15+
(* Simple abstraction for version information that enforces a simple
16+
format and predicatable semantics *)
17+
18+
exception Format of string
19+
20+
(** in decreasing oder of sginificance *)
21+
type t = int list
22+
23+
let of_string str =
24+
let int str = Scanf.sscanf str "%u%!" Fun.id in
25+
try String.split_on_char '.' str |> List.map int with _ -> raise (Format str)
26+
27+
let to_string t =
28+
let str int = Printf.sprintf "%d" int in
29+
t |> List.map str |> String.concat "."
30+
31+
(** Total order over versions; 1.2.3 is equal to 1.2.3.0 *)
32+
let rec compare v1 v2 =
33+
match (v1, v2) with
34+
| [], [] ->
35+
0
36+
| 0 :: xs, [] ->
37+
compare xs []
38+
| _, [] ->
39+
1
40+
| [], 0 :: ys ->
41+
compare [] ys
42+
| [], _ ->
43+
-1
44+
| x :: xs, y :: ys when x = y ->
45+
compare xs ys
46+
| x :: _, y :: _ when x < y ->
47+
-1
48+
| _ ->
49+
1
50+
51+
let ne x y = compare x y <> 0
52+
53+
let eq x y = compare x y = 0
54+
55+
let le x y = compare x y <= 0
56+
57+
let ge x y = compare x y >= 0
58+
59+
let gt x y = compare x y > 0
60+
61+
let lt x y = compare x y < 0
62+
63+
let is_valid str =
64+
try
65+
ignore (of_string str) ;
66+
true
67+
with Format _ -> false
68+
69+
module String = struct
70+
let wrap f v1 v2 = f (of_string v1) (of_string v2)
71+
72+
let compare = wrap compare
73+
74+
let ne = wrap ne
75+
76+
let eq = wrap eq
77+
78+
let le = wrap le
79+
80+
let ge = wrap ge
81+
82+
let gt = wrap gt
83+
84+
let lt = wrap lt
85+
end

ocaml/xapi-aux/version.mli

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
(*
2+
Copyright (c) Cloud Software Group, Inc.
3+
4+
This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published
6+
by the Free Software Foundation; version 2.1 only. with the special
7+
exception on linking described in file LICENSE.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
*)
14+
15+
(** a version, derived from a string representation - see below *)
16+
type t
17+
18+
(** A version string violates the supported syntax *)
19+
exception Format of string
20+
21+
val of_string : string -> t
22+
(** Parse a version; may raise [Format]. A version is a sequence of
23+
unsigned integers separated by a dot; for axample "1.2.3" is a legal
24+
version. Must have at least one component. Examples:
25+
- 3
26+
- 3.10
27+
- 3.10.4
28+
- 3.10.4.0.0
29+
- 3.10.4.0.1
30+
- 0
31+
- 0.2
32+
*)
33+
34+
val to_string : t -> string
35+
(** represent a version as a string *)
36+
37+
val compare : t -> t -> int
38+
(** Total order over versions; yields one of -1, 0, 1 as by convention.
39+
- 1.2.3 = 1.2.3.0
40+
- 1.10.2 > 1.9.1
41+
- 0.1.0.0 = 0.1
42+
*)
43+
44+
(* version equality relations *)
45+
val eq : t -> t -> bool
46+
47+
val ge : t -> t -> bool
48+
49+
val gt : t -> t -> bool
50+
51+
val le : t -> t -> bool
52+
53+
val lt : t -> t -> bool
54+
55+
val ne : t -> t -> bool
56+
57+
(* Validate the format of a version string *)
58+
val is_valid : string -> bool
59+
60+
(* Operations over version strings for convenience. Each function may
61+
raise [Format] *)
62+
module String : sig
63+
val compare : string -> string -> int
64+
65+
val ne : string -> string -> bool
66+
67+
val eq : string -> string -> bool
68+
69+
val le : string -> string -> bool
70+
71+
val ge : string -> string -> bool
72+
73+
val gt : string -> string -> bool
74+
75+
val lt : string -> string -> bool
76+
end

ocaml/xapi-aux/version_test.ml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
open Alcotest
2+
3+
let format () =
4+
check bool __LOC__ true (Version.is_valid "3") ;
5+
check bool __LOC__ true (Version.is_valid "0") ;
6+
check bool __LOC__ true (Version.is_valid "3.1") ;
7+
check bool __LOC__ true (Version.is_valid "3.1.4") ;
8+
check bool __LOC__ true (Version.is_valid "3.14") ;
9+
check bool __LOC__ false (Version.is_valid "") ;
10+
check bool __LOC__ false (Version.is_valid "3a") ;
11+
check bool __LOC__ false (Version.is_valid "3.1.4.") ;
12+
check bool __LOC__ false (Version.is_valid "3.1.4.a") ;
13+
check bool __LOC__ false (Version.is_valid "3.1.4a") ;
14+
check bool __LOC__ false (Version.is_valid "3.1:4") ;
15+
check bool __LOC__ false (Version.is_valid "-3.1.4")
16+
17+
let order () =
18+
check bool __LOC__ true (Version.String.eq "3" "3.0.0") ;
19+
check bool __LOC__ true (Version.String.le "3" "3.0.1") ;
20+
check bool __LOC__ true (Version.String.le "3.1" "3.10") ;
21+
check bool __LOC__ true (Version.String.eq "0" "0.0.0")
22+
23+
let tests = [test_case "format" `Quick format; test_case "order" `Quick order]
24+
25+
let () = run __MODULE__ [(__MODULE__, tests)]

ocaml/xapi-aux/version_test.mli

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(* empty *)

ocaml/xapi/storage_access.ml

+9-3
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,16 @@ exception Message_switch_failure
109109
(** Synchronise the SM table with the SMAPIv1 plugins on the disk and the SMAPIv2
110110
plugins mentioned in the configuration file whitelist. *)
111111
let on_xapi_start ~__context =
112+
(* An SM is either implemented as a plugin - for which we check its
113+
presence, or via an API *)
114+
let is_available (_rf, rc) =
115+
Sys.file_exists rc.API.sM_driver_filename
116+
|| Version.String.ge rc.sM_required_api_version "5.0"
117+
in
112118
let existing =
113-
List.map
114-
(fun (rf, rc) -> (rc.API.sM_type, (rf, rc)))
115-
(Db.SM.get_all_records ~__context)
119+
Db.SM.get_all_records ~__context
120+
|> List.filter is_available
121+
|> List.map (fun (rf, rc) -> (rc.API.sM_type, (rf, rc)))
116122
in
117123
let explicitly_configured_drivers =
118124
List.filter_map

0 commit comments

Comments
 (0)