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

Commit

Permalink
Support 1-step switch of motherboards
Browse files Browse the repository at this point in the history
  • Loading branch information
renatomassaro committed Dec 23, 2017
1 parent 4012e82 commit 18d6f89
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 56 deletions.
20 changes: 13 additions & 7 deletions lib/server/internal/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,21 @@ defmodule Helix.Server.Internal.Server do
def set_hostname(server, hostname) do
server
|> Server.set_hostname(hostname)
|> update()
|> Repo.update()
end

@spec attach(Server.t, Motherboard.id) ::
repo_return
@doc """
Updates the `server` motherboard to be `mobo_id`.
It doesn't matter if the server already has a motherboard attached to it; this
operation will overwrite any existing motherboard.
"""
def attach(server, mobo_id) do
result =
server
|> Server.update_changeset(%{motherboard_id: mobo_id})
|> Server.attach_motherboard(mobo_id)
|> Repo.update()

with {:ok, _} <- result do
Expand All @@ -60,6 +66,11 @@ defmodule Helix.Server.Internal.Server do

@spec detach(Server.t) ::
repo_return
@doc """
Detaches the currently attached motherboard from `server`
It doesn't matter if the server has no motherboard attached to it.
"""
def detach(server = %Server{}) do
result =
server
Expand All @@ -82,9 +93,4 @@ defmodule Helix.Server.Internal.Server do

:ok
end

@spec update(Server.changeset) ::
repo_return
defp update(changeset),
do: Repo.update(changeset)
end
65 changes: 29 additions & 36 deletions lib/server/model/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule Helix.Server.Model.Server do
use HELL.ID, field: :server_id, meta: [0x0010]

import Ecto.Changeset
import HELL.Ecto.Macros

alias Ecto.Changeset
alias HELL.Constant
Expand Down Expand Up @@ -54,7 +55,7 @@ defmodule Helix.Server.Model.Server do
end

@spec create_changeset(creation_params) ::
Changeset.t
changeset
def create_changeset(params) do
%__MODULE__{}
|> cast(params, @creation_fields)
Expand All @@ -64,16 +65,6 @@ defmodule Helix.Server.Model.Server do
|> validate_inclusion(:type, Server.Type.possible_types())
end

@spec update_changeset(t | Changeset.t, update_params) ::
Changeset.t
def update_changeset(struct, params) do
struct
|> cast(params, [])
|> unique_constraint(:motherboard_id)
|> attach_motherboard(params)
|> validate_required(@required_fields)
end

@spec set_hostname(t, hostname) ::
changeset
def set_hostname(server, hostname) do
Expand All @@ -82,38 +73,40 @@ defmodule Helix.Server.Model.Server do
|> put_change(:hostname, hostname)
end

@spec detach_motherboard(t | Changeset.t) ::
Changeset.t
def detach_motherboard(struct),
do: update_changeset(struct, %{motherboard_id: nil})

@spec attach_motherboard(t | Changeset.t, map) ::
Changeset.t
defp attach_motherboard(changeset, params) do
previous = get_field(changeset, :motherboard_id)
changeset = cast(changeset, params, [:motherboard_id])
next = get_change(changeset, :motherboard_id)

# Already has motherboard and is trying to override it
if previous && next do
add_error(changeset, :motherboard_id, "is already set")
else
changeset
end
@spec update_motherboard(t, Motherboard.id | nil) ::
changeset
defp update_motherboard(server, mobo_id) do
server
|> change()
|> unique_constraint(:motherboard_id)
|> put_change(:motherboard_id, mobo_id)
|> validate_required(@required_fields)
end

@spec generate_password(Changeset.t) ::
Changeset.t
@spec attach_motherboard(t, Motherboard.id) ::
changeset
@doc """
Assigns `new_mobo_id` to the Server model
"""
def attach_motherboard(server, new_mobo_id),
do: update_motherboard(server, new_mobo_id)

@spec detach_motherboard(t) ::
changeset
@doc """
Removes the `motherboard_id` field from the Server model.
"""
def detach_motherboard(server),
do: update_motherboard(server, nil)

@spec generate_password(changeset) ::
changeset
defp generate_password(changeset),
do: put_change(changeset, :password, Password.generate(:server))

defmodule Query do

import Ecto.Query
query do

alias Ecto.Queryable
alias Helix.Server.Model.Motherboard
alias Helix.Server.Model.Server

@spec by_id(Queryable.t, Server.idtb) ::
Queryable.t
Expand Down
1 change: 0 additions & 1 deletion lib/server/public/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ defmodule Helix.Server.Public.Server do
alias Helix.Network.Query.Network, as: NetworkQuery
alias Helix.Network.Query.Tunnel, as: TunnelQuery
alias Helix.Server.Model.Component
alias Helix.Server.Model.Motherboard
alias Helix.Server.Model.Server
alias Helix.Server.Action.Flow.Server, as: ServerFlow
alias Helix.Server.Action.Motherboard, as: MotherboardAction
Expand Down
22 changes: 11 additions & 11 deletions test/server/action/server_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,23 @@ defmodule Helix.Server.Action.ServerTest do
CacheHelper.sync_test()
end

test "fails when given motherboard is already attached" do
{server1, _} = ServerSetup.server()
{server2, _} = ServerSetup.server()
test "succeeds when server already has a motherboard" do
{server, _} = ServerSetup.server()

assert {:error, reason} =
ServerAction.attach(server1, server2.motherboard_id)
assert reason == :internal
{mobo, _} = ComponentSetup.component(type: :mobo)

assert {:ok, new_server} = ServerAction.attach(server, mobo.component_id)
assert new_server.motherboard_id == mobo.component_id

CacheHelper.sync_test()
end

test "fails when server already has a motherboard" do
{server, _} = ServerSetup.server()

{mobo, _} = ComponentSetup.component(type: :mobo)
test "fails when given motherboard is already attached" do
{server1, _} = ServerSetup.server()
{server2, _} = ServerSetup.server()

assert {:error, reason} = ServerAction.attach(server, mobo.component_id)
assert {:error, reason} =
ServerAction.attach(server1, server2.motherboard_id)
assert reason == :internal

CacheHelper.sync_test()
Expand Down
61 changes: 60 additions & 1 deletion test/server/websocket/channel/server/topics/motherboard_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ defmodule Helix.Server.Websocket.Channel.Server.Topics.MotherboardTest do
@internet_id NetworkHelper.internet_id()

describe "motherboard.update" do
test "updates the components" do
test "updates the components (same motherboard)" do
{socket, %{gateway: server, gateway_entity: entity}} =
ChannelSetup.join_server(own_server: true)

Expand Down Expand Up @@ -117,6 +117,65 @@ defmodule Helix.Server.Websocket.Channel.Server.Topics.MotherboardTest do
assert motherboard.slots.nic_2.custom.network_id == nc_custom.network_id
end

test "updates the mobo (1-step switch to a new mobo)" do
{socket, %{gateway: server, gateway_entity: entity}} =
ChannelSetup.join_server(own_server: true)

# This will be our new mobo
{new_mobo, _} = ComponentSetup.component(type: :mobo)
EntityAction.link_component(entity, new_mobo)

# Get current motherboard components
motherboard = MotherboardQuery.fetch(server.motherboard_id)
[old_cpu] = MotherboardQuery.get_cpus(motherboard)
[old_ram] = MotherboardQuery.get_rams(motherboard)
[old_hdd] = MotherboardQuery.get_hdds(motherboard)
[old_nic] = MotherboardQuery.get_nics(motherboard)

# Get current NetworkConnection assigned to `old_nic`
old_nc = NetworkQuery.Connection.fetch_by_nic(old_nic)

params =
%{
"motherboard_id" => to_string(new_mobo.component_id),
"slots" => %{
"cpu_1" => to_string(old_cpu.component_id),
"ram_1" => to_string(old_ram.component_id),
"hdd_1" => to_string(old_hdd.component_id),
"nic_1" => to_string(old_nic.component_id),
},
"network_connections" => %{
to_string(old_nic.component_id) => %{
"ip" => old_nc.ip,
"network_id" => to_string(old_nc.network_id)
},
}
}

# Request the update
ref = push socket, "motherboard.update", params
assert_reply ref, :ok, _, timeout(:slow)

# Wait for completion
wait_events [:motherboard_updated]

# Let's make sure the new motherboard is the one we've just requested
motherboard = MotherboardQuery.fetch(new_mobo.component_id)

# Components are the same as before
assert motherboard.slots.cpu_1 == old_cpu
assert motherboard.slots.ram_1 == old_ram
assert motherboard.slots.hdd_1 == old_hdd
assert motherboard.slots.nic_1 == old_nic

# Previous server mobo_id no longer exists
refute MotherboardQuery.fetch(server.motherboard_id)

# And the NetworkConnection is also the same
mobo_nc = NetworkQuery.Connection.fetch_by_nic(old_nic.component_id)
assert mobo_nc == old_nc
end

test "detaches the mobo (and unlinks the underlying components)" do
{socket, %{gateway: server}} = ChannelSetup.join_server(own_server: true)

Expand Down

0 comments on commit 18d6f89

Please sign in to comment.