Skip to content

Commit

Permalink
feat(block): added blockCommit, blockJobInfo, and blockJobAbort
Browse files Browse the repository at this point in the history
  • Loading branch information
Rush authored and mbroadst committed Aug 23, 2016
1 parent 3680239 commit b2fdc02
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 23 deletions.
1 change: 1 addition & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
'src/secret.cc',
'src/storage_pool.cc',
'src/storage_volume.cc',
'src/worker.cc'
],
'include_dirs' : [
"<!(node -e \"require('nan')\")"
Expand Down
162 changes: 139 additions & 23 deletions src/domain.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "error.h"
#include "hypervisor.h"
#include "domain.h"
#include "worker.h"

namespace NLV {

Expand Down Expand Up @@ -69,6 +70,9 @@ void Domain::Initialize(Handle<Object> exports)
Nan::SetPrototypeMethod(t, "getMemoryStats", GetMemoryStats);
Nan::SetPrototypeMethod(t, "getVcpus", GetVcpus);
Nan::SetPrototypeMethod(t, "setVcpus", SetVcpus);
Nan::SetPrototypeMethod(t, "blockCommit", BlockCommit);
Nan::SetPrototypeMethod(t, "blockJobInfo", BlockJobInfo);
Nan::SetPrototypeMethod(t, "blockJobAbort", BlockJobAbort);

// UNFINISHED SYNC ACCESSORS/MUTATORS
Nan::SetPrototypeMethod(t, "setSchedulerParameters", SetSchedulerParameters);
Expand Down Expand Up @@ -112,11 +116,46 @@ void Domain::Initialize(Handle<Object> exports)
NODE_DEFINE_CONSTANT(exports, VIR_MIGRATE_NON_SHARED_DISK);
NODE_DEFINE_CONSTANT(exports, VIR_MIGRATE_NON_SHARED_INC);

//virDomainSnapshotCreateXML
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_HALT);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_CREATE_LIVE);

//virDomainSnapshotDelete
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);

//virDomainModificationImpact
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_AFFECT_CURRENT);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_AFFECT_LIVE);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_AFFECT_CONFIG);

//virDomainBlockCommit
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_COMMIT_SHALLOW);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_COMMIT_DELETE);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_COMMIT_ACTIVE);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_COMMIT_RELATIVE);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES);

//virDomainBlockJobAbort
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_JOB_COMPLETED);

//virDomainBlockJobInfo
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_JOB_TYPE_PULL);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_JOB_TYPE_COPY);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT);

//virDomainXMLFlags
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_XML_SECURE);
NODE_DEFINE_CONSTANT(exports, VIR_DOMAIN_XML_INACTIVE);
Expand Down Expand Up @@ -1482,6 +1521,86 @@ NLV_WORKER_EXECUTE(Domain, SetVcpus)

data_ = true;
}
#include <unistd.h>
NAN_METHOD(Domain::BlockCommit)
{
Nan::HandleScope scope;
if (info.Length() < 5 || !info[0]->IsString() || !info[1]->IsString() || !info[2]->IsString()
|| !info[3]->IsNumber()) {
Nan::ThrowTypeError("you must specify path, base, top, bandwidth, and optionally flags");
return;
}

std::string path(*Nan::Utf8String(info[0]->ToString()));
std::string base(*Nan::Utf8String(info[1]->ToString()));
std::string top(*Nan::Utf8String(info[2]->ToString()));
unsigned long bandwidth = info[3]->Int32Value();
unsigned int flags = GetFlags(info[4]);

virDomainPtr domain = Nan::ObjectWrap::Unwrap<Domain>(info.This())->handle_;
Worker::Queue(info[info.Length() -1], [=] (Worker::SetOnFinishedHandler onFinished) {
if (virDomainBlockCommit(domain, path.c_str(), base.c_str(), top.c_str(), bandwidth, flags) < 0) {
return virSaveLastError();
}
return onFinished(PrimitiveReturnHandler(true));
});
}

NAN_METHOD(Domain::BlockJobInfo)
{
Nan::HandleScope scope;
if (info.Length() < 1 || !info[0]->IsString()) {
Nan::ThrowTypeError("you must specify path and optionally flags");
return;
}

std::string path(*Nan::Utf8String(info[0]->ToString()));
unsigned int flags = GetFlags(info[1]);

virDomainPtr domain = Nan::ObjectWrap::Unwrap<Domain>(info.This())->handle_;
Worker::Queue(info[info.Length() -1], [=] (Worker::SetOnFinishedHandler onFinished) {
virDomainBlockJobInfo info;
int ret = virDomainGetBlockJobInfo(domain, path.c_str(), &info, flags);
if(ret == -1) {
return virSaveLastError();
}
if(ret == 0) {
return onFinished(PrimitiveReturnHandler(false));
}

return onFinished([&](Nan::Callback* callback) {
Nan::HandleScope scope;
v8::Local<Object> data = Nan::New<Object>();
data->Set(Nan::New("type").ToLocalChecked(), Nan::New<Integer>((unsigned int)info.type));
data->Set(Nan::New("bandwidth").ToLocalChecked(), Nan::New<Integer>((unsigned int)info.bandwidth));
data->Set(Nan::New("cur").ToLocalChecked(), Nan::New<Integer>((unsigned int)info.cur));
data->Set(Nan::New("end").ToLocalChecked(), Nan::New<Integer>((unsigned int)info.end));
Local<Value> argv[] = { Nan::Null(), data };
callback->Call(2, argv);
});
});
}

NAN_METHOD(Domain::BlockJobAbort)
{
if (info.Length() < 1 || !info[0]->IsString()) {
Nan::ThrowTypeError("you must specify path and optionally flags");
return;
}

std::string path(*Nan::Utf8String(info[0]->ToString()));
unsigned int flags = GetFlags(info[1]);

virDomainPtr domain = Nan::ObjectWrap::Unwrap<Domain>(info.This())->handle_;

Worker::Queue(info[info.Length() -1], [=] (Worker::SetOnFinishedHandler onFinished) {
//abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
if (virDomainBlockJobAbort(domain, path.c_str(), flags) < 0) {
return virSaveLastError();
}
return onFinished(PrimitiveReturnHandler(true));
});
}

NAN_METHOD(Domain::SendKeys)
{
Expand Down Expand Up @@ -1845,34 +1964,31 @@ NLV_WORKER_EXECUTE(Domain, TakeSnapshot)
NAN_METHOD(Domain::DeleteSnapshot) {
Nan::HandleScope scope;

if(info.Length() != 2 ||
(!info[0]->IsString() || !info[1]->IsFunction())) {
Nan::ThrowTypeError("you must specify a string and a callback");
if(info.Length() < 2 ||
(!info[0]->IsString())) {
Nan::ThrowTypeError("you must specify a string and optional flags");
return;
}

std::string name = *Nan::Utf8String(info[0]->ToString());
unsigned int flags = GetFlags(info[1]);

Domain *domain = Nan::ObjectWrap::Unwrap<Domain>(info.This());
Nan::Callback *callback = new Nan::Callback(info[1].As<Function>());
Nan::AsyncQueueWorker(new DeleteSnapshotWorker(callback, domain->handle_, *Nan::Utf8String(info[0]->ToString())));
return;
}

NLV_WORKER_EXECUTE(Domain, DeleteSnapshot)
{
unsigned int flags = 0;
virDomainSnapshotPtr snapshot = NULL;

snapshot = virDomainSnapshotLookupByName(Handle(), name_.c_str(), flags);
if(snapshot == NULL) {
SetVirError(virSaveLastError());
return;
}

if(virDomainSnapshotDelete(snapshot, flags) == -1)
SetVirError(virSaveLastError());
auto domain = Nan::ObjectWrap::Unwrap<Domain>(info.This())->handle_;
//Nan::Callback *callback = new Nan::Callback(info[1].As<Function>());
Worker::Queue(info[info.Length() - 1], [=](Worker::SetOnFinishedHandler onFinished) {
auto snapshot = virDomainSnapshotLookupByName(domain, name.c_str(), 0);
if(snapshot == NULL) {
return virSaveLastError();
}

virDomainSnapshotFree(snapshot);
if(virDomainSnapshotDelete(snapshot, flags) == -1) {
virDomainSnapshotFree(snapshot); // TODO: add some auto cleanup scope
return virSaveLastError();
}
virDomainSnapshotFree(snapshot);

return onFinished(PrimitiveReturnHandler(true));
});
}

NAN_METHOD(Domain::LookupSnapshotByName) {
Expand Down
34 changes: 34 additions & 0 deletions src/domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class Domain : public NLVObject<virDomainPtr, DomainCleanupHandler>
static NAN_METHOD(GetMemoryStats);
static NAN_METHOD(GetVcpus);
static NAN_METHOD(SetVcpus);
static NAN_METHOD(BlockCommit);
static NAN_METHOD(BlockJobInfo);
static NAN_METHOD(BlockJobAbort);
static NAN_METHOD(ToXml);
static NAN_METHOD(GetMetadata);
static NAN_METHOD(SetMetadata);
Expand Down Expand Up @@ -480,6 +483,37 @@ class Domain : public NLVObject<virDomainPtr, DomainCleanupHandler>
unsigned int count_;
};

class OldBlockCommitWorker : public NLVPrimitiveReturnWorker<virDomainPtr, bool> {
public:
OldBlockCommitWorker(Nan::Callback *callback, virDomainPtr handle, std::string path,
std::string base, std::string top, unsigned long bandwidth, unsigned int flags)
: NLVPrimitiveReturnWorker<virDomainPtr, bool>(callback, handle),
path_(path), base_(base), top_(top), bandwidth_(bandwidth), flags_(flags) {}
void Execute();
private:
std::string path_;
std::string base_;
std::string top_;
unsigned long bandwidth_;
unsigned int flags_;
};

class BlockCommitWorker : public NLVPrimitiveReturnWorker<virDomainPtr, bool> {
public:
BlockCommitWorker(Nan::Callback *callback, virDomainPtr handle, std::function<virErrorPtr(virDomainPtr)> func)
: NLVPrimitiveReturnWorker<virDomainPtr, bool>(callback, handle),
func_(func) {}
void Execute() {
NLV_WORKER_ASSERT_DOMAIN();
virErrorPtr error = func_(Handle());
if(error) {
SetVirError(error);
}
}
private:
std::function<virErrorPtr(virDomainPtr)> func_;
};

class SetMigrationMaxDowntimeWorker : public NLVPrimitiveReturnWorker<virDomainPtr, bool> {
public:
SetMigrationMaxDowntimeWorker(Nan::Callback *callback, virDomainPtr handle, long long downtime, unsigned int flags)
Expand Down
1 change: 1 addition & 0 deletions src/nlv_async_worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class NLVAsyncWorkerBase : public Nan::AsyncWorker

};


/**
* Base class for most NLV async workers
*/
Expand Down
16 changes: 16 additions & 0 deletions src/nlv_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,22 @@ NAN_INLINE void AsyncQueueWorker(Nan::AsyncWorker *worker, Local<Object> parent
Nan::AsyncQueueWorker(worker);
}

NAN_INLINE unsigned int GetFlags(v8::Handle<v8::Value> val) {
if(val->IsUndefined() || val->IsFunction()) {
return 0;
}
if(!val->IsArray()) {
Nan::ThrowTypeError("flags must be an array");
return 0;
}

Local<Array> flags_ = Local<Array>::Cast(val);
unsigned int flags = 0;
for (unsigned int i = 0; i < flags_->Length(); i++)
flags |= flags_->Get(Nan::New<Integer>(i))->Int32Value();
return flags;
}

};


Expand Down
13 changes: 13 additions & 0 deletions src/worker.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "worker.h"

using namespace NLV;

void Worker::Queue(v8::Handle<v8::Value> v8_callback, ExecuteHandler handler) {
if(!v8_callback->IsFunction()) {
Nan::ThrowTypeError("you must specify a function as the callback");;
return;
}
Nan::Callback *callback = new Nan::Callback(v8_callback.As<Function>());
auto worker = new NLV::Worker(callback, handler);
Nan::AsyncQueueWorker(worker);
}
45 changes: 45 additions & 0 deletions src/worker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "nlv_async_worker.h"

namespace NLV {
class Worker : public NLVAsyncWorkerBase {
public:
typedef std::function<void(Nan::Callback*)> OnFinishedHandler;

typedef std::function<virErrorPtr(OnFinishedHandler)> SetOnFinishedHandler;

typedef std::function<virErrorPtr(SetOnFinishedHandler)> ExecuteHandler;

ExecuteHandler execute_handler;
OnFinishedHandler on_finished_handler;

explicit Worker(Nan::Callback *callback, ExecuteHandler handler)
: NLVAsyncWorkerBase(callback), execute_handler(handler) { };

void HandleOKCallback() {
on_finished_handler(callback);
}

virtual void Execute() {
auto error = execute_handler([=] (OnFinishedHandler handler) {
on_finished_handler = handler;
return nullptr;
});
if(error) {
SetVirError(error);
}
}

// TODO: make it a template so that it can accept arbitrary number of arguments
// of objects to make persistent for the duration of the worker run
static void Queue(v8::Handle<v8::Value> v8_callback, ExecuteHandler handler);
};

template<class T>
Worker::OnFinishedHandler PrimitiveReturnHandler(T val) {
return [=](Nan::Callback* callback) {
Nan::HandleScope scope;
v8::Local<v8::Value> argv[] = { Nan::Null(), Nan::New(val) };
callback->Call(2, argv);
};
}
};

0 comments on commit b2fdc02

Please sign in to comment.