diff --git a/go.mod b/go.mod index 9efe48825..1d9e112bd 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/aziontech/azion-cli go 1.17 require ( - github.com/MaxwelMazur/tablecli v0.0.0-20230111205821-634576290228 + github.com/MaxwelMazur/tablecli v0.0.0-20230208145104-c9458b902b58 github.com/aziontech/azionapi-go-sdk v0.20.0 github.com/fatih/color v1.13.0 github.com/go-git/go-git/v5 v5.4.2 diff --git a/go.sum b/go.sum index af286926c..0e0cdf57e 100644 --- a/go.sum +++ b/go.sum @@ -186,8 +186,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -github.com/MaxwelMazur/tablecli v0.0.0-20230111205821-634576290228 h1:0v/h/69n72chjEeAWInSZ+0+WVGff/e/HK71DxcZPOo= -github.com/MaxwelMazur/tablecli v0.0.0-20230111205821-634576290228/go.mod h1:XTbnIbjcCDbZenA2rqSIQK9aa4MSL//Wt/b04tgdCO4= +github.com/MaxwelMazur/tablecli v0.0.0-20230208145104-c9458b902b58 h1:bqFhGlAuzkZzX+2P6fwKhg4PECvXF7Lr8V6g2iDrG0s= +github.com/MaxwelMazur/tablecli v0.0.0-20230208145104-c9458b902b58/go.mod h1:eepQZpVhQN9tZIbJ+/nLb+Gi/vUAjzQsB0eLhfnB5gk= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= @@ -471,6 +471,7 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -524,6 +525,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= diff --git a/messages/origins/errors.go b/messages/origins/errors.go index c064d2250..41af3b3e3 100644 --- a/messages/origins/errors.go +++ b/messages/origins/errors.go @@ -4,5 +4,7 @@ import "errors" var ( ErrorGetOrigins = errors.New("Failed to describe the origins. Check your settings and try again. If the error persists, contact Azion support.") + ErrorGetOrigin = errors.New("Failed to describe the origin. Check your settings and try again. If the error persists, contact Azion support.") ErrorMissingApplicationIDArgument = errors.New("A required flag is missing. You must supply an application_id as an argument. Run 'azioncli origins list --help' command to display more information and try again") + ErrorMissingArguments = errors.New("A required flag is missing. You must supply an application_id and origin_id as an argument. Run 'azioncli origins list --help' command to display more information and try again") ) diff --git a/messages/origins/messages.go b/messages/origins/messages.go index 65cf2695d..6601e2705 100644 --- a/messages/origins/messages.go +++ b/messages/origins/messages.go @@ -1,16 +1,29 @@ package origins var ( - //origins cmd + // [ origins ] OriginsUsage = "origins" OriginsShortDescription = "Origins is where data is fetched when the cache is not available." OriginsLongDescription = "Origins is the original source of data in content delivery systems (CDN), where data is fetched when cache is not available. Data is stored at origin and can be retrieved by clients through cache servers distributed around the world. The fetch is done from the cache first, and if the data is not available, it is fetched from origin and saved in the cache for future use. This allows for fast data delivery." OriginsFlagHelp = "Displays more information about the origins command" - //list cmd + // [ list ] OriginsListUsage = "list [flags]" OriginsListShortDescription = "Displays yours origins" OriginsListLongDescription = "Displays all your origins references to your edges" OriginsListHelpFlag = "Displays more information about the list subcommand" OriginsListFlagEdgeApplicationID = "Is a unique identifier for the edge application that references the origins to direct data requests correctly." + + // [ describe ] + OriginsDescribeUsage = "describe --application-id --origin-id [flags]" + OriginsDescribeShortDescription = "Returns the origin data" + OriginsDescribeLongDescription = "Displays information about the origin via a given ID to show the application’s attributes in detail" + OriginsDescribeFlagApplicationID = "Is a unique identifier for the edge application that references the origins to direct data requests correctly." + OriginsDescribeFlagOriginID = `is a unique identifier that identifies an "origins" in a list of results returned by the API. The "GetOrigin" function uses the "Origin Id" to search for the desired "origins" and returns an error if it is not found.` + OriginsDescribeFlagOut = "Exports the output to the given " + OriginsDescribeFlagFormat = "Changes the output format passing the json value to the flag" + OriginsDescribeHelpFlag = "Displays more information about the describe command" + + // [ general ] + OriginsFileWritten = "File successfully written to: %s\n" ) diff --git a/pkg/api/edge_applications/edge_applications.go b/pkg/api/edge_applications/edge_applications.go index 2ae1393c3..a186c61e7 100644 --- a/pkg/api/edge_applications/edge_applications.go +++ b/pkg/api/edge_applications/edge_applications.go @@ -2,6 +2,7 @@ package edgeapplications import ( "context" + "errors" "net/http" "strconv" "time" @@ -206,9 +207,23 @@ func (c *Client) List(ctx context.Context, opts *contracts.ListOptions) (sdk.Get return resp, nil } +func (c *Client) GetOrigin(ctx context.Context, edgeApplicationID, originID int64) (sdk.OriginsResultResponse, error) { + resp, httpResp, err := c.apiClient.EdgeApplicationsOriginsApi.EdgeApplicationsEdgeApplicationIdOriginsGet(ctx, edgeApplicationID).Execute() + if err != nil { + return sdk.OriginsResultResponse{}, utils.ErrorPerStatusCode(httpResp, err) + } + if len(resp.Results) > 0 { + for _, result := range resp.Results { + if result.OriginId == originID { + return result, nil + } + } + } + return sdk.OriginsResultResponse{}, utils.ErrorPerStatusCode(&http.Response{Status: "404 Not Found", StatusCode: http.StatusNotFound}, errors.New("404 Not Found")) +} + func (c *Client) ListOrigins(ctx context.Context, opts *contracts.ListOptions, edgeApplicationID int64) (sdk.OriginsResponse, error) { - req := c.apiClient.EdgeApplicationsOriginsApi.EdgeApplicationsEdgeApplicationIdOriginsGet(ctx, edgeApplicationID) - resp, httpResp, err := req.Execute() + resp, httpResp, err := c.apiClient.EdgeApplicationsOriginsApi.EdgeApplicationsEdgeApplicationIdOriginsGet(ctx, edgeApplicationID).Execute() if err != nil { return sdk.OriginsResponse{}, utils.ErrorPerStatusCode(httpResp, err) } diff --git a/pkg/cmd/edge_applications/init/init.go b/pkg/cmd/edge_applications/init/init.go index c21fc2e32..3a9436447 100644 --- a/pkg/cmd/edge_applications/init/init.go +++ b/pkg/cmd/edge_applications/init/init.go @@ -17,7 +17,6 @@ import ( "github.com/aziontech/azion-cli/utils" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" - // "github.com/go-git/go-git/v5/plumbing/storer" "github.com/go-git/go-git/v5/storage/memory" "github.com/spf13/cobra" "github.com/tidwall/gjson" diff --git a/pkg/cmd/origins/describe/describe.go b/pkg/cmd/origins/describe/describe.go new file mode 100644 index 000000000..89fa233ca --- /dev/null +++ b/pkg/cmd/origins/describe/describe.go @@ -0,0 +1,114 @@ +package describe + +import ( + "context" + "encoding/json" + "fmt" + "path/filepath" + + "github.com/fatih/color" + + "github.com/MakeNowJust/heredoc" + "github.com/MaxwelMazur/tablecli" + msg "github.com/aziontech/azion-cli/messages/origins" + + api "github.com/aziontech/azion-cli/pkg/api/edge_applications" + "github.com/aziontech/azion-cli/pkg/cmdutil" + "github.com/aziontech/azion-cli/pkg/contracts" + "github.com/aziontech/azion-cli/utils" + sdk "github.com/aziontech/azionapi-go-sdk/edgeapplications" + "github.com/spf13/cobra" +) + +var ( + applicationID int64 + originID int64 +) + +func NewCmd(f *cmdutil.Factory) *cobra.Command { + opts := &contracts.DescribeOptions{} + cmd := &cobra.Command{ + Use: msg.OriginsDescribeUsage, + Short: msg.OriginsDescribeShortDescription, + Long: msg.OriginsDescribeLongDescription, + SilenceUsage: true, + SilenceErrors: true, + Example: heredoc.Doc(` + $ azioncli origins describe --application-id 4312 --origin-id 31223 + $ azioncli origins describe --application-id 1337 --origin-id 31223--format json + $ azioncli origins describe --application-id 1337 --origin-id 31223--out "./tmp/test.json" --format json + `), + RunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Flags().Changed("application-id") || !cmd.Flags().Changed("origin-id") { + return msg.ErrorMissingArguments + } + + client := api.NewClient(f.HttpClient, f.Config.GetString("api_url"), f.Config.GetString("token")) + ctx := context.Background() + origin, err := client.GetOrigin(ctx, applicationID, originID) + if err != nil { + return msg.ErrorGetOrigin + } + + out := f.IOStreams.Out + formattedFuction, err := format(cmd, origin) + if err != nil { + return utils.ErrorFormatOut + } + + if cmd.Flags().Changed("out") { + err := cmdutil.WriteDetailsToFile(formattedFuction, opts.OutPath, out) + if err != nil { + return fmt.Errorf("%s: %w", utils.ErrorWriteFile, err) + } + fmt.Fprintf(out, msg.OriginsFileWritten, filepath.Clean(opts.OutPath)) + } else { + _, err := out.Write(formattedFuction[:]) + if err != nil { + return err + } + } + + return nil + }, + } + + cmd.Flags().Int64VarP(&applicationID, "application-id", "a", 0, msg.OriginsDescribeFlagApplicationID) + cmd.Flags().Int64VarP(&originID, "origin-id", "o", 0, msg.OriginsDescribeFlagOriginID) + cmd.Flags().StringVar(&opts.OutPath, "out", "", msg.OriginsDescribeFlagOut) + cmd.Flags().StringVar(&opts.Format, "format", "", msg.OriginsDescribeFlagFormat) + cmd.Flags().BoolP("help", "h", false, msg.OriginsDescribeHelpFlag) + + return cmd +} + +func format(cmd *cobra.Command, origin sdk.OriginsResultResponse) ([]byte, error) { + format, err := cmd.Flags().GetString("format") + if err != nil { + return nil, err + } + + if format == "json" || cmd.Flags().Changed("out") { + return json.MarshalIndent(origin, "", " ") + } + + tbl := tablecli.New("", "") + tbl.WithFirstColumnFormatter(color.New(color.FgGreen).SprintfFunc()) + tbl.AddRow("Origin ID: ", origin.OriginId) + tbl.AddRow("Name: ", origin.Name) + tbl.AddRow("Origin Type: ", origin.OriginType) + tbl.AddRow("Addresses: ", origin.Addresses) + tbl.AddRow("Origin Protocol Policy: ", origin.OriginProtocolPolicy) + tbl.AddRow("Is Origin Redirection Enable: ", origin.IsOriginRedirectionEnabled) + tbl.AddRow("Host Header: ", origin.HostHeader) + tbl.AddRow("Method: ", origin.Method) + tbl.AddRow("Origin Path: ", origin.OriginPath) + tbl.AddRow("Connection Timeout: ", origin.ConnectionTimeout) + tbl.AddRow("Timeout Between Bytes: ", origin.TimeoutBetweenBytes) + tbl.AddRow("Hmac Authentication: ", origin.HmacAuthentication) + tbl.AddRow("Hmac Region Name: ", origin.HmacRegionName) + tbl.AddRow("Hmac Secret Key: ", origin.HmacSecretKey) + tbl.AddRow("Hmac Access Key: ", origin.HmacAccessKey) + return tbl.GetByteFormat(), nil +} + diff --git a/pkg/cmd/origins/describe/describe_test.go b/pkg/cmd/origins/describe/describe_test.go new file mode 100644 index 000000000..1f823c91d --- /dev/null +++ b/pkg/cmd/origins/describe/describe_test.go @@ -0,0 +1,95 @@ +package describe + +import ( + "log" + "os" + "net/http" + "testing" + + "github.com/aziontech/azion-cli/pkg/httpmock" + "github.com/aziontech/azion-cli/pkg/testutils" + "github.com/stretchr/testify/require" +) + + +func TestDescribe(t *testing.T) { + t.Run("describe an domains", func(t *testing.T) { + mock := &httpmock.Registry{} + + mock.Register( + httpmock.REST("GET", "edge_applications/123423424/origins"), + httpmock.JSONFromFile("./fixtures/origins.json"), + ) + + f, _, _ := testutils.NewFactory(mock) + + cmd := NewCmd(f) + cmd.SetArgs([]string{"-a", "123423424", "-o", "88144"}) + + err := cmd.Execute() + require.NoError(t, err) + }) + t.Run("not found", func(t *testing.T) { + mock := &httpmock.Registry{} + + mock.Register( + httpmock.REST("GET", "edge_applications/123423424/origin"), + httpmock.StatusStringResponse(http.StatusNotFound, "Not Found"), + ) + + f, _, _ := testutils.NewFactory(mock) + + cmd := NewCmd(f) + + err := cmd.Execute() + require.Error(t, err) + }) + + t.Run("no id sent", func(t *testing.T) { + mock := &httpmock.Registry{} + mock.Register( + httpmock.REST("GET", "edge_applications/123423424/origins"), + httpmock.StatusStringResponse(http.StatusNotFound, "Not Found"), + ) + + f, _, _ := testutils.NewFactory(mock) + cmd := NewCmd(f) + cmd.SetArgs([]string{"-a", "123423424", "-o", "88149"}) + + err := cmd.Execute() + require.Error(t, err) + }) + + t.Run("export to a file", func(t *testing.T) { + mock := &httpmock.Registry{} + + mock.Register( + httpmock.REST("GET", "edge_applications/123423424/origins"), + httpmock.JSONFromFile("./fixtures/origins.json"), + ) + + f, stdout, _ := testutils.NewFactory(mock) + + cmd := NewCmd(f) + path := "./out.json" + cmd.SetArgs([]string{"-a", "123423424", "-o", "88144", "--out", path}) + + err := cmd.Execute() + if err != nil { + log.Println("error executing cmd err: ", err.Error()) + } + + _, err = os.ReadFile(path) + if err != nil { + t.Fatalf("error reading `out.json`: %v", err) + } + defer func() { + _ = os.Remove(path) + }() + + require.NoError(t, err) + + require.Equal(t, `File successfully written to: out.json +`, stdout.String()) + }) +} diff --git a/pkg/cmd/origins/describe/fixtures/noorigins.json b/pkg/cmd/origins/describe/fixtures/noorigins.json new file mode 100644 index 000000000..cc69cb477 --- /dev/null +++ b/pkg/cmd/origins/describe/fixtures/noorigins.json @@ -0,0 +1,10 @@ +{ + "count": 1, + "total_pages": 0, + "schema_version": 3, + "links": { + "previous": null, + "next": null + }, + "results": [] +} diff --git a/pkg/cmd/origins/describe/fixtures/origins.json b/pkg/cmd/origins/describe/fixtures/origins.json new file mode 100644 index 000000000..143543346 --- /dev/null +++ b/pkg/cmd/origins/describe/fixtures/origins.json @@ -0,0 +1,61 @@ +{ + "count": 2, + "total_pages": 1, + "schema_version": 3, + "links": { + "previous": null, + "next": null + }, + "results": [ + { + "origin_id": 88144, + "origin_key": "0cee30cd-1743-4202-b0dd-da9b636a6035", + "name": "Default Origin", + "origin_type": "single_origin", + "addresses": [ + { + "address": "www.new.api", + "weight": null, + "server_role": "primary", + "is_active": true + } + ], + "origin_protocol_policy": "preserve", + "is_origin_redirection_enabled": false, + "host_header": "www.new.api", + "method": "", + "origin_path": "", + "connection_timeout": 60, + "timeout_between_bytes": 120, + "hmac_authentication": false, + "hmac_region_name": "", + "hmac_access_key": "", + "hmac_secret_key": "" + }, + { + "origin_id": 91799, + "origin_key": "e4f0761b-d2ac-4168-aa4b-f525d08396fd", + "name": "Create Origin", + "origin_type": "single_origin", + "addresses": [ + { + "address": "httpbin.org", + "weight": null, + "server_role": "primary", + "is_active": true + } + ], + "origin_protocol_policy": "http", + "is_origin_redirection_enabled": false, + "host_header": "${host}", + "method": "", + "origin_path": "/requests", + "connection_timeout": 60, + "timeout_between_bytes": 120, + "hmac_authentication": false, + "hmac_region_name": "", + "hmac_access_key": "", + "hmac_secret_key": "" + } + ] +} diff --git a/pkg/cmd/origins/origins.go b/pkg/cmd/origins/origins.go index 221f9cca7..fee3863ec 100644 --- a/pkg/cmd/origins/origins.go +++ b/pkg/cmd/origins/origins.go @@ -1,8 +1,9 @@ -package origins +package origins import ( "github.com/MakeNowJust/heredoc" msg "github.com/aziontech/azion-cli/messages/origins" + "github.com/aziontech/azion-cli/pkg/cmd/origins/describe" "github.com/aziontech/azion-cli/pkg/cmd/origins/list" "github.com/aziontech/azion-cli/pkg/cmdutil" "github.com/spf13/cobra" @@ -21,6 +22,7 @@ func NewCmd(f *cmdutil.Factory) *cobra.Command { } originsCmd.AddCommand(list.NewCmd(f)) + originsCmd.AddCommand(describe.NewCmd(f)) originsCmd.Flags().BoolP("help", "h", false, msg.OriginsFlagHelp) return originsCmd