2019-09-27 17:50:46 +00:00
|
|
|
///
|
|
|
|
/// Copyright 2015-2019 Oliver Giles
|
|
|
|
///
|
|
|
|
/// This file is part of Laminar
|
|
|
|
///
|
|
|
|
/// Laminar is free software: you can redistribute it and/or modify
|
|
|
|
/// it under the terms of the GNU General Public License as published by
|
|
|
|
/// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
/// (at your option) any later version.
|
|
|
|
///
|
|
|
|
/// Laminar is distributed in the hope that it will be useful,
|
|
|
|
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
/// GNU General Public License for more details.
|
|
|
|
///
|
|
|
|
/// You should have received a copy of the GNU General Public License
|
|
|
|
/// along with Laminar. If not, see <http://www.gnu.org/licenses/>
|
|
|
|
///
|
|
|
|
#include "rpc.h"
|
|
|
|
#include "laminar.capnp.h"
|
2019-10-05 17:06:35 +00:00
|
|
|
#include "laminar.h"
|
2019-09-27 17:50:46 +00:00
|
|
|
#include "log.h"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// Used for returning run state to RPC clients
|
|
|
|
LaminarCi::JobResult fromRunState(RunState state) {
|
|
|
|
switch(state) {
|
|
|
|
case RunState::SUCCESS: return LaminarCi::JobResult::SUCCESS;
|
|
|
|
case RunState::FAILED: return LaminarCi::JobResult::FAILED;
|
|
|
|
case RunState::ABORTED: return LaminarCi::JobResult::ABORTED;
|
|
|
|
default:
|
|
|
|
return LaminarCi::JobResult::UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// This is the implementation of the Laminar Cap'n Proto RPC interface.
|
|
|
|
// As such, it implements the pure virtual interface generated from
|
2019-10-05 17:06:35 +00:00
|
|
|
// laminar.capnp with calls to the primary Laminar class
|
|
|
|
class RpcImpl : public LaminarCi::Server {
|
2019-09-27 17:50:46 +00:00
|
|
|
public:
|
2019-10-05 17:06:35 +00:00
|
|
|
RpcImpl(Laminar& l) :
|
2019-09-27 17:50:46 +00:00
|
|
|
LaminarCi::Server(),
|
|
|
|
laminar(l)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-10-05 17:06:35 +00:00
|
|
|
virtual ~RpcImpl() {
|
2019-09-27 17:50:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Queue a job, without waiting for it to start
|
|
|
|
kj::Promise<void> queue(QueueContext context) override {
|
|
|
|
std::string jobName = context.getParams().getJobName();
|
|
|
|
LLOG(INFO, "RPC queue", jobName);
|
2020-09-25 03:29:30 +00:00
|
|
|
std::shared_ptr<Run> run = laminar.queueJob(jobName, params(context.getParams().getParams()));
|
|
|
|
if(Run* r = run.get()) {
|
|
|
|
context.getResults().setResult(LaminarCi::MethodResult::SUCCESS);
|
|
|
|
context.getResults().setBuildNum(r->build);
|
|
|
|
} else {
|
|
|
|
context.getResults().setResult(LaminarCi::MethodResult::FAILED);
|
|
|
|
}
|
2019-09-27 17:50:46 +00:00
|
|
|
return kj::READY_NOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start a job, without waiting for it to finish
|
|
|
|
kj::Promise<void> start(StartContext context) override {
|
|
|
|
std::string jobName = context.getParams().getJobName();
|
|
|
|
LLOG(INFO, "RPC start", jobName);
|
|
|
|
std::shared_ptr<Run> run = laminar.queueJob(jobName, params(context.getParams().getParams()));
|
|
|
|
if(Run* r = run.get()) {
|
|
|
|
return r->whenStarted().then([context,r]() mutable {
|
|
|
|
context.getResults().setResult(LaminarCi::MethodResult::SUCCESS);
|
|
|
|
context.getResults().setBuildNum(r->build);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
context.getResults().setResult(LaminarCi::MethodResult::FAILED);
|
|
|
|
return kj::READY_NOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start a job and wait for the result
|
|
|
|
kj::Promise<void> run(RunContext context) override {
|
|
|
|
std::string jobName = context.getParams().getJobName();
|
|
|
|
LLOG(INFO, "RPC run", jobName);
|
|
|
|
std::shared_ptr<Run> run = laminar.queueJob(jobName, params(context.getParams().getParams()));
|
2019-12-21 13:29:37 +00:00
|
|
|
if(run) {
|
|
|
|
return run->whenFinished().then([context,run](RunState state) mutable {
|
2019-09-27 17:50:46 +00:00
|
|
|
context.getResults().setResult(fromRunState(state));
|
2019-12-21 13:29:37 +00:00
|
|
|
context.getResults().setBuildNum(run->build);
|
2019-09-27 17:50:46 +00:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
context.getResults().setResult(LaminarCi::JobResult::UNKNOWN);
|
|
|
|
return kj::READY_NOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// List jobs in queue
|
|
|
|
kj::Promise<void> listQueued(ListQueuedContext context) override {
|
|
|
|
const std::list<std::shared_ptr<Run>>& queue = laminar.listQueuedJobs();
|
|
|
|
auto res = context.getResults().initResult(queue.size());
|
|
|
|
int i = 0;
|
|
|
|
for(auto it : queue) {
|
|
|
|
res.set(i++, it->name);
|
|
|
|
}
|
|
|
|
return kj::READY_NOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
// List running jobs
|
|
|
|
kj::Promise<void> listRunning(ListRunningContext context) override {
|
|
|
|
const RunSet& active = laminar.listRunningJobs();
|
|
|
|
auto res = context.getResults().initResult(active.size());
|
|
|
|
int i = 0;
|
|
|
|
for(auto it : active) {
|
|
|
|
res[i].setJob(it->name);
|
|
|
|
res[i].setBuildNum(it->build);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return kj::READY_NOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
// List known jobs
|
|
|
|
kj::Promise<void> listKnown(ListKnownContext context) override {
|
|
|
|
std::list<std::string> known = laminar.listKnownJobs();
|
|
|
|
auto res = context.getResults().initResult(known.size());
|
|
|
|
int i = 0;
|
|
|
|
for(auto it : known) {
|
|
|
|
res.set(i++, it);
|
|
|
|
}
|
|
|
|
return kj::READY_NOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
kj::Promise<void> abort(AbortContext context) override {
|
|
|
|
std::string jobName = context.getParams().getRun().getJob();
|
|
|
|
uint buildNum = context.getParams().getRun().getBuildNum();
|
|
|
|
LLOG(INFO, "RPC abort", jobName, buildNum);
|
|
|
|
LaminarCi::MethodResult result = laminar.abort(jobName, buildNum)
|
|
|
|
? LaminarCi::MethodResult::SUCCESS
|
|
|
|
: LaminarCi::MethodResult::FAILED;
|
|
|
|
context.getResults().setResult(result);
|
|
|
|
return kj::READY_NOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Helper to convert an RPC parameter list to a hash map
|
|
|
|
ParamMap params(const capnp::List<LaminarCi::JobParam>::Reader& paramReader) {
|
|
|
|
ParamMap res;
|
|
|
|
for(auto p : paramReader) {
|
|
|
|
res[p.getName().cStr()] = p.getValue().cStr();
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-10-05 17:06:35 +00:00
|
|
|
Laminar& laminar;
|
2019-09-27 17:50:46 +00:00
|
|
|
std::unordered_map<const Run*, std::list<kj::PromiseFulfillerPair<RunState>>> runWaiters;
|
|
|
|
};
|
|
|
|
|
2019-10-05 17:06:35 +00:00
|
|
|
Rpc::Rpc(Laminar& li) :
|
2019-09-27 17:50:46 +00:00
|
|
|
rpcInterface(kj::heap<RpcImpl>(li))
|
|
|
|
{}
|
|
|
|
|
|
|
|
// Context for an RPC connection
|
|
|
|
struct RpcConnection {
|
|
|
|
RpcConnection(kj::Own<kj::AsyncIoStream>&& stream,
|
|
|
|
capnp::Capability::Client bootstrap,
|
|
|
|
capnp::ReaderOptions readerOpts) :
|
|
|
|
stream(kj::mv(stream)),
|
|
|
|
network(*this->stream, capnp::rpc::twoparty::Side::SERVER, readerOpts),
|
|
|
|
rpcSystem(capnp::makeRpcServer(network, bootstrap))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
kj::Own<kj::AsyncIoStream> stream;
|
|
|
|
capnp::TwoPartyVatNetwork network;
|
|
|
|
capnp::RpcSystem<capnp::rpc::twoparty::VatId> rpcSystem;
|
|
|
|
};
|
|
|
|
|
|
|
|
kj::Promise<void> Rpc::accept(kj::Own<kj::AsyncIoStream>&& connection) {
|
|
|
|
auto server = kj::heap<RpcConnection>(kj::mv(connection), rpcInterface, capnp::ReaderOptions());
|
|
|
|
return server->network.onDisconnect().attach(kj::mv(server));
|
|
|
|
}
|