meta/lib/recycledcloud/opennebula.ex
2021-04-09 11:36:33 +02:00

91 lines
2.4 KiB
Elixir

defmodule RecycledCloud.OpenNebula do
@moduledoc """
The OpenNebula context and XML-RPC Interface.
See http://docs.opennebula.io/5.12/integration/system_interfaces/api.html for details.
"""
alias RecycledCloud.OpenNebula.{VM, VMPool}
require Logger
# OpenNebula daemon.
@endpoint "/RPC2"
defp get_opennebula_config(key) do
Application.get_env(:recycledcloud, :opennebula, []) |> Keyword.get(key)
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
defp post(url, request) do
opts = []
headers = []
body = request |> XMLRPC.encode!
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}
end
end
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{
method_name: method,
params: [auth_string | params]
}
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)
end
end