Implement dump_info sys_call
parent
4f74887990
commit
00003c2a96
|
@ -31,6 +31,7 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
|
|||
@exchange "amq.topic"
|
||||
@known_kinds ~w(
|
||||
Device
|
||||
DiagnosticDump
|
||||
FarmEvent
|
||||
FarmwareEnv
|
||||
FarmwareInstallation
|
||||
|
@ -122,7 +123,7 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
|
|||
handle_asset(asset_kind, label, id, params, state)
|
||||
|
||||
_ ->
|
||||
Logger.info("ignoring router: #{key}")
|
||||
Logger.info("ignoring route: #{key}")
|
||||
json = JSON.encode!(%{args: %{label: label}, kind: "rpc_ok"})
|
||||
:ok = Basic.publish(state.chan, @exchange, "bot.#{device}.from_device", json)
|
||||
{:noreply, state}
|
||||
|
|
|
@ -37,7 +37,7 @@ defmodule FarmbotExt.API.DirtyWorker do
|
|||
def handle_info(:timeout, %{module: module} = state) do
|
||||
dirty = Private.list_dirty(module)
|
||||
local = Private.list_local(module)
|
||||
{:noreply, state, {:continue, dirty ++ local}}
|
||||
{:noreply, state, {:continue, Enum.uniq(dirty ++ local)}}
|
||||
end
|
||||
|
||||
@impl GenServer
|
||||
|
@ -46,13 +46,23 @@ defmodule FarmbotExt.API.DirtyWorker do
|
|||
end
|
||||
|
||||
def handle_continue([dirty | rest], %{module: module} = state) do
|
||||
Logger.info("[#{module} #{dirty.local_id} #{inspect(self())}] Handling dirty data")
|
||||
|
||||
case http_request(dirty, state) do
|
||||
# Valid data
|
||||
{:ok, %{status: s, body: body}} when s > 199 and s < 300 ->
|
||||
Logger.debug(
|
||||
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} ok"
|
||||
)
|
||||
|
||||
dirty |> module.changeset(body) |> handle_changeset(rest, state)
|
||||
|
||||
# Invalid data
|
||||
{:ok, %{status: s, body: %{} = body}} when s > 399 and s < 500 ->
|
||||
Logger.debug(
|
||||
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} error+body"
|
||||
)
|
||||
|
||||
changeset = module.changeset(dirty)
|
||||
|
||||
Enum.reduce(body, changeset, fn {key, val}, changeset ->
|
||||
|
@ -62,13 +72,22 @@ defmodule FarmbotExt.API.DirtyWorker do
|
|||
|
||||
# Invalid data, but the API didn't say why
|
||||
{:ok, %{status: s, body: _body}} when s > 399 and s < 500 ->
|
||||
Logger.debug(
|
||||
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} error"
|
||||
)
|
||||
|
||||
module.changeset(dirty)
|
||||
|> Map.put(:valid?, false)
|
||||
|> handle_changeset(rest, state)
|
||||
|
||||
# HTTP Error. (500, network error, timeout etc.)
|
||||
error ->
|
||||
Logger.error("HTTP Error: #{state.module} #{inspect(error)}")
|
||||
Logger.error(
|
||||
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP Error: #{state.module} #{
|
||||
inspect(error)
|
||||
}"
|
||||
)
|
||||
|
||||
{:noreply, state, @timeout}
|
||||
end
|
||||
end
|
||||
|
@ -87,25 +106,26 @@ defmodule FarmbotExt.API.DirtyWorker do
|
|||
# TODO(Connor) - Update the dirty field here, upload to rollbar?
|
||||
def handle_changeset(%{valid?: false, data: data} = changeset, rest, state) do
|
||||
message =
|
||||
Enum.map(changeset.errors, fn {key, val} ->
|
||||
"#{key}: #{val}"
|
||||
Enum.map(changeset.errors, fn
|
||||
{key, {msg, _meta}} when is_binary(key) -> "\t#{key}: #{msg}"
|
||||
{key, msg} when is_binary(key) -> "\t#{key}: #{msg}"
|
||||
end)
|
||||
|> Enum.join("\n")
|
||||
|
||||
Logger.error("Failed to sync: #{state.module} #{message}", changeset: changeset)
|
||||
Logger.error("Failed to sync: #{state.module} \n #{message}")
|
||||
_ = Repo.delete!(data)
|
||||
{:noreply, state, {:continue, rest}}
|
||||
end
|
||||
|
||||
defp http_request(%{id: nil} = dirty, state) do
|
||||
Logger.info("#{state.module} clean request (post)")
|
||||
Logger.debug("#{state.module} clean request (post)")
|
||||
path = state.module.path()
|
||||
data = render(state.module, dirty)
|
||||
API.post(API.client(), path, data)
|
||||
end
|
||||
|
||||
defp http_request(dirty, state) do
|
||||
Logger.info("#{state.module} dirty request (patch)")
|
||||
Logger.debug("#{state.module} dirty request (patch)")
|
||||
path = state.module.path()
|
||||
data = render(state.module, dirty)
|
||||
API.patch(API.client(), path, data)
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
defmodule FarmbotOS.SysCalls.DumpInfo do
|
||||
@moduledoc false
|
||||
require FarmbotCore.Logger
|
||||
alias FarmbotCore.{Asset, Asset.Private, Config, Project}
|
||||
|
||||
def dump_info do
|
||||
FarmbotCore.Logger.busy(1, "Recording diagnostic dump.")
|
||||
ifname = get_network_config()
|
||||
dmesg = dmesg()
|
||||
fbos_commit = Project.commit()
|
||||
fbos_version = Project.version()
|
||||
fw_version = fw_version()
|
||||
fw_commit = Project.arduino_commit()
|
||||
fw_hardware = extract_fw_hardware(fw_version)
|
||||
fw_data = fw_state(fw_version, fw_hardware)
|
||||
|
||||
params = %{
|
||||
network_interface: ifname,
|
||||
firmware_hardware: fw_hardware,
|
||||
firmware_commit: fw_commit,
|
||||
fbos_commit: fbos_commit,
|
||||
fbos_version: fbos_version,
|
||||
fbos_dmesg_dump: dmesg,
|
||||
firmware_state: FarmbotCore.JSON.encode!(fw_data)
|
||||
}
|
||||
|
||||
case Asset.new_diagnostic_dump(params) do
|
||||
{:ok, diag} ->
|
||||
_ = Private.mark_dirty!(diag, %{})
|
||||
FarmbotCore.Logger.success(1, "Diagnostic dump recorded.")
|
||||
:ok
|
||||
|
||||
{:error, changeset} ->
|
||||
{:error, "error creating diagnostic dump: #{inspect(changeset)}"}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_network_config do
|
||||
case Config.get_all_network_configs() do
|
||||
[%{name: ifname} | _] -> ifname
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp dmesg do
|
||||
{dmesg, _status} = System.cmd("dmesg", [])
|
||||
dmesg
|
||||
end
|
||||
|
||||
defp fw_version do
|
||||
case FarmbotFirmware.request({:software_version_read, []}) do
|
||||
{:ok, {_, {:report_software_version, [version]}}} -> version
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp extract_fw_hardware(nil), do: nil
|
||||
|
||||
defp extract_fw_hardware(str) do
|
||||
case String.split(str, ".") do
|
||||
[_, _, _, "G"] -> "farmduino_k14"
|
||||
[_, _, _, "F"] -> "farmduino"
|
||||
[_, _, _, "R"] -> "arduino"
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp fw_state(version, hardware) do
|
||||
pid = Process.whereis(FarmbotFirmware)
|
||||
|
||||
if state = pid && :sys.get_state(pid) do
|
||||
%{
|
||||
firmware_hardware: hardware,
|
||||
firmware_version: version,
|
||||
busy: state.status == :busy,
|
||||
serial_port: state.transport_args[:device],
|
||||
locked: state.status == :emergency_lock,
|
||||
current_command: inspect(state.command_queue)
|
||||
}
|
||||
else
|
||||
%{error: "Firmware process is not running. Could not collect info."}
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue