Skip to content

Commit

Permalink
added support for orchestrations
Browse files Browse the repository at this point in the history
  • Loading branch information
Erwin Dondorp committed Aug 16, 2024
1 parent 5ca2ef9 commit e60c24a
Show file tree
Hide file tree
Showing 11 changed files with 347 additions and 8 deletions.
12 changes: 12 additions & 0 deletions TODO.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Branch zzz-orchestrate
("zzz" to move it to the bottom of the list)
PoC for supporting the orchestration mechanism

PRO:
* previously, orchestrations were not supported

CON:
* so far, no one really need this

VERDICT:
Keep until there is an actual request for it
16 changes: 16 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,22 @@ saltgui_hide_saltenvs:
Typically only one of these variables should be set.
Jobs that were started without the `saltenv` parameter are, for this purpose only, assumed to use the value `default` for this parameter. This allows these jobs to be hidden/showed using the same mechanism. SaltGUI does not replicate the internal logic of the salt-master and/or the salt-minion to determine which saltenv would actually have been used for such jobs.

## Orchestrations
The Orchestrations page shows the available orchestrations with their steps. Name, target and function are listed in separate columns.
All other details will be visible in the details column. The steps are listed in priority order.
But note that additional dependencies may cause an alternative execution sequence.

In the configuration files, SaltStack does not clearly distingish between state-configuration and orchestration-configuration.
SaltGUI only shows information that has the orechestration format.

An orchestration can be executed. The output resembles the output of highstate commands, but now each step is a whole salt command instead of a state.
Since the orchestration is run by the salt-master, the results are organized for only this host.
Note that SaltStack uses a slightly different minion-name for that.

Note that each stage is started as a separate job. Neither SaltStack, nor SaltGUI, has information available to somehow group the results.

Unlike the highstate system, there are no events available in the SaltStack that can be used to track the progress of an orchestration.

## Issues
The Issues page provides an overview of the system and reports any issues.
When no issues are found, the list remains empty.
Expand Down
9 changes: 9 additions & 0 deletions saltgui/static/scripts/Api.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,15 @@ export class API {
return this.apiRequest("POST", "/", params);
}

getRunnerStateOrchestrateShowSls () {
const params = {
"arg": ["*"],
"client": "runner",
"fun": "state.orchestrate_show_sls"
};
return this.apiRequest("POST", "/", params);
}

getWheelConfigValues () {
const params = {
"client": "wheel",
Expand Down
6 changes: 5 additions & 1 deletion saltgui/static/scripts/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {LogoutPage} from "./pages/Logout.js";
import {MinionsPage} from "./pages/Minions.js";
import {NodegroupsPage} from "./pages/Nodegroups.js";
import {OptionsPage} from "./pages/Options.js";
import {OrchestrationsPage} from "./pages/Orchestrations.js";
import {Output} from "./output/Output.js";
import {PillarsMinionPage} from "./pages/PillarsMinion.js";
import {PillarsPage} from "./pages/Pillars.js";
Expand Down Expand Up @@ -57,6 +58,7 @@ export class Router {
this._registerPage(Router.templatesPage = new TemplatesPage(this));
this._registerPage(Router.eventsPage = new EventsPage(this));
this._registerPage(Router.reactorsPage = new ReactorsPage(this));
this._registerPage(Router.orchestrationsPage = new OrchestrationsPage(this));
this._registerPage(Router.optionsPage = new OptionsPage(this));
this._registerPage(Router.issuesPage = new IssuesPage(this));
this._registerPage(Router.logoutPage = new LogoutPage(this));
Expand Down Expand Up @@ -208,6 +210,7 @@ export class Router {
this._registerMenuItem(null, "keys", "keys", "k");
this._registerMenuItem(null, "jobs", "jobs", "j");
this._registerMenuItem("jobs", "highstate", "highstate", "h");
this._registerMenuItem("jobs", "orchestrations", "orchestrations", "o");
this._registerMenuItem("jobs", "templates", "templates", "t");
this._registerMenuItem(null, "events", "events", "e");
this._registerMenuItem("events", "reactors", "reactors", "r");
Expand Down Expand Up @@ -300,8 +303,9 @@ export class Router {
Router._showMenuItem(pages, Router.beaconsPage);
Router._showMenuItem(pages, Router.nodegroupsPage);
Router._showMenuItem(pages, Router.keysPage);
Router._showMenuItem(pages, Router.jobsPage, ["highstate", "templates"]);
Router._showMenuItem(pages, Router.jobsPage, ["highstate", "orchestrations", "templates"]);
Router._showMenuItem(pages, Router.highStatePage);
Router._showMenuItem(pages, Router.orchestrationsPage);
Router._showMenuItem(pages, Router.templatesPage);
Router._showMenuItem(pages, Router.eventsPage, ["reactors"]);
Router._showMenuItem(pages, Router.reactorsPage);
Expand Down
10 changes: 8 additions & 2 deletions saltgui/static/scripts/output/Output.js
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,10 @@ export class Output {

let minionResponse = pResponse[minionId];

if (commandCmd === "runner.state.orchestrate") {
minionResponse = minionResponse.return.return.data[minionId];
}

const isSuccess = Output._getIsSuccess(minionResponse);
minionResponse = Output._getMinionResponse(pCommand, minionResponse);
// provide the same (simplified) object for download
Expand Down Expand Up @@ -960,8 +964,10 @@ export class Output {
// first put all the values in an array
Object.keys(minionResponse).forEach(
(taskKey) => {
minionResponse[taskKey].___key___ = taskKey;
tasks.push(minionResponse[taskKey]);
if (typeof minionResponse[taskKey] === "object") {
minionResponse[taskKey].___key___ = taskKey;
tasks.push(minionResponse[taskKey]);
}
}
);
// then sort the array
Expand Down
3 changes: 2 additions & 1 deletion saltgui/static/scripts/output/OutputHighstate.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ export class OutputHighstate {
case "state.highstate":
case "state.sls":
case "state.sls_id":
case "runners.state.orchestrate":
break;
case "runner.state.orchestrate":
return true;
case "state.low":
// almost, but it is only one task
// and we can handle only an object with tasks
Expand Down
25 changes: 25 additions & 0 deletions saltgui/static/scripts/pages/Orchestrations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* global */

import {JobsSummaryPanel} from "../panels/JobsSummary.js";
import {OrchestrationsPanel} from "../panels/Orchestrations.js";
import {Page} from "./Page.js";
import {Utils} from "../Utils.js";

export class OrchestrationsPage extends Page {

constructor (pRouter) {
super("orchestrations", "Orchestrations", "page-orchestrations", "button-orchestrations", pRouter);

this.orchestrations = new OrchestrationsPanel();
super.addPanel(this.orchestrations);
this.jobs = new JobsSummaryPanel();
super.addPanel(this.jobs);
}

/* eslint-disable class-methods-use-this */
isVisible () {
/* eslint-enable class-methods-use-this */
// show orchestrations menu item if orchestrations defined
return Utils.getStorageItemBoolean("session", "orchestrations");
}
}
8 changes: 6 additions & 2 deletions saltgui/static/scripts/panels/Job.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,12 @@ export class JobPanel extends Panel {
} else if (info.Function.startsWith("wheel.")) {
minions = ["WHEEL"];
this.setWarningText("info", "WHEEL jobs are not associated with minions");
} else if (info.Function.startsWith("runners.")) {
minions = ["RUNNER"];
} else if (info.Function.startsWith("runner.")) {
if (typeof info.Result === "object") {
minions = Object.keys(info.Result);
} else {
minions = ["RUNNER"];
}
this.setWarningText("info", "RUNNER jobs are not associated with minions");
} else {
minions = Object.keys(this.result);
Expand Down
2 changes: 2 additions & 0 deletions saltgui/static/scripts/panels/Jobs.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ export class JobsPanel extends Panel {
this._hideJobs.push("runner.jobs.list_job");
this._hideJobs.push("runner.jobs.list_jobs");
this._hideJobs.push("runner.manage.versions");
// do not hide "runner.state.orchestrate"
this._hideJobs.push("runner.state.orchestrate_show_sls");
// wheel jobs
this._hideJobs.push("wheel.config.values");
this._hideJobs.push("wheel.key.accept");
Expand Down
29 changes: 27 additions & 2 deletions saltgui/static/scripts/panels/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,13 +304,21 @@ export class LoginPanel extends Panel {

// We need these functions to populate the dropdown boxes
const wheelConfigValuesPromise = this.api.getWheelConfigValues();
const runnerStateOrchestrateShowSlsPromise = this.api.getRunnerStateOrchestrateShowSls();

// these may have been hidden on a previous logout
Utils.hideAllMenus(false);

// We need these functions to populate the dropdown boxes
// or determine visibility of menu items
wheelConfigValuesPromise.then((pWheelConfigValuesData) => {
LoginPanel._handleLoginWheelConfigValues(pWheelConfigValuesData);
Router.updateMainMenu();
return true;
}, () => false);
runnerStateOrchestrateShowSlsPromise.then((pRunnerStateOrchestrateShowSlsData) => {
LoginPanel._handleRunnerStateOrchestrateShowSls(pRunnerStateOrchestrateShowSlsData);
Router.updateMainMenu();
return true;
}, () => false);

Expand Down Expand Up @@ -339,6 +347,25 @@ export class LoginPanel extends Panel {
}, 1000);
}

static _handleRunnerStateOrchestrateShowSls (pRunnerStateOrchestrateShowSlsData) {
// until we prove it it available
Utils.setStorageItem("session", "orchestrations", "false");

const ret = pRunnerStateOrchestrateShowSlsData.return[0];
for (const key in ret) {
const obj = ret[key];
for (const stepkey in obj) {
const step = obj[stepkey].salt;
for (const item of step) {
if (item === "function" || item === "state" || item === "runner" || item === "wheel") {
Utils.setStorageItem("session", "orchestrations", "true");
return;
}
}
}
}
}

static _handleLoginWheelConfigValues (pWheelConfigValuesData) {
const wheelConfigValuesData = pWheelConfigValuesData.return[0].data.return;

Expand Down Expand Up @@ -443,8 +470,6 @@ export class LoginPanel extends Panel {

const fullReturn = wheelConfigValuesData.saltgui_full_return;
Utils.setStorageItem("session", "full_return", fullReturn);

Router.updateMainMenu();
}

_onLoginFailure (error) {
Expand Down
Loading

0 comments on commit e60c24a

Please sign in to comment.