-
Notifications
You must be signed in to change notification settings - Fork 484
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
fix: Invoke Validate function when adding yaml DeviceProfile #2597
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two issues that I'd like to see addressed in the code. The first involves error handling, and if there's no other way around it, we'll have to live with it. If so, we should ensure that we don't make the same mistake with our V2 APIs.
The only other comment I have about your commit message:
fix: Invoke Validate function when adding yaml DeviceProfile
Add yaml format DeviceProfile should invoke Validate function to prevent uploading invalid DeviceProfile.
Signed-off-by: weichou <[email protected]>
Please add a scope to your commit summary so others can tell what service is being modified, and second there should always be a blank line between the commit summary and the message body, so your commit should look like this:
fix(metadata): Invoke Validate function when adding YAML DeviceProfile
Add YAML format DeviceProfile should invoke Validate function to prevent uploading invalid DeviceProfile.
Signed-off-by: weichou <[email protected]>
Note - also acronyms like YAML, TOML, ..., should always be uppercase.
@@ -281,6 +283,16 @@ func restAddProfileByYaml( | |||
return | |||
} | |||
|
|||
err = validateDeviceProfileStruct(dp) | |||
if err != nil { | |||
if err.Error() == duplicatedCommandNameError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems pretty fragile to have to define the constant duplicatedCommandNameError
in this file in order to be able to distinguish between two different errors conditions detected by the underlying DeviceProfile.Validate()
method that's called by validateDeviceProfileStruct
. This seems like a possible flaw in our original object validation approach implemented for our V1 REST endpoints.
The OpenAPI error description for this specific case says:
409: If an associated command's name is a duplicate for the profile or if the name is determined to not be unique with regard to others.
This description is poorly worded. I think what it means is this:
If the device profile defines more than one core command with the same name, or if it defines a core command which conflicts with an already existing core command from another device profile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is fragile, but it is a quick workaround to avoid breaking API backward compatibility. Do you have any other suggestion?
Your first statement is enough. We allow the same command name in different profile.
https://github.com/edgexfoundry/go-mod-core-contracts/blob/0746ea1719ff74015da8ef926f06a40e1e317cc2/models/deviceprofile.go#L87-L95
May we update the Swagger file in this PR to the following description?
If the device profile defines more than one core command with the same name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is fragile, but it is a quick workaround to avoid breaking API backward compatibility. Do you have any other suggestion?
Sure, but we never validated device profiles when using this endpoint... That said, if this aligns with the deviceprofile
import using JSON, I guess we can leave it as is. Does our new approach to validation being used for V2 allow more flexible error reporting? I would hate to see us make the same mistake twice...
Your first statement is enough. We allow the same command name in different profile.
https://github.com/edgexfoundry/go-mod-core-contracts/blob/0746ea1719ff74015da8ef926f06a40e1e317cc2/models/deviceprofile.go#L87-L95May we update the Swagger file in this PR to the following description?
If the device profile defines more than one core command with the same name.
Yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but we never validated device profiles when using this endpoint... That said, if this aligns with the
deviceprofile
import using JSON, I guess we can leave it as is. Does our new approach to validation being used for V2 allow more flexible error reporting? I would hate to see us make the same mistake twice...
We will avoid this situation in V2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May we update the Swagger file in this PR to the following description?
If the device profile defines more than one core command with the same name.
Swagger file updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is fragile, but it is a quick workaround to avoid breaking API backward compatibility. Do you have any other suggestion?
Is it breaking backward compatibility because the code doesn't match our OpenAPI documentation or is it breaking because the non-YAML deviceprofile
endpoint can return 409, and thus we want the deviceprofile/upload
, and ../uploadfile
endpoints to do the same???
I would argue that if none of the deviceprofile
endpoints ever return 409, then it's not breaking backward compatibility if the YAML endpoints don't return it either...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I actually did a bunch of testing this afternoon using Bruce's PR, as well as against the geneva snap (1.2.1). I found that 400 is returned for "duplicate core command names" not 409. In fact, I haven't looked at the actual code path, but even without the fix, the uploadfile endpoint does still return a 400 error in this situation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For json format:
I look into the source code
https://github.com/edgexfoundry/edgex-go/blob/master/internal/core/metadata/rest_deviceprofile.go#L74
if err := json.NewDecoder(r.Body).Decode(&dp); err != nil {
errorHandler.Handle(w, err, errorconcept.Common.InvalidRequest_StatusBadRequest)
return
}
It only return 400 when uploading the invalid device profile and the implementation not match the API doc.
https://github.com/edgexfoundry/edgex-go/blob/master/api/openapi/v1/core-metadata.yaml#L933
@weichou1229 also your branch is out of sync with master, so please re-base. |
No problem, modified the commit message and rebase on the master branch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my comments regarding the actual error that's supposed to be returned when an imported device profile contains core commands with duplicate names. Maybe the OpenAPI definition wasn't ever validated against the real service?
api/openapi/v1/core-metadata.yaml
Outdated
@@ -931,8 +931,7 @@ paths: | |||
400: | |||
description: For malformed or unparsable requests | |||
409: | |||
description: If an associated command's name is a duplicate for the profile | |||
or if the name is determined to not be unique with regard to others. | |||
description: If the device profile defines more than one core command with the same name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran some tests, and 409 is actually returned when a device profile with the same name already exists, not when duplicate core commands exist within a device profile (JSON or YAML). I checked against the geneva version 1.2.1 (using the snap), and sure enough when a device profile is imported with duplicate command names, the return code is 400.
So this description should really be:
If the profile's name matches an existing device profile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean?
- The deviceProfile POST API should return 400 for func (dp DeviceProfile) Validate() error.
- The deviceProfile POST API should return 409 If the profile's name matches an existing device profile.
@@ -281,6 +283,16 @@ func restAddProfileByYaml( | |||
return | |||
} | |||
|
|||
err = validateDeviceProfileStruct(dp) | |||
if err != nil { | |||
if err.Error() == duplicatedCommandNameError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I actually did a bunch of testing this afternoon using Bruce's PR, as well as against the geneva snap (1.2.1). I found that 400 is returned for "duplicate core command names" not 409. In fact, I haven't looked at the actual code path, but even without the fix, the uploadfile endpoint does still return a 400 error in this situation
Refactor deviceProfile adding func to use same validation logic for JSON and YAML format DeviceProfile. Signed-off-by: weichou <[email protected]>
Kudos, SonarCloud Quality Gate passed! 0 Bugs No Coverage information |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Fix #2596
PR Checklist
Please check if your PR fulfills the following requirements:
make test
has completed successfullyPR Type
What kind of change does this PR introduce?
What is the current behavior?
YAML DeviceProfile uploading API doesn't validate the content.
Issue Number: #2596
What is the new behavior?
Invoke Validate function when uploading yaml format DeviceProfile to prevent uploading invalid DeviceProfile.
Does this PR introduce a breaking change?
Are there any new imports or modules? If so, what are they used for and why?
Are there any specific instructions or things that should be known prior to reviewing?
Since deviceProfile.Validate() not validate the nested object, so create another function to validate that.
Other information