ultravisor 1.0.0
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/.vscode/launch.json +15 -0
- package/LICENSE +21 -0
- package/README.md +119 -0
- package/debug/Harness.js +4 -0
- package/package.json +51 -0
- package/source/Ultravisor.cjs +5 -0
- package/source/cli/Ultravisor-CLIProgram.cjs +79 -0
- package/source/cli/Ultravisor-Run.cjs +3 -0
- package/source/cli/commands/Ultravisor-Command-ScheduleOperation.cjs +28 -0
- package/source/cli/commands/Ultravisor-Command-ScheduleTask.cjs +28 -0
- package/source/cli/commands/Ultravisor-Command-ScheduleView.cjs +25 -0
- package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +26 -0
- package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +27 -0
- package/source/cli/commands/Ultravisor-Command-Start.cjs +25 -0
- package/source/cli/commands/Ultravisor-Command-Stop.cjs +21 -0
- package/source/config/Ultravisor-Default-Command-Configuration.cjs +5 -0
- package/source/services/Ultravisor-Hypervisor-Event-Base.cjs +11 -0
- package/source/services/Ultravisor-Hypervisor.cjs +11 -0
- package/source/services/Ultravisor-Operation-Manifest.cjs +11 -0
- package/source/services/Ultravisor-Operation.cjs +11 -0
- package/source/services/Ultravisor-Task.cjs +11 -0
- package/source/services/events/Ultravisor-Hypervisor-Event-Cron.cjs +11 -0
- package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +11 -0
- package/source/web_server/Ultravisor-API-Server.cjs +119 -0
- package/test/Ultravisor_tests.js +34 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2.0",
|
|
3
|
+
"configurations": [
|
|
4
|
+
{
|
|
5
|
+
"type": "node",
|
|
6
|
+
"request": "launch",
|
|
7
|
+
"name": "Debug Harness",
|
|
8
|
+
"skipFiles": [
|
|
9
|
+
"<node_internals>/**"
|
|
10
|
+
],
|
|
11
|
+
"program": "${workspaceFolder}/debug/Harness.js",
|
|
12
|
+
"cwd": "${workspaceFolder}/debug"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Steven Velozo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Ultravisor
|
|
2
|
+
|
|
3
|
+
Like a supervisor, only instead of super it's ULTRA. The hidden sixth hero of
|
|
4
|
+
Voltron. This tool allows you to run commands on schedule and process output
|
|
5
|
+
with llm models, providing user-friendly summaries and links back to the full
|
|
6
|
+
complete output from command running.
|
|
7
|
+
|
|
8
|
+
## Use Cases
|
|
9
|
+
|
|
10
|
+
* Periodic data pull from a REST API with localized storage
|
|
11
|
+
* Data integrations between one system and another
|
|
12
|
+
* Automatic execution of image generation models with randomized word choices
|
|
13
|
+
* Parsing of massive sets of files for meaning leveraging ai
|
|
14
|
+
|
|
15
|
+
## Primary Concepts
|
|
16
|
+
|
|
17
|
+
Ultravisor operates on a few key concepts:
|
|
18
|
+
|
|
19
|
+
* operation - one or many tasks that run in sequence and/or parallel
|
|
20
|
+
* task - this is the verb... "what to do"
|
|
21
|
+
* node - a specific executing ultravisor (often just one, but can be a cluster)
|
|
22
|
+
* global state - data shared across all tasks
|
|
23
|
+
* node state - data accessible locally only (when running with node affinity)
|
|
24
|
+
* metaoutput - the output from tasks and operations
|
|
25
|
+
* operation staging - temporary data from an operation
|
|
26
|
+
* output file store - final file output from an operation
|
|
27
|
+
* output data store - flexible database of final outputs from operations
|
|
28
|
+
|
|
29
|
+
### Operations
|
|
30
|
+
|
|
31
|
+
An operation is, generally speaking, a set of tasks. Tasks can be composed to
|
|
32
|
+
react to certain data/state situations. With clever use of global state, they
|
|
33
|
+
can even perform complicated series of actions across operations.
|
|
34
|
+
|
|
35
|
+
For instance, I could have one operation that runs a number of tasks on a
|
|
36
|
+
schedule to pull temperature from various locations in my house. Each task
|
|
37
|
+
can store the values in some kind of API, and, keep track of the latest value
|
|
38
|
+
as well as timestamp in global state. These tasks might run every 5-10 seconds
|
|
39
|
+
or so; where they store the data may be
|
|
40
|
+
|
|
41
|
+
Then, a second operation could be running every minute that inspects the global
|
|
42
|
+
state and adjusts a localized thermostat based on the current temperatures.
|
|
43
|
+
|
|
44
|
+
Or maybe I have a NAS full of video files that I would like to run a series of
|
|
45
|
+
machine learning algorithms on, to generate metadata on when scene cuts were
|
|
46
|
+
made in each film. I could setup an operation with a task to watch the cpu,
|
|
47
|
+
iops and memory load of a machine and run parallel tasks that saturate the
|
|
48
|
+
iops/cpu on the machine. This would be a scheduled, parameterized parallel set
|
|
49
|
+
of tasks.
|
|
50
|
+
|
|
51
|
+
### Tasks
|
|
52
|
+
|
|
53
|
+
Tasks can be really any program that is executable from a local shell, or,
|
|
54
|
+
within a browser environment. The browser part is especially interesting
|
|
55
|
+
since you can basically script sets of actions within web pages (e.g.
|
|
56
|
+
downloading all the files listed on a page... and/or enumerating all the pages
|
|
57
|
+
and running the recursive download task for each page).
|
|
58
|
+
|
|
59
|
+
Tasks can be executed based on a number of scenarios:
|
|
60
|
+
|
|
61
|
+
* On a schedule (5pm every day, every 5 minutes, up to 5 times a minute)
|
|
62
|
+
* After a condition is met (a condition in a browser, a disk drops below 5g)
|
|
63
|
+
* After another task is completed (ffmpeg returns successfully transcoding)
|
|
64
|
+
|
|
65
|
+
### Nodes
|
|
66
|
+
|
|
67
|
+
Any execution of Ultravisor. Can be distributed across multiple machines.
|
|
68
|
+
|
|
69
|
+
When run with multiple nodes, there is a star topology with the capability for
|
|
70
|
+
nodes to self promote to be the central node if the central node goes away.
|
|
71
|
+
|
|
72
|
+
### Global State
|
|
73
|
+
|
|
74
|
+
Global state is simple/plain JSON object that's synchronized across nodes. It
|
|
75
|
+
is meant to be used to store small facts and not process management state (e.g.
|
|
76
|
+
it isn't an appropriate storage location for a mutex lock but is great for the
|
|
77
|
+
most recent temperature readings from a set of sensors).
|
|
78
|
+
|
|
79
|
+
### Node State
|
|
80
|
+
|
|
81
|
+
Node state is similar to global state, but is only accessible to the local node
|
|
82
|
+
the task is running on. This is useful for storing configuration, paths or
|
|
83
|
+
other node-specific information.
|
|
84
|
+
|
|
85
|
+
### Metaoutput
|
|
86
|
+
|
|
87
|
+
Metaoutput is the output from running tasks and operations. It is stored in a
|
|
88
|
+
simple JSON manifest including consistent fields for understanding:
|
|
89
|
+
|
|
90
|
+
* Summary of Output
|
|
91
|
+
* Start Time, Stop Time, Status, Success/Failure for the Operation
|
|
92
|
+
* Start Time, Stop Time, Status, Success/Failure for each Task
|
|
93
|
+
* Output Data (text, json, binary, files, etc.)
|
|
94
|
+
* Run Log(s) for Tasks
|
|
95
|
+
* Links to Output
|
|
96
|
+
* Anything Else the Task/Operation Wants to Report
|
|
97
|
+
|
|
98
|
+
### Operation Staging
|
|
99
|
+
|
|
100
|
+
Operation staging is temporary storage for data during the execution of an
|
|
101
|
+
operation. This is useful for storing intermediate files, logs, or other data
|
|
102
|
+
that is not needed after the operation completes.
|
|
103
|
+
|
|
104
|
+
Operations can be flagged to have node affinity, or not. If affinity is set,
|
|
105
|
+
all tasks for the operation will run on the same node, allowing for enormous
|
|
106
|
+
local file stores for the operation itself. This is great for Machine Learning
|
|
107
|
+
operations that need to store large source files, intermediate learning data
|
|
108
|
+
and final output files.
|
|
109
|
+
|
|
110
|
+
### Output File Store
|
|
111
|
+
|
|
112
|
+
The centralized location for all final output files from operations. This is
|
|
113
|
+
meant to be a persistent storage location that is accessible across nodes.
|
|
114
|
+
|
|
115
|
+
### Output Data Store
|
|
116
|
+
|
|
117
|
+
The output data store is a flexible database for storing final output data from
|
|
118
|
+
operations. This can be used to store structured data, metadata, or any other
|
|
119
|
+
information that needs to be queried or analyzed later.
|
package/debug/Harness.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ultravisor",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cyclic process execution with ai integration.",
|
|
5
|
+
"main": "source/Ultravisor.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ultravisor": "./source/cli/Ultravisor-Run.cjs"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node source/cli/Ultravisor-Run.cjs",
|
|
11
|
+
"test": "npx mocha -u tdd -R spec",
|
|
12
|
+
"tests": "npx mocha -u tdd --exit -R spec --grep",
|
|
13
|
+
"coverage": "npx nyc --reporter=lcov --reporter=text-lcov npx mocha -- -u tdd -R spec",
|
|
14
|
+
"build": "npx quack build"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/stevenvelozo/ultravisor.git"
|
|
19
|
+
},
|
|
20
|
+
"author": "steven@velozo.com",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/stevenvelozo/ultravisor/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/stevenvelozo/ultravisor#readme",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"orator": "^5.0.1",
|
|
28
|
+
"orator-serviceserver-restify": "^2.0.5",
|
|
29
|
+
"pict": "^1.0.343",
|
|
30
|
+
"pict-service-commandlineutility": "^1.0.17",
|
|
31
|
+
"pict-serviceproviderbase": "^1.0.0"
|
|
32
|
+
},
|
|
33
|
+
"mocha": {
|
|
34
|
+
"diff": true,
|
|
35
|
+
"extension": [
|
|
36
|
+
"js"
|
|
37
|
+
],
|
|
38
|
+
"package": "./package.json",
|
|
39
|
+
"reporter": "spec",
|
|
40
|
+
"slow": "75",
|
|
41
|
+
"timeout": "5000",
|
|
42
|
+
"ui": "tdd",
|
|
43
|
+
"watch-files": [
|
|
44
|
+
"source/**/*.js",
|
|
45
|
+
"test/**/*.js"
|
|
46
|
+
],
|
|
47
|
+
"watch-ignore": [
|
|
48
|
+
"lib/vendor"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const libCLIProgram = require('pict-service-commandlineutility');
|
|
2
|
+
|
|
3
|
+
const libServiceHypervisor = require(`../services/Ultravisor-Hypervisor.cjs`);
|
|
4
|
+
|
|
5
|
+
const libServiceHypervisorEventBase = require(`../services/Ultravisor-Hypervisor-Event-Base.cjs`);
|
|
6
|
+
const libServiceHypervisorEventCron = require(`../services/events/Ultravisor-Hypervisor-Event-Cron.cjs`);
|
|
7
|
+
const libServiceHypervisorEventSolver = require(`../services/events/Ultravisor-Hypervisor-Event-Solver.cjs`);
|
|
8
|
+
|
|
9
|
+
const libServiceOperation = require(`../services/Ultravisor-Operation.cjs`);
|
|
10
|
+
const libServiceOperationManifest = require(`../services/Ultravisor-Operation-Manifest.cjs`);
|
|
11
|
+
|
|
12
|
+
const libServiceTask = require(`../services/Ultravisor-Task.cjs`);
|
|
13
|
+
|
|
14
|
+
// TODO: Remove this when Restify is fixed.
|
|
15
|
+
process.removeAllListeners('warning')
|
|
16
|
+
|
|
17
|
+
const libWebServerAPIServer = require(`../web_server/Ultravisor-API-Server.cjs`);
|
|
18
|
+
|
|
19
|
+
let _Ultravisor_Pict = new libCLIProgram(
|
|
20
|
+
{
|
|
21
|
+
"Product": "Ultravisor-CLI",
|
|
22
|
+
"Version": require('../../package.json').version,
|
|
23
|
+
"Description": require('../../package.json').description,
|
|
24
|
+
|
|
25
|
+
"Package": require('../../package.json'),
|
|
26
|
+
|
|
27
|
+
"LogStreams":
|
|
28
|
+
[
|
|
29
|
+
{
|
|
30
|
+
"level": "trace",
|
|
31
|
+
"streamtype": "process.stdout"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
|
|
35
|
+
"Command": "ultravisor",
|
|
36
|
+
|
|
37
|
+
"DefaultProgramConfiguration": require(`../config/Ultravisor-Default-Command-Configuration.cjs`),
|
|
38
|
+
|
|
39
|
+
"ProgramConfigurationFileName": ".ultravisor.json",
|
|
40
|
+
|
|
41
|
+
"AutoGatherProgramConfiguration": true,
|
|
42
|
+
"AutoAddConfigurationExplanationCommand": true
|
|
43
|
+
},
|
|
44
|
+
[
|
|
45
|
+
// Display the current ultravisor schedule
|
|
46
|
+
require('./commands/Ultravisor-Command-ScheduleView.cjs'),
|
|
47
|
+
|
|
48
|
+
// Add a task or operation to the current ultravisor schedule
|
|
49
|
+
require('./commands/Ultravisor-Command-ScheduleOperation.cjs'),
|
|
50
|
+
require('./commands/Ultravisor-Command-ScheduleTask.cjs'),
|
|
51
|
+
|
|
52
|
+
// Execute a single operation or task immediately, no matter what
|
|
53
|
+
require('./commands/Ultravisor-Command-SingleOperation.cjs'),
|
|
54
|
+
require('./commands/Ultravisor-Command-SingleTask.cjs'),
|
|
55
|
+
|
|
56
|
+
// Start and/or stop the hypervisor, API and web server
|
|
57
|
+
require('./commands/Ultravisor-Command-Start.cjs'),
|
|
58
|
+
require('./commands/Ultravisor-Command-Stop.cjs')
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
// Instantiate the file persistence service
|
|
62
|
+
_Ultravisor_Pict.instantiateServiceProvider('FilePersistence');
|
|
63
|
+
// Instantiate the data generation service
|
|
64
|
+
_Ultravisor_Pict.instantiateServiceProvider('DataGeneration');
|
|
65
|
+
|
|
66
|
+
_Ultravisor_Pict.fable.addAndInstantiateServiceTypeIfNotExists('Ultravisor-Hypervisor', libServiceHypervisor);
|
|
67
|
+
|
|
68
|
+
_Ultravisor_Pict.fable.addAndInstantiateServiceTypeIfNotExists('Ultravisor-Hypervisor-Event-Base', libServiceHypervisorEventBase);
|
|
69
|
+
_Ultravisor_Pict.fable.addAndInstantiateServiceTypeIfNotExists('Ultravisor-Hypervisor-Event-Cron', libServiceHypervisorEventCron);
|
|
70
|
+
_Ultravisor_Pict.fable.addAndInstantiateServiceTypeIfNotExists('Ultravisor-Hypervisor-Event-Solver', libServiceHypervisorEventSolver);
|
|
71
|
+
|
|
72
|
+
_Ultravisor_Pict.fable.addAndInstantiateServiceTypeIfNotExists('Ultravisor-Operation', libServiceOperation);
|
|
73
|
+
_Ultravisor_Pict.fable.addAndInstantiateServiceTypeIfNotExists('Ultravisor-Operation-Manifest', libServiceOperationManifest);
|
|
74
|
+
|
|
75
|
+
_Ultravisor_Pict.fable.addAndInstantiateServiceTypeIfNotExists('Ultravisor-Task', libServiceTask);
|
|
76
|
+
|
|
77
|
+
_Ultravisor_Pict.fable.addAndInstantiateServiceTypeIfNotExists('Ultravisor-API-Server', libWebServerAPIServer);
|
|
78
|
+
|
|
79
|
+
module.exports = _Ultravisor_Pict;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const libCommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
|
|
2
|
+
|
|
3
|
+
class UltravisorCommandScheduleOperation extends libCommandLineCommand
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pManifest, pServiceHash);
|
|
8
|
+
|
|
9
|
+
this.options.CommandKeyword = 'schedule_operation';
|
|
10
|
+
this.options.Description = 'Add an operation to the schedule.';
|
|
11
|
+
|
|
12
|
+
this.options.CommandArguments.push({ Name: '<operation>', Description: 'The operation to add to the schedule.' });
|
|
13
|
+
|
|
14
|
+
this.options.CommandOptions.push({ Name: '-t, --type [event_schedule_type]', Description: 'The event schedule type (cron, daily, hourly, solver).', Default: 'cron' });
|
|
15
|
+
this.options.CommandOptions.push({ Name: '-p, --parameters [event_schedule_parameters]', Description: 'The parameters for the schedule (e.g. the crontab entry or solver string).', Default: '' });
|
|
16
|
+
|
|
17
|
+
this.options.Aliases.push('so');
|
|
18
|
+
|
|
19
|
+
this.addCommand();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onRunAsync(fCallback)
|
|
23
|
+
{
|
|
24
|
+
return fCallback();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = UltravisorCommandScheduleOperation;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const libCommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
|
|
2
|
+
|
|
3
|
+
class UltravisorCommandScheduleTask extends libCommandLineCommand
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pManifest, pServiceHash);
|
|
8
|
+
|
|
9
|
+
this.options.CommandKeyword = 'schedule_task';
|
|
10
|
+
this.options.Description = 'Add a task to the schedule.';
|
|
11
|
+
|
|
12
|
+
this.options.CommandArguments.push({ Name: '<task>', Description: 'The task to add to the schedule.' });
|
|
13
|
+
|
|
14
|
+
this.options.CommandOptions.push({ Name: '-t, --type [event_schedule_type]', Description: 'The event schedule type (cron, daily, hourly, solver).', Default: 'cron' });
|
|
15
|
+
this.options.CommandOptions.push({ Name: '-p, --parameters [event_schedule_parameters]', Description: 'The parameters for the schedule (e.g. the crontab entry or solver string).', Default: '' });
|
|
16
|
+
|
|
17
|
+
this.options.Aliases.push('st');
|
|
18
|
+
|
|
19
|
+
this.addCommand();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onRunAsync(fCallback)
|
|
23
|
+
{
|
|
24
|
+
return fCallback();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = UltravisorCommandScheduleTask;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const libCommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
|
|
2
|
+
|
|
3
|
+
class UltravisorCommandScheduleView extends libCommandLineCommand
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pManifest, pServiceHash);
|
|
8
|
+
|
|
9
|
+
this.options.CommandKeyword = 'schedule';
|
|
10
|
+
this.options.Description = 'View the schedule.';
|
|
11
|
+
|
|
12
|
+
this.options.CommandOptions.push({ Name: '-f, --format [schedule_format]', Description: 'The visualization format (day, week, month) to output.', Default: 'day' });
|
|
13
|
+
|
|
14
|
+
this.options.Aliases.push('cal');
|
|
15
|
+
|
|
16
|
+
this.addCommand();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
onRunAsync(fCallback)
|
|
20
|
+
{
|
|
21
|
+
return fCallback();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = UltravisorCommandScheduleView;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const libCommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
|
|
2
|
+
|
|
3
|
+
class UltravisorCommandSingleOperationRun extends libCommandLineCommand
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pManifest, pServiceHash);
|
|
8
|
+
|
|
9
|
+
this.options.CommandKeyword = 'singleoperation';
|
|
10
|
+
this.options.Description = 'Execute a single ultravisor operation immediately, no matter what.';
|
|
11
|
+
|
|
12
|
+
this.options.CommandArguments.push({ Name: '<operation>', Description: 'The operation(s) to run.' });
|
|
13
|
+
this.options.CommandOptions.push({ Name: '-d, --dry_run', Description: 'Dry run the task.', Default: false });
|
|
14
|
+
|
|
15
|
+
this.options.Aliases.push('operation');
|
|
16
|
+
|
|
17
|
+
this.addCommand();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
onRunAsync(fCallback)
|
|
21
|
+
{
|
|
22
|
+
return fCallback();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = UltravisorCommandSingleOperationRun;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const libCommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
|
|
2
|
+
|
|
3
|
+
class UltravisorCommandSingleTaskRun extends libCommandLineCommand
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pManifest, pServiceHash);
|
|
8
|
+
|
|
9
|
+
this.options.CommandKeyword = 'singletask';
|
|
10
|
+
this.options.Description = 'Execute a single ultravisor task immediately, no matter what.';
|
|
11
|
+
|
|
12
|
+
this.options.CommandArguments.push({ Name: '<task>', Description: 'The task(s) to run.' });
|
|
13
|
+
this.options.CommandOptions.push({ Name: '-o, --operation [operation]', Description: 'The operation to scope the task(s) to.', Default: 'Default' });
|
|
14
|
+
this.options.CommandOptions.push({ Name: '-d, --dry_run', Description: 'Dry run the task.', Default: false });
|
|
15
|
+
|
|
16
|
+
this.options.Aliases.push('task');
|
|
17
|
+
|
|
18
|
+
this.addCommand();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
onRunAsync(fCallback)
|
|
22
|
+
{
|
|
23
|
+
return fCallback();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = UltravisorCommandSingleTaskRun;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const libCommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
|
|
2
|
+
|
|
3
|
+
class UltravisorCommandStartService extends libCommandLineCommand
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pManifest, pServiceHash);
|
|
8
|
+
|
|
9
|
+
this.options.CommandKeyword = 'start';
|
|
10
|
+
this.options.Description = 'Start the Ultravisor service.';
|
|
11
|
+
|
|
12
|
+
this.options.CommandOptions.push({ Name: '-v, --verbose', Description: 'Provide verbose console output.', Default: false });
|
|
13
|
+
|
|
14
|
+
this.addCommand();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
onRunAsync(fCallback)
|
|
18
|
+
{
|
|
19
|
+
// TODO: What to do with verbose!
|
|
20
|
+
console.log(`Starting Ultravisor API Server...`);
|
|
21
|
+
return this.fable['Ultravisor-API-Server'].start(fCallback);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = UltravisorCommandStartService;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const libCommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
|
|
2
|
+
|
|
3
|
+
class UltravisorCommandStopService extends libCommandLineCommand
|
|
4
|
+
{
|
|
5
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pFable, pManifest, pServiceHash);
|
|
8
|
+
|
|
9
|
+
this.options.CommandKeyword = 'stop';
|
|
10
|
+
this.options.Description = 'Stop the Ultravisor service.';
|
|
11
|
+
|
|
12
|
+
this.addCommand();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
onRunAsync(fCallback)
|
|
16
|
+
{
|
|
17
|
+
return fCallback();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = UltravisorCommandStopService;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const libPictService = require(`pict-serviceproviderbase`);
|
|
2
|
+
|
|
3
|
+
class UltravisorHypervisor extends libPictService
|
|
4
|
+
{
|
|
5
|
+
constructor(pPict, pOptions, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pPict, pOptions, pServiceHash);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = UltravisorHypervisor;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const libPictService = require(`pict-serviceproviderbase`);
|
|
2
|
+
|
|
3
|
+
class UltravisorOperationManifest extends libPictService
|
|
4
|
+
{
|
|
5
|
+
constructor(pPict, pOptions, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pPict, pOptions, pServiceHash);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = UltravisorOperationManifest;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const libUltravisorEventBase = require(`../Ultravisor-Hypervisor-Event-Base.cjs`);
|
|
2
|
+
|
|
3
|
+
class UltravisorEventCron extends libUltravisorEventBase
|
|
4
|
+
{
|
|
5
|
+
constructor(pPict, pOptions, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pPict, pOptions, pServiceHash);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = UltravisorEventCron;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const libUltravisorEventBase = require(`../Ultravisor-Hypervisor-Event-Base.cjs`);
|
|
2
|
+
|
|
3
|
+
class UltravisorEventSolver extends libUltravisorEventBase
|
|
4
|
+
{
|
|
5
|
+
constructor(pPict, pOptions, pServiceHash)
|
|
6
|
+
{
|
|
7
|
+
super(pPict, pOptions, pServiceHash);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = UltravisorEventSolver;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const libPictService = require(`pict-serviceproviderbase`);
|
|
2
|
+
|
|
3
|
+
const libOrator = require('orator');
|
|
4
|
+
const libOratorServiceServerRestify = require(`orator-serviceserver-restify`);
|
|
5
|
+
|
|
6
|
+
class UltravisorAPIServer extends libPictService
|
|
7
|
+
{
|
|
8
|
+
constructor(pPict, pOptions, pServiceHash)
|
|
9
|
+
{
|
|
10
|
+
super(pPict, pOptions, pServiceHash);
|
|
11
|
+
|
|
12
|
+
// Add Restify as the default service server type
|
|
13
|
+
this.fable.addServiceTypeIfNotExists('OratorServiceServer', libOratorServiceServerRestify);
|
|
14
|
+
this._OratorServer = this.fable.instantiateServiceProvider('OratorServiceServer', {});
|
|
15
|
+
|
|
16
|
+
// Add Orator as a service
|
|
17
|
+
this.fable.addServiceTypeIfNotExists('Orator', libOrator);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
wireEndpoints(fCallback)
|
|
21
|
+
{
|
|
22
|
+
if (!this._Orator)
|
|
23
|
+
{
|
|
24
|
+
return fCallback(new Error(`Ultravisor API Server: Cannot wire endpoints; Orator service is not initialized.`));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this._OratorServer.get
|
|
28
|
+
(
|
|
29
|
+
'/package',
|
|
30
|
+
(pRequest, pResponse, fNext) =>
|
|
31
|
+
{
|
|
32
|
+
// Send back the request parameters
|
|
33
|
+
pResponse.send(this.pict.settings.Package);
|
|
34
|
+
return fNext();
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return fCallback();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
start(fCallback)
|
|
42
|
+
{
|
|
43
|
+
const tmpAnticipate = this.fable.newAnticipate();
|
|
44
|
+
|
|
45
|
+
tmpAnticipate.anticipate(
|
|
46
|
+
function (fNext)
|
|
47
|
+
{
|
|
48
|
+
// Initialize the Orator service
|
|
49
|
+
if (!this.fable.settings.APIServerPort)
|
|
50
|
+
{
|
|
51
|
+
if (this.fable?.ProgramConfiguration?.UltravisorAPIServerPort)
|
|
52
|
+
{
|
|
53
|
+
this.fable.settings.APIServerPort = this.fable.ProgramConfiguration.UltravisorAPIServerPort;
|
|
54
|
+
}
|
|
55
|
+
else
|
|
56
|
+
{
|
|
57
|
+
this.fable.settings.APIServerPort = 55555;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return fNext();
|
|
61
|
+
}.bind(this));
|
|
62
|
+
|
|
63
|
+
this._Orator = this.fable.instantiateServiceProvider('Orator', {});
|
|
64
|
+
|
|
65
|
+
tmpAnticipate.anticipate(
|
|
66
|
+
function (fNext)
|
|
67
|
+
{
|
|
68
|
+
this.log.info(`Initializing Ultravisor Orator API Server on port ${this.fable.settings.APIServerPort}`);
|
|
69
|
+
this._Orator.initialize(
|
|
70
|
+
function (pError)
|
|
71
|
+
{
|
|
72
|
+
if (pError)
|
|
73
|
+
{
|
|
74
|
+
this.log.info(`Error initializing Orator for Ultravisor ${pError}`, pError);
|
|
75
|
+
return fCallback(pError);
|
|
76
|
+
}
|
|
77
|
+
this.log.info(`Orator initialized for Ultravisor API Server on port ${this.fable.settings.APIServerPort}`);
|
|
78
|
+
return fNext();
|
|
79
|
+
}.bind(this));
|
|
80
|
+
}.bind(this));
|
|
81
|
+
|
|
82
|
+
tmpAnticipate.anticipate(
|
|
83
|
+
function (fNext)
|
|
84
|
+
{
|
|
85
|
+
this.wireEndpoints(
|
|
86
|
+
function (pError)
|
|
87
|
+
{
|
|
88
|
+
if (pError)
|
|
89
|
+
{
|
|
90
|
+
this.log.info(`Error wiring Ultravisor API Server endpoints: ${pError}`, pError);
|
|
91
|
+
return fCallback(pError);
|
|
92
|
+
}
|
|
93
|
+
this.log.info(`Ultravisor API Server endpoints wired successfully.`);
|
|
94
|
+
return fNext();
|
|
95
|
+
}.bind(this));
|
|
96
|
+
}.bind(this));
|
|
97
|
+
|
|
98
|
+
tmpAnticipate.anticipate(
|
|
99
|
+
function (fNext)
|
|
100
|
+
{
|
|
101
|
+
this.log.info(`Starting Ultravisor Orator API Server on port ${this.fable.settings.APIServerPort}`);
|
|
102
|
+
this._Orator.startService(fNext);
|
|
103
|
+
}.bind(this));
|
|
104
|
+
|
|
105
|
+
tmpAnticipate.wait(
|
|
106
|
+
function (pError)
|
|
107
|
+
{
|
|
108
|
+
if (pError)
|
|
109
|
+
{
|
|
110
|
+
this.log.info(`Error starting Ultravisor API Server: ${pError}`, pError);
|
|
111
|
+
return fCallback(pError);
|
|
112
|
+
}
|
|
113
|
+
this.log.info(`Ultravisor Orator API Server started successfully.`);
|
|
114
|
+
return fCallback();
|
|
115
|
+
}.bind(this));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = UltravisorAPIServer;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for Ultravisor
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
var libUltravisor = require('../source/cli/Ultravisor-CLIProgram.cjs');
|
|
6
|
+
|
|
7
|
+
var Chai = require("chai");
|
|
8
|
+
var Expect = Chai.expect;
|
|
9
|
+
|
|
10
|
+
suite
|
|
11
|
+
(
|
|
12
|
+
'Ultravisor',
|
|
13
|
+
function()
|
|
14
|
+
{
|
|
15
|
+
setup ( () => {} );
|
|
16
|
+
|
|
17
|
+
suite
|
|
18
|
+
(
|
|
19
|
+
'Execution Sanity',
|
|
20
|
+
function()
|
|
21
|
+
{
|
|
22
|
+
test
|
|
23
|
+
(
|
|
24
|
+
'Ultravisor should load up okay.',
|
|
25
|
+
function()
|
|
26
|
+
{
|
|
27
|
+
let testUltravisor = libUltravisor;
|
|
28
|
+
Expect(testUltravisor.settings.Product).to.equal('Ultravisor-CLI');
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
);
|