Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.

Fix Internal server error in Get Profiles by invalid Params#6003

Merged
ocket8888 merged 16 commits intoapache:masterfrom
dmohan001c:getprofiles
Sep 20, 2021
Merged

Fix Internal server error in Get Profiles by invalid Params#6003
ocket8888 merged 16 commits intoapache:masterfrom
dmohan001c:getprofiles

Conversation

@dmohan001c
Copy link
Contributor

@dmohan001c dmohan001c commented Jul 8, 2021

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?

  • CDN in a Box
  • Traffic Control Client
  • Traffic Ops
  • CI tests

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?

  • Master

The following criteria are ALL met by this PR

  • This PR includes tests OR I have explained why tests are unnecessary
  • This PR includes documentation OR I have explained why documentation is unnecessary
  • This PR includes an update to CHANGELOG.md OR such an update is not necessary
  • This PR includes any and all required license headers
  • This PR DOES NOT FIX A SERIOUS SECURITY VULNERABILITY (see the Apache Software Foundation's security guidelines for details)

@dmohan001c dmohan001c changed the title Fix Fix Internal server error in Get Profiles by invalid Params Jul 8, 2021
@ocket8888 ocket8888 added bug something isn't working as intended low impact affects only a small portion of a CDN, and cannot itself break one Traffic Ops related to Traffic Ops labels Jul 8, 2021
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 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added another validation for the param and cdn to make sure it's an integer.

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done.

@dmohan001c dmohan001c marked this pull request as draft August 4, 2021 13:48
@dmohan001c dmohan001c marked this pull request as ready for review August 5, 2021 03:19
Copy link
Contributor

Choose a reason for hiding this comment

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

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)
		// }```

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated the DB Query to support params in GET profiles.

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

@dmohan001c dmohan001c Aug 10, 2021

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

V2 AND V3 profiles tests are failing. I am taking a look on it.

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@dmohan001c dmohan001c marked this pull request as draft August 12, 2021 14:04
@dmohan001c dmohan001c marked this pull request as ready for review August 12, 2021 17:09
@dmohan001c dmohan001c marked this pull request as draft August 13, 2021 07:38
@dmohan001c dmohan001c marked this pull request as ready for review August 23, 2021 11:28
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reverted the method signature

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

@dmohan001c dmohan001c closed this Aug 25, 2021
@dmohan001c dmohan001c reopened this Aug 25, 2021
// 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))
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably check for the error here.

Copy link
Contributor

Choose a reason for hiding this comment

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

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
}

Copy link
Contributor Author

@dmohan001c dmohan001c Sep 1, 2021

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Created a new client method


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)
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 as above here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

}
profileID := resp.Response[0].ID

// TODO: figure out what the 'Parameter' field of a Profile is and how
Copy link
Contributor

Choose a reason for hiding this comment

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

You can probably remove these commented lines now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@dmohan001c dmohan001c closed this Sep 13, 2021
@dmohan001c dmohan001c reopened this Sep 13, 2021
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason to keep that first line in there still?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably check for the returned error here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably check for the returned error here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably check for the returned error here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added error checks

@srijeet0406
Copy link
Contributor

@dmohan001c It looks like the go format checks are failing. Once that is fixed, I can test this and approve.

parameter := pr.Parameters[0]
respParameter, _, err := TOSession.GetParameterByName(*parameter.Name)
if err != nil {
t.Errorf("Cannot GET Parameter by name: %v - %v", err, resp)
Copy link
Contributor

Choose a reason for hiding this comment

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

This resp is the wrong response here. Also, I don't think you need to print the response here, just the error is fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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)
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, no need to print the response.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed.

if len(pr.Parameters) > 0 {
parameter := pr.Parameters[0]
respParameter, _, err := TOSession.GetParameterByName(*parameter.Name)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

same

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

if len(pr.Parameters) > 0 {
parameter := pr.Parameters[0]
opts.QueryParameters.Set("name", *parameter.Name)
respParameter, _, _ := TOSession.GetParameters(opts)
Copy link
Contributor

Choose a reason for hiding this comment

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

You should be checking the error here, as you are doing in the v2 and v3 tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added error checks

return to.GetProfileByParameterWithHdr(param, nil)
}

func (to *Session) GetProfileByParameterIdWithHdr(param int, header http.Header) ([]tc.Profile, toclientlib.ReqInf, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Godoc is missing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added godoc.

return data.Response, reqInf, err
}

func (to *Session) GetProfileByParameterId(param int) ([]tc.Profile, ReqInf, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Godoc is missing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added godoc,.

Copy link
Contributor

@srijeet0406 srijeet0406 left a comment

Choose a reason for hiding this comment

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

Code changes look good.
All tests pass.
Manual testing looks good as well.
LGTM!

@ocket8888 ocket8888 merged commit bf0df00 into apache:master Sep 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

bug something isn't working as intended low impact affects only a small portion of a CDN, and cannot itself break one Traffic Ops related to Traffic Ops

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unverified query parameter causes Internal Server Error

3 participants