Skip to content

Commit

Permalink
Stop the interface if it disappears
Browse files Browse the repository at this point in the history
  • Loading branch information
fhunleth committed May 10, 2019
1 parent f01bdd7 commit 098d569
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 15 deletions.
73 changes: 72 additions & 1 deletion lib/vintage_net/interface.ex
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,26 @@ defmodule VintageNet.Interface do
{:next_state, :retrying, new_data, actions}
end

@impl true
def handle_event(
:info,
{VintageNet, ["interface", ifname, "present"], _old_value, nil, _meta},
:reconfiguring,
%State{ifname: ifname, command_runner: pid, config: config} = data
) do
_ =
Logger.debug(
":configuring -> interface disappeared: retrying after #{config.retry_millis} ms"
)

Process.exit(pid, :kill)
{new_data, actions} = reply_to_waiters(data)
new_data = %{new_data | command_runner: nil}
actions = [{:state_timeout, config.retry_millis, :retry_timeout} | actions]
update_properties(:retrying, new_data)
{:next_state, :retrying, new_data, actions}
end

# :configured

def handle_event({:call, from}, :wait, :configured, %State{} = data) do
Expand Down Expand Up @@ -358,6 +378,27 @@ defmodule VintageNet.Interface do
end
end

@impl true
def handle_event(
:info,
{VintageNet, ["interface", ifname, "present"], _old_value, nil, _meta},
:configured,
%State{ifname: ifname, config: config} = data
) do
_ = Logger.debug(":configured -> interface disappeared")

{new_data, actions} = cancel_ioctls(data)

new_data = run_commands(new_data, config.down_cmds)

actions = [
{:state_timeout, config.down_cmd_millis, :unconfiguring_timeout} | actions
]

update_properties(:reconfiguring, new_data)
{:next_state, :reconfiguring, %{new_data | next_config: config}, actions}
end

# :reconfiguring

@impl true
Expand Down Expand Up @@ -515,6 +556,25 @@ defmodule VintageNet.Interface do
end
end

@impl true
def handle_event(
:info,
{VintageNet, ["interface", ifname, "present"], _old_value, true, _meta},
:retrying,
%State{ifname: ifname, config: new_config} = data
) do
rm(new_config.cleanup_files)
CommandRunner.create_files(new_config.files)
new_data = run_commands(data, new_config.up_cmds)

actions = [
{:state_timeout, new_config.up_cmd_millis, :configuring_timeout}
]

update_properties(:configuring, new_data)
{:next_state, :configuring, new_data, actions}
end

@impl true
def handle_event(
{:call, from},
Expand Down Expand Up @@ -578,6 +638,17 @@ defmodule VintageNet.Interface do
{:reply, from, data.config.source_config}
end

@impl true
def handle_event(
:info,
{VintageNet, ["interface", ifname, "present"], _old_value, present, _meta},
other_state,
%State{ifname: ifname} = data
) do
_ = Logger.debug("#{inspect(other_state)} -> interface #{ifname} is now #{inspect(present)}")
{:keep_state, data}
end

@impl true
def terminate(_reason, _state, %{ifname: ifname}) do
PropertyTable.clear(VintageNet, ["interface", ifname, "type"])
Expand Down Expand Up @@ -626,7 +697,7 @@ defmodule VintageNet.Interface do
config = data.config

PropertyTable.put(VintageNet, ["interface", ifname, "type"], config.type)
PropertyTable.put(VintageNet, ["interface", ifname, "state"], to_string(state))
PropertyTable.put(VintageNet, ["interface", ifname, "state"], state)
end

defp run_ioctl(data, from, mfa) do
Expand Down
49 changes: 35 additions & 14 deletions test/vintage_net/interface_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ defmodule VintageNet.InterfaceTest do
raw_config = %RawConfig{
ifname: @ifname,
type: @interface_type,
files: [{"testing", "Hello, world"}],
up_cmds: [],
down_cmds: []
files: [{"testing", "Hello, world"}]
}

start_and_configure(raw_config)
Expand Down Expand Up @@ -355,8 +353,7 @@ defmodule VintageNet.InterfaceTest do
in_tmp(context.test, fn ->
raw_config = %RawConfig{
ifname: @ifname,
type: @interface_type,
require_interface: false
type: @interface_type
}

start_and_configure(raw_config, 250)
Expand All @@ -369,8 +366,7 @@ defmodule VintageNet.InterfaceTest do
in_tmp(context.test, fn ->
raw_config = %RawConfig{
ifname: @ifname,
type: @interface_type,
require_interface: false
type: @interface_type
}

start_and_configure(raw_config, 250)
Expand All @@ -383,14 +379,12 @@ defmodule VintageNet.InterfaceTest do
in_tmp(context.test, fn ->
raw_config1 = %RawConfig{
ifname: @ifname,
type: @interface_type,
require_interface: false
type: @interface_type
}

raw_config2 = %RawConfig{
ifname: @ifname,
type: @interface_type,
require_interface: false
type: @interface_type
}

start_and_configure(raw_config1)
Expand Down Expand Up @@ -419,8 +413,7 @@ defmodule VintageNet.InterfaceTest do

raw_config2 = %RawConfig{
ifname: @ifname,
type: @interface_type,
require_interface: false
type: @interface_type
}

property = ["interface", @ifname, "state"]
Expand All @@ -429,10 +422,38 @@ defmodule VintageNet.InterfaceTest do
{:ok, _pid} = VintageNet.InterfacesSupervisor.start_interface(@ifname)
:ok = Interface.configure(raw_config1)

assert_receive {VintageNet, property, _old_value, "retrying", _meta}
assert_receive {VintageNet, property, _old_value, :retrying, _meta}

assert :ok == Interface.configure(raw_config2)
assert :ok == Interface.wait_until_configured(@ifname)
end)
end

test "interface disappearing stops interface", context do
in_tmp(context.test, fn ->
raw_config = %RawConfig{
ifname: @ifname,
type: @interface_type,
files: [{"testing", "Hello, world"}]
}

start_and_configure(raw_config)

assert File.exists?("testing")

# "remove" the interface
VintageNet.PropertyTable.clear(VintageNet, ["interface", @ifname, "present"])

Process.sleep(10)

refute File.exists?("testing")

# bring the interface back
VintageNet.PropertyTable.put(VintageNet, ["interface", @ifname, "present"], true)

Process.sleep(10)

assert File.exists?("testing")
end)
end
end

0 comments on commit 098d569

Please sign in to comment.