Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
23 changes: 16 additions & 7 deletions lib/hyper/node/fire_vmm/vm_linux/provider.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,32 @@ defmodule Hyper.Node.FireVMM.VmLinux.Provider do
end

@doc """
Install state of `builds` under `dir`: `:ok` if every asset file is present;
`{:error, :not_installed}` if none are; `{:error, :bad_install}` if only some
are (a partial/corrupt install - `Redist.File` keeps existing files, so
the remedy is to wipe and reinstall).
Install state of `builds` under `dir`: `:ok` if every asset file is present
with the manifest's SHA-256; `{:error, :not_installed}` if none are;
`{:error, :bad_install}` if only some are (a partial/corrupt install -
`Redist.File` keeps existing files, so the remedy is to wipe and reinstall).

Presence alone is not enough: after a manifest bump the old release's kernels
sit at the same asset paths, and skipping the hash check would keep booting
guests on the previous release forever.
"""
@spec install_state(Path.t(), [Manifest.Build.t()]) ::
:ok | {:error, :not_installed | :bad_install}
def install_state(dir, builds) do
present = Enum.count(builds, &File.regular?(build_path(dir, &1)))
installed = Enum.count(builds, &installed?(dir, &1))

cond do
present == length(builds) -> :ok
present == 0 -> {:error, :not_installed}
installed == length(builds) -> :ok
installed == 0 -> {:error, :not_installed}
true -> {:error, :bad_install}
end
end

defp installed?(dir, build) do
path = build_path(dir, build)
File.regular?(path) and Redist.Sha256.file(path) == build.sha256
end

defp install_all(builds) do
Enum.reduce_while(builds, :ok, fn build, :ok ->
case Redist.File.install(
Expand Down
12 changes: 6 additions & 6 deletions priv/vmlinux/manifest.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
{
"sha" : "54d6c3f843c01fb55107a024cca5bf60af235c42",
"sha" : "bab2b3a92382df318e60b6b52376d2a9f5b5456c",
"builds" : [ {
"name" : "x86_64-5.10",
"arch" : "x86_64",
"version" : "5.10.259",
"asset" : "vmlinux-x86_64-5.10",
"sha256" : "96b8f6a665536e560777f9634773b0ff01a41c24dda2e4ecd0f395b18f5cfa62"
"sha256" : "50b1a0b00d10b4e02ddcbe9e9860328968d400e86cbda4c0ed2bd2919947e315"
}, {
"name" : "x86_64-6.1",
"arch" : "x86_64",
"version" : "6.1.176",
"asset" : "vmlinux-x86_64-6.1",
"sha256" : "3a9a115ce4c07951dd83f9ba048607a890e59118d21d23f5f3135e41ef2ff05f"
"sha256" : "fd24f0ce7c5d6f23d86c9cf7c63a140b46bcf5e7756a9d522756a80ea89ce5e4"
}, {
"name" : "aarch64-5.10",
"arch" : "aarch64",
"version" : "5.10.259",
"asset" : "vmlinux-aarch64-5.10",
"sha256" : "853306d4d1c9110208c5df21c8602bc40d68556ce7fd3519e2f08e296460606a"
"sha256" : "de5009cb24e6204a6dedc3baf1790c8f3016bd724d4745e36e12f2ea45ce5bd2"
}, {
"name" : "aarch64-6.1",
"arch" : "aarch64",
"version" : "6.1.176",
"asset" : "vmlinux-aarch64-6.1",
"sha256" : "d7ecc631a3b59e0d66c8960b35a3374f402e45fb46179507c5aa48b4629e3017"
"sha256" : "f324c34ee5536690e39e65991393d5813ad34b4a991cfb85ca65440fba9ec6fa"
}, {
"name" : "x86_64-5.10-no-acpi",
"arch" : "x86_64",
"version" : "5.10.259",
"asset" : "vmlinux-x86_64-5.10-no-acpi",
"sha256" : "1b8bea12ee405322cad329f0a3ff20e36bb801bc11baabde9832b69f29072709"
"sha256" : "8c1cea3bd8b54f05a1fa13dbbc3c46b17b1df28875720a5b59a06971daaf32f7"
} ]
}
2 changes: 1 addition & 1 deletion test/hyper/node/fire_vmm/vm_linux/manifest_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ defmodule Hyper.Node.FireVMM.VmLinux.ManifestTest do

assert Manifest.asset_url(build) ==
"https://github.com/harmont-dev/hyper-vmlinux/releases/download/" <>
"release-54d6c3f843c01fb55107a024cca5bf60af235c42/vmlinux-x86_64-6.1"
"release-bab2b3a92382df318e60b6b52376d2a9f5b5456c/vmlinux-x86_64-6.1"
end
end
42 changes: 38 additions & 4 deletions test/hyper/node/fire_vmm/vm_linux/provider_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ defmodule Hyper.Node.FireVMM.VmLinux.ProviderTest do
assert Provider.install_state(dir, builds) == {:error, :not_installed}
end

test "install_state/2 is :ok when every asset file is present", %{dir: dir, builds: builds} do
for b <- builds, do: File.write!(Path.join(dir, b.asset), "kernel")
test "install_state/2 is :ok when every asset file is present with its manifest hash", %{
dir: dir,
builds: builds
} do
builds = Enum.map(builds, &write_asset(dir, &1))
assert Provider.install_state(dir, builds) == :ok
end

Expand All @@ -28,8 +31,30 @@ defmodule Hyper.Node.FireVMM.VmLinux.ProviderTest do
builds: builds
} do
assert length(builds) > 1
[first | _] = builds
File.write!(Path.join(dir, first.asset), "kernel")
[first | rest] = builds

assert Provider.install_state(dir, [write_asset(dir, first) | rest]) ==
{:error, :bad_install}
end

test "install_state/2 is :not_installed when every present file has a stale hash", %{
dir: dir,
builds: builds
} do
# A manifest bump leaves the previous release's kernels at the same asset
# paths; they must not count as installed or nodes would boot old kernels.
for b <- builds, do: File.write!(Path.join(dir, b.asset), "stale #{b.asset}")
assert Provider.install_state(dir, builds) == {:error, :not_installed}
end

test "install_state/2 is :bad_install when some present files have a stale hash", %{
dir: dir,
builds: builds
} do
assert length(builds) > 1
[first | rest] = builds
builds = [write_asset(dir, first) | rest]
for b <- rest, do: File.write!(Path.join(dir, b.asset), "stale #{b.asset}")
assert Provider.install_state(dir, builds) == {:error, :bad_install}
end

Expand All @@ -46,4 +71,13 @@ defmodule Hyper.Node.FireVMM.VmLinux.ProviderTest do
test "path/1 rejects an unknown build name" do
assert Provider.path("nope") == {:error, {:unknown_build, "nope"}}
end

# Writes fabricated content for `build` under `dir` and returns the build
# with its sha256 matching that content, so install_state/2 sees it as a
# faithful install.
defp write_asset(dir, build) do
content = "kernel #{build.asset}"
File.write!(Path.join(dir, build.asset), content)
%{build | sha256: Base.encode16(:crypto.hash(:sha256, content), case: :lower)}
end
end
Loading