Permalink
Browse files

Add support for storage volumes

  • Loading branch information...
1 parent c67329b commit 73a2df7cf730f45cda50ab31fefa1b0a7cea5c62 @msantos committed Aug 29, 2012
Showing with 548 additions and 28 deletions.
  1. +151 −14 bin/vert
  2. +1 −0 c_src/vert.c
  3. +7 −0 c_src/vert.h
  4. +19 −0 c_src/vert_func.h
  5. +21 −0 c_src/vert_storagepool.c
  6. +249 −0 c_src/vert_storagevol.c
  7. +3 −0 c_src/vert_util.c
  8. +6 −0 include/vert.hrl
  9. +91 −14 src/vert.erl
View
165 bin/vert
@@ -3,6 +3,8 @@
%%%
%%% Command line interface to libvirt
%%%
+-include_lib("kernel/include/file.hrl").
+
main(Opt) ->
% load vert
true = code:add_pathz(filename:dirname(escript:script_name())
@@ -133,19 +135,14 @@ call(["screenshot", Name | Arg]) ->
Screen = proplists:get_value("screen", Opt, 0),
File = proplists:get_value("file", Opt,
Name ++ "_" ++ os:getpid() ++ ".screen"),
-
{ok, Connect} = connect(Opt),
{ok, Domain} = domain(Connect, Name),
% XXX Put the stream in blocking mode. Seems to be the only way to
% XXX read from a stream.
{ok, Stream} = vert:virStreamNew(Connect, 0),
{ok, Mime} = vert:virDomainScreenshot(Domain, Stream, Screen),
-
- error_logger:info_report([{mime, Mime}]),
-
- screenshot(Stream, File),
-
- {ok, Mime};
+ read_stream(Stream, File),
+ rp({ok, Mime});
call(["send", Name | Commands]) ->
{ok, Ref} = vert_console:open(Name, [{recv_timeout, 0}]),
@@ -421,6 +418,111 @@ call(["pool-uuid", Name | Arg]) ->
{ok, Pool} = storagepool(Connect, Name),
rp(vert:virStoragePoolGetUUIDString(Pool));
+call(["vol-create-from", PName, File, VName | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Pool} = storagepool(Connect, PName),
+ {ok, XML} = file:read_file(File),
+ {ok, Vol} = storagevol(Connect, VName),
+ rp(vert:virStorageVolCreateXMLFrom(Pool, XML, Vol));
+
+call(["vol-create", Name, File | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Pool} = storagepool(Connect, Name),
+ {ok, XML} = file:read_file(File),
+ rp(vert:virStorageVolCreateXML(Pool, XML));
+
+call(["vol-delete", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ rp(vert:virStorageVolDelete(Vol));
+
+call(["vol-download", Name, File | Arg]) ->
+ Opt = getopt(Arg),
+ Offset = list_to_integer(proplists:get_value("offset", Opt, "0")),
+ Length = list_to_integer(proplists:get_value("length", Opt, "0")),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ {ok, Stream} = vert:virStreamNew(Connect, 0),
+ ok = vert:virStorageVolDownload(Vol, Stream, Offset, Length),
+ read_stream(Stream, File),
+ rp(ok);
+
+call(["vol-dumpxml", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ rp(vert:virStorageVolGetXMLDesc(Vol));
+
+call(["vol-info", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ rp(vert:virStorageVolGetInfo(Vol));
+
+call(["vol-key", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ rp(vert:virStorageVolGetKey(Vol));
+
+call(["vol-list", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Pool} = storagepool(Connect, Name),
+ {ok, Pools} = vert:virStoragePoolListVolumes(Pool),
+
+ rp({ok, [ begin
+ {ok, Vol} = vert:virStorageVolLookupByName(Pool, N),
+ {ok, Path} = vert:virStorageVolGetPath(Vol),
+ {ok, Key} = vert:virStorageVolGetKey(Vol),
+ {N, [{path, Path}, {key, Key}]}
+ end || N <- Pools ]});
+
+call(["vol-name", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ rp(vert:virStorageVolGetName(Vol));
+
+call(["vol-path", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ rp(vert:virStorageVolGetPath(Vol));
+
+call(["vol-pool", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ {ok, Pool} = vert:virStoragePoolLookupByVolume(Vol),
+ rp(vert:virStoragePoolGetName(Pool));
+
+call(["vol-upload", Name, File | Arg]) ->
+ Opt = getopt(Arg),
+ Offset = list_to_integer(proplists:get_value("offset", Opt, "0")),
+ Length = case proplists:get_value("length", Opt) of
+ undefined ->
+ {ok, #file_info{size = Size}} = file:read_file_info(File),
+ Size;
+ N ->
+ list_to_integer(N)
+ end,
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ {ok, Stream} = vert:virStreamNew(Connect),
+ ok = vert:virStorageVolUpload(Vol, Stream, Offset, Length),
+ send_stream(Stream, File),
+ rp(ok);
+
+call(["vol-wipe", Name | Arg]) ->
+ Opt = getopt(Arg),
+ {ok, Connect} = connect(Opt),
+ {ok, Vol} = storagevol(Connect, Name),
+ rp(vert:virStorageVolWipe(Vol));
+
call(_) ->
Help = [
"autostart",
@@ -472,7 +574,21 @@ call(_) ->
"pool-name",
"pool-refresh",
"pool-undefine",
- "pool-uuid"
+ "pool-uuid",
+
+ "vol-create",
+ "vol-create-from",
+ "vol-delete",
+ "vol-download",
+ "vol-dumpxml",
+ "vol-info",
+ "vol-key",
+ "vol-list",
+ "vol-name",
+ "vol-path",
+ "vol-pool",
+ "vol-upload",
+ "vol-wipe"
],
rp(Help),
@@ -526,6 +642,11 @@ storagepool(Connect, Name) ->
fun() -> vert:virStoragePoolLookupByName(Connect, Name) end ],
lookup(Fun).
+storagevol(Connect, Name) ->
+ Fun = [ fun() -> vert:virStorageVolLookupByKey(Connect, Name) end,
+ fun() -> vert:virStorageVolLookupByPath(Connect, Name) end ],
+ lookup(Fun).
+
lookup(Fun) ->
lookup(Fun, []).
lookup([], [{error, Error}|_]) ->
@@ -565,16 +686,32 @@ id_to_name(Connect, Ids) when is_list(Ids) ->
Name
end || Id <- Ids ].
-screenshot(Stream, File) ->
- screenshot(Stream, File, []).
-screenshot(Stream, File, Acc) ->
+read_stream(Stream, File) ->
+ {ok, FH} = file:open(File, [write, raw, binary]),
+ read_stream(Stream, File, FH).
+read_stream(Stream, File, FH) ->
case vert:virStreamRecv(Stream, 16#FFFF) of
{error, eagain} ->
timer:sleep(100),
- screenshot(Stream, File, Acc);
+ read_stream(Stream, File, FH);
{ok, <<>>} ->
- ok = file:write_file(File, lists:reverse(Acc));
+ vert:virStreamFinish(Stream),
+ file:close(FH);
{ok, Bytes} ->
error_logger:info_report([{got, File, byte_size(Bytes)}]),
- screenshot(Stream, File, [Bytes|Acc])
+ ok = file:write(FH, Bytes),
+ read_stream(Stream, File, FH)
end.
+
+send_stream(Stream, File) ->
+ {ok, FH} = file:open(File, [read, raw, binary]),
+ send_stream(Stream, File, FH).
+send_stream(Stream, File, FH) ->
+ case file:read(FH, 16#FFFF) of
+ eof ->
+ vert:virStreamFinish(Stream),
+ file:close(FH);
+ {ok, Bytes} ->
+ error_logger:info_report([{sending, File, byte_size(Bytes)}]),
+ ok = vert:virStreamSend(Stream, Bytes)
+ end.
View
@@ -87,6 +87,7 @@ load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info)
atom_network = enif_make_atom(env, "network");
atom_nwfilter = enif_make_atom(env, "nwfilter");
atom_storagepool = enif_make_atom(env, "storagepool");
+ atom_storagevol = enif_make_atom(env, "storagevol");
atom_stream = enif_make_atom(env, "stream");
atom_true = enif_make_atom(env, "true");
atom_false = enif_make_atom(env, "false");
View
@@ -52,6 +52,7 @@ ERL_NIF_TERM atom_interface;
ERL_NIF_TERM atom_network;
ERL_NIF_TERM atom_nwfilter;
ERL_NIF_TERM atom_storagepool;
+ERL_NIF_TERM atom_storagevol;
ERL_NIF_TERM atom_stream;
ERL_NIF_TERM atom_true;
ERL_NIF_TERM atom_false;
@@ -93,6 +94,7 @@ enum {
VERT_RES_NWFILTER,
VERT_RES_SECRET,
VERT_RES_STORAGEPOOL,
+ VERT_RES_STORAGEVOL,
VERT_RES_STREAM
};
@@ -125,6 +127,11 @@ enum {
return error_tuple(env, atom_badarg); \
} while (0)
+#define VERT_GET_UINT64(index, var) do { \
+ if (enif_get_uint64(env, argv[(index)], &var) < 0) \
+ return error_tuple(env, atom_badarg); \
+} while (0)
+
#define VERT_GET_IOLIST(index, var) do { \
if (!enif_inspect_iolist_as_binary(env, argv[(index)], &var)) \
return error_tuple(env, atom_badarg); \
View
@@ -163,11 +163,30 @@ ErlNifFunc vert_funcs[] = {
{"virStoragePoolLookupByName", 2, vert_virStoragePoolLookupByName},
{"virStoragePoolLookupByUUID", 2, vert_virStoragePoolLookupByUUID},
{"virStoragePoolLookupByUUIDString", 2, vert_virStoragePoolLookupByUUIDString},
+ {"virStoragePoolLookupByVolume", 1, vert_virStoragePoolLookupByVolume},
{"virStoragePoolNumOfVolumes", 1, vert_virStoragePoolNumOfVolumes},
{"virStoragePoolRefresh", 2, vert_virStoragePoolRefresh},
{"virStoragePoolSetAutostart", 2, vert_virStoragePoolSetAutostart},
{"virStoragePoolUndefine", 1, vert_virStoragePoolUndefine},
+ /* storagevol */
+ {"virStorageVolCreateXML", 3, vert_virStorageVolCreateXML},
+ {"virStorageVolCreateXMLFrom", 4, vert_virStorageVolCreateXMLFrom},
+ {"virStorageVolDelete", 2, vert_virStorageVolDelete},
+ {"virStorageVolDownload", 5, vert_virStorageVolDownload},
+ {"virStorageVolGetInfo", 1, vert_virStorageVolGetInfo},
+ {"virStorageVolGetKey", 1, vert_virStorageVolGetKey},
+ {"virStorageVolGetName", 1, vert_virStorageVolGetName},
+ {"virStorageVolGetPath", 1, vert_virStorageVolGetPath},
+ {"virStorageVolGetXMLDesc", 2, vert_virStorageVolGetXMLDesc},
+ {"virStorageVolLookupByKey", 2, vert_virStorageVolLookupByKey},
+ {"virStorageVolLookupByName", 2, vert_virStorageVolLookupByName},
+ {"virStorageVolLookupByPath", 2, vert_virStorageVolLookupByPath},
+ {"virStorageVolResize", 3, vert_virStorageVolResize},
+ {"virStorageVolUpload", 5, vert_virStorageVolUpload},
+ {"virStorageVolWipe", 2, vert_virStorageVolWipe},
+ {"virStorageVolWipePattern", 3, vert_virStorageVolWipePattern},
+
/* stream */
{"virStreamAbort", 1, vert_virStreamAbort},
{"virStreamFinish", 1, vert_virStreamFinish},
View
@@ -75,3 +75,24 @@ vert_virStoragePoolGetInfo(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
atom_ok,
enif_make_binary(env, &info));
}
+
+ ERL_NIF_TERM
+vert_virStoragePoolLookupByVolume(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{
+ VERT_RESOURCE *vp = NULL;
+ VERT_RESOURCE *pp = NULL;
+
+
+ VERT_GET_RESOURCE(0, vp, VERT_RES_STORAGEVOL);
+
+ VERT_RES_ALLOC(pp, VERT_RES_STORAGEPOOL, vp->conn);
+
+ pp->res = virStoragePoolLookupByVolume(vp->res);
+
+ if (pp->res == NULL) {
+ enif_release_resource(pp);
+ return verterr(env);
+ }
+
+ return vert_make_resource(env, pp, atom_storagepool);
+}
Oops, something went wrong.

0 comments on commit 73a2df7

Please sign in to comment.