Skip to content
This repository has been archived by the owner on Jun 11, 2023. It is now read-only.

Commit

Permalink
MotherboardUpdateRequest (check_params)
Browse files Browse the repository at this point in the history
  • Loading branch information
renatomassaro committed Dec 12, 2017
1 parent bf75c87 commit 43e5c58
Show file tree
Hide file tree
Showing 3 changed files with 318 additions and 0 deletions.
18 changes: 18 additions & 0 deletions lib/server/websocket/channel/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ channel Helix.Server.Websocket.Channel.Server do
alias Helix.Server.Websocket.Requests.Bootstrap, as: BootstrapRequest
alias Helix.Server.Websocket.Requests.Config.Check, as: ConfigCheckRequest
alias Helix.Server.Websocket.Requests.Config.Set, as: ConfigSetRequest
alias Helix.Server.Websocket.Requests.MotherboardUpdate,
as: MotherboardUpdateRequest
alias Helix.Server.Websocket.Requests.SetHostname, as: SetHostnameRequest

@doc """
Expand Down Expand Up @@ -124,6 +126,22 @@ channel Helix.Server.Websocket.Channel.Server do
"""
topic "config.check", ConfigCheckRequest

@doc """
{} => mobo.detach
\/ update
{
"motherboard_id" : "motherboard_id"
, "slots" :
{ "slot_id_a" : "component_id" , "slot_id_b" : null}
, "network_connections" :
{ "component_id" :
{ "ip" : "ip" , "network_id" : "network_id"}
}
}
"""
topic "motherboard.update", MotherboardUpdateRequest

@doc """
Updates the server hostname.
Expand Down
147 changes: 147 additions & 0 deletions lib/server/websocket/requests/motherboard_update.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import Helix.Websocket.Request

request Helix.Server.Websocket.Requests.MotherboardUpdate do

alias HELL.IPv4
alias HELL.Utils
alias Helix.Network.Model.Network
alias Helix.Server.Model.Component
alias Helix.Server.Public.Server, as: ServerPublic

def check_params(request, socket) do
if Enum.empty?(request.unsafe) do
check_detach(request, socket)
else
check_update(request, socket)
end
end

def check_detach(request, socket) do
with \
true <- socket.assigns.meta.access_type == :local || :bad_src
do
update_params(request, %{cmd: :detach}, reply: true)
else
:bad_src ->
reply_error(request, "bad_src")

_ ->
bad_request(request)
end
end

def check_update(request, socket) do
with \
true <- socket.assigns.meta.access_type == :local || :bad_src,
{:ok, mobo_id} <- Component.ID.cast(request.unsafe["motherboard_id"]),
{:ok, slots} <- cast_slots(request.unsafe["slots"]),
{:ok, ncs} <- cast_ncs(request.unsafe["network_connections"])
do
params = %{
slots: slots,
network_connections: ncs,
mobo_id: mobo_id,
cmd: :update
}

update_params(request, params, reply: true)
else
:bad_src ->
reply_error(request, "bad_src")

:bad_slots ->
reply_error(request, "bad_slot_data")

:bad_ncs ->
reply_error(request, "bad_network_connections")

_ ->
bad_request(request)
end
end

def check_permissions(request, socket) do
end

def handle_request(request, socket) do
end

render_empty()

defp cast_ncs(nil),
do: :bad_ncs
defp cast_ncs(network_connections) do
try do
ncs =
Enum.map(network_connections, fn {nic_id, nc} ->
{:ok, nic_id} = Component.ID.cast(nic_id)
{:ok, ip} = IPv4.cast(nc["ip"])
{:ok, network_id} = Network.ID.cast(nc["network_id"])

{nic_id, {ip, network_id}}
end)

{:ok, ncs}
rescue
_ ->
:bad_ncs
end
end

# TODO: Move to a SpecableHelper or something like that
defp cast_slots(nil),
do: :bad_slots
defp cast_slots(slots) do
try do
slots =
slots
|> Enum.map(fn {slot_id, component_id} ->
component_id =
if component_id do
Component.ID.cast!(component_id)
else
nil
end

{:ok, slot_id} = cast_slot_id(slot_id)

{slot_id, component_id}
end)
|> Enum.into(%{})

{:ok, slots}
rescue
_ ->
:bad_slots
end
end

defp cast_slot_id("cpu_" <> id),
do: concat_slot(:cpu, id)
defp cast_slot_id("ram_" <> id),
do: concat_slot(:ram, id)
defp cast_slot_id("hdd_" <> id),
do: concat_slot(:hdd, id)
defp cast_slot_id("nic_" <> id),
do: concat_slot(:nic, id)
defp cast_slot_id("usb_" <> id),
do: concat_slot(:usb, id)
defp cast_slot_id(_),
do: :error

defp concat_slot(component, id) do
case Integer.parse(id) do
{_, ""} ->
slot_id =
component
|> Utils.concat_atom("_")
|> Utils.concat_atom(id)

{:ok, slot_id}

_ ->
:error
end
end

end
153 changes: 153 additions & 0 deletions test/server/websocket/requests/motherboard_update_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
defmodule Helix.Server.Websocket.Requests.MotherboardUpdateTest do

use Helix.Test.Case.Integration

alias Helix.Websocket.Requestable
alias Helix.Network.Model.Network
alias Helix.Server.Model.Component
alias Helix.Server.Websocket.Requests.MotherboardUpdate,
as: MotherboardUpdateRequest

alias Helix.Test.Channel.Setup, as: ChannelSetup

@mock_socket ChannelSetup.mock_server_socket(access_type: :local)

describe "MotherboardUpdateRequest.check_params" do
test "casts the params to internal Helix format" do
params =
%{
"motherboard_id" => "::1",
"slots" => %{
"cpu_1" => "::f",
"ram_1" => nil,
},
"network_connections" => %{
"::5" => %{
"network_id" => "::",
"ip" => "1.2.3.4"
}
}
}

req = MotherboardUpdateRequest.new(params)
assert {:ok, req} = Requestable.check_params(req, @mock_socket)

assert req.params.cmd == :update
assert req.params.mobo_id == Component.ID.cast!(params["motherboard_id"])
assert req.params.slots.cpu_1 == Component.ID.cast!("::f")
refute req.params.slots.ram_1

[{nic_id, nip}] = req.params.network_connections

assert nic_id == Component.ID.cast!("::5")
assert nip == {"1.2.3.4", Network.ID.cast!("::")}
end

test "handles invalid slot data" do
base_params = %{"motherboard_id" => "::"}

# Invalid component type `notexists`
p1 =
%{
"slots" => %{"notexists_50" => "::"}
} |> Map.merge(base_params)

# Invalid slot `abc`
p2 =
%{
"slots" => %{"cpu_abc" => nil}
} |> Map.merge(base_params)

# Invalid component ID `wtf`
p3 =
%{
"slots" => %{"cpu_1" => "wtf"}
} |> Map.merge(base_params)

# Empty slots
p4 = base_params

req1 = MotherboardUpdateRequest.new(p1)
req2 = MotherboardUpdateRequest.new(p2)
req3 = MotherboardUpdateRequest.new(p3)
req4 = MotherboardUpdateRequest.new(p4)

assert {:error, %{message: reason1}, _} =
Requestable.check_params(req1, @mock_socket)
assert {:error, %{message: reason2}, _} =
Requestable.check_params(req2, @mock_socket)
assert {:error, %{message: reason3}, _} =
Requestable.check_params(req3, @mock_socket)
assert {:error, %{message: reason4}, _} =
Requestable.check_params(req4, @mock_socket)

assert reason1 == "bad_slot_data"
assert reason2 == reason1
assert reason3 == reason2
assert reason4 == reason3
end

test "handles invalid network connections" do
base_params =
%{
"motherboard_id" => "::f",
"slots" => %{"cpu_1" => "::1"},
}

# Empty NCs
p1 = base_params

# Invalid NIC ID
p2 =
%{
"network_connections" => %{
"invalid_component" => %{
"ip" => "1.2.3.4",
"network_id" => "::"
}
}
} |> Map.merge(base_params)

# Invalid IP
p3 =
%{
"network_connections" => %{
"::f" => %{
"ip" => "abc",
"network_id" => "::"
}
}
} |> Map.merge(base_params)

# Invalid network ID
p4 =
%{
"network_connections" => %{
"::f" => %{
"ip" => "127.0.0.1",
"network_id" => "invalid"
}
}
} |> Map.merge(base_params)

req1 = MotherboardUpdateRequest.new(p1)
req2 = MotherboardUpdateRequest.new(p2)
req3 = MotherboardUpdateRequest.new(p3)
req4 = MotherboardUpdateRequest.new(p4)

assert {:error, %{message: reason1}, _} =
Requestable.check_params(req1, @mock_socket)
assert {:error, %{message: reason2}, _} =
Requestable.check_params(req2, @mock_socket)
assert {:error, %{message: reason3}, _} =
Requestable.check_params(req3, @mock_socket)
assert {:error, %{message: reason4}, _} =
Requestable.check_params(req4, @mock_socket)

assert reason1 == "bad_network_connections"
assert reason2 == reason1
assert reason3 == reason2
assert reason4 == reason3
end
end
end

0 comments on commit 43e5c58

Please sign in to comment.