2015-09-13 20:25:26 +00:00
|
|
|
///
|
2018-07-20 11:15:59 +00:00
|
|
|
/// Copyright 2015-2018 Oliver Giles
|
2015-09-13 20:25:26 +00:00
|
|
|
///
|
|
|
|
/// 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.
|
|
|
|
///
|
2015-09-24 19:07:48 +00:00
|
|
|
/// Laminar is distributed in the hope that it will be useful,
|
2015-09-13 20:25:26 +00:00
|
|
|
/// 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/>
|
|
|
|
///
|
2017-12-20 06:24:25 +00:00
|
|
|
#ifndef LAMINAR_RUN_H_
|
|
|
|
#define LAMINAR_RUN_H_
|
2015-09-13 20:25:26 +00:00
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <queue>
|
2015-09-19 12:55:16 +00:00
|
|
|
#include <list>
|
2015-09-13 20:25:26 +00:00
|
|
|
#include <functional>
|
|
|
|
#include <ostream>
|
|
|
|
#include <unordered_map>
|
2018-04-20 11:18:10 +00:00
|
|
|
#include <memory>
|
2018-05-12 10:25:19 +00:00
|
|
|
#include <kj/async.h>
|
2018-09-28 07:36:10 +00:00
|
|
|
#include <kj/filesystem.h>
|
2015-09-13 20:25:26 +00:00
|
|
|
|
2019-07-04 09:28:33 +00:00
|
|
|
// Definition needed for musl
|
|
|
|
typedef unsigned int uint;
|
|
|
|
|
2015-09-13 20:25:26 +00:00
|
|
|
enum class RunState {
|
|
|
|
UNKNOWN,
|
|
|
|
PENDING,
|
2015-12-06 11:15:05 +00:00
|
|
|
RUNNING,
|
2015-09-13 20:25:26 +00:00
|
|
|
ABORTED,
|
|
|
|
FAILED,
|
|
|
|
SUCCESS
|
|
|
|
};
|
|
|
|
|
|
|
|
std::string to_string(const RunState& rs);
|
|
|
|
|
|
|
|
class Node;
|
|
|
|
|
2018-09-28 07:36:10 +00:00
|
|
|
typedef std::unordered_map<std::string, std::string> ParamMap;
|
|
|
|
|
|
|
|
// Represents an execution of a job.
|
2015-09-13 20:25:26 +00:00
|
|
|
class Run {
|
|
|
|
public:
|
2018-09-28 07:36:10 +00:00
|
|
|
Run(std::string name, ParamMap params, kj::Path&& rootPath);
|
2015-09-13 20:25:26 +00:00
|
|
|
~Run();
|
|
|
|
|
|
|
|
// copying this class would be asking for trouble...
|
|
|
|
Run(const Run&) = delete;
|
|
|
|
Run& operator=(const Run&) = delete;
|
|
|
|
|
2018-09-28 07:36:10 +00:00
|
|
|
// Call this to "start" the run with a specific number and node
|
|
|
|
bool configure(uint buildNum, std::shared_ptr<Node> node, const kj::Directory &fsHome);
|
|
|
|
|
2015-09-13 20:25:26 +00:00
|
|
|
// executes the next script (if any), returning true if there is nothing
|
2018-07-20 11:15:59 +00:00
|
|
|
// more to be done.
|
2015-09-13 20:25:26 +00:00
|
|
|
bool step();
|
|
|
|
|
2018-02-24 16:53:11 +00:00
|
|
|
// aborts this run
|
2018-09-09 09:15:23 +00:00
|
|
|
void abort(bool respectRunOnAbort);
|
2018-02-24 16:53:11 +00:00
|
|
|
|
2015-09-13 20:25:26 +00:00
|
|
|
// called when a process owned by this run has been reaped. The status
|
|
|
|
// may be used to set the run's job status
|
|
|
|
void reaped(int status);
|
|
|
|
|
|
|
|
std::string reason() const;
|
|
|
|
|
2018-09-28 07:36:10 +00:00
|
|
|
kj::Promise<void>&& whenStarted() { return kj::mv(started.promise); }
|
|
|
|
|
2018-04-20 11:18:10 +00:00
|
|
|
std::shared_ptr<Node> node;
|
2015-09-13 20:25:26 +00:00
|
|
|
RunState result;
|
2015-09-19 08:31:51 +00:00
|
|
|
RunState lastResult;
|
2015-09-13 20:25:26 +00:00
|
|
|
std::string name;
|
|
|
|
std::string parentName;
|
|
|
|
int parentBuild = 0;
|
2017-12-21 06:19:45 +00:00
|
|
|
uint build = 0;
|
2015-09-13 20:25:26 +00:00
|
|
|
std::string log;
|
2018-08-03 11:36:24 +00:00
|
|
|
kj::Maybe<pid_t> current_pid;
|
2018-07-20 11:15:59 +00:00
|
|
|
int output_fd;
|
2015-09-13 20:25:26 +00:00
|
|
|
std::unordered_map<std::string, std::string> params;
|
2019-02-15 16:24:36 +00:00
|
|
|
int timeout = 0;
|
2015-09-13 20:25:26 +00:00
|
|
|
|
|
|
|
time_t queuedAt;
|
|
|
|
time_t startedAt;
|
|
|
|
private:
|
2018-09-28 07:36:10 +00:00
|
|
|
// adds a script to the queue of scripts to be executed by this run
|
|
|
|
void addScript(kj::Path scriptPath, kj::Path scriptWorkingDir, bool runOnAbort = false);
|
|
|
|
|
|
|
|
// adds an environment file that will be sourced before this run
|
|
|
|
void addEnv(kj::Path path);
|
|
|
|
|
2017-08-07 05:06:49 +00:00
|
|
|
struct Script {
|
2018-09-28 07:36:10 +00:00
|
|
|
kj::Path path;
|
|
|
|
kj::Path cwd;
|
2018-09-09 09:15:23 +00:00
|
|
|
bool runOnAbort;
|
2017-08-07 05:06:49 +00:00
|
|
|
};
|
|
|
|
|
2018-09-28 07:36:10 +00:00
|
|
|
kj::Path rootPath;
|
2017-08-07 05:06:49 +00:00
|
|
|
std::queue<Script> scripts;
|
2018-09-28 07:36:10 +00:00
|
|
|
std::list<kj::Path> env;
|
|
|
|
std::string reasonMsg;
|
|
|
|
kj::PromiseFulfillerPair<void> started;
|
2015-09-13 20:25:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// All this below is a somewhat overengineered method of keeping track of
|
|
|
|
// currently executing builds (Run objects). This would probably scale
|
|
|
|
// very well, but it's completely gratuitous since we are not likely to
|
|
|
|
// be executing thousands of builds at the same time
|
|
|
|
#include <boost/multi_index_container.hpp>
|
|
|
|
#include <boost/multi_index/hashed_index.hpp>
|
|
|
|
#include <boost/multi_index/member.hpp>
|
|
|
|
#include <boost/multi_index/composite_key.hpp>
|
|
|
|
#include <boost/multi_index/global_fun.hpp>
|
|
|
|
#include <boost/multi_index/random_access_index.hpp>
|
|
|
|
#include <boost/multi_index/ordered_index.hpp>
|
|
|
|
|
|
|
|
namespace bmi = boost::multi_index;
|
|
|
|
|
2015-11-19 20:43:08 +00:00
|
|
|
struct _run_same {
|
2015-09-13 20:25:26 +00:00
|
|
|
typedef const Run* result_type;
|
|
|
|
const Run* operator()(const std::shared_ptr<Run>& run) const {
|
|
|
|
return run.get();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-11-19 20:43:08 +00:00
|
|
|
// A single Run can be fetched by...
|
|
|
|
struct _run_index : bmi::indexed_by<
|
2015-09-13 20:25:26 +00:00
|
|
|
bmi::hashed_unique<bmi::composite_key<
|
|
|
|
std::shared_ptr<Run>,
|
|
|
|
// a combination of their job name and build number
|
|
|
|
bmi::member<Run, std::string, &Run::name>,
|
2017-12-21 06:19:45 +00:00
|
|
|
bmi::member<Run, uint, &Run::build>
|
2015-09-13 20:25:26 +00:00
|
|
|
>>,
|
|
|
|
// or a pointer to a Run object.
|
2015-11-19 20:43:08 +00:00
|
|
|
bmi::hashed_unique<_run_same>,
|
2015-09-13 20:25:26 +00:00
|
|
|
// A group of Runs can be fetched by the time they started
|
|
|
|
bmi::ordered_non_unique<bmi::member<Run, time_t, &Run::startedAt>>,
|
|
|
|
// or by their job name
|
|
|
|
bmi::ordered_non_unique<bmi::member<Run, std::string, &Run::name>>
|
|
|
|
>
|
2015-11-19 20:43:08 +00:00
|
|
|
{};
|
|
|
|
|
|
|
|
struct RunSet: public boost::multi_index_container<
|
|
|
|
std::shared_ptr<Run>,
|
|
|
|
_run_index
|
2015-09-13 20:25:26 +00:00
|
|
|
> {
|
2018-07-20 11:15:59 +00:00
|
|
|
typename bmi::nth_index<RunSet, 0>::type& byNameNumber() { return get<0>(); }
|
|
|
|
typename bmi::nth_index<RunSet, 0>::type const& byNameNumber() const { return get<0>(); }
|
2017-12-20 07:02:12 +00:00
|
|
|
|
2018-07-20 11:15:59 +00:00
|
|
|
typename bmi::nth_index<RunSet, 1>::type& byRunPtr() { return get<1>(); }
|
|
|
|
typename bmi::nth_index<RunSet, 1>::type const& byRunPtr() const { return get<1>(); }
|
2017-12-20 07:02:12 +00:00
|
|
|
|
2018-07-20 11:15:59 +00:00
|
|
|
typename bmi::nth_index<RunSet, 2>::type& byStartedAt() { return get<2>(); }
|
|
|
|
typename bmi::nth_index<RunSet, 2>::type const& byStartedAt() const { return get<2>(); }
|
2017-12-20 07:02:12 +00:00
|
|
|
|
2018-07-20 11:15:59 +00:00
|
|
|
typename bmi::nth_index<RunSet, 3>::type& byJobName() { return get<3>(); }
|
|
|
|
typename bmi::nth_index<RunSet, 3>::type const& byJobName() const { return get<3>(); }
|
2015-09-13 20:25:26 +00:00
|
|
|
};
|
|
|
|
|
2017-12-20 06:24:25 +00:00
|
|
|
#endif // LAMINAR_RUN_H_
|