2021-02-11 14:34:40 +01:00
|
|
|
defmodule RecycledCloud.OpenNebula do
|
|
|
|
@moduledoc """
|
2021-04-09 11:36:33 +02:00
|
|
|
The OpenNebula context and XML-RPC Interface.
|
2021-02-11 14:34:40 +01:00
|
|
|
|
|
|
|
See http://docs.opennebula.io/5.12/integration/system_interfaces/api.html for details.
|
|
|
|
"""
|
|
|
|
|
2021-04-09 11:36:33 +02:00
|
|
|
alias RecycledCloud.OpenNebula.{VM, VMPool}
|
|
|
|
require Logger
|
|
|
|
|
2021-02-11 14:34:40 +01:00
|
|
|
# OpenNebula daemon.
|
|
|
|
@endpoint "/RPC2"
|
|
|
|
|
|
|
|
defp get_opennebula_config(key) do
|
|
|
|
Application.get_env(:recycledcloud, :opennebula, []) |> Keyword.get(key)
|
|
|
|
end
|
|
|
|
|
2021-04-09 11:36:33 +02:00
|
|
|
def get_locations() do
|
|
|
|
get_opennebula_config(:locations)
|
|
|
|
|> Enum.map(fn m -> Map.get(m, :name) end)
|
|
|
|
end
|
2021-02-11 14:34:40 +01:00
|
|
|
|
2021-04-09 11:36:33 +02:00
|
|
|
def get_location_config(name) do
|
|
|
|
get_opennebula_config(:locations)
|
|
|
|
|> Enum.find(fn m -> Map.get(m, :name) == name end)
|
2021-02-11 14:34:40 +01:00
|
|
|
end
|
|
|
|
|
2021-04-09 11:36:33 +02:00
|
|
|
##
|
|
|
|
# Related to XML-RPC calls
|
|
|
|
|
|
|
|
defp post(url, request) do
|
2021-02-11 14:34:40 +01:00
|
|
|
opts = []
|
|
|
|
headers = []
|
2021-04-09 11:36:33 +02:00
|
|
|
body = request |> XMLRPC.encode!
|
2021-02-11 14:34:40 +01:00
|
|
|
|
2021-04-09 11:36:33 +02:00
|
|
|
query = HTTPoison.post(url, body, headers, opts)
|
|
|
|
case query do
|
|
|
|
{:ok, response} ->
|
|
|
|
case response.body |> XMLRPC.decode! do
|
|
|
|
%{fault_code: _, fault_string: err} -> {:error, err}
|
|
|
|
%{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}
|
2021-02-11 14:34:40 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-04-09 11:36:33 +02:00
|
|
|
def query(location, method, params) do
|
|
|
|
user = Map.get(get_location_config(location), :user)
|
|
|
|
password = Map.get(get_location_config(location), :password)
|
|
|
|
auth_string = "#{user}:#{password}"
|
|
|
|
|
|
|
|
request = %XMLRPC.MethodCall{
|
2021-02-11 14:34:40 +01:00
|
|
|
method_name: method,
|
2021-04-09 11:36:33 +02:00
|
|
|
params: [auth_string | params]
|
2021-02-11 14:34:40 +01:00
|
|
|
}
|
|
|
|
|
2021-04-09 11:36:33 +02:00
|
|
|
address = get_location_config(location) |> Map.get(:xmlrpc_address)
|
|
|
|
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)
|
2021-02-11 14:34:40 +01:00
|
|
|
end
|
|
|
|
end
|