ultravisor 1.0.0 → 1.0.2
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/.babelrc +6 -0
- package/.browserslistrc +1 -0
- package/.browserslistrc-BACKUP +1 -0
- package/.gulpfile-quackage-config.json +7 -0
- package/.gulpfile-quackage.js +2 -0
- package/CONTRIBUTING.md +50 -0
- package/README.md +34 -0
- package/debug/Harness.js +2 -1
- package/docs/.nojekyll +0 -0
- package/docs/_sidebar.md +18 -0
- package/docs/_topbar.md +7 -0
- package/docs/architecture.md +103 -0
- package/docs/cover.md +15 -0
- package/docs/features/api.md +230 -0
- package/docs/features/cli.md +182 -0
- package/docs/features/configuration.md +245 -0
- package/docs/features/manifests.md +177 -0
- package/docs/features/operations.md +292 -0
- package/docs/features/scheduling.md +179 -0
- package/docs/features/tasks.md +1857 -0
- package/docs/index.html +39 -0
- package/docs/overview.md +75 -0
- package/docs/quickstart.md +167 -0
- package/docs/retold-catalog.json +24 -0
- package/docs/retold-keyword-index.json +19 -0
- package/package.json +5 -2
- package/source/Ultravisor.cjs +2 -2
- package/source/cli/Ultravisor-CLIProgram.cjs +38 -0
- package/source/cli/commands/Ultravisor-Command-ScheduleOperation.cjs +26 -2
- package/source/cli/commands/Ultravisor-Command-ScheduleTask.cjs +26 -2
- package/source/cli/commands/Ultravisor-Command-ScheduleView.cjs +22 -0
- package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +49 -1
- package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +51 -1
- package/source/cli/commands/Ultravisor-Command-Stop.cjs +4 -0
- package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +91 -0
- package/source/config/Ultravisor-Default-Command-Configuration.cjs +6 -1
- package/source/services/Ultravisor-Hypervisor-Event-Base.cjs +18 -1
- package/source/services/Ultravisor-Hypervisor-State.cjs +213 -0
- package/source/services/Ultravisor-Hypervisor.cjs +225 -1
- package/source/services/Ultravisor-Operation-Manifest.cjs +150 -1
- package/source/services/Ultravisor-Operation.cjs +190 -1
- package/source/services/Ultravisor-Task.cjs +339 -1
- package/source/services/events/Ultravisor-Hypervisor-Event-Cron.cjs +71 -1
- package/source/services/tasks/Ultravisor-Task-Base.cjs +264 -0
- package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +188 -0
- package/source/services/tasks/Ultravisor-Task-Command.cjs +65 -0
- package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +190 -0
- package/source/services/tasks/Ultravisor-Task-Conditional.cjs +104 -0
- package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +72 -0
- package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +336 -0
- package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +143 -0
- package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +146 -0
- package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +158 -0
- package/source/services/tasks/Ultravisor-Task-Request.cjs +56 -0
- package/source/services/tasks/Ultravisor-Task-Solver.cjs +89 -0
- package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +93 -0
- package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +127 -0
- package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +119 -0
- package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +109 -0
- package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +112 -0
- package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +499 -0
- package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +150 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +110 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +89 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +87 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +67 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +66 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +69 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +95 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +96 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +99 -0
- package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +102 -0
- package/source/web_server/Ultravisor-API-Server.cjs +463 -3
- package/test/Ultravisor_tests.js +6097 -1
- package/webinterface/.babelrc +6 -0
- package/webinterface/.browserslistrc +1 -0
- package/webinterface/.browserslistrc-BACKUP +1 -0
- package/webinterface/.gulpfile-quackage-config.json +7 -0
- package/webinterface/.gulpfile-quackage.js +2 -0
- package/webinterface/css/ultravisor.css +121 -0
- package/webinterface/html/index.html +32 -0
- package/webinterface/package.json +39 -0
- package/webinterface/source/Pict-Application-Ultravisor-Configuration.json +15 -0
- package/webinterface/source/Pict-Application-Ultravisor.js +414 -0
- package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +42 -0
- package/webinterface/source/views/PictView-Ultravisor-BottomBar.js +65 -0
- package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +236 -0
- package/webinterface/source/views/PictView-Ultravisor-Layout.js +83 -0
- package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +273 -0
- package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +243 -0
- package/webinterface/source/views/PictView-Ultravisor-OperationList.js +141 -0
- package/webinterface/source/views/PictView-Ultravisor-Schedule.js +280 -0
- package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +220 -0
- package/webinterface/source/views/PictView-Ultravisor-TaskList.js +248 -0
- package/webinterface/source/views/PictView-Ultravisor-TimingView.js +420 -0
- package/webinterface/source/views/PictView-Ultravisor-TopBar.js +147 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const libUltravisorTaskBase = require('../Ultravisor-Task-Base.cjs');
|
|
2
|
+
|
|
3
|
+
const libFS = require('fs');
|
|
4
|
+
const libPath = require('path');
|
|
5
|
+
|
|
6
|
+
class UltravisorTaskWriteText extends libUltravisorTaskBase
|
|
7
|
+
{
|
|
8
|
+
constructor(pFable)
|
|
9
|
+
{
|
|
10
|
+
super(pFable);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Write text content to a file in the staging folder.
|
|
15
|
+
*
|
|
16
|
+
* Task definition fields:
|
|
17
|
+
* - File: relative file path inside the staging folder
|
|
18
|
+
* - Address (optional): dot-notation path into GlobalState to
|
|
19
|
+
* resolve the data to write (used instead of Data)
|
|
20
|
+
* - Data: the string to write
|
|
21
|
+
*
|
|
22
|
+
* Either Address or Data must be provided. When Address is set,
|
|
23
|
+
* the data is resolved from pContext.GlobalState (or NodeState).
|
|
24
|
+
*/
|
|
25
|
+
execute(pTaskDefinition, pContext, pManifestEntry, fCallback)
|
|
26
|
+
{
|
|
27
|
+
let tmpStagingPath = this.resolveStagingPath(pContext);
|
|
28
|
+
let tmpFilePath = this.resolveStagingFilePath(tmpStagingPath, pTaskDefinition.File);
|
|
29
|
+
|
|
30
|
+
if (!tmpFilePath)
|
|
31
|
+
{
|
|
32
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
33
|
+
pManifestEntry.Status = 'Error';
|
|
34
|
+
pManifestEntry.Log.push(`WriteText: missing or invalid File field.`);
|
|
35
|
+
return fCallback(null, pManifestEntry);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Resolve data from Address or Data
|
|
39
|
+
let tmpData;
|
|
40
|
+
|
|
41
|
+
if (pTaskDefinition.Address && typeof(pTaskDefinition.Address) === 'string')
|
|
42
|
+
{
|
|
43
|
+
tmpData = this.resolveAddress(pTaskDefinition.Address, pContext);
|
|
44
|
+
pManifestEntry.Log.push(`WriteText: resolved data from Address "${pTaskDefinition.Address}".`);
|
|
45
|
+
}
|
|
46
|
+
else if (pTaskDefinition.hasOwnProperty('Data'))
|
|
47
|
+
{
|
|
48
|
+
tmpData = pTaskDefinition.Data;
|
|
49
|
+
}
|
|
50
|
+
else
|
|
51
|
+
{
|
|
52
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
53
|
+
pManifestEntry.Status = 'Error';
|
|
54
|
+
pManifestEntry.Log.push(`WriteText: missing Data or Address field.`);
|
|
55
|
+
return fCallback(null, pManifestEntry);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (tmpData === undefined)
|
|
59
|
+
{
|
|
60
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
61
|
+
pManifestEntry.Status = 'Error';
|
|
62
|
+
pManifestEntry.Log.push(`WriteText: resolved data is undefined.`);
|
|
63
|
+
return fCallback(null, pManifestEntry);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let tmpContent = (typeof(tmpData) === 'string')
|
|
67
|
+
? tmpData
|
|
68
|
+
: String(tmpData);
|
|
69
|
+
|
|
70
|
+
pManifestEntry.Log.push(`WriteText: writing to ${tmpFilePath}`);
|
|
71
|
+
|
|
72
|
+
try
|
|
73
|
+
{
|
|
74
|
+
let tmpDir = libPath.dirname(tmpFilePath);
|
|
75
|
+
if (!libFS.existsSync(tmpDir))
|
|
76
|
+
{
|
|
77
|
+
libFS.mkdirSync(tmpDir, { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
libFS.writeFileSync(tmpFilePath, tmpContent, 'utf8');
|
|
81
|
+
|
|
82
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
83
|
+
pManifestEntry.Status = 'Complete';
|
|
84
|
+
pManifestEntry.Success = true;
|
|
85
|
+
pManifestEntry.Output = `${tmpContent.length} bytes written`;
|
|
86
|
+
pManifestEntry.Log.push(`WriteText: wrote ${tmpContent.length} bytes.`);
|
|
87
|
+
}
|
|
88
|
+
catch (pError)
|
|
89
|
+
{
|
|
90
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
91
|
+
pManifestEntry.Status = 'Error';
|
|
92
|
+
pManifestEntry.Log.push(`WriteText: ${pError.message}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return fCallback(null, pManifestEntry);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = UltravisorTaskWriteText;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const libUltravisorTaskBase = require('../Ultravisor-Task-Base.cjs');
|
|
2
|
+
|
|
3
|
+
const libFS = require('fs');
|
|
4
|
+
const libPath = require('path');
|
|
5
|
+
|
|
6
|
+
class UltravisorTaskWriteXML extends libUltravisorTaskBase
|
|
7
|
+
{
|
|
8
|
+
constructor(pFable)
|
|
9
|
+
{
|
|
10
|
+
super(pFable);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Write XML content to a file in the staging folder.
|
|
15
|
+
*
|
|
16
|
+
* The Data field should be a string containing well-formed XML.
|
|
17
|
+
* Creates intermediate directories automatically.
|
|
18
|
+
*
|
|
19
|
+
* Task definition fields:
|
|
20
|
+
* - File: relative file path inside the staging folder
|
|
21
|
+
* - Address (optional): dot-notation path into GlobalState to
|
|
22
|
+
* resolve the data to write (used instead of Data)
|
|
23
|
+
* - Data: XML string to write
|
|
24
|
+
*
|
|
25
|
+
* Either Address or Data must be provided. When Address is set,
|
|
26
|
+
* the data is resolved from pContext.GlobalState (or NodeState).
|
|
27
|
+
*/
|
|
28
|
+
execute(pTaskDefinition, pContext, pManifestEntry, fCallback)
|
|
29
|
+
{
|
|
30
|
+
let tmpStagingPath = this.resolveStagingPath(pContext);
|
|
31
|
+
let tmpFilePath = this.resolveStagingFilePath(tmpStagingPath, pTaskDefinition.File);
|
|
32
|
+
|
|
33
|
+
if (!tmpFilePath)
|
|
34
|
+
{
|
|
35
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
36
|
+
pManifestEntry.Status = 'Error';
|
|
37
|
+
pManifestEntry.Log.push(`WriteXML: missing or invalid File field.`);
|
|
38
|
+
return fCallback(null, pManifestEntry);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Resolve data from Address or Data
|
|
42
|
+
let tmpData;
|
|
43
|
+
|
|
44
|
+
if (pTaskDefinition.Address && typeof(pTaskDefinition.Address) === 'string')
|
|
45
|
+
{
|
|
46
|
+
tmpData = this.resolveAddress(pTaskDefinition.Address, pContext);
|
|
47
|
+
pManifestEntry.Log.push(`WriteXML: resolved data from Address "${pTaskDefinition.Address}".`);
|
|
48
|
+
}
|
|
49
|
+
else if (pTaskDefinition.hasOwnProperty('Data'))
|
|
50
|
+
{
|
|
51
|
+
tmpData = pTaskDefinition.Data;
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
{
|
|
55
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
56
|
+
pManifestEntry.Status = 'Error';
|
|
57
|
+
pManifestEntry.Log.push(`WriteXML: missing Data or Address field.`);
|
|
58
|
+
return fCallback(null, pManifestEntry);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (tmpData === undefined)
|
|
62
|
+
{
|
|
63
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
64
|
+
pManifestEntry.Status = 'Error';
|
|
65
|
+
pManifestEntry.Log.push(`WriteXML: resolved data is undefined.`);
|
|
66
|
+
return fCallback(null, pManifestEntry);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let tmpContent = (typeof(tmpData) === 'string')
|
|
70
|
+
? tmpData
|
|
71
|
+
: String(tmpData);
|
|
72
|
+
|
|
73
|
+
pManifestEntry.Log.push(`WriteXML: writing to ${tmpFilePath}`);
|
|
74
|
+
|
|
75
|
+
try
|
|
76
|
+
{
|
|
77
|
+
let tmpDir = libPath.dirname(tmpFilePath);
|
|
78
|
+
if (!libFS.existsSync(tmpDir))
|
|
79
|
+
{
|
|
80
|
+
libFS.mkdirSync(tmpDir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
libFS.writeFileSync(tmpFilePath, tmpContent, 'utf8');
|
|
84
|
+
|
|
85
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
86
|
+
pManifestEntry.Status = 'Complete';
|
|
87
|
+
pManifestEntry.Success = true;
|
|
88
|
+
pManifestEntry.Output = `${tmpContent.length} bytes written`;
|
|
89
|
+
pManifestEntry.Log.push(`WriteXML: wrote ${tmpContent.length} bytes.`);
|
|
90
|
+
}
|
|
91
|
+
catch (pError)
|
|
92
|
+
{
|
|
93
|
+
pManifestEntry.StopTime = new Date().toISOString();
|
|
94
|
+
pManifestEntry.Status = 'Error';
|
|
95
|
+
pManifestEntry.Log.push(`WriteXML: ${pError.message}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return fCallback(null, pManifestEntry);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = UltravisorTaskWriteXML;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const libPictService = require(`pict-serviceproviderbase`);
|
|
2
2
|
|
|
3
|
+
const libPath = require('path');
|
|
3
4
|
const libOrator = require('orator');
|
|
4
5
|
const libOratorServiceServerRestify = require(`orator-serviceserver-restify`);
|
|
5
6
|
|
|
@@ -24,15 +25,440 @@ class UltravisorAPIServer extends libPictService
|
|
|
24
25
|
return fCallback(new Error(`Ultravisor API Server: Cannot wire endpoints; Orator service is not initialized.`));
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
// --- Package / Status ---
|
|
27
29
|
this._OratorServer.get
|
|
28
30
|
(
|
|
29
31
|
'/package',
|
|
30
|
-
(pRequest, pResponse, fNext)
|
|
32
|
+
function (pRequest, pResponse, fNext)
|
|
31
33
|
{
|
|
32
|
-
// Send back the request parameters
|
|
33
34
|
pResponse.send(this.pict.settings.Package);
|
|
34
35
|
return fNext();
|
|
35
|
-
}
|
|
36
|
+
}.bind(this)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
this._OratorServer.get
|
|
40
|
+
(
|
|
41
|
+
'/status',
|
|
42
|
+
function (pRequest, pResponse, fNext)
|
|
43
|
+
{
|
|
44
|
+
let tmpHypervisor = this.fable['Ultravisor-Hypervisor'];
|
|
45
|
+
pResponse.send({
|
|
46
|
+
Status: 'Running',
|
|
47
|
+
ScheduleEntries: tmpHypervisor.getSchedule().length,
|
|
48
|
+
ScheduleRunning: tmpHypervisor._Running
|
|
49
|
+
});
|
|
50
|
+
return fNext();
|
|
51
|
+
}.bind(this)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
this._OratorServer.get
|
|
55
|
+
(
|
|
56
|
+
'/stop',
|
|
57
|
+
function (pRequest, pResponse, fNext)
|
|
58
|
+
{
|
|
59
|
+
this.log.info(`Ultravisor API Server: Received stop request via API; stopping server.`);
|
|
60
|
+
let tmpHypervisor = this.fable['Ultravisor-Hypervisor'];
|
|
61
|
+
tmpHypervisor.stopSchedule();
|
|
62
|
+
pResponse.send({ "Status": "STOPPING" });
|
|
63
|
+
pResponse.end();
|
|
64
|
+
return this._Orator.stopService(fNext);
|
|
65
|
+
}.bind(this)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// --- Task CRUD ---
|
|
69
|
+
this._OratorServer.get
|
|
70
|
+
(
|
|
71
|
+
'/Task',
|
|
72
|
+
function (pRequest, pResponse, fNext)
|
|
73
|
+
{
|
|
74
|
+
this.fable['Ultravisor-Hypervisor-State'].getTaskList({},
|
|
75
|
+
function (pError, pTasks)
|
|
76
|
+
{
|
|
77
|
+
if (pError)
|
|
78
|
+
{
|
|
79
|
+
pResponse.send(500, { Error: pError.message });
|
|
80
|
+
return fNext();
|
|
81
|
+
}
|
|
82
|
+
pResponse.send(pTasks);
|
|
83
|
+
return fNext();
|
|
84
|
+
});
|
|
85
|
+
}.bind(this)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
this._OratorServer.get
|
|
89
|
+
(
|
|
90
|
+
'/Task/:GUIDTask',
|
|
91
|
+
function (pRequest, pResponse, fNext)
|
|
92
|
+
{
|
|
93
|
+
this.fable['Ultravisor-Hypervisor-State'].getTask(pRequest.params.GUIDTask,
|
|
94
|
+
function (pError, pTask)
|
|
95
|
+
{
|
|
96
|
+
if (pError)
|
|
97
|
+
{
|
|
98
|
+
pResponse.send(404, { Error: pError.message });
|
|
99
|
+
return fNext();
|
|
100
|
+
}
|
|
101
|
+
pResponse.send(pTask);
|
|
102
|
+
return fNext();
|
|
103
|
+
});
|
|
104
|
+
}.bind(this)
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
this._OratorServer.post
|
|
108
|
+
(
|
|
109
|
+
'/Task',
|
|
110
|
+
function (pRequest, pResponse, fNext)
|
|
111
|
+
{
|
|
112
|
+
this.fable['Ultravisor-Hypervisor-State'].updateTask(pRequest.body,
|
|
113
|
+
function (pError, pTask)
|
|
114
|
+
{
|
|
115
|
+
if (pError)
|
|
116
|
+
{
|
|
117
|
+
pResponse.send(400, { Error: pError.message });
|
|
118
|
+
return fNext();
|
|
119
|
+
}
|
|
120
|
+
pResponse.send(pTask);
|
|
121
|
+
return fNext();
|
|
122
|
+
});
|
|
123
|
+
}.bind(this)
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
this._OratorServer.put
|
|
127
|
+
(
|
|
128
|
+
'/Task/:GUIDTask',
|
|
129
|
+
function (pRequest, pResponse, fNext)
|
|
130
|
+
{
|
|
131
|
+
let tmpTaskData = pRequest.body || {};
|
|
132
|
+
tmpTaskData.GUIDTask = pRequest.params.GUIDTask;
|
|
133
|
+
this.fable['Ultravisor-Hypervisor-State'].updateTask(tmpTaskData,
|
|
134
|
+
function (pError, pTask)
|
|
135
|
+
{
|
|
136
|
+
if (pError)
|
|
137
|
+
{
|
|
138
|
+
pResponse.send(400, { Error: pError.message });
|
|
139
|
+
return fNext();
|
|
140
|
+
}
|
|
141
|
+
pResponse.send(pTask);
|
|
142
|
+
return fNext();
|
|
143
|
+
});
|
|
144
|
+
}.bind(this)
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
this._OratorServer.del
|
|
148
|
+
(
|
|
149
|
+
'/Task/:GUIDTask',
|
|
150
|
+
function (pRequest, pResponse, fNext)
|
|
151
|
+
{
|
|
152
|
+
let tmpState = this.fable['Ultravisor-Hypervisor-State'];
|
|
153
|
+
if (tmpState._Tasks.hasOwnProperty(pRequest.params.GUIDTask))
|
|
154
|
+
{
|
|
155
|
+
delete tmpState._Tasks[pRequest.params.GUIDTask];
|
|
156
|
+
tmpState.persistState();
|
|
157
|
+
pResponse.send({ Status: 'Deleted', GUIDTask: pRequest.params.GUIDTask });
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
{
|
|
161
|
+
pResponse.send(404, { Error: `Task ${pRequest.params.GUIDTask} not found.` });
|
|
162
|
+
}
|
|
163
|
+
return fNext();
|
|
164
|
+
}.bind(this)
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// --- Operation CRUD ---
|
|
168
|
+
this._OratorServer.get
|
|
169
|
+
(
|
|
170
|
+
'/Operation',
|
|
171
|
+
function (pRequest, pResponse, fNext)
|
|
172
|
+
{
|
|
173
|
+
this.fable['Ultravisor-Hypervisor-State'].getOperationList({},
|
|
174
|
+
function (pError, pOperations)
|
|
175
|
+
{
|
|
176
|
+
if (pError)
|
|
177
|
+
{
|
|
178
|
+
pResponse.send(500, { Error: pError.message });
|
|
179
|
+
return fNext();
|
|
180
|
+
}
|
|
181
|
+
pResponse.send(pOperations);
|
|
182
|
+
return fNext();
|
|
183
|
+
});
|
|
184
|
+
}.bind(this)
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
this._OratorServer.get
|
|
188
|
+
(
|
|
189
|
+
'/Operation/:GUIDOperation',
|
|
190
|
+
function (pRequest, pResponse, fNext)
|
|
191
|
+
{
|
|
192
|
+
this.fable['Ultravisor-Hypervisor-State'].getOperation(pRequest.params.GUIDOperation,
|
|
193
|
+
function (pError, pOperation)
|
|
194
|
+
{
|
|
195
|
+
if (pError)
|
|
196
|
+
{
|
|
197
|
+
pResponse.send(404, { Error: pError.message });
|
|
198
|
+
return fNext();
|
|
199
|
+
}
|
|
200
|
+
pResponse.send(pOperation);
|
|
201
|
+
return fNext();
|
|
202
|
+
});
|
|
203
|
+
}.bind(this)
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
this._OratorServer.post
|
|
207
|
+
(
|
|
208
|
+
'/Operation',
|
|
209
|
+
function (pRequest, pResponse, fNext)
|
|
210
|
+
{
|
|
211
|
+
this.fable['Ultravisor-Hypervisor-State'].updateOperation(pRequest.body,
|
|
212
|
+
function (pError, pOperation)
|
|
213
|
+
{
|
|
214
|
+
if (pError)
|
|
215
|
+
{
|
|
216
|
+
pResponse.send(400, { Error: pError.message });
|
|
217
|
+
return fNext();
|
|
218
|
+
}
|
|
219
|
+
pResponse.send(pOperation);
|
|
220
|
+
return fNext();
|
|
221
|
+
});
|
|
222
|
+
}.bind(this)
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
this._OratorServer.put
|
|
226
|
+
(
|
|
227
|
+
'/Operation/:GUIDOperation',
|
|
228
|
+
function (pRequest, pResponse, fNext)
|
|
229
|
+
{
|
|
230
|
+
let tmpOperationData = pRequest.body || {};
|
|
231
|
+
tmpOperationData.GUIDOperation = pRequest.params.GUIDOperation;
|
|
232
|
+
this.fable['Ultravisor-Hypervisor-State'].updateOperation(tmpOperationData,
|
|
233
|
+
function (pError, pOperation)
|
|
234
|
+
{
|
|
235
|
+
if (pError)
|
|
236
|
+
{
|
|
237
|
+
pResponse.send(400, { Error: pError.message });
|
|
238
|
+
return fNext();
|
|
239
|
+
}
|
|
240
|
+
pResponse.send(pOperation);
|
|
241
|
+
return fNext();
|
|
242
|
+
});
|
|
243
|
+
}.bind(this)
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
this._OratorServer.del
|
|
247
|
+
(
|
|
248
|
+
'/Operation/:GUIDOperation',
|
|
249
|
+
function (pRequest, pResponse, fNext)
|
|
250
|
+
{
|
|
251
|
+
let tmpState = this.fable['Ultravisor-Hypervisor-State'];
|
|
252
|
+
if (tmpState._Operations.hasOwnProperty(pRequest.params.GUIDOperation))
|
|
253
|
+
{
|
|
254
|
+
delete tmpState._Operations[pRequest.params.GUIDOperation];
|
|
255
|
+
tmpState.persistState();
|
|
256
|
+
pResponse.send({ Status: 'Deleted', GUIDOperation: pRequest.params.GUIDOperation });
|
|
257
|
+
}
|
|
258
|
+
else
|
|
259
|
+
{
|
|
260
|
+
pResponse.send(404, { Error: `Operation ${pRequest.params.GUIDOperation} not found.` });
|
|
261
|
+
}
|
|
262
|
+
return fNext();
|
|
263
|
+
}.bind(this)
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
// --- Task Execution ---
|
|
267
|
+
this._OratorServer.get
|
|
268
|
+
(
|
|
269
|
+
'/Task/:GUIDTask/Execute',
|
|
270
|
+
function (pRequest, pResponse, fNext)
|
|
271
|
+
{
|
|
272
|
+
let tmpState = this.fable['Ultravisor-Hypervisor-State'];
|
|
273
|
+
let tmpTaskService = this.fable['Ultravisor-Task'];
|
|
274
|
+
|
|
275
|
+
tmpState.getTask(pRequest.params.GUIDTask,
|
|
276
|
+
function (pError, pTask)
|
|
277
|
+
{
|
|
278
|
+
if (pError)
|
|
279
|
+
{
|
|
280
|
+
pResponse.send(404, { Error: pError.message });
|
|
281
|
+
return fNext();
|
|
282
|
+
}
|
|
283
|
+
tmpTaskService.executeTask(pTask, {},
|
|
284
|
+
function (pExecError, pManifestEntry)
|
|
285
|
+
{
|
|
286
|
+
if (pExecError)
|
|
287
|
+
{
|
|
288
|
+
pResponse.send(500, { Error: pExecError.message });
|
|
289
|
+
return fNext();
|
|
290
|
+
}
|
|
291
|
+
// Store the task result as a manifest so it appears in /Manifest
|
|
292
|
+
let tmpManifestService = this.fable['Ultravisor-Operation-Manifest'];
|
|
293
|
+
tmpManifestService.createTaskManifest(pManifestEntry);
|
|
294
|
+
pResponse.send(pManifestEntry);
|
|
295
|
+
return fNext();
|
|
296
|
+
}.bind(this));
|
|
297
|
+
}.bind(this));
|
|
298
|
+
}.bind(this)
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
// --- Operation Execution ---
|
|
302
|
+
this._OratorServer.get
|
|
303
|
+
(
|
|
304
|
+
'/Operation/:GUIDOperation/Execute',
|
|
305
|
+
function (pRequest, pResponse, fNext)
|
|
306
|
+
{
|
|
307
|
+
let tmpState = this.fable['Ultravisor-Hypervisor-State'];
|
|
308
|
+
let tmpOperationService = this.fable['Ultravisor-Operation'];
|
|
309
|
+
|
|
310
|
+
tmpState.getOperation(pRequest.params.GUIDOperation,
|
|
311
|
+
function (pError, pOperation)
|
|
312
|
+
{
|
|
313
|
+
if (pError)
|
|
314
|
+
{
|
|
315
|
+
pResponse.send(404, { Error: pError.message });
|
|
316
|
+
return fNext();
|
|
317
|
+
}
|
|
318
|
+
tmpOperationService.executeOperation(pOperation,
|
|
319
|
+
function (pExecError, pManifest)
|
|
320
|
+
{
|
|
321
|
+
if (pExecError)
|
|
322
|
+
{
|
|
323
|
+
pResponse.send(500, { Error: pExecError.message });
|
|
324
|
+
return fNext();
|
|
325
|
+
}
|
|
326
|
+
pResponse.send(pManifest);
|
|
327
|
+
return fNext();
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
}.bind(this)
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
// --- Schedule ---
|
|
334
|
+
this._OratorServer.get
|
|
335
|
+
(
|
|
336
|
+
'/Schedule',
|
|
337
|
+
function (pRequest, pResponse, fNext)
|
|
338
|
+
{
|
|
339
|
+
pResponse.send(this.fable['Ultravisor-Hypervisor'].getSchedule());
|
|
340
|
+
return fNext();
|
|
341
|
+
}.bind(this)
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
this._OratorServer.post
|
|
345
|
+
(
|
|
346
|
+
'/Schedule/Task',
|
|
347
|
+
function (pRequest, pResponse, fNext)
|
|
348
|
+
{
|
|
349
|
+
let tmpBody = pRequest.body || {};
|
|
350
|
+
let tmpHypervisor = this.fable['Ultravisor-Hypervisor'];
|
|
351
|
+
|
|
352
|
+
tmpHypervisor.scheduleTask(tmpBody.GUIDTask, tmpBody.ScheduleType, tmpBody.Parameters,
|
|
353
|
+
function (pError, pEntry)
|
|
354
|
+
{
|
|
355
|
+
if (pError)
|
|
356
|
+
{
|
|
357
|
+
pResponse.send(400, { Error: pError.message });
|
|
358
|
+
return fNext();
|
|
359
|
+
}
|
|
360
|
+
pResponse.send(pEntry);
|
|
361
|
+
return fNext();
|
|
362
|
+
});
|
|
363
|
+
}.bind(this)
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
this._OratorServer.post
|
|
367
|
+
(
|
|
368
|
+
'/Schedule/Operation',
|
|
369
|
+
function (pRequest, pResponse, fNext)
|
|
370
|
+
{
|
|
371
|
+
let tmpBody = pRequest.body || {};
|
|
372
|
+
let tmpHypervisor = this.fable['Ultravisor-Hypervisor'];
|
|
373
|
+
|
|
374
|
+
tmpHypervisor.scheduleOperation(tmpBody.GUIDOperation, tmpBody.ScheduleType, tmpBody.Parameters,
|
|
375
|
+
function (pError, pEntry)
|
|
376
|
+
{
|
|
377
|
+
if (pError)
|
|
378
|
+
{
|
|
379
|
+
pResponse.send(400, { Error: pError.message });
|
|
380
|
+
return fNext();
|
|
381
|
+
}
|
|
382
|
+
pResponse.send(pEntry);
|
|
383
|
+
return fNext();
|
|
384
|
+
});
|
|
385
|
+
}.bind(this)
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
this._OratorServer.del
|
|
389
|
+
(
|
|
390
|
+
'/Schedule/:GUID',
|
|
391
|
+
function (pRequest, pResponse, fNext)
|
|
392
|
+
{
|
|
393
|
+
this.fable['Ultravisor-Hypervisor'].removeScheduleEntry(pRequest.params.GUID,
|
|
394
|
+
function (pError, pResult)
|
|
395
|
+
{
|
|
396
|
+
if (pError)
|
|
397
|
+
{
|
|
398
|
+
pResponse.send(404, { Error: pError.message });
|
|
399
|
+
return fNext();
|
|
400
|
+
}
|
|
401
|
+
pResponse.send({ Status: 'Deleted', GUID: pRequest.params.GUID });
|
|
402
|
+
return fNext();
|
|
403
|
+
});
|
|
404
|
+
}.bind(this)
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
this._OratorServer.get
|
|
408
|
+
(
|
|
409
|
+
'/Schedule/Start',
|
|
410
|
+
function (pRequest, pResponse, fNext)
|
|
411
|
+
{
|
|
412
|
+
this.fable['Ultravisor-Hypervisor'].startSchedule(
|
|
413
|
+
function ()
|
|
414
|
+
{
|
|
415
|
+
pResponse.send({ Status: 'Schedule Started' });
|
|
416
|
+
return fNext();
|
|
417
|
+
});
|
|
418
|
+
}.bind(this)
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
this._OratorServer.get
|
|
422
|
+
(
|
|
423
|
+
'/Schedule/Stop',
|
|
424
|
+
function (pRequest, pResponse, fNext)
|
|
425
|
+
{
|
|
426
|
+
this.fable['Ultravisor-Hypervisor'].stopSchedule(
|
|
427
|
+
function ()
|
|
428
|
+
{
|
|
429
|
+
pResponse.send({ Status: 'Schedule Stopped' });
|
|
430
|
+
return fNext();
|
|
431
|
+
});
|
|
432
|
+
}.bind(this)
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
// --- Manifests ---
|
|
436
|
+
this._OratorServer.get
|
|
437
|
+
(
|
|
438
|
+
'/Manifest',
|
|
439
|
+
function (pRequest, pResponse, fNext)
|
|
440
|
+
{
|
|
441
|
+
pResponse.send(this.fable['Ultravisor-Operation-Manifest'].getManifestList());
|
|
442
|
+
return fNext();
|
|
443
|
+
}.bind(this)
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
this._OratorServer.get
|
|
447
|
+
(
|
|
448
|
+
'/Manifest/:GUIDRun',
|
|
449
|
+
function (pRequest, pResponse, fNext)
|
|
450
|
+
{
|
|
451
|
+
let tmpManifest = this.fable['Ultravisor-Operation-Manifest'].getManifest(pRequest.params.GUIDRun);
|
|
452
|
+
if (tmpManifest)
|
|
453
|
+
{
|
|
454
|
+
pResponse.send(tmpManifest);
|
|
455
|
+
}
|
|
456
|
+
else
|
|
457
|
+
{
|
|
458
|
+
pResponse.send(404, { Error: `Manifest ${pRequest.params.GUIDRun} not found.` });
|
|
459
|
+
}
|
|
460
|
+
return fNext();
|
|
461
|
+
}.bind(this)
|
|
36
462
|
);
|
|
37
463
|
|
|
38
464
|
return fCallback();
|
|
@@ -79,6 +505,14 @@ class UltravisorAPIServer extends libPictService
|
|
|
79
505
|
}.bind(this));
|
|
80
506
|
}.bind(this));
|
|
81
507
|
|
|
508
|
+
tmpAnticipate.anticipate(
|
|
509
|
+
function (fNext)
|
|
510
|
+
{
|
|
511
|
+
// Enable JSON body parsing for POST/PUT requests
|
|
512
|
+
this._OratorServer.server.use(this._OratorServer.bodyParser());
|
|
513
|
+
return fNext();
|
|
514
|
+
}.bind(this));
|
|
515
|
+
|
|
82
516
|
tmpAnticipate.anticipate(
|
|
83
517
|
function (fNext)
|
|
84
518
|
{
|
|
@@ -95,6 +529,32 @@ class UltravisorAPIServer extends libPictService
|
|
|
95
529
|
}.bind(this));
|
|
96
530
|
}.bind(this));
|
|
97
531
|
|
|
532
|
+
tmpAnticipate.anticipate(
|
|
533
|
+
function (fNext)
|
|
534
|
+
{
|
|
535
|
+
let tmpWebInterfacePath = this.fable?.ProgramConfiguration?.UltravisorWebInterfacePath;
|
|
536
|
+
if (tmpWebInterfacePath && (typeof tmpWebInterfacePath === 'string'))
|
|
537
|
+
{
|
|
538
|
+
// Resolve relative paths against the current working directory
|
|
539
|
+
let tmpResolvedPath = libPath.resolve(process.cwd(), tmpWebInterfacePath);
|
|
540
|
+
this.log.info(`Ultravisor: Serving web interface from [${tmpResolvedPath}]`);
|
|
541
|
+
|
|
542
|
+
// Workaround: Orator's addStaticRoute serves bare "/" with
|
|
543
|
+
// Content-Type application/octet-stream because serve-static
|
|
544
|
+
// overwrites the MIME header that Orator sets. Add an
|
|
545
|
+
// explicit redirect so "/" always loads /index.html which is
|
|
546
|
+
// served with the correct text/html content type.
|
|
547
|
+
this._OratorServer.get('/',
|
|
548
|
+
function (pRequest, pResponse, fNext)
|
|
549
|
+
{
|
|
550
|
+
pResponse.redirect('/index.html', fNext);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
this._Orator.addStaticRoute(tmpResolvedPath, 'index.html', '/*');
|
|
554
|
+
}
|
|
555
|
+
return fNext();
|
|
556
|
+
}.bind(this));
|
|
557
|
+
|
|
98
558
|
tmpAnticipate.anticipate(
|
|
99
559
|
function (fNext)
|
|
100
560
|
{
|