Skip to content

Commit

Permalink
add retry logic and feature flag in microsegmentation UI (AthenZ#1710)
Browse files Browse the repository at this point in the history
* add retry logic and feature flag in microsegmentation UI

Signed-off-by: craman <[email protected]>

* address PR comments

Signed-off-by: craman <[email protected]>

Co-authored-by: craman <[email protected]>
  • Loading branch information
2 people authored and Dvir Guttman committed Mar 27, 2023
1 parent ca772c1 commit 0bffa96
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import AddSegmentation from "../../../components/microsegmentation/AddSegmentati
import API from "../../../api";

describe('AddSegmentation', () => {
const pageFeatureFlag ={
'policyValidation': true
};
it('should render', () => {
let domain = 'domain';
const showAddSegmentation = true;
const cancel = function() {};
const submit = function() {};
let _csrf = 'csrf';

const { getByTestId } = render(
<AddSegmentation
api={API()}
Expand All @@ -35,6 +37,7 @@ describe('AddSegmentation', () => {
_csrf={_csrf}
showAddSegment={showAddSegmentation}
justificationRequired={false}
pageFeatureFlag={pageFeatureFlag}
/>
);
const addsegment = getByTestId('add-segment');
Expand Down Expand Up @@ -64,6 +67,7 @@ describe('AddSegmentation', () => {
_csrf={_csrf}
showAddSegment={showAddSegmentation}
justificationRequired={false}
pageFeatureFlag={pageFeatureFlag}
/>
);
const addSegmentation = getByTestId('add-modal-message');
Expand Down
15 changes: 15 additions & 0 deletions ui/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,21 @@ const Api = (req) => {
});
},

getPageFeatureFlag(pageName) {
return new Promise((resolve, reject) => {
fetchr
.read('page-feature-flag')
.params({ pageName })
.end((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
},

getInstances(domainName, serviceName, category) {
return new Promise((resolve, reject) => {
fetchr
Expand Down
64 changes: 32 additions & 32 deletions ui/src/components/microsegmentation/AddSegmentation.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ export default class AddSegmentation extends React.Component {
this.setState({ members });
}

createPolicy(policyName, roleName, resource, action, roleCreated) {
createPolicy(policyName, roleName, resource, action) {
//Validating ACL policy and adding/updating assertion. if get policy threw a 404 then create a new policy
var foundAssertionMatch = false;

Expand All @@ -320,7 +320,7 @@ export default class AddSegmentation extends React.Component {
foundAssertionMatch = true;
}
});
if (foundAssertionMatch && roleCreated) {
if (foundAssertionMatch) {
this.api
.deleteRole(
this.props.domain,
Expand All @@ -336,10 +336,6 @@ export default class AddSegmentation extends React.Component {
.catch((err) => {
reject(RequestUtils.xhrErrorCheckHelper(err));
});
} else if (foundAssertionMatch) {
if (!this.state.errorMessage) {
this.props.onSubmit();
}
} else {
this.api
.addAssertion(
Expand Down Expand Up @@ -805,8 +801,7 @@ export default class AddSegmentation extends React.Component {
policyName,
role.name,
resource,
action,
true
action
);
})
.catch((err) => {
Expand Down Expand Up @@ -1294,30 +1289,35 @@ export default class AddSegmentation extends React.Component {
filterable
/>
</SectionDiv>
<SectionDiv>
<StyledInputLabel>Validation</StyledInputLabel>
<CheckBoxSectionDiv>
<StyledCheckBox
checked={this.state.validationCheckbox}
name={
'checkbox-validate-policy' +
this.state.isCategory
}
id={
'checkbox-validate-policy' +
this.state.isCategory
}
key={
'checkbox-validate-policy' +
this.state.isCategory
}
label='Validate Microsegmentation policy against PES network policy'
onChange={(event) =>
this.inputChanged(event, 'validationCheckbox')
}
/>
</CheckBoxSectionDiv>
</SectionDiv>
{this.props.pageFeatureFlag['policyValidation'] && (
<SectionDiv>
<StyledInputLabel>Validation</StyledInputLabel>
<CheckBoxSectionDiv>
<StyledCheckBox
checked={this.state.validationCheckbox}
name={
'checkbox-validate-policy' +
this.state.isCategory
}
id={
'checkbox-validate-policy' +
this.state.isCategory
}
key={
'checkbox-validate-policy' +
this.state.isCategory
}
label='Validate Microsegmentation policy against PES network policy'
onChange={(event) =>
this.inputChanged(
event,
'validationCheckbox'
)
}
/>
</CheckBoxSectionDiv>
</SectionDiv>
)}
{this.props.justificationRequired && (
<SectionDiv>
<StyledInputLabel>Justification</StyledInputLabel>
Expand Down
1 change: 1 addition & 0 deletions ui/src/components/microsegmentation/RuleRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ export default class RuleRow extends React.Component {
justificationRequired={this.props.justificationRequired}
editMode={true}
data={editData}
pageFeatureFlag={this.props.pageFeatureFlag}
/>
) : (
''
Expand Down
1 change: 1 addition & 0 deletions ui/src/components/microsegmentation/RuleTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export default class RuleTable extends React.Component {
onUpdateSuccess={this.props.onSubmit}
_csrf={this.props._csrf}
justificationRequired={this.props.justificationRequired}
pageFeatureFlag={this.props.pageFeatureFlag}
/>
);
});
Expand Down
2 changes: 2 additions & 0 deletions ui/src/components/microsegmentation/RulesList.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export default class RulesList extends React.Component {
_csrf={this.props._csrf}
showAddSegment={this.state.showAddSegmentation}
justificationRequired={this.props.isDomainAuditEnabled}
pageFeatureFlag={this.props.pageFeatureFlag}
/>
) : (
''
Expand Down Expand Up @@ -197,6 +198,7 @@ export default class RulesList extends React.Component {
data={this.state.segmentationData.outbound}
caption='Outbound'
justificationRequired={this.props.isDomainAuditEnabled}
pageFeatureFlag={this.props.pageFeatureFlag}
/>
) : null}
{!showInbound && !showOutbound && this.state.tabularView ? (
Expand Down
5 changes: 5 additions & 0 deletions ui/src/config/default-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ const config = {
],
statusPath: process.env.UI_SESSION_SECRET_PATH || 'keys/cookie-session',
featureFlag: true,
pageFeatureFlag: {
microsegmentation: {
policyValidation: true,
},
},
serviceHeaderLinks: [
{
description:
Expand Down
5 changes: 4 additions & 1 deletion ui/src/pages/domain/[domain]/microsegmentation.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ export async function getServerSideProps(context) {
api.getFeatureFlag(),
api.getMeta(bServicesParams),
api.getMeta(bServicesParamsAll),
api.getPageFeatureFlag("microsegmentation"),
]).catch((err) => {
let response = RequestUtils.errorCheckHelper(err);
reload = response.reload;
error = response.error;
return [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}];
return [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}];
});
let businessServiceOptions = [];
if (data[9] && data[9].validValues) {
Expand Down Expand Up @@ -146,6 +147,7 @@ export async function getServerSideProps(context) {
featureFlag: true,
validBusinessServices: businessServiceOptions,
validBusinessServicesAll: businessServiceOptionsAll,
pageFeatureFlag: data[11],
}
};
}
Expand Down Expand Up @@ -222,6 +224,7 @@ export default class MicrosegmentationPage extends React.Component {
_csrf={_csrf}
isDomainAuditEnabled={auditEnabled}
data={segmentationData}
pageFeatureFlag={this.props.pageFeatureFlag}
/>
</RolesContentDiv>
</RolesContainerDiv>
Expand Down
123 changes: 75 additions & 48 deletions ui/src/server/handlers/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -807,59 +807,78 @@ Fetchr.registerService({
Fetchr.registerService({
name: 'assertionId',
read(req, resource, params, config, callback) {
new Promise((resolve, reject) => {
req.clients.zms.getPolicy(
{
policyName: params.policyName,
domainName: params.domainName,
},
(err, data) => {
if (err) {
reject(err);
}
if (data) {
resolve(data);
}
const timeout = 1000;
const numberOfRetry = 2;
const delay = (ms) => new Promise((res) => setTimeout(res, ms));

const getAssertionId = (data) => {
data.assertions.forEach((assertion) => {
if (
assertion.role ===
params.domainName + ':role.' + params.roleName &&
assertion.resource ===
params.domainName + ':' + params.resource &&
assertion.action === params.action &&
assertion.effect === params.effect
) {
return assertion.id;
}
);
})
.then((policyData) => {
let flag = 0;
policyData.assertions.forEach((assertion) => {
if (
assertion.role ===
params.domainName + ':role.' + params.roleName &&
assertion.resource ===
params.domainName + ':' + params.resource &&
assertion.action === params.action &&
assertion.effect === params.effect
) {
flag = 1;
callback(null, assertion.id);
});
return -1;
};

const getPolicy = () => {
return new Promise((resolve, reject) => {
return req.clients.zms.getPolicy(
{
policyName: params.policyName,
domainName: params.domainName,
},
(err, data) => {
if (data) {
resolve(data);
} else {
reject(err);
}
}
});
);
});
};

if (!flag) {
let error = {
status: 404,
message: {
message:
'Failed to get assertion for policy ' +
params.policyName +
'.',
},
};
callback(errorHandler.fetcherError(error));
}
async function retryGetPolicy() {
for (let i = 1; i <= numberOfRetry; i++) {
await getPolicy()
.then(async (data) => {
let assertionId = getAssertionId(data);
if (assertionId == -1) {
if (i == numberOfRetry) {
let error = {
status: 404,
message: {
message:
'Failed to get assertion for policy ' +
params.policyName +
'.',
},
};
throw error;
}
}
})
.catch((err) => {
if (i == numberOfRetry) {
throw err;
}
});
await delay(timeout);
}
}

retryGetPolicy()
.then((data) => {
callback(null, data);
})
.catch((err) => {
debug(
`principal: ${req.session.shortId} rid: ${
req.headers.rid
} Error from ZMS while calling getPolicy API for microsegmentation: ${JSON.stringify(
err
)}`
);
callback(errorHandler.fetcherError(err));
});
},
Expand Down Expand Up @@ -1986,6 +2005,13 @@ Fetchr.registerService({
},
});

Fetchr.registerService({
name: 'page-feature-flag',
read(req, resource, params, config, callback) {
callback(null, appConfig.pageFeatureFlag[params.pageName]);
},
});

Fetchr.registerService({
name: 'microsegmentation',

Expand Down Expand Up @@ -2606,6 +2632,7 @@ module.exports.load = function (config, secrets) {
allPrefixes: config.allPrefixes,
zmsLoginUrl: config.zmsLoginUrl,
featureFlag: config.featureFlag,
pageFeatureFlag: config.pageFeatureFlag,
serviceHeaderLinks: config.serviceHeaderLinks,
templates: config.templates,
};
Expand Down

0 comments on commit 0bffa96

Please sign in to comment.