Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed the issue osc-core issue #543 #621

Merged

Conversation

bmmukund
Copy link

@bmmukund bmmukund commented Dec 12, 2017

Description

Modified the Error message to be more appropriate when deleting a DA without deleting the SFC.

Motivation and Context

Error message should be more suggestive - e.g. DA cannot be deleted unless the SFC is deleted
#543

How Has This Been Tested?

Tested manually.

Screenshots (if appropriate):

Types of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

@bmmukund
Copy link
Author

@sudhirappaji,
Please review my code changes.

@@ -53,6 +60,10 @@ public DistributedAppliance validateAndLoad(BaseDeleteRequest request) throws Ex
da.getId()));
}

// DE5296->Error message to be more appropriate when deleting a DA without
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comments related to the issue - DES296.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your comments . I removed the comments and will be updated in next review request.

@@ -185,7 +185,6 @@ public static synchronized Long generateUniqueTag(EntityManager em, VirtualSyste
}

public static boolean isProtectingWorkload(VirtualSystem vs) {
return !vs.getServiceFunctionChains().isEmpty() ||
CollectionUtils.emptyIfNull(vs.getDeploymentSpecs()).stream().anyMatch(ds -> DeploymentSpecEntityMgr.isProtectingWorkload(ds));
return CollectionUtils.emptyIfNull(vs.getDeploymentSpecs()).stream().anyMatch(ds -> DeploymentSpecEntityMgr.isProtectingWorkload(ds));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getServiceFunctionChains().isEmpty() should not be removed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its required to remove this check because getServiceFunctionChains().isEmpty() will not separate the SFC call and would not be able to throw the appropriate error message.

@@ -62,4 +73,26 @@ public DistributedAppliance validateAndLoad(BaseDeleteRequest request) throws Ex

return da;
}

private void validateDAReferenceToSfcAndSecurityGroup(EntityManager em, DistributedAppliance da) throws Exception {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply the eclipse settings for code style.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review comments . I will use eclipse code style before putting next review request.

private void validateDAReferenceToSfcAndSecurityGroup(EntityManager em, DistributedAppliance da) throws Exception {
for (VirtualSystem vs : da.getVirtualSystems()) {
if (!vs.getServiceFunctionChains().isEmpty()) {
// DE5296-->Look if these SFCs are binded to any of the SG of same DA
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the comments

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review comments . I removed it.

// DE5296-->Look if these SFCs are binded to any of the SG of same DA
for (ServiceFunctionChain sfc : vs.getServiceFunctionChains()) {
List<SecurityGroup> sgList = SecurityGroupEntityMgr.listSecurityGroupsBySfcId(em, sfc.getId());
String sgNames = sgList.stream().filter(sg -> !sg.getMarkedForDeletion()).map(sg -> sg.getName())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we not looking for marked for deletion?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review comments .I made changes.

@sudhirappaji
Copy link
Member

@bmmukund , make sure coding guidelines are checked and followed and also unit test guidelines are checked.

@@ -53,6 +60,10 @@ public DistributedAppliance validateAndLoad(BaseDeleteRequest request) throws Ex
da.getId()));
}

// DE5296->Error message to be more appropriate when deleting a DA without
// deleting the SFC
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not look like the line below is deleting, pls remote this comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review comments .I made changes

if (!vs.getServiceFunctionChains().isEmpty()) {
// DE5296-->Look if these SFCs are binded to any of the SG of same DA
for (ServiceFunctionChain sfc : vs.getServiceFunctionChains()) {
List<SecurityGroup> sgList = SecurityGroupEntityMgr.listSecurityGroupsBySfcId(em, sfc.getId());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add this to a private method to improve readability: validateSfcReferenceToSecurityGroup. This combination of private methods will make the overall intended validation clearer

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review comments .I made changes as suggested.


private void validateDAReferenceToSfcAndSecurityGroup(EntityManager em, DistributedAppliance da) throws Exception {
for (VirtualSystem vs : da.getVirtualSystems()) {
if (!vs.getServiceFunctionChains().isEmpty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to a private method named validateVSReferenceToSfcAndSecurityGroup. In that method you can return immediately if the getSFCs is empty. This will reduce if-nesting and improve readability.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review comments .I moved it into new suggested method.

@bmmukund bmmukund force-pushed the osc_core_DA_SFC_Error_Fix branch 2 times, most recently from 05a5179 to 493c328 Compare December 18, 2017 12:00
@bmmukund
Copy link
Author

@emanoelxavier, @sudhirappaji,
Please review the changes.

private void validateVSReferenceToSfcAndSecurityGroup(EntityManager em, DistributedAppliance da, VirtualSystem vs)
throws Exception {

if (!getSFCs(vs)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not improving the readability. It is also not reducing nesting. Instead simply start this method with if vs.getsfcs == null || vs.getsfcs.isempty then return immediately.

return null;
}

private boolean getSFCs(VirtualSystem vs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this method, see the other comment.

throws Exception {

if (!getSFCs(vs)) {
if (validateSfcReferenceToSecurityGroup(em, da, vs) != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern is very strange. A method or function returning an exception is a code smell and should always be avoided. Exceptions are usually meant to be thrown not returned. Especially here where you check to see if it returns and exception and if so you call the same method again but then you throw. instead simply make the method validateSfcReferenceToSG throw and call it for each sfc in the VS looping through the sfcs . You also should not need to pass the VS as a parameter for this method at all since you would have the loop of ln 93 on this method instead. The pattern is... if empty return, if not loop through the sfcs in the VS, for each SFC call validateSfcRErferencetoSG which does not take a VS and does not return anything.

@bmmukund bmmukund force-pushed the osc_core_DA_SFC_Error_Fix branch 2 times, most recently from acccb63 to cc54476 Compare December 21, 2017 08:40
@arvindn05
Copy link
Member

arvindn05 commented Dec 21, 2017

@bmmukund travis build needs to succeed so folks can continue reviewing. Also make sure your branch is upto date with master.
looks like below test is failing
testValidateAndLoad_WhenChainedToSfcDeleteRequest_ThrowsValidationException(org.osc.core.broker.service.request.DeleteDistributedApplianceRequestValidatorTest)

@bmmukund bmmukund force-pushed the osc_core_DA_SFC_Error_Fix branch from cc54476 to 239c8b6 Compare December 27, 2017 09:15
@codecov
Copy link

codecov bot commented Dec 27, 2017

Codecov Report

Merging #621 into master will increase coverage by 0.01%.
The diff coverage is 53.84%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #621      +/-   ##
============================================
+ Coverage     26.49%   26.51%   +0.01%     
- Complexity     1614     1617       +3     
============================================
  Files           501      501              
  Lines         20089    20113      +24     
  Branches       2380     2383       +3     
============================================
+ Hits           5323     5333      +10     
- Misses        14358    14368      +10     
- Partials        408      412       +4
Impacted Files Coverage Δ Complexity Δ
...er/service/persistence/VirtualSystemEntityMgr.java 52.7% <100%> (+1.35%) 8 <2> (-1) ⬇️
...or/DeleteDistributedApplianceRequestValidator.java 70% <50%> (-30%) 13 <6> (+6)
...ice/persistence/DistributedApplianceEntityMgr.java 37.31% <0%> (-1.5%) 4% <0%> (-1%)
...ver/src/main/java/org/osc/core/broker/job/Job.java 68.37% <0%> (-0.61%) 69% <0%> (-1%)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 05d9339...1512249. Read the comment docs.

@bmmukund
Copy link
Author

@arvindn05 ,
Please review the code changes which i have done for the unit test cases.

arvindn05
arvindn05 previously approved these changes Dec 27, 2017
.collect(Collectors.joining(", "));
if (!sgNames.isEmpty()) {
throw new VmidcBrokerValidationException(String.format(
"Cannot delete deployment appliance with name '%s' which is currently referencing Service Function Chain '%s' and binded to a SecurityGroup(s) '%s'",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

distributed appliance

@@ -185,7 +185,7 @@ public static synchronized Long generateUniqueTag(EntityManager em, VirtualSyste
}

public static boolean isProtectingWorkload(VirtualSystem vs) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add javadoc to these methods to make it clear what they consider protected workload?

org.osc.core.broker.service.persistence.DistributedApplianceEntityMgr.isProtectingWorkload(DistributedAppliance)
org.osc.core.broker.service.persistence.VirtualSystemEntityMgr.isProtectingWorkload(VirtualSystem)
org.osc.core.broker.service.persistence.DeploymentSpecEntityMgr.isProtectingWorkload(DeploymentSpec)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please address this comment and add javadco.

for (ServiceFunctionChain sfc : vs.getServiceFunctionChains()) {
validateSfcReferenceToSecurityGroup(em, da, sfc);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra ln


private void validateVSReferenceToSfcAndSecurityGroup(EntityManager em, DistributedAppliance da, VirtualSystem vs)
throws Exception {
if (vs.getServiceFunctionChains() == null || vs.getServiceFunctionChains().isEmpty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isempty is not needed here, if empty the loop below simply wont execute.


}

private void validateSfcReferenceToSecurityGroup(EntityManager em, DistributedAppliance da,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit strange to have the da as a parameter here just to have the name in the exception message. The business logic of this method does not need a DA. Instead of passing the da it would be better to throw the exception without the da name in the message. On the method validateDAReferenceToSfcAndSecurityGroup (which a;ready has the DA) you can catch the exception, add the da name on the message and throw a new exception of the same type. This will keep the messages on the methods they belong to and avoid extra unnecessary parameters. In general the less parameters on a method the better,

@@ -56,6 +67,9 @@
@Mock
EntityManager em;

@Mock
Copy link
Contributor

@emanoelxavier emanoelxavier Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per our unit test guidelines https://github.com/opensecuritycontroller/community/blob/master/development/code-guidelines/unit_test_guidelines.md *EntityManagers should not be mocked. There are two approaches we use to deal with database entities/dependencies in our unit tests:

  1. Mocking the EntityManager (em.find): This works if the class under test depends simply on find by id or save, update, etc. This was the case for this class prior to your change, thus we were mocking em.find and that was enough here.
  2. Using an in-memory db. This is needed if the class under test depends on more complex queries, typically using query builders. This is the case now for this class after your changes, listSecurityGroupsBySfcId uses a query builder. So this is the option you should choose to implement these unit tests. We have many unit tests using in memory db, for instance AgentRegisterServiceRequestValidatorTest. Please take a look at those to see how that works and you can mimic the same approach here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bmmukund looks like none of my comments on this file have been addressed.

@@ -150,6 +165,63 @@ public void testValidateAndLoad_WhenChainedToSfcDeleteRequest_ThrowsValidationEx
this.validator.validateAndLoad(createRequest(VALID_ID_WITH_SFC, false));
}

@Test
public void testValidateSfcToSecurityGroup_WhenDADeleteRequest_ThrowsValidationException() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bmmukund it seems you missed this comment.

}

@Test
public void testValidateDaToSfc_WhenDADeleteRequest_ThrowsValidationException() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bmmukund bmmukund force-pushed the osc_core_DA_SFC_Error_Fix branch 4 times, most recently from 0abf5f1 to 63b7764 Compare December 28, 2017 20:41
Modified and added test cases.

Added back to original intialization

Made the changes according to the review comments.

Did required changes for unit test case.

Did the changes as per review comments.
@bmmukund bmmukund force-pushed the osc_core_DA_SFC_Error_Fix branch from 63b7764 to 06eb96e Compare December 29, 2017 07:29
@bmmukund
Copy link
Author

@emanoelxavier ,Please check if this be approved, so that Sudhir can go ahead and merge.

@sudhirappaji
Copy link
Member

@bmmukund , I notice that commits (for while incorporating the review comments in PR) are squashed. This should not be done and finally before the merger to master, this shall be squashed by the approver/gate keeper. Otherwise history is lost while reviewing PR. Please take note of it.

@@ -185,7 +185,7 @@ public static synchronized Long generateUniqueTag(EntityManager em, VirtualSyste
}

public static boolean isProtectingWorkload(VirtualSystem vs) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please address this comment and add javadco.

try {
validateVSReferenceToSfcAndSecurityGroup(em, vs);
} catch (VmidcBrokerValidationException ex) {
throw new VmidcBrokerValidationException(ex.getMessage() + " with name " + da.getName());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will be a user facing message...we should format this better.

The message will show
Cannot delete distributed appliance which is currently referencing Service Function Chain 'foosfc' and binded to a SecurityGroup(s) 'foosg' with name 'fooda'

I would just avoid this catch block or format the message like below

`Cannot delete distributed appliance 'fooda' which is currently referencing Service Function Chain 'foosfc' and binded to a SecurityGroup(s) 'foosg'.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for the suggested message. The main purpose of the catch is to avoid passing the da as a param just to have it in the message, makes the signature of the method validateVSReferenceToSfcAndSecurityGroup harder to understand.

try {
validateVSReferenceToSfcAndSecurityGroup(em, vs);
} catch (VmidcBrokerValidationException ex) {
throw new VmidcBrokerValidationException(ex.getMessage() + " with name " + da.getName());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for the suggested message. The main purpose of the catch is to avoid passing the da as a param just to have it in the message, makes the signature of the method validateVSReferenceToSfcAndSecurityGroup harder to understand.

@bmmukund bmmukund force-pushed the osc_core_DA_SFC_Error_Fix branch from 4a770f4 to d514a8d Compare January 12, 2018 11:17
@bmmukund bmmukund self-assigned this Jan 12, 2018
@bmmukund
Copy link
Author

@emanoelxavier,@arvindn05,@sudhirappaji,
Please review the incorporated changes for the review comments.

@bmmukund bmmukund closed this Jan 12, 2018
@sudhirappaji
Copy link
Member

@bmmukund , why did you close this PR? This is yet to be approved.
After the approval, this shall be merged with the master. Please reopen the PR and allow the reviewers to review and approve.

@sudhirappaji sudhirappaji reopened this Jan 12, 2018
try {
validateVSReferenceToSfcAndSecurityGroup(em, vs);
} catch (VmidcBrokerValidationException ex) {
throw new VmidcBrokerValidationException(da.getName() + " " + ex.getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be "Cannot delete the DA {da.getName}," + ex.getMessage

.collect(Collectors.joining(", "));
if (!sgNames.isEmpty()) {
throw new VmidcBrokerValidationException(String.format(
"distributed appliance cannot be deleted which is currently referencing Service Function Chain '%s' and binded to a SecurityGroup(s) '%s'",
Copy link
Contributor

@emanoelxavier emanoelxavier Jan 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you missed my comment before... once again there is nothing in this method about DA. The message should not have any comment about DA. It should be something like "The Service Function Chain sfc_name is referenced by the Security Group sg_name" . Also avoid using type names in the messages: SecurityGroup -> Security Group, this is also consistent with your use of Service Function Chain (rather than SFC or ServiceFunctionChain).

sfc.getName(), sgNames));
} else if (!sfc.getMarkedForDeletion() && sfc != null) {
throw new VmidcBrokerValidationException(String.format(
"distributed appliance cannot be deleted which is currently referencing Service Function Chain '%s'",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here.


@RunWith(PowerMockRunner.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a TODO here explaining this is a workaround to justify the usage of powermock. The better solution should be refactoring this test class to use an in mem db.

@@ -150,6 +162,65 @@ public void testValidateAndLoad_WhenChainedToSfcDeleteRequest_ThrowsValidationEx
this.validator.validateAndLoad(createRequest(VALID_ID_WITH_SFC, false));
}

@Test
public void testValidateDAReferenceToSfcAndSecurityGroup_WhenChainedToSfcAndSgDeleteRequest_ThrowsValidationException()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test name is still not consistent with the guidelines. Please review all the details on the guidelines with attention and let me know if you have any questions. Test names should be testMethodUnderTest_... in this case testValidateAndLoad... just like the other methods in this class. Also please your TODO around these methods as well (the same TODO i mentioned above). Also ensure to track this debt with an issue on GitHub, the correct way of doing this is refactoring this test class to use an in mem db.

@bmmukund bmmukund force-pushed the osc_core_DA_SFC_Error_Fix branch 3 times, most recently from 22cacec to 14d1494 Compare January 12, 2018 22:12
@bmmukund
Copy link
Author

@emanoelxavier ,
I have done the required changes.Please review and let me know if any changes needs to be done.

@@ -184,8 +184,12 @@ public static synchronized Long generateUniqueTag(EntityManager em, VirtualSyste
return prevVal;
}

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete this javadoc before merging.

try {
validateVSReferenceToSfcAndSecurityGroup(em, vs);
} catch (VmidcBrokerValidationException ex) {
throw new VmidcBrokerValidationException(String.format("Cannot delete the distributed appliance '%s' reason:",da.getName())+" "+ex.getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Cannot delete the distributed appliance '%s' reason: ", da.getName()) + ex.getMessage()) Please attempt to the spaces and details.

String sgNames = sgList.stream().filter(sg -> !sg.getMarkedForDeletion()).map(sg -> sg.getName())
.collect(Collectors.joining(", "));
if (!sgNames.isEmpty()) {
throw new VmidcBrokerValidationException(String.format("Service Function Chain '%s' and binded to a Security Group(s) '%s'",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and binded -> is binded. Please do a detailed cursory read of the code.

throw new VmidcBrokerValidationException(String.format("Service Function Chain '%s' and binded to a Security Group(s) '%s'",
sfc.getName(), sgNames));
} else if (!sfc.getMarkedForDeletion() && sfc != null) {
throw new VmidcBrokerValidationException(String.format("Service Function Chain '%s'",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This msg does not make sense.... Service Function Chain ?? The message must be a complete statement.

Change1:Reframed the Error Message.
Change2:Renamed the test methods.
Change3:Added the TODO comments for future references.
Change4:Reframed the throw message
@bmmukund bmmukund force-pushed the osc_core_DA_SFC_Error_Fix branch from abfab86 to 25162a9 Compare January 12, 2018 23:02
@bmmukund
Copy link
Author

@emanoelxavier ,
I did the required changes.Related to java doc,As Arvind asked me to include.Hence,i am not removing Please review the code and let me know if any changes needs to be done.

@sudhirappaji
Copy link
Member

@bmmukund ,please update the branch, I will take a look and merge it on Monday

@sudhirappaji sudhirappaji merged commit 2e8ac34 into opensecuritycontroller:master Jan 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants