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

Add MotherboardUpdateRequest #357

Merged
merged 12 commits into from
Dec 23, 2017
101 changes: 101 additions & 0 deletions lib/entity/henforcer/entity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ defmodule Helix.Entity.Henforcer.Entity do

import Helix.Henforcer

alias Helix.Network.Model.Network
alias Helix.Network.Query.Network, as: NetworkQuery
alias Helix.Server.Model.Component
alias Helix.Server.Model.Server
alias Helix.Server.Henforcer.Component, as: ComponentHenforcer
alias Helix.Server.Henforcer.Server, as: ServerHenforcer
alias Helix.Server.Query.Component, as: ComponentQuery
alias Helix.Entity.Model.Entity
alias Helix.Entity.Query.Entity, as: EntityQuery

Expand Down Expand Up @@ -63,4 +68,100 @@ defmodule Helix.Entity.Henforcer.Entity do
end
|> wrap_relay(%{entity: entity, server: server})
end

@type owns_component_relay ::
%{entity: Entity.t, component: Component.t, owned_components: [Component.t]}
@type owns_component_relay_partial :: owns_component_relay
@type owns_component_error ::
{false, {:component, :not_belongs}, owns_component_relay_partial}
| ComponentHenforcer.component_exists_error
| entity_exists_error

@spec owns_component?(Entity.idt, Component.idt, [Component.t] | nil) ::
{true, owns_component_relay}
| owns_component_error
@doc """
Henforces the Entity is the owner of the given component. The third parameter,
`owned`, allows users of this function to pass a previously fetched list of
components owned by the entity (cache).
"""
def owns_component?(entity_id = %Entity.ID{}, component, owned) do
henforce entity_exists?(entity_id) do
owns_component?(relay.entity, component, owned)
end
end

def owns_component?(entity, component_id = %Component.ID{}, owned) do
henforce(ComponentHenforcer.component_exists?(component_id)) do
owns_component?(entity, relay.component, owned)
end
end

def owns_component?(entity = %Entity{}, component = %Component{}, nil) do
owned_components =
entity
|> EntityQuery.get_components()
|> Enum.map(&(ComponentQuery.fetch(&1.component_id)))

owns_component?(entity, component, owned_components)
end

def owns_component?(entity = %Entity{}, component = %Component{}, owned) do
if component in owned do
reply_ok()
else
reply_error({:component, :not_belongs})
end
|> wrap_relay(
%{entity: entity, component: component, owned_components: owned}
)
end

@type owns_nip_relay ::
%{
network_connection: Network.Connection.t,
entity: Entity.t,
entity_network_connections: [Network.Connection.t]
}
@type owns_nip_relay_partial ::
%{
entity: Entity.t,
entity_network_connections: [Network.Connection.t]
}
@type owns_nip_error ::
{false, {:network_connection, :not_belongs}, owns_nip_relay_partial}
| entity_exists_error

@typep owned_ncs :: [Network.Connection.t] | nil

@spec owns_nip?(Entity.idt, Network.id, Network.ip, owned_ncs) ::
{true, owns_nip_relay}
| owns_nip_error
@doc """
Henforces the Entity is the owner of the given NIP (NetworkConnection). The
third parameter, `owned`, allows users of this function to pass a previously
fetched list of NCs owned by the entity (cache).
"""
def owns_nip?(entity_id = %Entity.ID{}, network_id, ip, owned) do
henforce entity_exists?(entity_id) do
owns_nip?(relay.entity, network_id, ip, owned)
end
end

def owns_nip?(entity = %Entity{}, network_id, ip, nil) do
owned_nips = NetworkQuery.Connection.get_by_entity(entity.entity_id)

owns_nip?(entity, network_id, ip, owned_nips)
end

def owns_nip?(entity = %Entity{}, network_id, ip, owned) do
nc = Enum.find(owned, &(&1.network_id == network_id and &1.ip == ip))

if nc do
reply_ok(%{network_connection: nc})
else
reply_error({:network_connection, :not_belongs})
end
|> wrap_relay(%{entity_network_connections: owned, entity: entity})
end
end
2 changes: 2 additions & 0 deletions lib/event/dispatcher.ex
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ defmodule Helix.Event.Dispatcher do
##############################################################################

# All
event ServerEvent.Motherboard.Updated
event ServerEvent.Motherboard.UpdateFailed
event ServerEvent.Server.Password.Acquired
event ServerEvent.Server.Joined

Expand Down
2 changes: 1 addition & 1 deletion lib/henforcer/henforcer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ defmodule Helix.Henforcer do
@spec is_b?(x) ::
{true, is_b_relay}
| is_b_error
| can_d_error
def is_b?(x)

def is_c?(y)
Expand Down Expand Up @@ -310,6 +309,7 @@ defmodule Helix.Henforcer do
case unquote(henforcer) do
{true, sub_relay} ->
{true, relay(unquote(relay), sub_relay)}

{false, reason, sub_relay} ->
{false, reason, relay(unquote(relay), sub_relay)}
end
Expand Down
2 changes: 1 addition & 1 deletion lib/network/action/network/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ defmodule Helix.Network.Action.Network.Connection do
end
end

@spec update_nic(Network.Connection.t, Component.nic) ::
@spec update_nic(Network.Connection.t, Component.nic | nil) ::
{:ok, Network.Connection.t}
| {:error, :internal}
@doc """
Expand Down
4 changes: 2 additions & 2 deletions lib/network/internal/network/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ defmodule Helix.Network.Internal.Network.Connection do
|> Repo.insert()
end

@spec update_nic(Network.Connection.t, Component.nic) ::
@spec update_nic(Network.Connection.t, Component.nic | nil) ::
repo_result
@doc """
Updates the NIC assigned to the NetworkConnection
"""
def update_nic(nc = %Network.Connection{}, new_nic = %Component{}) do
def update_nic(nc = %Network.Connection{}, new_nic) do
nc
|> Network.Connection.update_nic(new_nic)
|> Repo.update()
Expand Down
9 changes: 9 additions & 0 deletions lib/network/model/network/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ defmodule Helix.Network.Model.Network.Connection do
|> validate_required(@required_fields)
end

@spec update_nic(t, nil) ::
changeset
def update_nic(nc = %__MODULE__{}, nil) do
nc
|> change
|> put_change(:nic_id, nil)
|> validate_required(@required_fields)
end

@spec update_ip(t, ip) ::
changeset
def update_ip(nc = %__MODULE__{}, new_ip) do
Expand Down
4 changes: 2 additions & 2 deletions lib/process/public/view/process.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defmodule Helix.Process.Public.View.Process do
:full
| :partial

@typep process(access_type) ::
@typep process(access) ::
%{
process_id: String.t,
target_ip: String.t,
Expand All @@ -28,7 +28,7 @@ defmodule Helix.Process.Public.View.Process do
file: file,
state: String.t,
type: String.t,
access: access_type
access: access
}

@typep full_access ::
Expand Down
3 changes: 2 additions & 1 deletion lib/process/resources.ex
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ defmodule Helix.Process.Resources do
they are identical to the resource's initial value.
"""
def reject_empty(resources) do
Enum.reject(resources, fn {res, val} ->
resources
|> Enum.reject(fn {res, val} ->
val == call_resource(res, :initial, [])
end)
|> Map.new()
Expand Down
2 changes: 1 addition & 1 deletion lib/server/action/flow/motherboard.ex
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ defmodule Helix.Server.Action.Flow.Motherboard do
[Motherboard.slot]
defp map_components_slots(components) do
Enum.map(components, fn component ->
{component, Utils.concat_atom(component.type, :_0)}
{component, Utils.concat_atom(component.type, :_1)}
end)
end

Expand Down
101 changes: 101 additions & 0 deletions lib/server/action/flow/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@ defmodule Helix.Server.Action.Flow.Server do
alias Helix.Event
alias Helix.Entity.Action.Entity, as: EntityAction
alias Helix.Entity.Model.Entity
alias Helix.Network.Model.Network
alias Helix.Server.Action.Motherboard, as: MotherboardAction
alias Helix.Server.Action.Server, as: ServerAction
alias Helix.Server.Model.Component
alias Helix.Server.Model.Motherboard
alias Helix.Server.Model.Server

alias Helix.Server.Event.Motherboard.Updated, as: MotherboardUpdatedEvent
alias Helix.Server.Event.Motherboard.UpdateFailed,
as: MotherboardUpdateFailedEvent

@type update_mobo_result :: {:ok, Server.t, Motherboard.t}
@type detach_mobo_result :: {:ok, Server.t}

@spec setup(Server.type, Entity.t, Component.mobo, Event.relay) ::
{:ok, Server.t}
@doc """
Expand Down Expand Up @@ -43,4 +53,95 @@ defmodule Helix.Server.Action.Flow.Server do
"""
def set_hostname(server, hostname, _relay),
do: ServerAction.set_hostname(server, hostname)

@spec update_mobo(
Server.t,
Motherboard.t,
MotherboardAction.motherboard_data,
entity_ncs :: [Network.Connection.t],
relay :: Event.relay)
::
update_mobo_result
@doc """
Updates the server motherboard.

`new_mobo_data` holds all information about how the new motherboard should
look like.

Emits `MotherboardUpdatedEvent` in case of success, and
`MotherboardUpdateFailedEvent` otherwise.
"""
def update_mobo(
server = %Server{},
motherboard,
new_mobo_data,
entity_ncs,
relay)
do
new_mobo_id = new_mobo_data.mobo.component_id

flowing do
with \
{:ok, new_motherboard, events} <-
MotherboardAction.update(motherboard, new_mobo_data, entity_ncs),
on_success(fn -> Event.emit(events, from: relay) end),

{:ok, new_server} <- update_server_mobo(server, new_mobo_id)
do
emit_motherboard_updated(new_server, relay)

{:ok, new_server, new_motherboard}
else
_ ->
emit_motherboard_update_failed(server, :internal, relay)
end
end
end

@spec detach_mobo(Server.t, Motherboard.t, Event.relay) ::
detach_mobo_result
@doc """
Detaches the server motherboard.

Emits `MotherboardUpdatedEvent` in case of success, and
`MotherboardUpdateFailedEvent` otherwise.
"""
def detach_mobo(server = %Server{}, motherboard = %Motherboard{}, relay) do
flowing do
with \
:ok <- MotherboardAction.detach(motherboard),
{:ok, new_server} <- ServerAction.detach(server)
do
emit_motherboard_updated(new_server, relay)

{:ok, new_server}
else
_ ->
emit_motherboard_update_failed(server, :internal, relay)
end
end
end

@spec update_server_mobo(Server.t, Component.id) ::
{:ok, Server.t}
defp update_server_mobo(server = %Server{motherboard_id: mobo_id}, mobo_id),
do: {:ok, server}
defp update_server_mobo(server, mobo_id),
do: ServerAction.attach(server, mobo_id)

@spec emit_motherboard_updated(Server.t, Event.relay) ::
term
defp emit_motherboard_updated(server, relay) do
server
|> MotherboardUpdatedEvent.new()
|> Event.emit(from: relay)
end

@spec emit_motherboard_update_failed(Server.t, term, Event.relay) ::
term
defp emit_motherboard_update_failed(server, reason, relay) do
server
|> MotherboardUpdateFailedEvent.new(reason)
|> Event.emit(from: relay)
end
end
10 changes: 10 additions & 0 deletions lib/server/action/motherboard.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ defmodule Helix.Server.Action.Motherboard do

alias Helix.Server.Internal.Motherboard, as: MotherboardInternal

@type motherboard_data :: __MODULE__.Update.motherboard_data
@type update_component :: __MODULE__.Update.update_component
@type update_nc :: __MODULE__.Update.update_nc

defdelegate setup(mobo, initial_components),
to: MotherboardInternal

Expand All @@ -12,4 +16,10 @@ defmodule Helix.Server.Action.Motherboard do

defdelegate unlink(component),
to: MotherboardInternal

defdelegate update(cur_mobo_data, new_mobo_data, entity_ncs),
to: __MODULE__.Update

defdelegate detach(motherboard),
to: __MODULE__.Update
end
Loading