Merge pull request #47 from reynir/query-manifest

Verify devices with manifest
This commit is contained in:
Reynir Björnsson 2020-11-30 12:15:39 +01:00 committed by GitHub
commit 91ba8be8ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 4 deletions

View file

@ -102,7 +102,9 @@ let setup_log style_renderer level =
let create_vm force image cpuid memory argv block_devices bridges compression restart_on_fail exit_codes =
let open Rresult.R.Infix in
Bos.OS.File.read (Fpath.v image) >>| fun image ->
let img_file = Fpath.v image in
Bos.OS.File.read img_file >>= fun image ->
Vmm_unix.manifest_devices_match ~bridges ~block_devices img_file >>| fun () ->
let image, compressed = match compression with
| 0 -> Cstruct.of_string image, false
| level ->

View file

@ -16,6 +16,30 @@ let find_string_value k = function
| Some (_, `String value) -> Ok value
| _ -> Rresult.R.error_msgf "couldn't find %s in json dictionary" k
let find_devices x =
let open Rresult in
let device dev =
find_string_value "name" dev >>= fun name ->
find_string_value "type" dev >>| fun typ ->
name, typ
in
match x with
| `Null | `Bool _ | `Float _ | `String _ | `A _ ->
Rresult.R.error_msg "couldn't find devices in json"
| `O dict ->
match List.find_opt (fun (key, _) -> String.equal key "devices") dict with
| Some (_, `A devices) ->
List.fold_left
(fun acc dev ->
acc >>= fun (block_devices, networks) ->
device dev >>= fun (name, typ) ->
match typ with
| "BLOCK_BASIC" -> Ok (name :: block_devices, networks)
| "NET_BASIC" -> Ok (block_devices, name :: networks)
| _ -> Rresult.R.error_msgf "unknown device type %s in json" typ)
(Ok ([], [])) devices
| _ -> Rresult.R.error_msg "devices field is not array in json"
let json_of_string src =
let dec d = match Jsonm.decode d with
| `Lexeme l -> l

View file

@ -201,6 +201,48 @@ let solo5_image_target image =
let solo5_tender = function Spt -> "solo5-spt" | Hvt -> "solo5-hvt"
let solo5_image_devices image =
check_solo5_cmd "solo5-elftool" >>= fun cmd ->
let cmd = Bos.Cmd.(cmd % "query-manifest" % p image) in
Bos.OS.Cmd.(run_out cmd |> out_string |> success) >>= fun s ->
R.error_to_msg ~pp_error:Jsonm.pp_error
(Vmm_json.json_of_string s) >>= fun data ->
Vmm_json.find_devices data
let equal_string_lists b1 b2 err =
let open Astring in
if String.Set.(equal (of_list b1) (of_list b2)) then
Ok ()
else
R.error_msg err
let devices_match ~bridges ~block_devices (manifest_block, manifest_net) =
equal_string_lists manifest_block block_devices
"specified block device(s) does not match with manifest" >>= fun () ->
equal_string_lists manifest_net bridges
"specified bridge(s) does not match with the manifest"
let manifest_devices_match ~bridges ~block_devices image_file =
solo5_image_devices image_file >>=
let bridges = List.map fst bridges in
devices_match ~bridges ~block_devices
let bridge_name (service, b) = match b with None -> service | Some b -> b
let bridge_exists bridge_name =
let cmd =
match Lazy.force uname with
| FreeBSD -> Bos.Cmd.(v "ifconfig" % bridge_name)
| Linux -> Bos.Cmd.(v "ip" % "link" % "show" % bridge_name)
in
Bos.OS.Cmd.(run_out ~err:err_null cmd |> out_null |> success)
|> R.reword_error (fun _e -> R.msgf "interface %s does not exist" bridge_name)
let bridges_exist bridges =
List.fold_left
(fun acc b -> acc >>= fun () -> bridge_exists (bridge_name b))
(Ok ()) bridges
let prepare name vm =
(match vm.Unikernel.typ with
| `Solo5 ->
@ -214,6 +256,8 @@ let prepare name vm =
Bos.OS.File.write filename (Cstruct.to_string image) >>= fun () ->
solo5_image_target filename >>= fun target ->
check_solo5_cmd (solo5_tender target) >>= fun _ ->
manifest_devices_match ~bridges:vm.Unikernel.bridges ~block_devices:vm.Unikernel.block_devices filename >>= fun () ->
bridges_exist vm.Unikernel.bridges >>= fun () ->
let fifo = Name.fifo_file name in
begin match fifo_exists fifo with
| Ok true -> Ok ()
@ -230,11 +274,11 @@ let prepare name vm =
let _ = Unix.umask old_umask in
R.error_msgf "file %a error in %s: %a" Fpath.pp fifo f pp_unix_err e
end >>= fun () ->
List.fold_left (fun acc (net, bri) ->
List.fold_left (fun acc arg ->
acc >>= fun acc ->
let bridge = match bri with None -> net | Some b -> b in
let bridge = bridge_name arg in
create_tap bridge >>= fun tap ->
Ok ((net, tap) :: acc))
Ok ((fst arg, tap) :: acc))
(Ok []) vm.Unikernel.bridges >>= fun taps ->
Ok (List.rev taps)

View file

@ -37,3 +37,6 @@ val dump : ?name:string -> Cstruct.t -> (unit, [> R.msg ]) result
val restore : ?name:string -> unit -> (Cstruct.t, [> R.msg | `NoFile ]) result
val vm_device : Unikernel.t -> (string, [> R.msg ]) result
val manifest_devices_match : bridges:(string * string option) list ->
block_devices:string list -> Fpath.t -> (unit, [> R.msg]) result