vmmd: actually, first check resources, then exec VM, then insert VM
in case the insertion fails, raise Invalid_argument this leads to more sane failure behaviour, and also cleans up resources in case vmm_resources.insert_vm fails (or cpuset/open of the fifo, create_process)
This commit is contained in:
parent
131dec0cdd
commit
a9c32d7801
|
@ -31,8 +31,9 @@ let create stat_out log_out cons_out data_out cons succ_cont fail_cont =
|
||||||
data_out data
|
data_out data
|
||||||
| Ok () -> match succ_cont !state with
|
| Ok () -> match succ_cont !state with
|
||||||
| Error (`Msg msg) ->
|
| Error (`Msg msg) ->
|
||||||
Logs.err (fun m -> m "create continuation failed %s" msg) ;
|
Logs.err (fun m -> m "create (exec) failed %s" msg) ;
|
||||||
Lwt.return_unit
|
let data = fail_cont () in
|
||||||
|
data_out data
|
||||||
| Ok (state', stat, log, data, name, vm) ->
|
| Ok (state', stat, log, data, name, vm) ->
|
||||||
state := state' ;
|
state := state' ;
|
||||||
s := { !s with vm_created = succ !s.vm_created } ;
|
s := { !s with vm_created = succ !s.vm_created } ;
|
||||||
|
|
|
@ -51,16 +51,15 @@ let find_block t name = Vmm_trie.find name t.block_devices
|
||||||
|
|
||||||
let set_block_usage t name active =
|
let set_block_usage t name active =
|
||||||
match Vmm_trie.find name t with
|
match Vmm_trie.find name t with
|
||||||
| None -> Error (`Msg "unknown block device")
|
| None -> invalid_arg ("block device " ^ Name.to_string name ^ " not in trie")
|
||||||
| Some (size, curr) ->
|
| Some (size, curr) ->
|
||||||
if curr = active then
|
if curr = active
|
||||||
Error (`Msg "failed because the requested block usage was already set")
|
then invalid_arg ("block device " ^ Name.to_string name ^ " already in state " ^ (if curr then "active" else "inactive"))
|
||||||
else
|
else fst (Vmm_trie.insert name (size, active) t)
|
||||||
Ok (fst (Vmm_trie.insert name (size, active) t))
|
|
||||||
|
|
||||||
let maybe_use_block t name vm active =
|
let use_block t name vm active =
|
||||||
match vm.Unikernel.config.Unikernel.block_device with
|
match vm.Unikernel.config.Unikernel.block_device with
|
||||||
| None -> Ok t
|
| None -> t
|
||||||
| Some block ->
|
| Some block ->
|
||||||
let block_name = Name.block_name name block in
|
let block_name = Name.block_name name block in
|
||||||
set_block_usage t block_name active
|
set_block_usage t block_name active
|
||||||
|
@ -68,9 +67,9 @@ let maybe_use_block t name vm active =
|
||||||
let remove_vm t name = match find_vm t name with
|
let remove_vm t name = match find_vm t name with
|
||||||
| None -> Error (`Msg "unknown vm")
|
| None -> Error (`Msg "unknown vm")
|
||||||
| Some vm ->
|
| Some vm ->
|
||||||
maybe_use_block t.block_devices name vm false >>| fun block_devices ->
|
let block_devices = use_block t.block_devices name vm false in
|
||||||
let unikernels = Vmm_trie.remove name t.unikernels in
|
let unikernels = Vmm_trie.remove name t.unikernels in
|
||||||
{ t with block_devices ; unikernels }
|
Ok { t with block_devices ; unikernels }
|
||||||
|
|
||||||
let remove_policy t name = match find_policy t name with
|
let remove_policy t name = match find_policy t name with
|
||||||
| None -> Error (`Msg "unknown policy")
|
| None -> Error (`Msg "unknown policy")
|
||||||
|
@ -126,12 +125,10 @@ let check_vm t name vm =
|
||||||
vm_ok
|
vm_ok
|
||||||
|
|
||||||
let insert_vm t name vm =
|
let insert_vm t name vm =
|
||||||
check_vm t name vm.Unikernel.config >>= fun () ->
|
let unikernels, old = Vmm_trie.insert name vm t.unikernels in
|
||||||
match Vmm_trie.insert name vm t.unikernels with
|
(match old with None -> () | Some _ -> invalid_arg ("unikernel " ^ Name.to_string name ^ " already exists in trie")) ;
|
||||||
| unikernels, None ->
|
let block_devices = use_block t.block_devices name vm true in
|
||||||
maybe_use_block t.block_devices name vm true >>| fun block_devices ->
|
{ t with unikernels ; block_devices }
|
||||||
{ t with unikernels ; block_devices }
|
|
||||||
| _, Some _ -> Error (`Msg "vm already exists")
|
|
||||||
|
|
||||||
let check_block t name size =
|
let check_block t name size =
|
||||||
let block_ok = match find_block t name with
|
let block_ok = match find_block t name with
|
||||||
|
|
|
@ -37,9 +37,12 @@ val find_block : t -> Name.t -> (int * bool) option
|
||||||
allowed under the current policies. *)
|
allowed under the current policies. *)
|
||||||
val check_vm : t -> Name.t -> Unikernel.config -> (unit, [> `Msg of string ]) result
|
val check_vm : t -> Name.t -> Unikernel.config -> (unit, [> `Msg of string ]) result
|
||||||
|
|
||||||
(** [insert_vm t Name.t vm] inserts [vm] under [Name.t] in [t], and returns the new [t] or
|
(** [insert_vm t Name.t vm] inserts [vm] under [Name.t] in [t], and returns the
|
||||||
an error. *)
|
new [t]. The caller has to ensure (using {!check_vm}) that a VM with the
|
||||||
val insert_vm : t -> Name.t -> Unikernel.t -> (t, [> `Msg of string]) result
|
same name does not yet exist, and the block device is not in use.
|
||||||
|
@raise Invalid_argument if block device is already in use, or VM already
|
||||||
|
exists. *)
|
||||||
|
val insert_vm : t -> Name.t -> Unikernel.t -> t
|
||||||
|
|
||||||
(** [insert_policy t Name.t policy] inserts [policy] under [Name.t] in [t], and returns
|
(** [insert_policy t Name.t policy] inserts [policy] under [Name.t] in [t], and returns
|
||||||
the new [t] or an error. *)
|
the new [t] or an error. *)
|
||||||
|
|
|
@ -210,7 +210,7 @@ let exec name config taps block =
|
||||||
Logs.debug (fun m -> m "created process %d: %a" pid Bos.Cmd.pp cmd) ;
|
Logs.debug (fun m -> m "created process %d: %a" pid Bos.Cmd.pp cmd) ;
|
||||||
(* we gave a copy (well, two copies) of that file descriptor to the solo5
|
(* we gave a copy (well, two copies) of that file descriptor to the solo5
|
||||||
process and don't really need it here anymore... *)
|
process and don't really need it here anymore... *)
|
||||||
close stdout ;
|
close_no_err stdout ;
|
||||||
Ok Unikernel.{ config ; cmd ; pid ; taps }
|
Ok Unikernel.{ config ; cmd ; pid ; taps }
|
||||||
with
|
with
|
||||||
Unix.Unix_error (e, _, _) ->
|
Unix.Unix_error (e, _, _) ->
|
||||||
|
|
|
@ -132,19 +132,25 @@ let handle_create t hdr name vm_config =
|
||||||
(header, `Command (`Console_cmd `Console_add))
|
(header, `Command (`Console_cmd `Console_add))
|
||||||
in
|
in
|
||||||
let success t =
|
let success t =
|
||||||
(* actually execute the vm *)
|
(* actually execute the vm:
|
||||||
|
- check for safety that executing it would not exceed any resources
|
||||||
|
- execute it
|
||||||
|
- update resources
|
||||||
|
--> if either the first or second fails, then the fail continuation
|
||||||
|
below needs to be called *)
|
||||||
let block_device = match vm_config.Unikernel.block_device with
|
let block_device = match vm_config.Unikernel.block_device with
|
||||||
| None -> None
|
| None -> None
|
||||||
| Some block -> Some (Name.block_name name block)
|
| Some block -> Some (Name.block_name name block)
|
||||||
in
|
in
|
||||||
Vmm_unix.exec name vm_config taps block_device >>= fun vm ->
|
Vmm_resources.check_vm t.resources name vm_config >>= fun () ->
|
||||||
|
Vmm_unix.exec name vm_config taps block_device >>| fun vm ->
|
||||||
Logs.debug (fun m -> m "exec()ed vm") ;
|
Logs.debug (fun m -> m "exec()ed vm") ;
|
||||||
Vmm_resources.insert_vm t.resources name vm >>= fun resources ->
|
let resources = Vmm_resources.insert_vm t.resources name vm in
|
||||||
let t = { t with resources } in
|
let t = { t with resources } in
|
||||||
dump_unikernels t ;
|
dump_unikernels t ;
|
||||||
let t, log_out = log t name (`Unikernel_start (name, vm.Unikernel.pid, vm.Unikernel.taps, None)) in
|
let t, log_out = log t name (`Unikernel_start (name, vm.Unikernel.pid, vm.Unikernel.taps, None)) in
|
||||||
let t, stat_out = setup_stats t name vm in
|
let t, stat_out = setup_stats t name vm in
|
||||||
Ok (t, stat_out, log_out, (hdr, `Success (`String "created VM")), name, vm)
|
(t, stat_out, log_out, (hdr, `Success (`String "created VM")), name, vm)
|
||||||
and fail () =
|
and fail () =
|
||||||
match Vmm_unix.free_resources name taps with
|
match Vmm_unix.free_resources name taps with
|
||||||
| Ok () -> (hdr, `Failure "could not create VM: console failed")
|
| Ok () -> (hdr, `Failure "could not create VM: console failed")
|
||||||
|
|
Loading…
Reference in a new issue