Compare commits
No commits in common. "8e5ba0269fa1822bb4bab33a2a8396275247a382" and "65c9c072972779927afd8024a3d97535bad6a80f" have entirely different histories.
8e5ba0269f
...
65c9c07297
10 changed files with 110 additions and 232 deletions
|
@ -1,8 +1,3 @@
|
||||||
# management 0.4.0, 2021-04-09
|
|
||||||
|
|
||||||
* Initial VM dashboard
|
|
||||||
* Various typo fixes and error catching.
|
|
||||||
|
|
||||||
# management 0.3.1, 2021-02-03
|
# management 0.3.1, 2021-02-03
|
||||||
|
|
||||||
* Allow forgery on the support request form
|
* Allow forgery on the support request form
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
defmodule RecycledCloud.OpenNebula do
|
defmodule RecycledCloud.OpenNebula do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
The OpenNebula context and XML-RPC Interface.
|
OpenNebula XML-RPC Interface.
|
||||||
|
|
||||||
See http://docs.opennebula.io/5.12/integration/system_interfaces/api.html for details.
|
See http://docs.opennebula.io/5.12/integration/system_interfaces/api.html for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alias RecycledCloud.OpenNebula.{VM, VMPool}
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
# OpenNebula daemon.
|
# OpenNebula daemon.
|
||||||
@endpoint "/RPC2"
|
@endpoint "/RPC2"
|
||||||
|
|
||||||
|
@ -15,77 +12,33 @@ defmodule RecycledCloud.OpenNebula do
|
||||||
Application.get_env(:recycledcloud, :opennebula, []) |> Keyword.get(key)
|
Application.get_env(:recycledcloud, :opennebula, []) |> Keyword.get(key)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_locations() do
|
|
||||||
get_opennebula_config(:locations)
|
|
||||||
|> Enum.map(fn m -> Map.get(m, :name) end)
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_location_config(name) do
|
|
||||||
get_opennebula_config(:locations)
|
|
||||||
|> Enum.find(fn m -> Map.get(m, :name) == name end)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Related to XML-RPC calls
|
# Related to XML-RPC calls
|
||||||
|
|
||||||
defp post(url, request) do
|
defp get_auth_string() do
|
||||||
|
"#{get_opennebula_config(:user)}:#{get_opennebula_config(:password)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp post!(call, endpoint) do
|
||||||
|
url = get_opennebula_config(:server) <> endpoint
|
||||||
opts = []
|
opts = []
|
||||||
headers = []
|
headers = []
|
||||||
body = request |> XMLRPC.encode!
|
body = call |> XMLRPC.encode!
|
||||||
|
|
||||||
query = HTTPoison.post(url, body, headers, opts)
|
response = HTTPoison.post!(url, body, headers, opts).body |> XMLRPC.decode!
|
||||||
case query do
|
case response do
|
||||||
{:ok, response} ->
|
%{fault_code: _, fault_string: err} -> {:error, err}
|
||||||
case response.body |> XMLRPC.decode! do
|
%{param: [false, err | _]} -> {:error, err}
|
||||||
%{fault_code: _, fault_string: err} -> {:error, err}
|
%{param: [true, result | _]} -> {:ok, result}
|
||||||
%{param: [false, err | _]} -> {:error, err}
|
|
||||||
%{param: [true, result | _]} -> {:ok, result}
|
|
||||||
end
|
|
||||||
{:error, %HTTPoison.Error{id: nil, reason: reason}} ->
|
|
||||||
Logger.warn("Error querying OpenNebula: #{inspect(reason)}")
|
|
||||||
{:error, reason}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def query(location, method, params) do
|
def query(method, params) do
|
||||||
user = Map.get(get_location_config(location), :user)
|
call = %XMLRPC.MethodCall{
|
||||||
password = Map.get(get_location_config(location), :password)
|
|
||||||
auth_string = "#{user}:#{password}"
|
|
||||||
|
|
||||||
request = %XMLRPC.MethodCall{
|
|
||||||
method_name: method,
|
method_name: method,
|
||||||
params: [auth_string | params]
|
params: [get_auth_string() | params]
|
||||||
}
|
}
|
||||||
|
|
||||||
address = get_location_config(location) |> Map.get(:xmlrpc_address)
|
call |> post!(@endpoint)
|
||||||
post(address <> @endpoint, request)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Public / external calls.
|
|
||||||
|
|
||||||
def get_vm(location, id), do: VM.get(id).(location)
|
|
||||||
|
|
||||||
def get_vms_for_user(location, username) do
|
|
||||||
call = VMPool.get(%{
|
|
||||||
filter_flag: :all,
|
|
||||||
range_start: :infinite,
|
|
||||||
range_end: :infinite,
|
|
||||||
state_filter: VM.state_for(:any_except_done),
|
|
||||||
kv_filter: ""
|
|
||||||
})
|
|
||||||
|
|
||||||
case call.(location) do
|
|
||||||
{:ok, %{VM: vms}} ->
|
|
||||||
Enum.filter(vms,
|
|
||||||
fn vm -> List.to_string(Map.get(vm, :UNAME)) == username end)
|
|
||||||
{:error, _err} -> %{}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_vms_for_user(username) do
|
|
||||||
get_locations()
|
|
||||||
|> Enum.map(fn l -> %{l => get_vms_for_user(l, username)} end)
|
|
||||||
|> Enum.reduce(%{}, &Map.merge/2)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,68 +22,6 @@ defmodule RecycledCloud.OpenNebula.VM do
|
||||||
{:cloning_failure, 11}
|
{:cloning_failure, 11}
|
||||||
]
|
]
|
||||||
|
|
||||||
@lcm_states [
|
|
||||||
{:LCM_INIT , 0},
|
|
||||||
{:PROLOG , 1},
|
|
||||||
{:BOOT , 2},
|
|
||||||
{:RUNNING , 3},
|
|
||||||
{:MIGRATE , 4},
|
|
||||||
{:SAVE_STOP , 5},
|
|
||||||
{:SAVE_SUSPEND , 6},
|
|
||||||
{:SAVE_MIGRATE , 7},
|
|
||||||
{:PROLOG_MIGRATE , 8},
|
|
||||||
{:PROLOG_RESUME , 9},
|
|
||||||
{:EPILOG_STOP , 10},
|
|
||||||
{:EPILOG , 11},
|
|
||||||
{:SHUTDOWN , 12},
|
|
||||||
{:CLEANUP_RESUBMIT , 15},
|
|
||||||
{:UNKNOWN , 16},
|
|
||||||
{:HOTPLUG , 17},
|
|
||||||
{:SHUTDOWN_POWEROFF , 18},
|
|
||||||
{:BOOT_UNKNOWN , 19},
|
|
||||||
{:BOOT_POWEROFF , 20},
|
|
||||||
{:BOOT_SUSPENDED , 21},
|
|
||||||
{:BOOT_STOPPED , 22},
|
|
||||||
{:CLEANUP_DELETE , 23},
|
|
||||||
{:HOTPLUG_SNAPSHOT , 24},
|
|
||||||
{:HOTPLUG_NIC , 25},
|
|
||||||
{:HOTPLUG_SAVEAS , 26},
|
|
||||||
{:HOTPLUG_SAVEAS_POWEROFF , 27},
|
|
||||||
{:HOTPLUG_SAVEAS_SUSPENDED , 28},
|
|
||||||
{:SHUTDOWN_UNDEPLOY , 29},
|
|
||||||
{:EPILOG_UNDEPLOY , 30},
|
|
||||||
{:PROLOG_UNDEPLOY , 31},
|
|
||||||
{:BOOT_UNDEPLOY , 32},
|
|
||||||
{:HOTPLUG_PROLOG_POWEROFF , 33},
|
|
||||||
{:HOTPLUG_EPILOG_POWEROFF , 34},
|
|
||||||
{:BOOT_MIGRATE , 35},
|
|
||||||
{:BOOT_FAILURE , 36},
|
|
||||||
{:BOOT_MIGRATE_FAILURE , 37},
|
|
||||||
{:PROLOG_MIGRATE_FAILURE , 38},
|
|
||||||
{:PROLOG_FAILURE , 39},
|
|
||||||
{:EPILOG_FAILURE , 40},
|
|
||||||
{:EPILOG_STOP_FAILURE , 41},
|
|
||||||
{:EPILOG_UNDEPLOY_FAILURE , 42},
|
|
||||||
{:PROLOG_MIGRATE_POWEROFF , 43},
|
|
||||||
{:PROLOG_MIGRATE_POWEROFF_FAILURE, 44},
|
|
||||||
{:PROLOG_MIGRATE_SUSPEND , 45},
|
|
||||||
{:PROLOG_MIGRATE_SUSPEND_FAILURE , 46},
|
|
||||||
{:BOOT_UNDEPLOY_FAILURE , 47},
|
|
||||||
{:BOOT_STOPPED_FAILURE , 48},
|
|
||||||
{:PROLOG_RESUME_FAILURE , 49},
|
|
||||||
{:PROLOG_UNDEPLOY_FAILURE , 50},
|
|
||||||
{:DISK_SNAPSHOT_POWEROFF , 51},
|
|
||||||
{:DISK_SNAPSHOT_REVERT_POWEROFF , 52},
|
|
||||||
{:DISK_SNAPSHOT_DELETE_POWEROFF , 53},
|
|
||||||
{:DISK_SNAPSHOT_SUSPENDED , 54},
|
|
||||||
{:DISK_SNAPSHOT_REVERT_SUSPENDED , 55},
|
|
||||||
{:DISK_SNAPSHOT_DELETE_SUSPENDED , 56},
|
|
||||||
{:DISK_SNAPSHOT , 57},
|
|
||||||
{:DISK_SNAPSHOT_DELETE , 59},
|
|
||||||
{:PROLOG_MIGRATE_UNKNOWN , 60},
|
|
||||||
{:PROLOG_MIGRATE_UNKNOWN_FAILURE , 61},
|
|
||||||
]
|
|
||||||
|
|
||||||
@actions [
|
@actions [
|
||||||
"terminate-hard",
|
"terminate-hard",
|
||||||
"terminate",
|
"terminate",
|
||||||
|
@ -153,17 +91,17 @@ defmodule RecycledCloud.OpenNebula.VM do
|
||||||
{:ALIAS_DETACH_ACTION , 47},
|
{:ALIAS_DETACH_ACTION , 47},
|
||||||
]
|
]
|
||||||
|
|
||||||
defp find(table, state) when is_integer(state) do
|
def state_for(state) when is_atom(state) do
|
||||||
case Enum.find(table, fn {_atom, value} -> value == state end) do
|
@states |> Keyword.get(state)
|
||||||
|
end
|
||||||
|
|
||||||
|
def state_for(state) when is_integer(state) do
|
||||||
|
case Enum.find(@states, fn {_atom, value} -> value == state end) do
|
||||||
{atom, _value} -> atom
|
{atom, _value} -> atom
|
||||||
nil -> nil
|
nil -> nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def state_for(state) when is_atom(state), do: @states |> Keyword.get(state)
|
|
||||||
def state_for(state) when is_integer(state), do: find(@states, state)
|
|
||||||
def lcm_state_for(state) when is_integer(state), do: find(@lcm_states, state)
|
|
||||||
|
|
||||||
def event_for(event) when is_integer(event) do
|
def event_for(event) when is_integer(event) do
|
||||||
case Enum.find(@events, fn {_atom, value} -> value == event end) do
|
case Enum.find(@events, fn {_atom, value} -> value == event end) do
|
||||||
{atom, _value} -> atom
|
{atom, _value} -> atom
|
||||||
|
@ -172,24 +110,32 @@ defmodule RecycledCloud.OpenNebula.VM do
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(id) do
|
def get(id) do
|
||||||
fn location ->
|
case ONE.query("one.vm.info", [id]) do
|
||||||
case ONE.query(location, "one.vm.info", [id]) do
|
{:ok, raw} ->
|
||||||
{:ok, raw} ->
|
data = raw
|
||||||
data = raw
|
|> Schema.scan("vm")
|
||||||
|> Schema.scan("vm")
|
|> Schema.map_record
|
||||||
|> Schema.map_record
|
{:ok, data}
|
||||||
{:ok, data}
|
{:error, err} -> {:error, err}
|
||||||
{:error, err} -> {:error, err}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_by_username(username) do
|
||||||
|
{:ok, %{VM: vms}} = RecycledCloud.OpenNebula.VMPool.get(%{
|
||||||
|
filter_flag: :all,
|
||||||
|
range_start: :infinite,
|
||||||
|
range_end: :infinite,
|
||||||
|
state_filter: state_for(:any_except_done),
|
||||||
|
kv_filter: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
Enum.filter(vms, fn vm -> List.to_string(Map.get(vm, :UNAME)) == username end)
|
||||||
|
end
|
||||||
|
|
||||||
def execute(vm_id, action) when action in @actions do
|
def execute(vm_id, action) when action in @actions do
|
||||||
fn location ->
|
case ONE.query("one.vm.action", [action, vm_id]) do
|
||||||
case ONE.query(location, "one.vm.action", [action, vm_id]) do
|
{:ok, _raw} -> :ok
|
||||||
{:ok, _raw} -> :ok
|
{:error, err} -> {:error, err}
|
||||||
{:error, err} -> {:error, err}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,16 +40,14 @@ defmodule RecycledCloud.OpenNebula.VMPool do
|
||||||
kv_filter: kv_filter
|
kv_filter: kv_filter
|
||||||
}) do
|
}) do
|
||||||
|
|
||||||
fn location ->
|
params = [filter_flag, range_start, range_end, state, kv_filter]
|
||||||
params = [filter_flag, range_start, range_end, state, kv_filter]
|
case ONE.query("one.vmpool.info", params) do
|
||||||
case ONE.query(location, "one.vmpool.info", params) do
|
{:ok, raw} ->
|
||||||
{:ok, raw} ->
|
data = raw
|
||||||
data = raw
|
|> Schema.scan("vm_pool")
|
||||||
|> Schema.scan("vm_pool")
|
|> Schema.map_record
|
||||||
|> Schema.map_record
|
{:ok, data}
|
||||||
{:ok, data}
|
{:error, err} -> {:error, err}
|
||||||
{:error, err} -> {:error, err}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
defmodule RecycledCloudWeb.VirtualMachineHostingController do
|
defmodule RecycledCloudWeb.VirtualMachineHostingController do
|
||||||
use RecycledCloudWeb, :controller
|
use RecycledCloudWeb, :controller
|
||||||
|
|
||||||
alias RecycledCloud.OpenNebula, as: ONE
|
alias RecycledCloud.OpenNebula.VM
|
||||||
|
|
||||||
def index(conn, _params) do
|
def index(conn, _params) do
|
||||||
username = conn.assigns.current_user.username
|
username = conn.assigns.current_user.username
|
||||||
vms = ONE.get_vms_for_user(username)
|
vms = VM.get_by_username(username)
|
||||||
|
|
||||||
render(conn, "index.html", vms: vms)
|
render(conn, "index.html", vms: vms)
|
||||||
end
|
end
|
||||||
|
|
||||||
# def start(conn, %{"id" => id}) do
|
def start(conn, %{"id" => id}) do
|
||||||
# case VM.execute(String.to_integer(id), "resume") do
|
case VM.execute(String.to_integer(id), "resume") do
|
||||||
# :ok ->
|
:ok ->
|
||||||
# conn
|
conn
|
||||||
# |> put_flash(:info, "Start request sent to VMM.")
|
|> put_flash(:info, "Start request sent to VMM.")
|
||||||
# |> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
|> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
||||||
# {:error, err} ->
|
{:error, err} ->
|
||||||
# conn
|
conn
|
||||||
# |> put_flash(:error, "Something went wrong: #{inspect(err)}")
|
|> put_flash(:error, "Something went wrong: #{inspect(err)}")
|
||||||
# |> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
|> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
||||||
# end
|
end
|
||||||
# end
|
end
|
||||||
#
|
|
||||||
# def stop(conn, %{"id" => id}) do
|
|
||||||
# case VM.execute(String.to_integer(id), "poweroff") do
|
|
||||||
# :ok ->
|
|
||||||
# conn
|
|
||||||
# |> put_flash(:stop, "Stop request sent to VMM.")
|
|
||||||
# |> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
|
||||||
# {:error, err} ->
|
|
||||||
# conn
|
|
||||||
# |> put_flash(:error, "Something went wrong: #{inspect(err)}")
|
|
||||||
# |> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
def show(conn, %{"location" => location, "id" => id}) do
|
def stop(conn, %{"id" => id}) do
|
||||||
case ONE.get_vm(location, String.to_integer(id)) do
|
case VM.execute(String.to_integer(id), "poweroff") do
|
||||||
|
:ok ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:stop, "Stop request sent to VMM.")
|
||||||
|
|> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
||||||
|
{:error, err} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, "Something went wrong: #{inspect(err)}")
|
||||||
|
|> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show(conn, %{"id" => id}) do
|
||||||
|
case VM.get(String.to_integer(id)) do
|
||||||
{:error, err} ->
|
{:error, err} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:error, "Could not fetch VM details: #{inspect(err)}")
|
|> put_flash(:error, "Could not fetch VM details: #{inspect(err)}")
|
||||||
|
@ -46,7 +46,6 @@ defmodule RecycledCloudWeb.VirtualMachineHostingController do
|
||||||
owner = vm |> Map.get(:UNAME) |> List.to_string
|
owner = vm |> Map.get(:UNAME) |> List.to_string
|
||||||
if owner == conn.assigns.current_user.username do
|
if owner == conn.assigns.current_user.username do
|
||||||
conn
|
conn
|
||||||
|> assign(:location, location)
|
|
||||||
|> assign(:vm, vm)
|
|> assign(:vm, vm)
|
||||||
|> render("show.html")
|
|> render("show.html")
|
||||||
else
|
else
|
||||||
|
|
|
@ -76,7 +76,9 @@ defmodule RecycledCloudWeb.Router do
|
||||||
post "/billing/partner/update", BillingController, :update
|
post "/billing/partner/update", BillingController, :update
|
||||||
|
|
||||||
get "/hosting/vm", VirtualMachineHostingController, :index
|
get "/hosting/vm", VirtualMachineHostingController, :index
|
||||||
get "/hosting/vm/:location/:id", VirtualMachineHostingController, :show
|
get "/hosting/vm/:id", VirtualMachineHostingController, :show
|
||||||
|
get "/hosting/vm/:id/start", VirtualMachineHostingController, :start
|
||||||
|
get "/hosting/vm/:id/stop", VirtualMachineHostingController, :stop
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", RecycledCloudWeb do
|
scope "/", RecycledCloudWeb do
|
||||||
|
|
|
@ -1,37 +1,36 @@
|
||||||
<h1>Virtual Machines</h1>
|
<h1>Virtual Machines</h1>
|
||||||
|
|
||||||
<p>This page list all the Virtual Machines linked to your account. Note that
|
<p>This page list all the Virtual Machines linked to your account. It is
|
||||||
SSH keys are not (yet) synced with OpenNebula: you'll have to add your key in
|
not possible to interect with them yet.</p>
|
||||||
<i><%= @current_user.username %> (top-right) > Settings > Add SSH Key</i> in
|
|
||||||
OpenNebula for every location you want to use.</p>
|
|
||||||
|
|
||||||
<%= for location <- Map.keys(@vms) do %>
|
<%= for location <- ["LNTH"] do %>
|
||||||
<h2>Location: <%= location %></h2>
|
<h2>Location: <%= location %></h2>
|
||||||
|
|
||||||
<p>
|
|
||||||
You can access the OpenNebula dashboard with your LDAP credentials at:
|
|
||||||
<a href="<%= Map.get(ONE.get_location_config(location), :public_address) %>">
|
|
||||||
<%= Map.get(ONE.get_location_config(location), :public_address) %>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 15%;">ID</th>
|
<th>#</th>
|
||||||
<th style="width: 40%;">Name</th>
|
<th>Name</th>
|
||||||
<th style="width: 30%;">State</th>
|
<th>State</th>
|
||||||
<th style="width: 15%">Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<%= for vm <- Map.get(@vms, location) do %>
|
<%= for vm <- @vms do %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= location %>#<%= Map.get(vm, :ID) %></td>
|
<td><%= Map.get(vm, :ID) %></td>
|
||||||
<td><%= Map.get(vm, :NAME) %></td>
|
<td><%= Map.get(vm, :NAME) %></td>
|
||||||
<td><%= render_state(vm) %></td>
|
<td><%= VM.state_for(Map.get(vm, :STATE)) %></td>
|
||||||
<td>
|
<td>
|
||||||
<%= link "Show history »", to: Routes.virtual_machine_hosting_path(@conn, :show, location, Map.get(vm, :ID)) %>
|
<%= case VM.state_for(Map.get(vm, :STATE)) do
|
||||||
|
:poweroff ->
|
||||||
|
link "start", to: Routes.virtual_machine_hosting_path(@conn, :start, Map.get(vm, :ID))
|
||||||
|
:active ->
|
||||||
|
link "stop", to: Routes.virtual_machine_hosting_path(@conn, :stop, Map.get(vm, :ID))
|
||||||
|
_ -> ""
|
||||||
|
end %>
|
||||||
|
|
||||||
|
<%= link "show details", to: Routes.virtual_machine_hosting_path(@conn, :show, Map.get(vm, :ID)) %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
<h1>VM <%= @location %>#<%= Map.get(@vm, :ID) %> - <%= Map.get(@vm, :NAME) %></h1>
|
<h1>VM#<%= Map.get(@vm, :ID) %> - <%= Map.get(@vm, :NAME) %></h1>
|
||||||
|
|
||||||
<p>
|
<ul>
|
||||||
This VM is located in the <%= @location %> location, its state is <%=
|
<li>State: <b><%= VM.state_for(Map.get(@vm, :STATE)) %></b></li>
|
||||||
render_state(@vm) %>. The OpenNebula dashboard can be accessed at
|
<li>LCM State: <b><%= Map.get(@vm, :LCM_STATE) %></b></li<
|
||||||
<a href="<%= Map.get(ONE.get_location_config(@location), :public_address) %>">
|
</ul>
|
||||||
<%= Map.get(ONE.get_location_config(@location), :public_address) %>
|
|
||||||
</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2>History</h2>
|
<h2>History</h2>
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,5 @@
|
||||||
defmodule RecycledCloudWeb.VirtualMachineHostingView do
|
defmodule RecycledCloudWeb.VirtualMachineHostingView do
|
||||||
use RecycledCloudWeb, :view
|
use RecycledCloudWeb, :view
|
||||||
|
|
||||||
alias RecycledCloud.OpenNebula, as: ONE
|
|
||||||
alias RecycledCloud.OpenNebula.VM
|
alias RecycledCloud.OpenNebula.VM
|
||||||
|
|
||||||
def render_state(vm) do
|
|
||||||
state = Map.get(vm, :STATE) |> VM.state_for
|
|
||||||
if state == :active do
|
|
||||||
lcm_state = Map.get(vm, :LCM_STATE) |> VM.lcm_state_for
|
|
||||||
raw("#{state} (<b>#{lcm_state}</b>)")
|
|
||||||
else
|
|
||||||
raw("#{state}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -4,7 +4,7 @@ defmodule RecycledCloud.MixProject do
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :recycledcloud,
|
app: :recycledcloud,
|
||||||
version: "0.4.0",
|
version: "0.3.1",
|
||||||
elixir: "~> 1.7",
|
elixir: "~> 1.7",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
||||||
|
|
Loading…
Reference in a new issue