@pixlcore/xyrun 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/main.js +39 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ To use xyRun in a xyOps Event Plugin, make sure you set the Plugin's `runner` pr
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- Handles monitoring
|
|
11
|
+
- Handles monitoring processes, network connections, CPU and memory usage of remote jobs, and passing those metrics back to xyOps.
|
|
12
12
|
- Handles input files by creating a temporary directory for you job and pre-downloading all files from the xyOps master server.
|
|
13
13
|
- Handles output files by intercepting the `files` message and uploading them directly to the xyOps master server.
|
|
14
14
|
|
|
@@ -53,6 +53,12 @@ Then wrap your remote command with a `xyrun` prefix:
|
|
|
53
53
|
ssh user@target xyrun node /path/to/your-script.js
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
# Script Mode
|
|
57
|
+
|
|
58
|
+
When no sub-command is specified on the CLI, xyRun will look inside the job JSON data (passed in via STDIN) for a parameter named `script`. If this is found, it is quickly written out to a temp file, made executable (775), and that is what it launches. It is assumed that the provided `script` will contain a proper [Shebang](https://en.wikipedia.org/wiki/Shebang_%28Unix%29) line.
|
|
59
|
+
|
|
60
|
+
This allows xyRun to act as a "Remote Shell Plugin" for certain xyOps jobs that require it.
|
|
61
|
+
|
|
56
62
|
# Development
|
|
57
63
|
|
|
58
64
|
You can install the source code by using [Git](https://en.wikipedia.org/wiki/Git) ([Node.js](https://nodejs.org/) is also required):
|
package/main.js
CHANGED
|
@@ -16,6 +16,8 @@ const pkg = require('./package.json');
|
|
|
16
16
|
const noop = function() {};
|
|
17
17
|
const async = Tools.async;
|
|
18
18
|
|
|
19
|
+
process.title = "xyRun";
|
|
20
|
+
|
|
19
21
|
const app = {
|
|
20
22
|
|
|
21
23
|
activeJobs: {},
|
|
@@ -129,8 +131,26 @@ const app = {
|
|
|
129
131
|
var child = null;
|
|
130
132
|
var worker = {};
|
|
131
133
|
|
|
134
|
+
// setup environment for child
|
|
132
135
|
var child_args = process.argv.slice(2);
|
|
133
136
|
var child_cmd = child_args.shift();
|
|
137
|
+
var child_opts = {
|
|
138
|
+
env: Object.assign( {}, process.env )
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
if (!child_cmd && job.params && job.params.script) {
|
|
142
|
+
// no direct command specified, but user wants a "script" executed from the job params
|
|
143
|
+
var script_file = Path.join( job.cwd, 'xyops-script-temp-' + job.id + '.sh' );
|
|
144
|
+
child_cmd = Path.resolve(script_file);
|
|
145
|
+
child_args = [];
|
|
146
|
+
|
|
147
|
+
// quickly write out script file and make it executable
|
|
148
|
+
Tools.mkdirpSync( job.cwd, { mode: 0o777 } );
|
|
149
|
+
fs.writeFileSync( script_file, job.params.script.replace(/\r\n/g, "\n"), { mode: 0o775 } );
|
|
150
|
+
|
|
151
|
+
// set the cwd to the job cwd, as it's a more controlled environment
|
|
152
|
+
child_opts.cwd = job.cwd;
|
|
153
|
+
}
|
|
134
154
|
|
|
135
155
|
if (!child_cmd) {
|
|
136
156
|
// no command!
|
|
@@ -155,11 +175,6 @@ const app = {
|
|
|
155
175
|
|
|
156
176
|
console.log( "Running command: " + child_cmd, child_args );
|
|
157
177
|
|
|
158
|
-
// setup environment for child
|
|
159
|
-
var child_opts = {
|
|
160
|
-
env: Object.assign( {}, process.env )
|
|
161
|
-
};
|
|
162
|
-
|
|
163
178
|
// get uid / gid info for child env vars
|
|
164
179
|
if (!this.platform.windows) {
|
|
165
180
|
child_opts.uid = job.uid || process.getuid();
|
|
@@ -335,7 +350,7 @@ const app = {
|
|
|
335
350
|
if (job.kill === 'none') {
|
|
336
351
|
// kill none, just unref and finish
|
|
337
352
|
worker.child.unref();
|
|
338
|
-
this.
|
|
353
|
+
this.finishJob();
|
|
339
354
|
return;
|
|
340
355
|
}
|
|
341
356
|
|
|
@@ -436,9 +451,6 @@ const app = {
|
|
|
436
451
|
|
|
437
452
|
if (!file.path) return; // sanity
|
|
438
453
|
|
|
439
|
-
// prepend job cwd if path is not absolute
|
|
440
|
-
if (!Path.isAbsolute(file.path)) file.path = Path.join(job.cwd, file.path);
|
|
441
|
-
|
|
442
454
|
if (file.filename) {
|
|
443
455
|
// if user specified a custom filename, then do not perform a glob
|
|
444
456
|
to_upload.push(file);
|
|
@@ -463,9 +475,18 @@ const app = {
|
|
|
463
475
|
// upload all job files (from user) if applicable
|
|
464
476
|
var self = this;
|
|
465
477
|
var final_files = [];
|
|
466
|
-
|
|
478
|
+
|
|
467
479
|
if (!job.files || !job.files.length || !Tools.isaArray(job.files)) return callback();
|
|
468
480
|
|
|
481
|
+
if (!job.base_url) {
|
|
482
|
+
console.error("Error: Cannot upload files: Missing 'base_url' property in job data.");
|
|
483
|
+
return callback();
|
|
484
|
+
}
|
|
485
|
+
if (!job.auth_token) {
|
|
486
|
+
console.error("Error: Cannot upload files: Missing 'auth_token' property in job data.");
|
|
487
|
+
return callback();
|
|
488
|
+
}
|
|
489
|
+
|
|
469
490
|
async.eachSeries( job.files,
|
|
470
491
|
function(file, callback) {
|
|
471
492
|
var filename = Path.basename(file.filename || file.path).replace(/[^\w\-\+\.\,\s\(\)\[\]\{\}\'\"\!\&\^\%\$\#\@\*\?\~]+/g, '_');
|
|
@@ -503,7 +524,7 @@ const app = {
|
|
|
503
524
|
filename: filename,
|
|
504
525
|
path: json.key,
|
|
505
526
|
size: json.size,
|
|
506
|
-
server:
|
|
527
|
+
server: job.server,
|
|
507
528
|
job: job.id
|
|
508
529
|
});
|
|
509
530
|
|
|
@@ -567,8 +588,8 @@ const app = {
|
|
|
567
588
|
return;
|
|
568
589
|
}
|
|
569
590
|
|
|
570
|
-
// update job data
|
|
571
|
-
console.log( JSON.stringify({ xy: 1, procs: job.procs, conns: job.conns, cpu: job.cpu, mem: job.mem }) );
|
|
591
|
+
// update job data with stats in tow
|
|
592
|
+
console.log( JSON.stringify({ xy: 1, rpid: process.pid, procs: job.procs, conns: job.conns, cpu: job.cpu, mem: job.mem }) );
|
|
572
593
|
|
|
573
594
|
self.jobTickInProgress = false;
|
|
574
595
|
}
|
|
@@ -579,20 +600,21 @@ const app = {
|
|
|
579
600
|
measureJobResources(job, pids) {
|
|
580
601
|
// scan process list for all processes that are descendents of job pid
|
|
581
602
|
delete job.procs;
|
|
603
|
+
var root_pid = process.pid;
|
|
582
604
|
|
|
583
|
-
if (pids[
|
|
605
|
+
if (pids[ root_pid ]) {
|
|
584
606
|
// add all procs into job
|
|
585
607
|
job.procs = {};
|
|
586
|
-
job.procs[
|
|
608
|
+
job.procs[ root_pid ] = pids[ root_pid ];
|
|
587
609
|
|
|
588
|
-
var info = pids[
|
|
610
|
+
var info = pids[ root_pid ];
|
|
589
611
|
var cpu = info.cpu;
|
|
590
612
|
var mem = info.memRss;
|
|
591
613
|
|
|
592
614
|
// also consider children of the child (up to 100 generations deep)
|
|
593
615
|
var levels = 0;
|
|
594
616
|
var family = {};
|
|
595
|
-
family[
|
|
617
|
+
family[ root_pid ] = 1;
|
|
596
618
|
|
|
597
619
|
while (Tools.numKeys(family) && (++levels <= 100)) {
|
|
598
620
|
for (var fpid in family) {
|