Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/candidate-9.6.x' into candidate-…
Browse files Browse the repository at this point in the history
…9.8.x
  • Loading branch information
GordonSmith committed Aug 2, 2024
2 parents 9c55704 + 3727324 commit 68895e9
Show file tree
Hide file tree
Showing 19 changed files with 243 additions and 130 deletions.
27 changes: 21 additions & 6 deletions ecl/agentexec/agentexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ class WaitThread : public CInterfaceOf<IPooledThread>
virtual void threadmain() override
{
Owned<IException> exception;
bool sharedK8sJob = false;
try
{
StringAttr jobSpecName(apptype);
Expand All @@ -276,6 +277,7 @@ class WaitThread : public CInterfaceOf<IPooledThread>
bool useChildProcesses = compConfig->getPropBool("@useChildProcesses");
if (isContainerized() && !useChildProcesses)
{
sharedK8sJob = true;
constexpr unsigned queueWaitingTimeoutMs = 10000;
constexpr unsigned queueWaitingCheckPeriodMs = 1000;
if (!owner.lingerQueue || !queueJobIfQueueWaiting(owner.lingerQueue, item, queueWaitingCheckPeriodMs, queueWaitingCheckPeriodMs))
Expand Down Expand Up @@ -337,13 +339,26 @@ class WaitThread : public CInterfaceOf<IPooledThread>
{
EXCLOG(exception);
Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
Owned<IWorkUnit> workunit = factory->updateWorkUnit(wuid);
if (workunit)
Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
if (cw)
{
workunit->setState(WUStateFailed);
StringBuffer eStr;
addExceptionToWorkunit(workunit, SeverityError, "agentexec", exception->errorCode(), exception->errorMessage(eStr).str(), nullptr, 0, 0, 0);
workunit->commit();
// if either a) NOT a thoragent with useChildProcesses=false (default in k8s config) or b) is still in an executing state
if (!sharedK8sJob || (cw->getState() == WUStateRunning) || (cw->getState() == WUStateBlocked) || (cw->getState() == WUStateWait))
{
// For a shared k8s job, i.e. where this agent is thoragent launching shared (multiJobLinger) k8s jobs
// the job agent should handle the job state.
// In that scenario, this is a fallback that should only come into effect if the job workflow instance has failed to handle the exception
// e.g. because it abruptly disappeared.
Owned<IWorkUnit> workunit = &cw->lock();
// recheck now locked
if ((workunit->getState() == WUStateRunning) || (workunit->getState() == WUStateBlocked) || (workunit->getState() == WUStateWait))
{
workunit->setState(WUStateFailed);
StringBuffer eStr;
addExceptionToWorkunit(workunit, SeverityError, "agentexec", exception->errorCode(), exception->errorMessage(eStr).str(), nullptr, 0, 0, 0);
workunit->commit();
}
}
}
}
}
Expand Down
173 changes: 90 additions & 83 deletions esp/src/eclwatch/CurrentUserDetailsWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,89 +26,96 @@ define([

],
function (declare, lang, nlsHPCCMod, dom, domForm, arrayUtil,
registry,
_Widget, WsAccount,
template) {

var nlsHPCC = nlsHPCCMod.default;
return declare("CurrentUserDetailsWidget", [_Widget], {
templateString: template,
baseClass: "CurrentUserDetailsWidget",
i18n: nlsHPCC,

user: null,

getTitle: function () {
return this.i18n.UserDetails;
},

postCreate: function (args) {
this.inherited(arguments);
this.userForm = registry.byId(this.id + "UserForm");
},

resize: function (args) {
this.inherited(arguments);
this.widget.BorderContainer.resize();
},

// Hitched actions ---
_onSave: function (event) {
var context = this;
var dialog = this.params.Widget;

if (this.userForm.validate()) {
var formInfo = domForm.toObject(this.id + "UserForm");
WsAccount.UpdateUser({
showOkMsg: true,
request: {
username: this.user,
oldpass: formInfo.oldPassword,
newpass1: formInfo.newPassword,
newpass2: formInfo.newPassword
}
}).then(function (response) {
if (lang.exists("UpdateUserResponse", response)) {
arrayUtil.forEach(context.userForm.getDescendants(), function (item, idx) {
item.set("value", "");
});
}
});
dialog.hide();
}
},

// Implementation ---
init: function (params) {
if (this.inherited(arguments))
return;

this.user = params.Username;
this.refresh();
},

refresh: function () {
if (this.user) {
this.updateInput("User", null, this.user);
this.updateInput("Username", null, this.user);

registry,
_Widget, WsAccount,
template) {

var nlsHPCC = nlsHPCCMod.default;
return declare("CurrentUserDetailsWidget", [_Widget], {
templateString: template,
baseClass: "CurrentUserDetailsWidget",
i18n: nlsHPCC,

user: null,
canUpdatePassword: false,

getTitle: function () {
return this.i18n.UserDetails;
},

postCreate: function (args) {
this.inherited(arguments);
this.userForm = registry.byId(this.id + "UserForm");
},

resize: function (args) {
this.inherited(arguments);
this.widget.BorderContainer.resize();
},

// Hitched actions ---
_onSave: function (event) {
var context = this;
WsAccount.MyAccount({
}).then(function (response) {
if (lang.exists("MyAccountResponse.firstName", response)) {
context.updateInput("FirstName", null, response.MyAccountResponse.firstName);
}
if (lang.exists("MyAccountResponse.employeeID", response)) {
context.updateInput("EmployeeID", null, response.MyAccountResponse.employeeID);
}
if (lang.exists("MyAccountResponse.lastName", response)) {
context.updateInput("LastName", null, response.MyAccountResponse.lastName);
}
if (lang.exists("MyAccountResponse.passwordExpiration", response)) {
context.updateInput("PasswordExpiration", null, response.MyAccountResponse.passwordExpiration);
}
});
var dialog = this.params.Widget;

if (this.canUpdatePassword && this.userForm.validate()) {
var formInfo = domForm.toObject(this.id + "UserForm");
WsAccount.UpdateUser({
showOkMsg: true,
request: {
username: this.user,
oldpass: formInfo.oldPassword,
newpass1: formInfo.newPassword,
newpass2: formInfo.newPassword
}
}).then(function (response) {
if (lang.exists("UpdateUserResponse", response)) {
arrayUtil.forEach(context.userForm.getDescendants(), function (item, idx) {
item.set("value", "");
});
}
});
dialog.hide();
}
},

// Implementation ---
init: function (params) {
if (this.inherited(arguments))
return;

this.user = params.Username;
this.refresh();
},

refresh: function () {
if (this.user) {
this.updateInput("User", null, this.user);
this.updateInput("Username", null, this.user);

var context = this;
WsAccount.MyAccount({
}).then(function (response) {
if (lang.exists("MyAccountResponse.firstName", response)) {
context.updateInput("FirstName", null, response.MyAccountResponse.firstName);
}
if (lang.exists("MyAccountResponse.employeeID", response)) {
context.updateInput("EmployeeID", null, response.MyAccountResponse.employeeID);
}
if (lang.exists("MyAccountResponse.lastName", response)) {
context.updateInput("LastName", null, response.MyAccountResponse.lastName);
}
if (lang.exists("MyAccountResponse.passwordExpiration", response)) {
context.updateInput("PasswordExpiration", null, response.MyAccountResponse.passwordExpiration);
}
if (!response?.MyAccountResponse?.CanUpdatePassword) {
context.setDisabled("dijit_form_ValidationTextBox_0", true);
context.setDisabled("dojox_form__NewPWBox_0", true);
context.setDisabled("dojox_form__VerifyPWBox_0", true);
}
context.canUpdatePassword = response?.MyAccountResponse?.CanUpdatePassword;
});
}
}
}
});
});
});
8 changes: 4 additions & 4 deletions esp/src/eclwatch/WUQueryWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,19 @@ define([
},

_onSetToFailed: function (event) {
WsWorkunits.WUAction(this.workunitsGrid.getSelected(), "SetToFailed");
WsWorkunits.WUAction(this.workunitsGrid.getSelected(), "SetToFailed").then(() => this.refreshGrid());
},

_onAbort: function (event) {
WsWorkunits.WUAction(this.workunitsGrid.getSelected(), "Abort");
WsWorkunits.WUAction(this.workunitsGrid.getSelected(), "Abort").then(() => this.refreshGrid());
},

_onProtect: function (event) {
WsWorkunits.WUAction(this.workunitsGrid.getSelected(), "Protect");
WsWorkunits.WUAction(this.workunitsGrid.getSelected(), "Protect").then(() => this.refreshGrid());
},

_onUnprotect: function (event) {
WsWorkunits.WUAction(this.workunitsGrid.getSelected(), "Unprotect");
WsWorkunits.WUAction(this.workunitsGrid.getSelected(), "Unprotect").then(() => this.refreshGrid());
},

_onReschedule: function (event) {
Expand Down
8 changes: 4 additions & 4 deletions esp/src/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion esp/src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"@hpcc-js/chart": "2.83.4",
"@hpcc-js/codemirror": "2.62.1",
"@hpcc-js/common": "2.71.18",
"@hpcc-js/comms": "2.94.0",
"@hpcc-js/comms": "2.94.1",
"@hpcc-js/dataflow": "8.1.7",
"@hpcc-js/eclwatch": "2.74.8",
"@hpcc-js/graph": "2.85.16",
Expand Down
24 changes: 16 additions & 8 deletions esp/src/src-react/components/MyAccount.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as React from "react";
import { DefaultButton, Dialog, DialogFooter, DialogType, MessageBar, MessageBarType, PrimaryButton } from "@fluentui/react";
import { useConst } from "@fluentui/react-hooks";
import { AccountService, WsAccount } from "@hpcc-js/comms";
import { scopedLogger } from "@hpcc-js/util";
import { PasswordStatus } from "../hooks/user";
import nlsHPCC from "src/nlsHPCC";
import { TableGroup } from "./forms/Groups";
import { useConst } from "@fluentui/react-hooks";

const logger = scopedLogger("src-react/components/MyAccount.tsx");

Expand Down Expand Up @@ -36,8 +37,14 @@ export const MyAccount: React.FunctionComponent<MyAccountProps> = ({
};
}, [currentUser]);

const resetForm = React.useCallback(() => {
setOldPassword("");
setNewPassword1("");
setNewPassword2("");
}, []);

const saveUser = React.useCallback(() => {
if (oldPassword !== "" && newPassword1 !== "") {
if (currentUser?.CanUpdatePassword && oldPassword !== "" && newPassword1 !== "") {
service.UpdateUser({
username: currentUser.username,
oldpass: oldPassword,
Expand All @@ -51,13 +58,14 @@ export const MyAccount: React.FunctionComponent<MyAccountProps> = ({
} else {
setShowError(false);
setErrorMessage("");
resetForm();
onClose();
}
})
.catch(err => logger.error(err))
;
}
}, [currentUser, newPassword1, newPassword2, oldPassword, onClose, service]);
}, [currentUser, newPassword1, newPassword2, oldPassword, onClose, resetForm, service]);

return <Dialog hidden={!show} onDismiss={onClose} dialogContentProps={dialogContentProps} minWidth="640px">
{showError &&
Expand All @@ -70,10 +78,10 @@ export const MyAccount: React.FunctionComponent<MyAccountProps> = ({
"employeeID": { label: nlsHPCC.EmployeeID, type: "string", value: currentUser?.employeeID, readonly: true },
"firstname": { label: nlsHPCC.FirstName, type: "string", value: currentUser?.firstName, readonly: true },
"lastname": { label: nlsHPCC.LastName, type: "string", value: currentUser?.lastName, readonly: true },
"oldPassword": { label: nlsHPCC.OldPassword, type: "password", value: oldPassword },
"newPassword1": { label: nlsHPCC.NewPassword, type: "password", value: newPassword1 },
"newPassword2": { label: nlsHPCC.ConfirmPassword, type: "password", value: newPassword2, errorMessage: passwordMismatch },
"PasswordExpiration": { label: nlsHPCC.PasswordExpiration, type: "string", value: currentUser?.passwordExpiration, readonly: true },
"oldPassword": { label: nlsHPCC.OldPassword, type: "password", value: oldPassword, disabled: () => !currentUser?.CanUpdatePassword },
"newPassword1": { label: nlsHPCC.NewPassword, type: "password", value: newPassword1, disabled: () => !currentUser?.CanUpdatePassword },
"newPassword2": { label: nlsHPCC.ConfirmPassword, type: "password", value: newPassword2, errorMessage: passwordMismatch, disabled: () => !currentUser?.CanUpdatePassword },
"PasswordExpiration": { label: nlsHPCC.PasswordExpiration, type: "string", value: currentUser?.passwordDaysRemaining === PasswordStatus.NeverExpires ? nlsHPCC.PasswordNeverExpires : currentUser?.passwordExpiration, readonly: true },
}} onChange={(id, value) => {
switch (id) {
case "oldPassword":
Expand All @@ -96,7 +104,7 @@ export const MyAccount: React.FunctionComponent<MyAccountProps> = ({
}} />
<DialogFooter>
<PrimaryButton onClick={saveUser} text={nlsHPCC.Save} />
<DefaultButton onClick={onClose} text={nlsHPCC.Cancel} />
<DefaultButton onClick={() => { resetForm(); onClose(); }} text={nlsHPCC.Cancel} />
</DialogFooter>
</Dialog>;
};
9 changes: 7 additions & 2 deletions esp/src/src-react/components/Result.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import { Checkbox, CommandBar, ContextualMenuItemType, DefaultButton, Dialog, DialogFooter, DialogType, ICommandBarItemProps, PrimaryButton, SpinButton, Stack } from "@fluentui/react";
import { Checkbox, CommandBar, ContextualMenuItemType, DefaultButton, Dialog, DialogFooter, DialogType, ICommandBarItemProps, PrimaryButton, SpinButton, Spinner, Stack } from "@fluentui/react";
import { useConst } from "@fluentui/react-hooks";
import { Result as CommsResult, XSDXMLNode } from "@hpcc-js/comms";
import { scopedLogger } from "@hpcc-js/util";
Expand Down Expand Up @@ -247,6 +247,7 @@ export const Result: React.FunctionComponent<ResultProps> = ({
const [wu] = useWorkunit(wuid);
const [result, setResult] = React.useState<CommsResult>(resultTable.calcResult());
const [FilterFields, setFilterFields] = React.useState<Fields>({});
const [loading, setLoading] = React.useState(true);
const [showFilter, setShowFilter] = React.useState(false);

React.useEffect(() => {
Expand Down Expand Up @@ -276,6 +277,7 @@ export const Result: React.FunctionComponent<ResultProps> = ({
};
});
setFilterFields(filterFields);
setLoading(false);
}).catch(err => {
logger.error(err);
if (err.message.indexOf("Cannot open the workunit result") > -1) {
Expand Down Expand Up @@ -370,7 +372,10 @@ export const Result: React.FunctionComponent<ResultProps> = ({
header={<CommandBar items={buttons} farItems={rightButtons} />}
main={
<>
<AutosizeHpccJSComponent widget={resultTable} />
{loading ?
<Spinner label={nlsHPCC.Loading} /> :
<AutosizeHpccJSComponent widget={resultTable} />
}
<Filter showFilter={showFilter} setShowFilter={setShowFilter} filterFields={filterFields} onApply={pushParams} />
<ViewHTMLConfirm />
</>
Expand Down
Loading

0 comments on commit 68895e9

Please sign in to comment.