Fix Internal server error in Get Profiles by invalid Params#6003
Fix Internal server error in Get Profiles by invalid Params#6003ocket8888 merged 16 commits intoapache:masterfrom
Conversation
There was a problem hiding this comment.
This is an internal database error and should probably remain as an internal server error.
Instead, what you can do is add another validation for the param query parameter to make sure it's an integer.
Also, you can add the JOIN clause for the profile_parameter to the main select query (just like the cdn join part), instead of checking for it separately.
Additionally, as mentioned in the GH issue, there are a lot of client methods that use the profile param as a string(name), instead of an int(id). We should probably fix those in this PR as well.
There was a problem hiding this comment.
added another validation for the param and cdn to make sure it's an integer.
There was a problem hiding this comment.
As I mentioned in the previous comment, this should just stay the same as it was before.
You could add another validation for the param being an int.
There was a problem hiding this comment.
Instead of checking for individual query parameters like this, we should just add them as part of the checkers on lines 116-120.
You should also add the checker for the ParamQueryParam in there, something like this:
queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
CDNQueryParam: dbhelpers.WhereColumnInfo{Column: "c.id", Checker: api.IsInt},
NameQueryParam: dbhelpers.WhereColumnInfo{Column: "prof.name"},
IDQueryParam: dbhelpers.WhereColumnInfo{Column: "prof.id", Checker: api.IsInt},
ParamQueryParam: dbhelpers.WhereColumnInfo{Column: "pp.parameter", Checker: api.IsInt},
}
Then, on line 126, if ParamQueryParam is present, you add the Left Join... subquery to the main select query.
This way, we can have one single place where we check for all the query params.
The API v2 and v3 tests currently fail because they are passing in a param name as an ID to the client methods. These will need to be fixed. Also, there is this section of code in the v4 tests, which can be uncommented after the fix:
// passing it to this is supposed to work.
// resp, _, err = TOSession.GetProfileByParameter(pr.Parameter)
// if err != nil {
// t.Errorf("cannot GET Profile by param: %v - %v", err, resp)
// }```
There was a problem hiding this comment.
updated the DB Query to support params in GET profiles.
There was a problem hiding this comment.
Once you add the ParamQueryParam to the queryParamsToQueryCols, the BuildWhereAndOrderByAndPagination function will automatically add the WHERE clause to the query, you don't need to modify the where variable above. Instead, what you can do is add just the LEFT JOIN profile_parameter pp ON prof.id = pp.profile part if the parameter_id param is present.
With the current changes, the query comes out to be this:
SELECT prof.description, prof.id, prof.last_updated, prof.name, prof.routing_disabled, prof.type, c.id as cdn, c.name as cdn_name FROM profile prof LEFT JOIN cdn c ON prof.cdn = c.id LEFT JOIN profile_parameter pp ON prof.id = pp.profile WHERE pp.parameter=:param AND pp.parameter=:parameter_id
We don't need the two WHERE clauses in our query. Also, I think the tests are still failing for API v2 and v3.
There was a problem hiding this comment.
If I didn't change the WHERE as per above statement, the query looks incorrect.
SELECT prof.description, prof.id, prof.last_updated, prof.name, prof.routing_disabled, prof.type, c.id as cdn, c.name as cdn_name FROM profile prof LEFT JOIN cdn c ON prof.cdn = c.id WHERE pp.parameter=:param LEFT JOIN profile_parameter pp ON prof.id = pp.profile.
getting internal server error. So, the above changes look good to me.
There was a problem hiding this comment.
V2 AND V3 profiles tests are failing. I am taking a look on it.
There was a problem hiding this comment.
No, the WHERE clause will be created by the BuildWhereAndOrderByAndPagination function and you dont need to account for it, if you're passing in all the right query params into it.
e95ffe5 to
1b27620
Compare
There was a problem hiding this comment.
You can't actually change the existing client signatures because that breaks the clients that are using them. I suggest creating a new method that takes in the parameterID, instead of the parameter name, and then using that method in the tests. You can leave the GetProfileByParameterWithHdr method as it is.
There was a problem hiding this comment.
reverted the method signature
8a5a9bd to
6aeff07
Compare
traffic_ops/v3-client/profile.go
Outdated
There was a problem hiding this comment.
You can't change the signatures of these methods, if this code is not a part of a major release. There might be other client scripts using these methods, which will break if you change the signature. Instead, I would suggest doing something like you did in the v2 client method above. That way, the method signature stays the same.
b533e99 to
391d26a
Compare
traffic_ops/v2-client/profile.go
Outdated
| // GetProfileByParameter GETs a Profile by the Profile "param". | ||
| func (to *Session) GetProfileByParameter(param string) ([]tc.Profile, ReqInf, error) { | ||
| URI := fmt.Sprintf("%s?param=%s", API_PROFILES, url.QueryEscape(param)) | ||
| paramId, _ := strconv.Atoi(url.QueryEscape(param)) |
There was a problem hiding this comment.
We should probably check for the error here.
There was a problem hiding this comment.
Also, as I suggested earlier, instead of breaking the way pre existing client methods work, why not create a new client method that takes in a param ID instead of a param name, and then make the GET call? Something like this:
func (to *Session) GetProfileByParameterID(paramID string, header http.Header) ([]tc.Profile, ReqInf, error) {
uri := fmt.Sprintf("%s?param=%d", APIProfiles, paramID)
var data tc.ProfilesResponse
reqInf, err := to.get(uri, header, &data)
return data.Response, reqInf, err
}
There was a problem hiding this comment.
I don't want to create a new method, since the bug fixes require the API to accept int parameters(there is no change in method signature), If we keep the existing methods as per your advice, if someone accidentally calls the method, it will throw an error since that API is not anymore supporting string.
There was a problem hiding this comment.
Created a new client method
traffic_ops/v3-client/profile.go
Outdated
|
|
||
| func (to *Session) GetProfileByParameterWithHdr(param string, header http.Header) ([]tc.Profile, toclientlib.ReqInf, error) { | ||
| URI := fmt.Sprintf("%s?param=%s", APIProfiles, url.QueryEscape(param)) | ||
| URI := fmt.Sprintf("%s?param=%s", APIProfiles, param) |
There was a problem hiding this comment.
Same comment as above here.
| } | ||
| profileID := resp.Response[0].ID | ||
|
|
||
| // TODO: figure out what the 'Parameter' field of a Profile is and how |
There was a problem hiding this comment.
You can probably remove these commented lines now.
| @@ -518,11 +518,31 @@ func GetTestProfiles(t *testing.T) { | |||
| profileID := resp.Response[0].ID | |||
|
|
|||
| // TODO: figure out what the 'Parameter' field of a Profile is and how | |||
There was a problem hiding this comment.
Any reason to keep that first line in there still?
There was a problem hiding this comment.
I removed this line.
| t.Errorf("cannot GET Profile by param: %v - %v", err, resp) | ||
| if len(pr.Parameters) > 0 { | ||
| parameter := pr.Parameters[0] | ||
| respParameter, _, _ := TOSession.GetParameterByName(*parameter.Name) |
There was a problem hiding this comment.
We should probably check for the returned error here.
There was a problem hiding this comment.
added error checks
| t.Fatalf("Expected 304 status code, got %v", reqInf.StatusCode) | ||
| if len(pr.Parameters) > 0 { | ||
| parameter := pr.Parameters[0] | ||
| respParameter, _, _ := TOSession.GetParameterByName(*parameter.Name) |
There was a problem hiding this comment.
We should probably check for the returned error here.
There was a problem hiding this comment.
added error checks.
| t.Errorf("cannot GET Profile by param: %v - %v", err, resp) | ||
| if len(pr.Parameters) > 0 { | ||
| parameter := pr.Parameters[0] | ||
| respParameter, _, _ := TOSession.GetParameterByName(*parameter.Name) |
There was a problem hiding this comment.
We should probably check for the returned error here.
There was a problem hiding this comment.
added error checks
|
@dmohan001c It looks like the |
| parameter := pr.Parameters[0] | ||
| respParameter, _, err := TOSession.GetParameterByName(*parameter.Name) | ||
| if err != nil { | ||
| t.Errorf("Cannot GET Parameter by name: %v - %v", err, resp) |
There was a problem hiding this comment.
This resp is the wrong response here. Also, I don't think you need to print the response here, just the error is fine.
There was a problem hiding this comment.
removed the response in error statement
| if parameterID > 0 { | ||
| resp, _, err = TOSession.GetProfileByParameterId(parameterID) | ||
| if err != nil { | ||
| t.Errorf("cannot GET Profile by param: %v - %v", err, resp) |
There was a problem hiding this comment.
Same comment here, no need to print the response.
There was a problem hiding this comment.
removed the response from print statement
| parameter := pr.Parameters[0] | ||
| respParameter, _, err := TOSession.GetParameterByName(*parameter.Name) | ||
| if err != nil { | ||
| t.Errorf("Cannot GET Parameter by name: %v - %v", err, respParameter) |
| if len(pr.Parameters) > 0 { | ||
| parameter := pr.Parameters[0] | ||
| respParameter, _, err := TOSession.GetParameterByName(*parameter.Name) | ||
| if err != nil { |
| if len(pr.Parameters) > 0 { | ||
| parameter := pr.Parameters[0] | ||
| opts.QueryParameters.Set("name", *parameter.Name) | ||
| respParameter, _, _ := TOSession.GetParameters(opts) |
There was a problem hiding this comment.
You should be checking the error here, as you are doing in the v2 and v3 tests.
There was a problem hiding this comment.
added error checks
| return to.GetProfileByParameterWithHdr(param, nil) | ||
| } | ||
|
|
||
| func (to *Session) GetProfileByParameterIdWithHdr(param int, header http.Header) ([]tc.Profile, toclientlib.ReqInf, error) { |
| return data.Response, reqInf, err | ||
| } | ||
|
|
||
| func (to *Session) GetProfileByParameterId(param int) ([]tc.Profile, ReqInf, error) { |
srijeet0406
left a comment
There was a problem hiding this comment.
Code changes look good.
All tests pass.
Manual testing looks good as well.
LGTM!
What does this PR (Pull Request) do?
This updates the Error message in GET profiles?param=test and profiles?cdn=test
Which Traffic Control components are affected by this PR?
What is the best way to verify this PR?
Execute all the Integration tests and make sure the tests are passed.
If this is a bug fix, what versions of Traffic Control are affected?
The following criteria are ALL met by this PR