Wire initial VM management frontend
This commit is contained in:
parent
053d5a3320
commit
7e6439be67
8 changed files with 242 additions and 1 deletions
0
lib/opennebula.ex
Normal file
0
lib/opennebula.ex
Normal file
|
@ -22,12 +22,88 @@ defmodule RecycledCloud.OpenNebula.VM do
|
||||||
{:cloning_failure, 11}
|
{:cloning_failure, 11}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@actions [
|
||||||
|
"terminate-hard",
|
||||||
|
"terminate",
|
||||||
|
"undeploy-hard",
|
||||||
|
"undeploy",
|
||||||
|
"poweroff-hard",
|
||||||
|
"poweroff",
|
||||||
|
"reboot-hard",
|
||||||
|
"reboot",
|
||||||
|
"hold",
|
||||||
|
"release",
|
||||||
|
"stop",
|
||||||
|
"suspend",
|
||||||
|
"resume",
|
||||||
|
"resched",
|
||||||
|
"unresched"
|
||||||
|
]
|
||||||
|
|
||||||
|
@events [
|
||||||
|
{:NONE_ACTION , 0},
|
||||||
|
{:MIGRATE_ACTION , 1},
|
||||||
|
{:LIVE_MIGRATE_ACTION , 2},
|
||||||
|
{:SHUTDOWN_ACTION , 3},
|
||||||
|
{:SHUTDOWN_HARD_ACTION , 4},
|
||||||
|
{:UNDEPLOY_ACTION , 5},
|
||||||
|
{:UNDEPLOY_HARD_ACTION , 6},
|
||||||
|
{:HOLD_ACTION , 7},
|
||||||
|
{:RELEASE_ACTION , 8},
|
||||||
|
{:STOP_ACTION , 9},
|
||||||
|
{:SUSPEND_ACTION , 10},
|
||||||
|
{:RESUME_ACTION , 11},
|
||||||
|
{:BOOT_ACTION , 12},
|
||||||
|
{:DELETE_ACTION , 13},
|
||||||
|
{:DELETE_RECREATE_ACTION , 14},
|
||||||
|
{:REBOOT_ACTION , 15},
|
||||||
|
{:REBOOT_HARD_ACTION , 16},
|
||||||
|
{:RESCHED_ACTION , 17},
|
||||||
|
{:UNRESCHED_ACTION , 18},
|
||||||
|
{:POWEROFF_ACTION , 19},
|
||||||
|
{:POWEROFF_HARD_ACTION , 20},
|
||||||
|
{:DISK_ATTACH_ACTION , 21},
|
||||||
|
{:DISK_DETACH_ACTION , 22},
|
||||||
|
{:NIC_ATTACH_ACTION , 23},
|
||||||
|
{:NIC_DETACH_ACTION , 24},
|
||||||
|
{:DISK_SNAPSHOT_CREATE_ACTION , 25},
|
||||||
|
{:DISK_SNAPSHOT_DELETE_ACTION , 26},
|
||||||
|
{:TERMINATE_ACTION , 27},
|
||||||
|
{:TERMINATE_HARD_ACTION , 28},
|
||||||
|
{:DISK_RESIZE_ACTION , 29},
|
||||||
|
{:DEPLOY_ACTION , 30},
|
||||||
|
{:CHOWN_ACTION , 31},
|
||||||
|
{:CHMOD_ACTION , 32},
|
||||||
|
{:UPDATECONF_ACTION , 33},
|
||||||
|
{:RENAME_ACTION , 34},
|
||||||
|
{:RESIZE_ACTION , 35},
|
||||||
|
{:UPDATE_ACTION , 36},
|
||||||
|
{:SNAPSHOT_CREATE_ACTION , 37},
|
||||||
|
{:SNAPSHOT_DELETE_ACTION , 38},
|
||||||
|
{:SNAPSHOT_REVERT_ACTION , 39},
|
||||||
|
{:DISK_SAVEAS_ACTION , 40},
|
||||||
|
{:DISK_SNAPSHOT_REVERT_ACTION , 41},
|
||||||
|
{:RECOVER_ACTION , 42},
|
||||||
|
{:RETRY_ACTION , 43},
|
||||||
|
{:MONITOR_ACTION , 44},
|
||||||
|
{:DISK_SNAPSHOT_RENAME_ACTION , 45},
|
||||||
|
{:ALIAS_ATTACH_ACTION , 46},
|
||||||
|
{:ALIAS_DETACH_ACTION , 47},
|
||||||
|
]
|
||||||
|
|
||||||
def state_for(state) when is_atom(state) do
|
def state_for(state) when is_atom(state) do
|
||||||
@states |> Keyword.get(state)
|
@states |> Keyword.get(state)
|
||||||
end
|
end
|
||||||
|
|
||||||
def state_for(state) when is_integer(state) do
|
def state_for(state) when is_integer(state) do
|
||||||
case Enum.find(@states, fn {atom, value} -> value == state end) do
|
case Enum.find(@states, fn {_atom, value} -> value == state end) do
|
||||||
|
{atom, _value} -> atom
|
||||||
|
nil -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_for(event) when is_integer(event) do
|
||||||
|
case Enum.find(@events, fn {_atom, value} -> value == event end) do
|
||||||
{atom, _value} -> atom
|
{atom, _value} -> atom
|
||||||
nil -> nil
|
nil -> nil
|
||||||
end
|
end
|
||||||
|
@ -43,4 +119,23 @@ defmodule RecycledCloud.OpenNebula.VM do
|
||||||
{:error, err} -> {:error, err}
|
{:error, err} -> {:error, err}
|
||||||
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
|
||||||
|
case ONE.query("one.vm.action", [action, vm_id]) do
|
||||||
|
{:ok, _raw} -> :ok
|
||||||
|
{:error, err} -> {:error, err}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
defmodule RecycledCloudWeb.VirtualMachineHostingController do
|
||||||
|
use RecycledCloudWeb, :controller
|
||||||
|
|
||||||
|
alias RecycledCloud.OpenNebula.VM
|
||||||
|
|
||||||
|
def index(conn, _params) do
|
||||||
|
username = conn.assigns.current_user.username
|
||||||
|
vms = VM.get_by_username(username)
|
||||||
|
|
||||||
|
render(conn, "index.html", vms: vms)
|
||||||
|
end
|
||||||
|
|
||||||
|
def start(conn, %{"id" => id}) do
|
||||||
|
case VM.execute(String.to_integer(id), "resume") do
|
||||||
|
:ok ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Start 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 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, %{"id" => id}) do
|
||||||
|
case VM.get(String.to_integer(id)) do
|
||||||
|
{:error, err} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, "Could not fetch VM details: #{inspect(err)}")
|
||||||
|
|> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
||||||
|
{:ok, vm} ->
|
||||||
|
owner = vm |> Map.get(:UNAME) |> List.to_string
|
||||||
|
if owner == conn.assigns.current_user.username do
|
||||||
|
conn
|
||||||
|
|> assign(:vm, vm)
|
||||||
|
|> render("show.html")
|
||||||
|
else
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, "You are not the owner of this machine.")
|
||||||
|
|> redirect(to: Routes.virtual_machine_hosting_path(conn, :index))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -74,6 +74,11 @@ defmodule RecycledCloudWeb.Router do
|
||||||
get "/users/settings/keys/:key_id/delete", UserKeysController, :delete
|
get "/users/settings/keys/:key_id/delete", UserKeysController, :delete
|
||||||
get "/billing", BillingController, :index
|
get "/billing", BillingController, :index
|
||||||
post "/billing/partner/update", BillingController, :update
|
post "/billing/partner/update", BillingController, :update
|
||||||
|
|
||||||
|
get "/hosting/vm", VirtualMachineHostingController, :index
|
||||||
|
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
|
||||||
|
|
|
@ -6,13 +6,25 @@
|
||||||
<li><%= link "Settings", to: Routes.user_settings_path(@conn, :edit) %></li>
|
<li><%= link "Settings", to: Routes.user_settings_path(@conn, :edit) %></li>
|
||||||
<li><%= link "Billing", to: Routes.billing_path(@conn, :index) %></li>
|
<li><%= link "Billing", to: Routes.billing_path(@conn, :index) %></li>
|
||||||
<li><%= link "Log out", to: Routes.user_session_path(@conn, :delete), method: :delete %></li>
|
<li><%= link "Log out", to: Routes.user_session_path(@conn, :delete), method: :delete %></li>
|
||||||
|
<hr />
|
||||||
|
<!--
|
||||||
|
<li><%= link "Web Hosting", to: Routes.page_path(@conn, :index) %></li>
|
||||||
|
<li><%= link "Name Service", to: Routes.page_path(@conn, :index) %></li>
|
||||||
|
<li><%= link "Storage Services", to: Routes.page_path(@conn, :index) %></li>
|
||||||
|
-->
|
||||||
|
<li><%= link "Virtual Machines", to: Routes.virtual_machine_hosting_path(@conn, :index) %></li>
|
||||||
<% else %>
|
<% else %>
|
||||||
<li><%= link "Log in", to: Routes.user_session_path(@conn, :new) %></li>
|
<li><%= link "Log in", to: Routes.user_session_path(@conn, :new) %></li>
|
||||||
<li><%= link "Register", to: Routes.user_registration_path(@conn, :new) %></li>
|
<li><%= link "Register", to: Routes.user_registration_path(@conn, :new) %></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<hr />
|
<hr />
|
||||||
<li>
|
<li>
|
||||||
|
<a href="https://status.recycled.cloud">
|
||||||
|
Infrastructure status
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<a href="https://recycled.cloud">
|
<a href="https://recycled.cloud">
|
||||||
Back to recycled.cloud ↵
|
Back to recycled.cloud ↵
|
||||||
</a>
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<h1>Virtual Machines</h1>
|
||||||
|
|
||||||
|
<p>This page list all the Virtual Machines linked to your account. It is
|
||||||
|
not possible to interect with them yet.</p>
|
||||||
|
|
||||||
|
<%= for location <- ["LNTH"] do %>
|
||||||
|
<h2>Location: <%= location %></h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>State</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<%= for vm <- @vms do %>
|
||||||
|
<tr>
|
||||||
|
<td><%= Map.get(vm, :ID) %></td>
|
||||||
|
<td><%= Map.get(vm, :NAME) %></td>
|
||||||
|
<td><%= VM.state_for(Map.get(vm, :STATE)) %></td>
|
||||||
|
<td>
|
||||||
|
<%= 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>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% end %>
|
|
@ -0,0 +1,27 @@
|
||||||
|
<h1>VM#<%= Map.get(@vm, :ID) %> - <%= Map.get(@vm, :NAME) %></h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>State: <b><%= VM.state_for(Map.get(@vm, :STATE)) %></b></li>
|
||||||
|
<li>LCM State: <b><%= Map.get(@vm, :LCM_STATE) %></b></li<
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>History</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Time</th>
|
||||||
|
<th>Action</th>
|
||||||
|
<th>Host</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<%= for entry <- @vm |> Map.get(:HISTORY_RECORDS) |> Map.get(:HISTORY) do %>
|
||||||
|
<tr>
|
||||||
|
<td><%= DateTime.from_unix!(Map.get(entry, :STIME)) %></td>
|
||||||
|
<td><%= VM.event_for(Map.get(entry, :ACTION)) %></td>
|
||||||
|
<td><%= Map.get(entry, :HOSTNAME) %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
|
@ -0,0 +1,5 @@
|
||||||
|
defmodule RecycledCloudWeb.VirtualMachineHostingView do
|
||||||
|
use RecycledCloudWeb, :view
|
||||||
|
|
||||||
|
alias RecycledCloud.OpenNebula.VM
|
||||||
|
end
|
Loading…
Reference in a new issue