Skip to content

Commit

Permalink
Checks execution policy addendum (#2744)
Browse files Browse the repository at this point in the history
* HostDetails start execution button with guard

* Cluster details check execution with policy

* addressing review feedbacks
  • Loading branch information
CDimonaco authored Jul 4, 2024
1 parent bc874f1 commit b962efc
Show file tree
Hide file tree
Showing 10 changed files with 385 additions and 79 deletions.
51 changes: 29 additions & 22 deletions assets/js/pages/ClusterDetails/AscsErsClusterDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import ProviderLabel from '@common/ProviderLabel';
import SapSystemLink from '@common/SapSystemLink';
import Table from '@common/Table';
import Tooltip from '@common/Tooltip';
import DisabledGuard from '@common/DisabledGuard';

import ClusterNodeName from '@pages/ClusterDetails/ClusterNodeName';
import CheckResultsOverview from '@pages/CheckResultsOverview';
Expand Down Expand Up @@ -83,6 +84,7 @@ function AscsErsClusterDetails({
sapSystems,
details,
catalog,
userAbilities,
lastExecution,
onStartExecution = () => {},
navigate = () => {},
Expand Down Expand Up @@ -146,30 +148,35 @@ function AscsErsClusterDetails({
Show Results
</Button>

<Tooltip
isEnabled={!hasSelectedChecks}
content="Select some Checks first!"
place="bottom"
wrap={false}
<DisabledGuard
userAbilities={userAbilities}
permitted={['all:cluster_checks_execution']}
>
<Button
type="primary"
className="mx-0.5"
size="small"
onClick={() => {
onStartExecution(clusterID, hosts, selectedChecks);
}}
disabled={startExecutionDisabled}
<Tooltip
isEnabled={!hasSelectedChecks}
content="Select some Checks first!"
place="bottom"
wrap={false}
>
<EOS_PLAY_CIRCLE
className={classNames('inline-block align-sub', {
'fill-white': !startExecutionDisabled,
'fill-gray-200': startExecutionDisabled,
})}
/>{' '}
Start Execution
</Button>
</Tooltip>
<Button
type="primary"
className="mx-0.5"
size="small"
onClick={() => {
onStartExecution(clusterID, hosts, selectedChecks);
}}
disabled={startExecutionDisabled}
>
<EOS_PLAY_CIRCLE
className={classNames('inline-block align-sub', {
'fill-white': !startExecutionDisabled,
'fill-gray-200': startExecutionDisabled,
})}
/>{' '}
Start Execution
</Button>
</Tooltip>
</DisabledGuard>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const failoverDetails = ascsErsClusterDetailsFactory.build({
catalog,
});

const userAbilities = [{ name: 'all', resource: 'all' }];

export default {
title: 'Layouts/AscsErsClusterDetails',
components: AscsErsClusterDetails,
Expand All @@ -72,6 +74,7 @@ export const Single = {
hosts: buildHostsFromAscsErsClusterDetails(details),
sapSystems: buildSapSystemsFromAscsErsClusterDetails(details),
details,
userAbilities,
},
render: (args) => (
<ContainerWrapper>
Expand Down Expand Up @@ -123,6 +126,7 @@ export const Failover = {
clusterName,
cibLastWritten,
provider,
userAbilities,
hosts: buildHostsFromAscsErsClusterDetails(failoverDetails),
sapSystems: buildSapSystemsFromAscsErsClusterDetails(failoverDetails),
details: failoverDetails,
Expand Down
94 changes: 94 additions & 0 deletions assets/js/pages/ClusterDetails/AscsErsClusterDetails.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { providerData } from '@common/ProviderLabel/ProviderLabel';

import AscsErsClusterDetails from './AscsErsClusterDetails';

const userAbilities = [{ name: 'all', resource: 'all' }];

describe('ClusterDetails AscsErsClusterDetails component', () => {
it('should show the main details of a ASCS/ERS cluster', () => {
const {
Expand Down Expand Up @@ -49,6 +51,7 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
hosts={buildHostsFromAscsErsClusterDetails(details)}
sapSystems={sapSystems}
details={details}
userAbilities={userAbilities}
/>
);

Expand Down Expand Up @@ -105,6 +108,7 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
hosts={buildHostsFromAscsErsClusterDetails(details)}
sapSystems={buildSapSystemsFromAscsErsClusterDetails(details)}
details={details}
userAbilities={userAbilities}
/>
);

Expand Down Expand Up @@ -168,6 +172,7 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
hosts={buildHostsFromAscsErsClusterDetails(details)}
sapSystems={buildSapSystemsFromAscsErsClusterDetails(details)}
details={details}
userAbilities={userAbilities}
/>
);

Expand Down Expand Up @@ -198,6 +203,7 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
hosts={buildHostsFromAscsErsClusterDetails(details)}
sapSystems={[]}
details={details}
userAbilities={userAbilities}
/>
);

Expand Down Expand Up @@ -226,6 +232,7 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
provider={provider}
sapSystems={[]}
details={details}
userAbilities={userAbilities}
/>
);
const unregisteredHostContainer = screen.getByText(
Expand Down Expand Up @@ -260,6 +267,7 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
hosts={buildHostsFromAscsErsClusterDetails(details)}
sapSystems={sapSystems}
details={details}
userAbilities={userAbilities}
/>
);

Expand Down Expand Up @@ -309,6 +317,7 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
sapSystems={[]}
details={details}
lastExecution={null}
userAbilities={userAbilities}
/>
);

Expand Down Expand Up @@ -398,10 +407,95 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
sapSystems={[]}
details={details}
lastExecution={lastExecution}
userAbilities={userAbilities}
/>
);

expect(screen.getByText('Start Execution')).toBeDisabled();
}
);

describe('forbidden actions', () => {
it('should disable check execution button when the user abilities are not compatible', async () => {
const user = userEvent.setup();

const {
clusterID,
clusterName,
cib_last_written: cibLastWritten,
type: clusterType,
sid,
provider,
details,
} = clusterFactory.build({ type: 'ascs_ers' });

const hosts = hostFactory.buildList(2, { cluster_id: clusterID });

renderWithRouter(
<AscsErsClusterDetails
clusterID={clusterID}
clusterName={clusterName}
selectedChecks={['ABCD']}
hasSelectedChecks
hosts={hosts}
clusterType={clusterType}
cibLastWritten={cibLastWritten}
sid={sid}
provider={provider}
sapSystems={[]}
details={details}
lastExecution={null}
userAbilities={[{ name: 'all', resource: 'other' }]}
/>
);

const startExecutionButton = screen.getByText('Start Execution');
await user.hover(startExecutionButton);
expect(
screen.queryByText('You are not authorized for this action')
).toBeInTheDocument();
});

it('should enable check execution button when the user abilities are compatible', async () => {
const user = userEvent.setup();

const {
clusterID,
clusterName,
cib_last_written: cibLastWritten,
type: clusterType,
sid,
provider,
details,
} = clusterFactory.build({ type: 'ascs_ers' });

const hosts = hostFactory.buildList(2, { cluster_id: clusterID });

renderWithRouter(
<AscsErsClusterDetails
clusterID={clusterID}
clusterName={clusterName}
selectedChecks={['ABCD']}
hasSelectedChecks
hosts={hosts}
clusterType={clusterType}
cibLastWritten={cibLastWritten}
sid={sid}
provider={provider}
sapSystems={[]}
details={details}
lastExecution={null}
userAbilities={[
{ name: 'all', resource: 'cluster_checks_execution' },
]}
/>
);

const startExecutionButton = screen.getByText('Start Execution');
await user.hover(startExecutionButton);
expect(
screen.queryByText('You are not authorized for this action')
).not.toBeInTheDocument();
});
});
});
5 changes: 5 additions & 0 deletions assets/js/pages/ClusterDetails/ClusterDetailsPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '@state/selectors/cluster';
import { getCatalog } from '@state/selectors/catalog';
import { getLastExecution } from '@state/selectors/lastExecutions';
import { getUserProfile } from '@state/selectors/user';
import { updateCatalog } from '@state/catalog';
import { executionRequested, updateLastExecution } from '@state/lastExecutions';
import { buildEnv } from '@lib/checks';
Expand Down Expand Up @@ -41,6 +42,8 @@ export function ClusterDetailsPage() {
getFilesystemType(state, clusterID)
);

const { abilities } = useSelector(getUserProfile);

useEffect(() => {
const env = buildEnv({
provider,
Expand Down Expand Up @@ -76,6 +79,7 @@ export function ClusterDetailsPage() {
return (
<HanaClusterDetails
clusterID={clusterID}
userAbilities={abilities}
clusterName={getClusterName(cluster)}
selectedChecks={cluster.selected_checks}
hasSelectedChecks={hasSelectedChecks}
Expand All @@ -98,6 +102,7 @@ export function ClusterDetailsPage() {
return (
<AscsErsClusterDetails
clusterID={clusterID}
userAbilities={abilities}
clusterName={getClusterName(cluster)}
selectedChecks={cluster.selected_checks}
hasSelectedChecks={hasSelectedChecks}
Expand Down
3 changes: 3 additions & 0 deletions assets/js/pages/ClusterDetails/ClusterDetailsPage.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ describe('ClusterDetails ClusterDetailsPage component', () => {
[cluster.id]: { data: null, loading: false, error: null },
},
catalog: { data: null, loading: false, error: null },
user: {
abilities: [{ name: 'all', resource: 'all' }],
},
};

const [statefulClusterDetailsPage, _] = withState(
Expand Down
51 changes: 29 additions & 22 deletions assets/js/pages/ClusterDetails/HanaClusterDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import PageHeader from '@common/PageHeader';
import ProviderLabel from '@common/ProviderLabel';
import SapSystemLink from '@common/SapSystemLink';
import Tooltip from '@common/Tooltip';
import DisabledGuard from '@common/DisabledGuard';

import CheckResultsOverview from '@pages/CheckResultsOverview';

Expand Down Expand Up @@ -40,6 +41,7 @@ function HanaClusterDetails({
sapSystems,
details,
catalog,
userAbilities,
lastExecution,
onStartExecution = () => {},
navigate = () => {},
Expand Down Expand Up @@ -98,30 +100,35 @@ function HanaClusterDetails({
Show Results
</Button>

<Tooltip
isEnabled={!hasSelectedChecks}
content="Select some Checks first!"
place="bottom"
wrap={false}
<DisabledGuard
userAbilities={userAbilities}
permitted={['all:cluster_checks_execution']}
>
<Button
type="primary"
className="mx-0.5 border border-green-500"
size="small"
onClick={() => {
onStartExecution(clusterID, hosts, selectedChecks);
}}
disabled={startExecutionDisabled}
<Tooltip
isEnabled={!hasSelectedChecks}
content="Select some Checks first!"
place="bottom"
wrap={false}
>
<EOS_PLAY_CIRCLE
className={classNames('inline-block align-sub', {
'fill-white': !startExecutionDisabled,
'fill-gray-200': startExecutionDisabled,
})}
/>{' '}
Start Execution
</Button>
</Tooltip>
<Button
type="primary"
className="mx-0.5 border border-green-500"
size="small"
onClick={() => {
onStartExecution(clusterID, hosts, selectedChecks);
}}
disabled={startExecutionDisabled}
>
<EOS_PLAY_CIRCLE
className={classNames('inline-block align-sub', {
'fill-white': !startExecutionDisabled,
'fill-gray-200': startExecutionDisabled,
})}
/>{' '}
Start Execution
</Button>
</Tooltip>
</DisabledGuard>
</div>
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions assets/js/pages/ClusterDetails/HanaClusterDetails.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {

import HanaClusterDetails from './HanaClusterDetails';

const userAbilities = [{ name: 'all', resource: 'all' }];

const {
id: clusterID,
name: clusterName,
Expand Down Expand Up @@ -144,6 +146,7 @@ export const Hana = {
details,
lastExecution,
catalog,
userAbilities,
onStartExecution: () => {},
navigate: () => {},
},
Expand Down
Loading

0 comments on commit b962efc

Please sign in to comment.