From a8340bfff7380003fbc2a718a2875f6384b2b521 Mon Sep 17 00:00:00 2001 From: Idan Novogroder <43949240+idanovo@users.noreply.github.com> Date: Mon, 28 Feb 2022 15:27:53 +0200 Subject: [PATCH] Bugfix/2935 lakectl bug on not found html (#2966) * Changed all CLI commands to fail on unexpected status code returned and avoiding redirect automatically. --- cmd/lakectl/cmd/abuse.go | 10 ++--- cmd/lakectl/cmd/annotate.go | 21 +++++----- cmd/lakectl/cmd/auth.go | 53 +++++++++++++------------- cmd/lakectl/cmd/branch.go | 13 ++++--- cmd/lakectl/cmd/branch_protect.go | 8 ++-- cmd/lakectl/cmd/cat_hook_output.go | 4 +- cmd/lakectl/cmd/commit.go | 3 +- cmd/lakectl/cmd/common_helpers.go | 30 ++++++++++++++- cmd/lakectl/cmd/common_helpers_test.go | 4 +- cmd/lakectl/cmd/diff.go | 5 ++- cmd/lakectl/cmd/doctor.go | 2 +- cmd/lakectl/cmd/fs.go | 12 +++--- cmd/lakectl/cmd/gc.go | 7 +--- cmd/lakectl/cmd/ingest.go | 3 +- cmd/lakectl/cmd/log.go | 10 +++-- cmd/lakectl/cmd/merge.go | 4 +- cmd/lakectl/cmd/metastore.go | 7 ++-- cmd/lakectl/cmd/refs.go | 5 ++- cmd/lakectl/cmd/repo.go | 19 ++++----- cmd/lakectl/cmd/root.go | 8 ++++ cmd/lakectl/cmd/runs_describe.go | 12 +++--- cmd/lakectl/cmd/runs_list.go | 4 +- cmd/lakectl/cmd/show.go | 3 +- cmd/lakectl/cmd/tag.go | 14 ++++--- pkg/api/ui_handler.go | 3 +- 25 files changed, 160 insertions(+), 104 deletions(-) diff --git a/cmd/lakectl/cmd/abuse.go b/cmd/lakectl/cmd/abuse.go index a88db02417b..15a292cbf1e 100644 --- a/cmd/lakectl/cmd/abuse.go +++ b/cmd/lakectl/cmd/abuse.go @@ -119,7 +119,7 @@ var abuseRandomWritesCmd = &cobra.Command{ client := getClient() resp, err := client.GetRepositoryWithResponse(cmd.Context(), u.Repository) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) repo := resp.JSON200 storagePrefix := repo.StorageNamespace @@ -173,19 +173,19 @@ var abuseCreateBranchesCmd = &cobra.Command{ currentOffset := api.PaginationAfter(branchPrefix) amount := api.PaginationAmount(paginationAmount) for { - res, err := client.ListBranchesWithResponse(cmd.Context(), u.Repository, &api.ListBranchesParams{ + resp, err := client.ListBranchesWithResponse(cmd.Context(), u.Repository, &api.ListBranchesParams{ After: ¤tOffset, Amount: &amount, }) - DieOnResponseError(res, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) - for _, ref := range res.JSON200.Results { + for _, ref := range resp.JSON200.Results { if !strings.HasPrefix(ref.Id, branchPrefix) { return } add(ref.Id) // this branch should be deleted! } - pagination := res.JSON200.Pagination + pagination := resp.JSON200.Pagination if !pagination.HasMore { return } diff --git a/cmd/lakectl/cmd/annotate.go b/cmd/lakectl/cmd/annotate.go index 6358b331de0..d021915d039 100644 --- a/cmd/lakectl/cmd/annotate.go +++ b/cmd/lakectl/cmd/annotate.go @@ -1,6 +1,7 @@ package cmd import ( + "net/http" "strings" "github.com/spf13/cobra" @@ -31,33 +32,33 @@ var annotateCmd = &cobra.Command{ client := getClient() pfx := api.PaginationPrefix(*pathURI.Path) context := cmd.Context() - res, err := client.ListObjectsWithResponse(context, pathURI.Repository, pathURI.Ref, &api.ListObjectsParams{Prefix: &pfx}) - DieOnResponseError(res, err) + resp, err := client.ListObjectsWithResponse(context, pathURI.Repository, pathURI.Ref, &api.ListObjectsParams{Prefix: &pfx}) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) var from string for { params := &api.ListObjectsParams{ Prefix: &pfx, After: api.PaginationAfterPtr(from), } - resp, err := client.ListObjectsWithResponse(context, pathURI.Repository, pathURI.Ref, params) - DieOnResponseError(resp, err) + listObjectsResp, err := client.ListObjectsWithResponse(context, pathURI.Repository, pathURI.Ref, params) + DieOnErrorOrUnexpectedStatusCode(listObjectsResp, err, http.StatusOK) for _, obj := range resp.JSON200.Results { logCommitsParams := &api.LogCommitsParams{ Amount: api.PaginationAmountPtr(1), Objects: &[]string{obj.Path}, } - res, err := client.LogCommitsWithResponse(context, pathURI.Repository, pathURI.Ref, logCommitsParams) - DieOnResponseError(res, err) + logCommitsResp, err := client.LogCommitsWithResponse(context, pathURI.Repository, pathURI.Ref, logCommitsParams) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) data := objectCommitData{ Object: obj.Path, } - if len(res.JSON200.Results) > 0 { - data.Commit = res.JSON200.Results[0] - data.CommitMessage = splitOnNewLine(stringTrimLen((res.JSON200.Results[0].Message), annotateMessageSize)) + if len(logCommitsResp.JSON200.Results) > 0 { + data.Commit = logCommitsResp.JSON200.Results[0] + data.CommitMessage = splitOnNewLine(stringTrimLen((logCommitsResp.JSON200.Results[0].Message), annotateMessageSize)) } Write(annotateTemplate, data) } - pagination := resp.JSON200.Pagination + pagination := listObjectsResp.JSON200.Pagination if !pagination.HasMore { break } diff --git a/cmd/lakectl/cmd/auth.go b/cmd/lakectl/cmd/auth.go index 2ee921397e9..d35fbcd4bd0 100644 --- a/cmd/lakectl/cmd/auth.go +++ b/cmd/lakectl/cmd/auth.go @@ -3,6 +3,7 @@ package cmd import ( "encoding/json" "io" + "net/http" "os" "strings" "time" @@ -63,7 +64,7 @@ var authUsersList = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) users := resp.JSON200.Results rows := make([][]interface{}, len(users)) @@ -87,7 +88,7 @@ var authUsersCreate = &cobra.Command{ resp, err := clt.CreateUserWithResponse(cmd.Context(), api.CreateUserJSONRequestBody{ Id: id, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) user := resp.JSON201 Write(userCreatedTemplate, user) }, @@ -101,7 +102,7 @@ var authUsersDelete = &cobra.Command{ clt := getClient() resp, err := clt.DeleteUserWithResponse(cmd.Context(), id) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("User deleted successfully\n") }, } @@ -125,7 +126,7 @@ var authUsersGroupsList = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) groups := resp.JSON200.Results rows := make([][]interface{}, len(groups)) @@ -160,7 +161,7 @@ var authUsersPoliciesList = &cobra.Command{ Amount: api.PaginationAmountPtr(amount), Effective: &effective, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) policies := resp.JSON200.Results rows := make([][]interface{}, 0) @@ -185,7 +186,7 @@ var authUsersPoliciesAttach = &cobra.Command{ policy, _ := cmd.Flags().GetString("policy") clt := getClient() resp, err := clt.AttachPolicyToUserWithResponse(cmd.Context(), id, policy) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) Fmt("Policy attached successfully\n") }, } @@ -199,7 +200,7 @@ var authUsersPoliciesDetach = &cobra.Command{ clt := getClient() resp, err := clt.DetachPolicyFromUserWithResponse(cmd.Context(), id, policy) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("Policy detached successfully\n") }, @@ -219,12 +220,12 @@ var authUsersCredentialsCreate = &cobra.Command{ if id == "" { resp, err := clt.GetCurrentUserWithResponse(cmd.Context()) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) id = resp.JSON200.User.Id } resp, err := clt.CreateCredentialsWithResponse(cmd.Context(), id) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) credentials := resp.JSON201 Write(credentialsCreatedTemplate, credentials) @@ -241,11 +242,11 @@ var authUsersCredentialsDelete = &cobra.Command{ if id == "" { resp, err := clt.GetCurrentUserWithResponse(cmd.Context()) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) id = resp.JSON200.User.Id } resp, err := clt.DeleteCredentialsWithResponse(cmd.Context(), id, accessKeyID) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("Credentials deleted successfully\n") }, @@ -262,7 +263,7 @@ var authUsersCredentialsList = &cobra.Command{ clt := getClient() if id == "" { resp, err := clt.GetCurrentUserWithResponse(cmd.Context()) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) id = resp.JSON200.User.Id } @@ -270,7 +271,7 @@ var authUsersCredentialsList = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) credentials := resp.JSON200.Results rows := make([][]interface{}, len(credentials)) @@ -302,7 +303,7 @@ var authGroupsList = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) groups := resp.JSON200.Results rows := make([][]interface{}, len(groups)) @@ -326,7 +327,7 @@ var authGroupsCreate = &cobra.Command{ resp, err := clt.CreateGroupWithResponse(cmd.Context(), api.CreateGroupJSONRequestBody{ Id: id, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) group := resp.JSON201 Write(groupCreatedTemplate, group) }, @@ -340,7 +341,7 @@ var authGroupsDelete = &cobra.Command{ clt := getClient() resp, err := clt.DeleteGroupWithResponse(cmd.Context(), id) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("Group deleted successfully\n") }, } @@ -364,7 +365,7 @@ var authGroupsListMembers = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) users := resp.JSON200.Results rows := make([][]interface{}, len(users)) @@ -386,7 +387,7 @@ var authGroupsAddMember = &cobra.Command{ clt := getClient() resp, err := clt.AddGroupMembershipWithResponse(cmd.Context(), id, user) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) Fmt("User successfully added\n") }, } @@ -400,7 +401,7 @@ var authGroupsRemoveMember = &cobra.Command{ clt := getClient() resp, err := clt.DeleteGroupMembershipWithResponse(cmd.Context(), id, user) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("User successfully removed\n") }, } @@ -424,7 +425,7 @@ var authGroupsPoliciesList = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) policies := resp.JSON200.Results rows := make([][]interface{}, 0) @@ -450,7 +451,7 @@ var authGroupsPoliciesAttach = &cobra.Command{ clt := getClient() resp, err := clt.AttachPolicyToGroupWithResponse(cmd.Context(), id, policy) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) Fmt("Policy attached successfully\n") }, @@ -465,7 +466,7 @@ var authGroupsPoliciesDetach = &cobra.Command{ clt := getClient() resp, err := clt.DetachPolicyFromGroupWithResponse(cmd.Context(), id, policy) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("Policy detached successfully\n") }, @@ -490,7 +491,7 @@ var authPoliciesList = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) policies := resp.JSON200.Results rows := make([][]interface{}, len(policies)) @@ -534,7 +535,7 @@ var authPoliciesCreate = &cobra.Command{ Id: id, Statement: doc.Statement, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) createdPolicy := resp.JSON201 Write(policyCreatedTemplate, struct { @@ -561,7 +562,7 @@ var authPoliciesShow = &cobra.Command{ clt := getClient() resp, err := clt.GetPolicyWithResponse(cmd.Context(), id) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) policy := *resp.JSON200 Write(policyDetailsTemplate, struct { @@ -584,7 +585,7 @@ var authPoliciesDelete = &cobra.Command{ clt := getClient() resp, err := clt.DeletePolicyWithResponse(cmd.Context(), id) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("Policy deleted successfully\n") }, } diff --git a/cmd/lakectl/cmd/branch.go b/cmd/lakectl/cmd/branch.go index 37f7e4707c9..9267f8e655d 100644 --- a/cmd/lakectl/cmd/branch.go +++ b/cmd/lakectl/cmd/branch.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "net/http" "strings" "github.com/spf13/cobra" @@ -36,7 +37,7 @@ var branchListCmd = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) refs := resp.JSON200.Results rows := make([][]interface{}, len(refs)) @@ -70,7 +71,7 @@ var branchCreateCmd = &cobra.Command{ Name: u.Ref, Source: sourceURI.Ref, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) Fmt("created branch '%s' %s\n", u.Ref, string(resp.Body)) }, } @@ -88,7 +89,7 @@ var branchDeleteCmd = &cobra.Command{ u := MustParseRefURI("branch", args[0]) Fmt("Branch: %s\n", u.String()) resp, err := client.DeleteBranchWithResponse(cmd.Context(), u.Repository, u.Ref) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) }, } @@ -122,7 +123,7 @@ var branchRevertCmd = &cobra.Command{ ParentNumber: parentNumber, Ref: commitRef, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("commit %s successfully reverted\n", commitRef) } }, @@ -178,7 +179,7 @@ var branchResetCmd = &cobra.Command{ return } resp, err := clt.ResetBranchWithResponse(cmd.Context(), u.Repository, u.Ref, api.ResetBranchJSONRequestBody(reset)) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) }, } @@ -191,7 +192,7 @@ var branchShowCmd = &cobra.Command{ u := MustParseRefURI("branch", args[0]) Fmt("Branch: %s\n", u.String()) resp, err := client.GetBranchWithResponse(cmd.Context(), u.Repository, u.Ref) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) branch := resp.JSON200 Fmt("%s\n", branch) }, diff --git a/cmd/lakectl/cmd/branch_protect.go b/cmd/lakectl/cmd/branch_protect.go index 94fc327a520..d29d36386d7 100644 --- a/cmd/lakectl/cmd/branch_protect.go +++ b/cmd/lakectl/cmd/branch_protect.go @@ -1,6 +1,8 @@ package cmd import ( + "net/http" + "github.com/spf13/cobra" "github.com/treeverse/lakefs/pkg/api" ) @@ -24,7 +26,7 @@ var branchProtectListCmd = &cobra.Command{ client := getClient() u := MustParseRepoURI("repository", args[0]) resp, err := client.GetBranchProtectionRulesWithResponse(cmd.Context(), u.Repository) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) patterns := make([][]interface{}, len(*resp.JSON200)) for i, rule := range *resp.JSON200 { patterns[i] = []interface{}{rule.Pattern} @@ -48,7 +50,7 @@ var branchProtectAddCmd = &cobra.Command{ resp, err := client.CreateBranchProtectionRuleWithResponse(cmd.Context(), u.Repository, api.CreateBranchProtectionRuleJSONRequestBody{ Pattern: args[1], }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) }, } @@ -64,7 +66,7 @@ var branchProtectDeleteCmd = &cobra.Command{ resp, err := client.DeleteBranchProtectionRuleWithResponse(cmd.Context(), u.Repository, api.DeleteBranchProtectionRuleJSONRequestBody{ Pattern: args[1], }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) }, } diff --git a/cmd/lakectl/cmd/cat_hook_output.go b/cmd/lakectl/cmd/cat_hook_output.go index a99e6042777..2330ea37a1a 100644 --- a/cmd/lakectl/cmd/cat_hook_output.go +++ b/cmd/lakectl/cmd/cat_hook_output.go @@ -1,6 +1,8 @@ package cmd import ( + "net/http" + "github.com/spf13/cobra" ) @@ -20,7 +22,7 @@ var catHookOutputCmd = &cobra.Command{ client := getClient() ctx := cmd.Context() resp, err := client.GetRunHookOutputWithResponse(ctx, u.Repository, runID, hookRunID) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) Fmt("%s\n", string(resp.Body)) }, } diff --git a/cmd/lakectl/cmd/commit.go b/cmd/lakectl/cmd/commit.go index 398934c2c17..7c6a0e81771 100644 --- a/cmd/lakectl/cmd/commit.go +++ b/cmd/lakectl/cmd/commit.go @@ -2,6 +2,7 @@ package cmd import ( "errors" + "net/http" "strings" "github.com/spf13/cobra" @@ -57,7 +58,7 @@ var commitCmd = &cobra.Command{ Message: message, Metadata: &metadata, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) commit := resp.JSON201 Write(CommitCreateTemplate, struct { diff --git a/cmd/lakectl/cmd/common_helpers.go b/cmd/lakectl/cmd/common_helpers.go index f9a7675a78c..87c14d1b454 100644 --- a/cmd/lakectl/cmd/common_helpers.go +++ b/cmd/lakectl/cmd/common_helpers.go @@ -9,17 +9,18 @@ import ( "io" "net/http" "os" + "reflect" "regexp" + "strconv" "strings" "text/template" "time" - "github.com/treeverse/lakefs/pkg/uri" - "github.com/jedib0t/go-pretty/v6/table" "github.com/jedib0t/go-pretty/v6/text" "github.com/treeverse/lakefs/pkg/api" "github.com/treeverse/lakefs/pkg/api/helpers" + "github.com/treeverse/lakefs/pkg/uri" "golang.org/x/term" ) @@ -206,6 +207,31 @@ func DieOnResponseError(response interface{}, err error) { DieErr(retrievedErr) } } +func DieOnErrorOrUnexpectedStatusCode(response interface{}, err error, expectedStatusCode int) { + DieOnResponseError(response, err) + var statusCode int + if httpResponse, ok := response.(*http.Response); ok { + statusCode = httpResponse.StatusCode + } else { + r := reflect.Indirect(reflect.ValueOf(response)) + f := r.FieldByName("HTTPResponse") + httpResponse, _ := f.Interface().(*http.Response) + if httpResponse != nil { + statusCode = httpResponse.StatusCode + } + } + + if statusCode == 0 { + Die("could not get status code from response", 1) + } + if statusCode != expectedStatusCode { + // redirected to not found page + if statusCode == http.StatusFound { + Die("got not-found error, probably wrong endpoint url", 1) + } + Die("got unexpected status code: "+strconv.Itoa(statusCode)+", expected: "+strconv.Itoa(expectedStatusCode), 1) + } +} func DieOnHTTPError(httpResponse *http.Response) { err := helpers.HTTPResponseAsError(httpResponse) diff --git a/cmd/lakectl/cmd/common_helpers_test.go b/cmd/lakectl/cmd/common_helpers_test.go index 88fcc155741..22ae23342d2 100644 --- a/cmd/lakectl/cmd/common_helpers_test.go +++ b/cmd/lakectl/cmd/common_helpers_test.go @@ -1,6 +1,8 @@ package cmd -import "testing" +import ( + "testing" +) func TestIsValidAccessKeyID(t *testing.T) { type args struct { diff --git a/cmd/lakectl/cmd/diff.go b/cmd/lakectl/cmd/diff.go index 2e29668cc7a..9d36e0c5092 100644 --- a/cmd/lakectl/cmd/diff.go +++ b/cmd/lakectl/cmd/diff.go @@ -3,6 +3,7 @@ package cmd import ( "context" "fmt" + "net/http" "os" "github.com/jedib0t/go-pretty/v6/text" @@ -83,7 +84,7 @@ func printDiffBranch(ctx context.Context, client api.ClientWithResponsesInterfac After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(int(pageSize)), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) for _, line := range resp.JSON200.Results { FmtDiff(line, false) @@ -111,7 +112,7 @@ func printDiffRefs(ctx context.Context, client api.ClientWithResponsesInterface, Amount: api.PaginationAmountPtr(amount), Type: diffType, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) for _, line := range resp.JSON200.Results { FmtDiff(line, true) diff --git a/cmd/lakectl/cmd/doctor.go b/cmd/lakectl/cmd/doctor.go index 9582384caab..559d2adeffa 100644 --- a/cmd/lakectl/cmd/doctor.go +++ b/cmd/lakectl/cmd/doctor.go @@ -127,7 +127,7 @@ func ListRepositoriesAndAnalyze(ctx context.Context) error { case resp.JSON401 != nil: return &CredentialsError{msgOnErrCredential, resp.JSON401.Message} // In case we get the "not found" HTML page (the status is 200 and not 404 in this case). - case resp.HTTPResponse != nil && resp.HTTPResponse.StatusCode == 200: + case resp.HTTPResponse != nil && resp.HTTPResponse.StatusCode == 302: return &WrongEndpointURIError{msgOnErrWrongEndpointURI, ""} case resp.JSONDefault != nil: return &UnknownConfigError{msgOnErrUnknownConfig, resp.JSONDefault.Message} diff --git a/cmd/lakectl/cmd/fs.go b/cmd/lakectl/cmd/fs.go index 5eeacbf172c..f0c6bfdde1f 100644 --- a/cmd/lakectl/cmd/fs.go +++ b/cmd/lakectl/cmd/fs.go @@ -41,12 +41,12 @@ var fsStatCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { pathURI := MustParsePathURI("path", args[0]) client := getClient() - res, err := client.StatObjectWithResponse(cmd.Context(), pathURI.Repository, pathURI.Ref, &api.StatObjectParams{ + resp, err := client.StatObjectWithResponse(cmd.Context(), pathURI.Repository, pathURI.Ref, &api.StatObjectParams{ Path: *pathURI.Path, }) - DieOnResponseError(res, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) - stat := res.JSON200 + stat := resp.JSON200 Write(fsStatTemplate, stat) }, } @@ -88,7 +88,7 @@ var fsListCmd = &cobra.Command{ Delimiter: ¶msDelimiter, } resp, err := client.ListObjectsWithResponse(cmd.Context(), pathURI.Repository, pathURI.Ref, params) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) results := resp.JSON200.Results // trim prefix if non recursive @@ -292,7 +292,7 @@ var fsStageCmd = &cobra.Command{ resp, err := client.StageObjectWithResponse(cmd.Context(), pathURI.Repository, pathURI.Ref, &api.StageObjectParams{ Path: *pathURI.Path, }, api.StageObjectJSONRequestBody(obj)) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) Write(fsStatTemplate, resp.JSON201) }, @@ -365,7 +365,7 @@ var fsRmCmd = &cobra.Command{ Delimiter: ¶msDelimiter, } resp, err := client.ListObjectsWithResponse(cmd.Context(), pathURI.Repository, pathURI.Ref, params) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) results := resp.JSON200.Results for i := range results { diff --git a/cmd/lakectl/cmd/gc.go b/cmd/lakectl/cmd/gc.go index 6752c028851..3c8e2a9143c 100644 --- a/cmd/lakectl/cmd/gc.go +++ b/cmd/lakectl/cmd/gc.go @@ -70,10 +70,7 @@ Example configuration file: } client := getClient() resp, err := client.SetGarbageCollectionRulesWithResponse(cmd.Context(), u.Repository, body) - DieOnResponseError(resp, err) - if resp.StatusCode() != http.StatusNoContent { - Die("Failed to update config", 1) - } + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) }, } @@ -87,7 +84,7 @@ var gcGetConfigCmd = &cobra.Command{ isJSON := MustBool(cmd.Flags().GetBool(jsonFlagName)) client := getClient() resp, err := client.GetGarbageCollectionRulesWithResponse(cmd.Context(), u.Repository) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) if isJSON { Write("{{ . | json }}", resp.JSON200) } else { diff --git a/cmd/lakectl/cmd/ingest.go b/cmd/lakectl/cmd/ingest.go index f15fa0b0927..9631c5ab1fd 100644 --- a/cmd/lakectl/cmd/ingest.go +++ b/cmd/lakectl/cmd/ingest.go @@ -2,6 +2,7 @@ package cmd import ( "context" + "net/http" "strings" "sync" "time" @@ -27,7 +28,7 @@ func stageWorker(ctx context.Context, client api.ClientWithResponsesInterface, w for req := range requests { resp, err := client.StageObjectWithResponse( ctx, req.repository, req.branch, req.params, req.body) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) responses <- resp } } diff --git a/cmd/lakectl/cmd/log.go b/cmd/lakectl/cmd/log.go index c9b3a00599a..d70f74afeb4 100644 --- a/cmd/lakectl/cmd/log.go +++ b/cmd/lakectl/cmd/log.go @@ -1,6 +1,8 @@ package cmd import ( + "net/http" + "github.com/spf13/cobra" "github.com/treeverse/lakefs/pkg/api" ) @@ -53,16 +55,16 @@ var logCmd = &cobra.Command{ logCommitsParams.Prefixes = &prefixesList } for pagination.HasMore { - res, err := client.LogCommitsWithResponse(cmd.Context(), branchURI.Repository, branchURI.Ref, logCommitsParams) - DieOnResponseError(res, err) - pagination = res.JSON200.Pagination + resp, err := client.LogCommitsWithResponse(cmd.Context(), branchURI.Repository, branchURI.Ref, logCommitsParams) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) + pagination = resp.JSON200.Pagination logCommitsParams.After = api.PaginationAfterPtr(pagination.NextOffset) data := struct { Commits []api.Commit Pagination *Pagination ShowMetaRangeID bool }{ - Commits: res.JSON200.Results, + Commits: resp.JSON200.Results, ShowMetaRangeID: showMetaRangeID, Pagination: &Pagination{ Amount: amount, diff --git a/cmd/lakectl/cmd/merge.go b/cmd/lakectl/cmd/merge.go index b710774339f..a7c4b32a184 100644 --- a/cmd/lakectl/cmd/merge.go +++ b/cmd/lakectl/cmd/merge.go @@ -1,6 +1,8 @@ package cmd import ( + "net/http" + "github.com/spf13/cobra" "github.com/treeverse/lakefs/pkg/api" ) @@ -35,7 +37,7 @@ var mergeCmd = &cobra.Command{ if resp != nil && resp.JSON409 != nil { Die("Conflict found.", 1) } - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) Write(mergeCreateTemplate, struct { Merge FromTo diff --git a/cmd/lakectl/cmd/metastore.go b/cmd/lakectl/cmd/metastore.go index 6b92d815a5c..0fbbea77e4f 100644 --- a/cmd/lakectl/cmd/metastore.go +++ b/cmd/lakectl/cmd/metastore.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "net/http" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -282,12 +283,12 @@ var createSymlinkCmd = &cobra.Command{ defer fromClientDeferFunc() defer toClientDeferFunc() - res, err := apiClient.CreateSymlinkFileWithResponse(cmd.Context(), repo, branch, &api.CreateSymlinkFileParams{Location: &path}) + resp, err := apiClient.CreateSymlinkFileWithResponse(cmd.Context(), repo, branch, &api.CreateSymlinkFileParams{Location: &path}) if err != nil { DieErr(err) } - DieOnResponseError(res, err) - location := res.JSON201.Location + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) + location := resp.JSON201.Location err = metastore.CopyOrMergeToSymlink(cmd.Context(), fromClient, toClient, fromDB, fromTable, toDB, toTable, location, cfg.GetFixSparkPlaceholder()) if err != nil { diff --git a/cmd/lakectl/cmd/refs.go b/cmd/lakectl/cmd/refs.go index 41a5923e4c8..4be4b7c6e17 100644 --- a/cmd/lakectl/cmd/refs.go +++ b/cmd/lakectl/cmd/refs.go @@ -3,6 +3,7 @@ package cmd import ( "encoding/json" "io" + "net/http" "github.com/spf13/cobra" "github.com/treeverse/lakefs/pkg/api" @@ -48,7 +49,7 @@ Since a bare repo is expected, in case of transient failure, delete the reposito // execute the restore operation client := getClient() resp, err := client.RestoreRefsWithResponse(cmd.Context(), repoURI.Repository, api.RestoreRefsJSONRequestBody(manifest)) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) Write(refsRestoreSuccess, nil) }, } @@ -63,7 +64,7 @@ var refsDumpCmd = &cobra.Command{ Fmt("Repository: %s\n", repoURI.String()) client := getClient() resp, err := client.DumpRefsWithResponse(cmd.Context(), repoURI.Repository) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) Write(metadataDumpTemplate, struct { Response interface{} diff --git a/cmd/lakectl/cmd/repo.go b/cmd/lakectl/cmd/repo.go index 9d02f171b8d..64d05c18037 100644 --- a/cmd/lakectl/cmd/repo.go +++ b/cmd/lakectl/cmd/repo.go @@ -1,6 +1,7 @@ package cmd import ( + "net/http" "time" "github.com/spf13/cobra" @@ -26,18 +27,18 @@ var repoListCmd = &cobra.Command{ after := MustString(cmd.Flags().GetString("after")) clt := getClient() - res, err := clt.ListRepositoriesWithResponse(cmd.Context(), &api.ListRepositoriesParams{ + resp, err := clt.ListRepositoriesWithResponse(cmd.Context(), &api.ListRepositoriesParams{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(res, err) - repos := res.JSON200.Results + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) + repos := resp.JSON200.Results rows := make([][]interface{}, len(repos)) for i, repo := range repos { ts := time.Unix(repo.CreationDate, 0).String() rows[i] = []interface{}{repo.Id, ts, repo.DefaultBranch, repo.StorageNamespace} } - pagination := res.JSON200.Pagination + pagination := resp.JSON200.Pagination PrintTable(rows, []interface{}{"Repository", "Creation Date", "Default Ref Name", "Storage Namespace"}, &pagination, amount) }, } @@ -64,10 +65,10 @@ var repoCreateCmd = &cobra.Command{ StorageNamespace: args[1], DefaultBranch: &defaultBranch, }) - DieOnResponseError(respCreateRepo, err) + DieOnErrorOrUnexpectedStatusCode(respCreateRepo, err, http.StatusCreated) respGetRepo, err := clt.GetRepositoryWithResponse(cmd.Context(), u.Repository) - DieOnResponseError(respGetRepo, err) + DieOnErrorOrUnexpectedStatusCode(respGetRepo, err, http.StatusOK) repo := respGetRepo.JSON200 Fmt("Repository '%s' created:\nstorage namespace: %s\ndefault branch: %s\ntimestamp: %d\n", @@ -99,10 +100,10 @@ var repoCreateBareCmd = &cobra.Command{ Name: u.Repository, StorageNamespace: args[1], }) - DieOnResponseError(respCreateRepo, err) + DieOnErrorOrUnexpectedStatusCode(respCreateRepo, err, http.StatusOK) respGetRepo, err := clt.GetRepositoryWithResponse(cmd.Context(), u.Repository) - DieOnResponseError(respGetRepo, err) + DieOnErrorOrUnexpectedStatusCode(respGetRepo, err, http.StatusOK) repo := respGetRepo.JSON200 Fmt("Repository '%s' created:\nstorage namespace: %s\ndefault branch: %s\ntimestamp: %d\n", @@ -125,7 +126,7 @@ var repoDeleteCmd = &cobra.Command{ DieFmt("Delete Repository '%s' aborted\n", u.Repository) } resp, err := clt.DeleteRepositoryWithResponse(cmd.Context(), u.Repository) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) Fmt("Repository '%s' deleted\n", u.Repository) }, } diff --git a/cmd/lakectl/cmd/root.go b/cmd/lakectl/cmd/root.go index 134b0bcff8b..dabcbe148d9 100644 --- a/cmd/lakectl/cmd/root.go +++ b/cmd/lakectl/cmd/root.go @@ -108,9 +108,17 @@ func getClient() *api.ClientWithResponses { if u.Path == "" || u.Path == "/" { serverEndpoint = strings.TrimRight(serverEndpoint, "/") + api.BaseURL } + httpClient := &http.Client{ + // avoid redirect automatically + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + client, err := api.NewClientWithResponses( serverEndpoint, api.WithRequestEditorFn(basicAuthProvider.Intercept), + api.WithHTTPClient(httpClient), ) if err != nil { Die(fmt.Sprintf("could not initialize API client: %s", err), 1) diff --git a/cmd/lakectl/cmd/runs_describe.go b/cmd/lakectl/cmd/runs_describe.go index 1e8ab0d7a31..0bb2cb45523 100644 --- a/cmd/lakectl/cmd/runs_describe.go +++ b/cmd/lakectl/cmd/runs_describe.go @@ -37,7 +37,7 @@ var runsDescribeCmd = &cobra.Command{ // run result information runsRes, err := client.GetRunWithResponse(ctx, u.Repository, runID) - DieOnResponseError(runsRes, err) + DieOnErrorOrUnexpectedStatusCode(runsRes, err, http.StatusOK) runResult := runsRes.JSON200 Write(actionRunResultTemplate, convertRunResultTable(runResult)) @@ -51,7 +51,7 @@ var runsDescribeCmd = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amountForPagination), }) - DieOnResponseError(runHooksRes, err) + DieOnErrorOrUnexpectedStatusCode(runHooksRes, err, http.StatusOK) pagination = runHooksRes.JSON200.Pagination data := struct { Hooks []api.HookRun @@ -80,14 +80,14 @@ var runsDescribeCmd = &cobra.Command{ func makeHookLog(ctx context.Context, client api.ClientWithResponsesInterface, repositoryID string, runID string) func(hookRunID string) (string, error) { return func(hookRunID string) (string, error) { - res, err := client.GetRunHookOutputWithResponse(ctx, repositoryID, runID, hookRunID) + resp, err := client.GetRunHookOutputWithResponse(ctx, repositoryID, runID, hookRunID) if err != nil { return "", err } - if res.StatusCode() != http.StatusOK { - return "", helpers.ResponseAsError(res) + if resp.StatusCode() != http.StatusOK { + return "", helpers.ResponseAsError(resp) } - return string(res.Body), nil + return string(resp.Body), nil } } diff --git a/cmd/lakectl/cmd/runs_list.go b/cmd/lakectl/cmd/runs_list.go index d5f666163f0..42f2e17aaa3 100644 --- a/cmd/lakectl/cmd/runs_list.go +++ b/cmd/lakectl/cmd/runs_list.go @@ -1,6 +1,8 @@ package cmd import ( + "net/http" + "github.com/spf13/cobra" "github.com/treeverse/lakefs/pkg/api" ) @@ -44,7 +46,7 @@ var runsListCmd = &cobra.Command{ Branch: optionalBranch, Commit: optionalCommit, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) results := resp.JSON200.Results rows := make([][]interface{}, len(results)) diff --git a/cmd/lakectl/cmd/show.go b/cmd/lakectl/cmd/show.go index d0ebf9c2276..4a4eeb02d30 100644 --- a/cmd/lakectl/cmd/show.go +++ b/cmd/lakectl/cmd/show.go @@ -1,6 +1,7 @@ package cmd import ( + "net/http" "strings" "github.com/spf13/cobra" @@ -38,7 +39,7 @@ var showCmd = &cobra.Command{ case "commit": client := getClient() resp, err := client.GetCommitWithResponse(cmd.Context(), u.Repository, identifier) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) commit := resp.JSON200 showMetaRangeID, _ := cmd.Flags().GetBool("show-meta-range-id") diff --git a/cmd/lakectl/cmd/tag.go b/cmd/lakectl/cmd/tag.go index 1946b444e12..254297ae8e5 100644 --- a/cmd/lakectl/cmd/tag.go +++ b/cmd/lakectl/cmd/tag.go @@ -1,6 +1,8 @@ package cmd import ( + "net/http" + "github.com/spf13/cobra" "github.com/treeverse/lakefs/pkg/api" ) @@ -31,7 +33,7 @@ var tagListCmd = &cobra.Command{ After: api.PaginationAfterPtr(after), Amount: api.PaginationAmountPtr(amount), }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) refs := resp.JSON200.Results rows := make([][]interface{}, len(refs)) @@ -76,11 +78,11 @@ var tagCreateCmd = &cobra.Command{ if force { // checking validity of the commitRef before deleting the old one res, err := client.GetCommitWithResponse(ctx, tagURI.Repository, commitRef) - DieOnResponseError(res, err) + DieOnErrorOrUnexpectedStatusCode(res, err, http.StatusOK) resp, err := client.DeleteTagWithResponse(ctx, tagURI.Repository, tagURI.Ref) if err != nil && (resp == nil || resp.JSON404 == nil) { - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) } } @@ -88,7 +90,7 @@ var tagCreateCmd = &cobra.Command{ Id: tagURI.Ref, Ref: commitRef, }) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusCreated) commitID := *resp.JSON201 Fmt("Created tag '%s' (%s)\n", tagURI.Ref, commitID) @@ -110,7 +112,7 @@ var tagDeleteCmd = &cobra.Command{ ctx := cmd.Context() resp, err := client.DeleteTagWithResponse(ctx, u.Repository, u.Ref) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusNoContent) }, } @@ -125,7 +127,7 @@ var tagShowCmd = &cobra.Command{ ctx := cmd.Context() resp, err := client.GetTagWithResponse(ctx, u.Repository, u.Ref) - DieOnResponseError(resp, err) + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) Fmt("%s %s", resp.JSON200.Id, resp.JSON200.CommitId) }, } diff --git a/pkg/api/ui_handler.go b/pkg/api/ui_handler.go index d210197c4b9..37cd3c8c628 100644 --- a/pkg/api/ui_handler.go +++ b/pkg/api/ui_handler.go @@ -80,7 +80,8 @@ func NewHandlerWithDefault(root http.FileSystem, handler http.Handler, defaultPa } _, err := root.Open(path.Clean(urlPath)) if err != nil && os.IsNotExist(err) { - r.URL.Path = defaultPath + http.Redirect(w, r, defaultPath, http.StatusFound) + return } // consistent content-type contentType := gomime.TypeByExtension(filepath.Ext(r.URL.Path))