Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
2423adf
Remove old and deprecated environment deployment
graduta Aug 12, 2025
aa097f4
Use 'useVars' instead of 'vars' for DeploymentRequest object
graduta Aug 13, 2025
e0a0099
Redirect user to env-details page if request is successful
graduta Aug 13, 2025
3bf374e
Update types and docs
graduta Aug 14, 2025
7b653dc
Update adapter of environment event
graduta Aug 14, 2025
e6330d8
Update service to retrieve also failed deployments
graduta Aug 14, 2025
2dce08a
Add new property for environments during deployment
graduta Aug 14, 2025
a3358e8
Update front-end tests for new redirects
graduta Aug 14, 2025
f69356b
Fix test on front-end
graduta Aug 14, 2025
9805675
Merge branch 'dev' of github.com:AliceO2Group/WebUi into feature/COG/…
graduta Aug 14, 2025
4c7f73c
Add logging for deployment request from user
graduta Aug 15, 2025
3d2c07a
Remove previous ReqHandler
graduta Aug 15, 2025
4d55f0f
Add option to remove environment by ID from cache
graduta Aug 15, 2025
03b7e02
Add function to acknowledge environments in error in cache
graduta Aug 15, 2025
e1caf5d
Add handler for new endpoint on acknowledge on deployment
graduta Aug 15, 2025
c8d85c0
Remove decomissioned feature tests
graduta Aug 15, 2025
7d8f8a9
Rename page as per standard
graduta Aug 15, 2025
cb6a9b5
Extract function for reuse
graduta Aug 15, 2025
0472a97
Extract reusable components
graduta Aug 15, 2025
d681bfd
Fix incorrect call in deployment controller
graduta Aug 15, 2025
4fae0f5
Remove previous requests components
graduta Aug 15, 2025
f63dac6
Remove testing case
graduta Aug 15, 2025
f7056df
Update Enums
graduta Aug 15, 2025
cd761a2
Update logic for deployments to be kept if in error
graduta Aug 15, 2025
6a40ac0
Update front-end from events rather than heartbit
graduta Aug 15, 2025
86c9d1a
Improve code safety
graduta Aug 15, 2025
622b54c
Update based on review comments
graduta Aug 18, 2025
364d245
Remove from cache if env was successfully destroyed
graduta Aug 18, 2025
9ec3def
Add test on event for env cache
graduta Aug 18, 2025
f7eaff3
Wait for network before button
graduta Aug 18, 2025
d5b1936
Increase timeout for lock and detector selection
graduta Aug 18, 2025
c5bd1d3
Use old library instead of locator
graduta Aug 18, 2025
46fcdce
Use waitForFunction instead
graduta Aug 18, 2025
04d56d5
Add util waitForTimeout for specific test
graduta Aug 18, 2025
7ad2465
Use await for rest of scenarios in transition
graduta Aug 18, 2025
dc2c766
Update tests to use timeout in waiting for page to render
graduta Aug 18, 2025
eb1a409
Remove deprecates tests
graduta Aug 18, 2025
f0df210
Use waitfor shutdown as well
graduta Aug 18, 2025
548571d
Add docs about env deployments
graduta Aug 18, 2025
ef71308
Merge branch 'dev' into feature/COG/OGUI-1675/front-end-migration-to-…
graduta Aug 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- [Description](#description)
- [Requirements](#requirements)
- [Installation](#installation)
- [Business logic for Developers to know](#business-logic-for-developers-to-know)
- [Configuration](#configuration)
- [O2Control gRPC](#o2control-grpc)
- [Apricot gRPC](#apricot-grpc)
Expand Down Expand Up @@ -53,6 +54,7 @@ It communicates with [Control agent](https://github.com/AliceO2Group/Control) ov
6. Start web app: `npm start`
7. Open browser and navigate to http://localhost:8080

## [Business logic for Developers to know](./docs/BUSINESS_FOR_DEVELOPER_TO_KNOW.md)
## Configuration
### O2Control gRPC
* `hostname` - gRPC hostname
Expand Down
28 changes: 28 additions & 0 deletions Control/docs/BUSINESS_FOR_DEVELOPER_TO_KNOW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Business logic for developers to know

ALICE's Experiment Control System ([ECS](https://github.com/AliceO2Group/Control)) uses entities named environments to enable users to take data in ALICE. These environments are a set of software and hardware configurations used for preparation and during data-taking operations.

## Environment States and Transitions
Environments can transition ([link](https://github.com/AliceO2Group/Control/blob/master/core/protos/o2control.proto#L228)) between multiple states. These states can be:
- state machines - [link](https://github.com/AliceO2Group/Control/blob/master/core/environment/environment.go#L153-L160)
- virtual states (states that are not real but used for software logic such as DESTROY or PENDING)

Thus, for the GUI to provide a good user experience, the ECS GUI introduces a few logic items that are to be known when developing for ECS GUI:

## Deployment and ECS GUI private attributes
A deployment is a set of operations that prepares hardware and software for data taking operations. A deployment is a definition in ECS GUI that covers an environment first transition from:
- `PENDING` (virtual state) -> `STANDBY` -> `DEPLOY` -> `CONFIGURED`

For this sequence of actions, ECS GUI assigns a private attribute `isDeploying` and `deploymentError` to the environment so that it can display to the User all the information needed.
- `isDeploying` set to:
- `true` - only by:
- the response of the `NewEnvironmentAsync`
- the first event from ECS via Kafka of state `PENDING`
- `false` - only if:
- an event with state `CONFIGURED` and message `'transition completed successfully'` is received
- an event with an error message is received during when `isDeploying` is `true` already (TBD)
- `deploymentError` is updated every time there is an event with an error (TBD)

These attributes allow the GUI to display all necessary deployment information to the user.

If a deployment fails, the ECS will remove it from the active environments list. Thus, the GUI uses `deploymentError` to make sure the environment is kept in-memory until the user acknowledges the error.
4 changes: 4 additions & 0 deletions Control/lib/adapters/EnvironmentInfoAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class EnvironmentInfoAdapter {
const {
id,
currentRunNumber,
isDeploying,
deploymentError,
createdWhen,
firstTaskInError = null,
state = '',
Expand All @@ -69,6 +71,8 @@ class EnvironmentInfoAdapter {
const environmentInfo = {
id,
currentRunNumber,
isDeploying,
deploymentError,
createdWhen,
firstTaskInError,
state,
Expand Down
15 changes: 6 additions & 9 deletions Control/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ const {NotificationService, ConsulService} = require('@aliceo2/web-ui');

// AliECS Core
const { AliEcsSynchronizer } = require('./kafka/AliEcsSynchronizer.js');
const AliecsRequestHandler = require('./control-core/RequestHandler.js');
const ApricotService = require('./control-core/ApricotService.js');
const ControlService = require('./control-core/ControlService.js');
const GrpcServiceClient = require('./control-core/GrpcServiceClient.js');
Expand Down Expand Up @@ -115,7 +114,7 @@ module.exports.setup = (http, ws) => {
ctrlProxy, apricotService, cacheService, broadcastService, environmentCacheService
);
const workflowService = new WorkflowTemplateService(ctrlProxy, apricotService);
const deploymentService = new DeploymentService(environmentService, workflowService);
const deploymentService = new DeploymentService(environmentService, workflowService, environmentCacheService);

/**
* Controllers are initialized with the services they depend on.
Expand All @@ -124,10 +123,6 @@ module.exports.setup = (http, ws) => {
const workflowController = new WorkflowTemplateController(workflowService);
const deploymentController = new DeploymentController(deploymentService);

const aliecsReqHandler = new AliecsRequestHandler(ctrlService, apricotService);
aliecsReqHandler.setWs(ws);
aliecsReqHandler.workflowService = workflowService;

const bkpService = new BookkeepingService(config.bookkeeping ?? {});
const runService = new RunService(bkpService, apricotService, cacheService);
runService.retrieveStaticConfigurations();
Expand Down Expand Up @@ -174,9 +169,6 @@ module.exports.setup = (http, ws) => {
ctrlProxy.methods.forEach(
(method) => http.post(`/${method}`, coreMiddleware, (req, res) => ctrlService.executeCommand(req, res)),
);
http.post('/core/request', coreMiddleware, (req, res) => aliecsReqHandler.add(req, res));
http.get('/core/requests', coreMiddleware, (req, res) => aliecsReqHandler.getAll(req, res));
http.post('/core/removeRequest/:id', coreMiddleware, (req, res) => aliecsReqHandler.remove(req, res));

http.get('/workflow/template/default/source', workflowController.getDefaultTemplateSource.bind(workflowController));
http.get('/workflow/template/mappings', workflowController.getWorkflowMapping.bind(workflowController));
Expand Down Expand Up @@ -208,6 +200,11 @@ module.exports.setup = (http, ws) => {
deploymentController.newAsyncDeploymentHandler.bind(deploymentController)
);

http.delete('/deploy/:id',
minimumRoleMiddleware(Role.DETECTOR),
deploymentController.acknowledgeDeploymentFailureHandler.bind(deploymentController)
);

http.post('/core/environments/configuration/save', (req, res) => apricotService.saveCoreEnvConfig(req, res));
http.post('/core/environments/configuration/update', (req, res) => apricotService.updateCoreEnvConfig(req, res));

Expand Down
1 change: 0 additions & 1 deletion Control/lib/common/broadcastKeys.enum.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const BroadcastKeys = Object.freeze({
NOTIFICATION: 'notification',
RESOURCES_CLEANUP: 'resources-cleanup',
O2_ROC_CONFIG: 'o2-roc-config',
REQUESTS: 'requests',
COMPONENT_STATUS: 'component-STATUS',
CALIBRATION_RUNS_BY_DETECTOR: 'CALIBRATION_RUNS_BY_DETECTOR',
CALIBRATION_RUNS_REQUESTS: 'CALIBRATION_RUNS_REQUESTS',
Expand Down
30 changes: 30 additions & 0 deletions Control/lib/common/environmentState.enum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @license
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
* All rights not expressly granted are reserved.
*
* This software is distributed under the terms of the GNU General Public
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

/**
* Available environment transitions of ECS
* @link https://github.com/AliceO2Group/Control/blob/master/core/environment/environment.go#L153-L160
*/
const EnvironmentState = Object.freeze({
STANDBY: 'STANDBY',
DEPLOYED: 'DEPLOYED',
DONE: 'DONE',
CONFIGURED: 'CONFIGURED',
RUNNING: 'RUNNING',
PENDING: 'PENDING',
ERROR: 'ERROR',
UNKNOWN: 'UNKNOWN'
});

exports.EnvironmentState = EnvironmentState;
4 changes: 3 additions & 1 deletion Control/lib/common/environmentTransitionType.enum.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
*/

/**
* Available environment transitions as per: https://github.com/AliceO2Group/Control/blob/master/core/protos/o2control.proto#L228
* Available environment transitions as per:
* @link https://github.com/AliceO2Group/Control/blob/master/core/protos/o2control.proto#L228
*/
const EnvironmentTransitionType = Object.freeze({
NOOP: 'NOOP',
Expand All @@ -23,6 +24,7 @@ const EnvironmentTransitionType = Object.freeze({
RESET: 'RESET',
GO_ERROR: 'GO_ERROR',
DEPLOY: 'DEPLOY',
DESTROY: 'DESTROY',
});

exports.EnvironmentTransitionType = EnvironmentTransitionType;
23 changes: 2 additions & 21 deletions Control/lib/control-core/GrpcServiceClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
// Doc: https://grpc.io/docs/languages/node/
const protoLoader = require('@grpc/proto-loader');
const grpcLibrary = require('@grpc/grpc-js');
const path = require('path');
const {LogManager, grpcErrorToNativeError, ServiceUnavailableError, InvalidInputError} = require('@aliceo2/web-ui');
const {Status} = require(path.join(__dirname, './../../protobuf/status_pb.js'));
const {EnvironmentInfo} = require(path.join(__dirname, './../../protobuf/environmentinfo_pb.js'));
const {LogManager, ServiceUnavailableError, InvalidInputError} = require('@aliceo2/web-ui');
const RECONNECT_DELTA_TIME = 1000; // 1 second

/**
Expand Down Expand Up @@ -102,23 +99,7 @@ class GrpcServiceClient {
return new Promise((resolve, reject) => {
this.client[methodName](args, options, (error, response) => {
if (error) {
try {
if (methodName === 'NewEnvironment' && error.metadata?.internalRepr?.has('grpc-status-details-bin')) {
const buffer = error.metadata.get('grpc-status-details-bin')[0];
Status.deserializeBinary(buffer).getDetailsList().map((detail) => {
if (detail.getTypeName() == 'o2control.EnvironmentInfo') {
const deserialized = detail.unpack(EnvironmentInfo.deserializeBinary, detail.getTypeName());
error.envId = deserialized.array[0];
}
});
}
reject(error);
} catch (exception) {
this._logger.debugMessage('Failed new env details error' + exception);
reject(exception);
}
reject(grpcErrorToNativeError(error));
return;
reject(error);
}
resolve(response);
});
Expand Down
Loading
Loading