Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update unikernel with new build from builds.robur.coop #105

Merged
merged 36 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9835cb3
function to post a request to update the binary
PizieDust Jan 24, 2025
6516b85
add alert to unikernel update page
PizieDust Jan 24, 2025
75ef5f6
use buttons and not anchor links
PizieDust Jan 24, 2025
14e568c
add endpoint to process unikernel binary updates
PizieDust Jan 24, 2025
9ef1fc2
add function to process unikernel binary updates
PizieDust Jan 24, 2025
cd0b134
check manifest diff of bridges and block devices
robur-team Jan 24, 2025
c752556
use solo5-elftool without owee
PizieDust Jan 29, 2025
4f62a04
pass bridge or block diffs in error message
PizieDust Jan 29, 2025
d1d3379
pass unikernel name in post request to unikernel update function
PizieDust Jan 29, 2025
81ccc1a
use unikernel name in update unikernel layout
PizieDust Jan 29, 2025
a14fd89
update to perform a manifest check before updating
PizieDust Jan 29, 2025
15af0fc
formatted code
Jan 29, 2025
727f92d
minor refactorings
PizieDust Jan 31, 2025
de9bfbf
properly handle device manifest
PizieDust Jan 31, 2025
7065a19
no upgrade button if no binary in latest build
PizieDust Jan 31, 2025
316d8a7
move string_or_none to utils and refactor
PizieDust Jan 31, 2025
ae7ef43
add a unikernel_info to json function and related sub functions
PizieDust Jan 31, 2025
375c3e8
optionally display previous config of the currently running unikernel…
PizieDust Jan 31, 2025
dc60471
send unikernel config in post request
PizieDust Jan 31, 2025
8bde8cc
process update using new arguments or previous arguments
PizieDust Jan 31, 2025
2f6a161
config.ml: pin owee and constrain solo5-elftool
reynir Jan 31, 2025
09acf8b
Fix type error in albatross.ml
reynir Jan 31, 2025
30ed5bb
formatted code
Jan 31, 2025
a6e8d2d
Fixup! Type error
reynir Jan 31, 2025
4506d2f
refactor error messages
PizieDust Feb 4, 2025
e917cf1
response type
PizieDust Feb 4, 2025
33912d3
Switch to ocaml-solo5-elftool 0.4.0
reynir Feb 4, 2025
6a70891
formatted code
Feb 4, 2025
0b0c792
Fixup! Switch to ocaml-solo5-elftool 0.4.0
reynir Feb 4, 2025
52ceff5
Remove pin
reynir Feb 4, 2025
7770c00
remove repeated parsing function
PizieDust Feb 6, 2025
3e29986
don't parse typ, mac addresses or digest values in json emmitted to user
PizieDust Feb 6, 2025
851a2c8
return and display better error messages
PizieDust Feb 6, 2025
b1fd02e
specify which albatross query this is from
PizieDust Feb 6, 2025
db8ef49
consistent naming
PizieDust Feb 6, 2025
40a4b74
pass json dict instead of string
PizieDust Feb 6, 2025
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
128 changes: 128 additions & 0 deletions albatross.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
let ( let* ) = Result.bind

module String_set = Set.Make (String)

module Make (T : Mirage_time.S) (P : Mirage_clock.PCLOCK) (S : Tcpip.Stack.V4V6) =
struct
module TLS = Tls_mirage.Make (S.TCP)
Expand Down Expand Up @@ -91,6 +95,130 @@ struct
}
| Error (`Msg err) -> Error err

let manifest_devices_match ~bridges ~block_devices binary =
let cachet =
let map () ~pos len =
if pos >= String.length binary || len <= 0 then
(Cachet.Bstr.empty :> Cachet.bigstring)
else
let len = min len (max 0 (String.length binary - pos)) in
let b : Cachet.bigstring =
Bigarray.Array1.create Bigarray.char Bigarray.c_layout len
in
for i = 0 to len - 1 do
b.{i} <- binary.[pos + i]
done;
b
in
Cachet.make ~cachesize:8 ~map ()
in
let* mft : Solo5_elftool.mft = Solo5_elftool.query_manifest cachet in
let req_bridges =
List.map (fun (name, _, _) -> name) bridges |> String_set.of_list
and req_block_devices =
List.map (fun (name, _, _) -> name) block_devices |> String_set.of_list
and mft_bridges =
List.filter_map
(function Solo5_elftool.Dev_net_basic name -> Some name | _ -> None)
mft.Solo5_elftool.entries
|> String_set.of_list
and mft_block_devices =
List.filter_map
(function Solo5_elftool.Dev_block_basic name -> Some name | _ -> None)
mft.Solo5_elftool.entries
|> String_set.of_list
in
let req_only_bridges = String_set.(diff req_bridges mft_bridges |> elements)
and mft_only_bridges = String_set.(diff mft_bridges req_bridges |> elements)
and req_only_blocks =
String_set.(diff req_block_devices mft_block_devices |> elements)
and mft_only_blocks =
String_set.(diff mft_block_devices req_block_devices |> elements)
in
match
(req_only_bridges, mft_only_bridges, req_only_blocks, mft_only_blocks)
with
| [], [], [], [] -> Ok ()
| req_only_bridges, [], [], [] ->
Error
(`Msg
("Extra network interfaces specified: "
^ String.concat ", " req_only_bridges
^ ". Please remove them from the 'network_interfaces' list of \
your configuration."))
| [], mft_only_bridges, [], [] ->
Error
(`Msg
("Missing required network interfaces: "
^ String.concat ", " mft_only_bridges
^ ". Please add them to the 'network_interfaces' list of your \
configuration."))
| [], [], req_only_blocks, [] ->
Error
(`Msg
("Extra block devices specified: "
^ String.concat ", " req_only_blocks
^ ". Please remove them from the 'block_devices' list of your \
configuration."))
| [], [], [], mft_only_blocks ->
Error
(`Msg
("Missing required block devices: "
^ String.concat ", " mft_only_blocks
^ ". Please add them to the 'block_devices' list of your \
configuration."))
| req_only_bridges, [], req_only_blocks, [] ->
Error
(`Msg
("Extra network interfaces: "
^ String.concat ", " req_only_bridges
^ " and extra block devices: "
^ String.concat ", " req_only_blocks
^ ". Please remove them from the 'network_interfaces' lists and \
'block_devices' list of your configuration."))
| [], mft_only_bridges, [], mft_only_blocks ->
Error
(`Msg
("Missing network interfaces: "
^ String.concat ", " mft_only_bridges
^ " and missing block devices: "
^ String.concat ", " mft_only_blocks
^ ". Please add them to the 'network_interfaces' lists and \
'block_devices' list of your configuration."))
| req_only_bridges, [], [], mft_only_blocks ->
Error
(`Msg
("Extra network interfaces: "
^ String.concat ", " req_only_bridges
^ " and missing block devices: "
^ String.concat ", " mft_only_blocks
^ ". Please remove the network interfaces from the \
'network_interfaces' list and add the block devices to the \
'block_devices' list of your configuration."))
| [], mft_only_bridges, req_only_blocks, [] ->
Error
(`Msg
("Missing network interfaces: "
^ String.concat ", " mft_only_bridges
^ " and extra block devices: "
^ String.concat ", " req_only_blocks
^ ". Please add the network interfaces to the \
'network_interfaces' list and remove the block devices from \
the 'block_devices' list of your configuration."))
| req_only_bridges, mft_only_bridges, req_only_blocks, mft_only_blocks ->
Error
(`Msg
("Missing network interfaces: "
^ String.concat ", " req_only_bridges
^ " and missing block devices: "
^ String.concat ", " req_only_blocks
^ " while also having extra network interfaces: "
^ String.concat ", " mft_only_bridges
^ " and extra block devices: "
^ String.concat ", " mft_only_blocks
^ ". Please update 'network_interfaces' and 'block_devices' \
accordingly."))

let key_ids exts pub issuer =
let open X509 in
let auth = (Some (Public_key.id issuer), General_name.empty, None) in
Expand Down
25 changes: 8 additions & 17 deletions albatross_json.ml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
open Utils.Json

let unikernel_info (unikernel_name, info) =
let typ = function `Solo5 -> `String "solo5"
and fail_behaviour = function
let fail_behaviour = function
| `Quit -> `String "quit"
| `Restart ex ->
let els =
Expand Down Expand Up @@ -33,33 +32,25 @@ let unikernel_info (unikernel_name, info) =
in
`List (List.map block bs)
and bridges bs =
let bridge (name, dev, mac) =
let bridge (name, dev, _) =
let dev = Option.value ~default:name dev in
let mac =
Option.value ~default:(Vmm_core.Name.mac unikernel_name dev) mac
in
`Assoc
[
("name", `String name);
("host_device", `String dev);
("mac", `String (Macaddr.to_string mac));
]
`Assoc [ ("name", `String name); ("host_device", `String dev) ]
in
`List (List.map bridge bs)
and argv args =
`List (List.map (fun a -> `String a) (Option.value ~default:[] args))
and digest d = `String (Ohex.encode d) in
in
`Assoc
[
("name", `String (Vmm_core.Name.to_string unikernel_name));
("typ", typ info.Vmm_core.Unikernel.typ);
("fail_behaviour", fail_behaviour info.fail_behaviour);
( "name",
`String (Option.value ~default:"" (Vmm_core.Name.name unikernel_name))
);
("fail_behaviour", fail_behaviour info.Vmm_core.Unikernel.fail_behaviour);
("cpuid", cpuid info.cpuid);
("memory", memory info.memory);
("block_devices", block_devices info.block_devices);
("network_interfaces", bridges info.bridges);
("arguments", argv info.argv);
("digest", digest info.digest);
]

let unikernel_infos is = `List (List.map unikernel_info is)
Expand Down
50 changes: 49 additions & 1 deletion assets/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -920,11 +920,59 @@ async function updateToken(value) {
buttonLoading(tokenButton, false, "Update Token")
}
} catch (error) {
postAlert("bg-secondary-300", data.data);
postAlert("bg-secondary-300", error);
buttonLoading(tokenButton, false, "Update Token")
}
}

async function updateUnikernel(job, build, unikernel_name) {
const updateButton = document.getElementById("update-unikernel-button");
const unikernelArguments = document.getElementById("unikernel-arguments").value;
const argumentsToggle = document.getElementById("arguments-toggle").checked;
const molly_csrf = document.getElementById("molly-csrf").value;
const formAlert = document.getElementById("unikernel-arguments-alert");
if (argumentsToggle && !unikernelArguments) {
postAlert("bg-secondary-300", "You must give arguments for this build else switch 'Update the configuration for this build' off");
buttonLoading(updateButton, false, "Proceed to update")
return;
}
try {
buttonLoading(updateButton, true, "Updating...")
const response = await fetch("/api/unikernel/update", {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(
{
"job": job,
"build": build,
"unikernel_name": unikernel_name,
"unikernel_arguments": argumentsToggle ? JSON.parse(unikernelArguments) : null,
"molly_csrf": molly_csrf
})
})
const data = await response.json();
if (data.status === 200) {
postAlert("bg-primary-300", "Unikernel updated succesfully");
setTimeout(() => window.location.reload(), 1000);
buttonLoading(updateButton, false, "Proceed to update")
} else {
postAlert("bg-secondary-300", data.data);
formAlert.classList.remove("hidden", "text-primary-500");
formAlert.classList.add("text-secondary-500");
formAlert.textContent = data.data
buttonLoading(updateButton, false, "Proceed to update")
}
} catch (error) {
postAlert("bg-secondary-300", error);
formAlert.classList.remove("hidden", "text-primary-500");
formAlert.classList.add("text-secondary-500");
formAlert.textContent = data.data
buttonLoading(updateButton, false, "Proceed to update")
}
}

function isValidName(s) {
const length = s.length;
if (length === 0 || length >= 64) return false;
Expand Down
1 change: 1 addition & 0 deletions config.ml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ let mollymawk =
package "duration";
package ~min:"0.2.0" "ohex";
package "http-mirage-client";
package "solo5-elftool" ~min:"0.4.0";
]
in
main ~packages "Unikernel.Main"
Expand Down
Loading