From 12e7485d7eb69035528eb4ab9749884088b41a22 Mon Sep 17 00:00:00 2001 From: "Colton J. McCurdy" Date: Wed, 27 May 2020 14:54:40 -0400 Subject: [PATCH] logging: adds Google Cloud Pub/Sub logging endpoint support --- pkg/api/interface.go | 6 + pkg/app/run.go | 25 +- pkg/app/run_test.go | 85 ++++ pkg/logging/googlepubsub/create.go | 108 +++++ pkg/logging/googlepubsub/delete.go | 47 ++ pkg/logging/googlepubsub/describe.go | 59 +++ pkg/logging/googlepubsub/doc.go | 3 + .../googlepubsub_integration_test.go | 420 ++++++++++++++++++ pkg/logging/googlepubsub/googlepubsub_test.go | 211 +++++++++ pkg/logging/googlepubsub/list.go | 76 ++++ pkg/logging/googlepubsub/root.go | 28 ++ pkg/logging/googlepubsub/update.go | 144 ++++++ pkg/mock/api.go | 31 ++ 13 files changed, 1238 insertions(+), 5 deletions(-) create mode 100644 pkg/logging/googlepubsub/create.go create mode 100644 pkg/logging/googlepubsub/delete.go create mode 100644 pkg/logging/googlepubsub/describe.go create mode 100644 pkg/logging/googlepubsub/doc.go create mode 100644 pkg/logging/googlepubsub/googlepubsub_integration_test.go create mode 100644 pkg/logging/googlepubsub/googlepubsub_test.go create mode 100644 pkg/logging/googlepubsub/list.go create mode 100644 pkg/logging/googlepubsub/root.go create mode 100644 pkg/logging/googlepubsub/update.go diff --git a/pkg/api/interface.go b/pkg/api/interface.go index 5fe70849e..2cb3d2e89 100644 --- a/pkg/api/interface.go +++ b/pkg/api/interface.go @@ -184,6 +184,12 @@ type Interface interface { UpdateKafka(*fastly.UpdateKafkaInput) (*fastly.Kafka, error) DeleteKafka(*fastly.DeleteKafkaInput) error + CreatePubsub(*fastly.CreatePubsubInput) (*fastly.Pubsub, error) + ListPubsubs(*fastly.ListPubsubsInput) ([]*fastly.Pubsub, error) + GetPubsub(*fastly.GetPubsubInput) (*fastly.Pubsub, error) + UpdatePubsub(*fastly.UpdatePubsubInput) (*fastly.Pubsub, error) + DeletePubsub(*fastly.DeletePubsubInput) error + GetUser(*fastly.GetUserInput) (*fastly.User, error) GetRegions() (*fastly.RegionsResponse, error) diff --git a/pkg/app/run.go b/pkg/app/run.go index e2dab6256..b55d8385e 100644 --- a/pkg/app/run.go +++ b/pkg/app/run.go @@ -27,6 +27,7 @@ import ( "github.com/fastly/cli/pkg/logging/elasticsearch" "github.com/fastly/cli/pkg/logging/ftp" "github.com/fastly/cli/pkg/logging/gcs" + "github.com/fastly/cli/pkg/logging/googlepubsub" "github.com/fastly/cli/pkg/logging/heroku" "github.com/fastly/cli/pkg/logging/honeycomb" "github.com/fastly/cli/pkg/logging/https" @@ -288,11 +289,6 @@ func Run(args []string, env config.Environment, file config.File, configFilePath httpsUpdate := https.NewUpdateCommand(httpsRoot.CmdClause, &globals) httpsDelete := https.NewDeleteCommand(httpsRoot.CmdClause, &globals) - statsRoot := stats.NewRootCommand(app, &globals) - statsRegions := stats.NewRegionsCommand(statsRoot.CmdClause, &globals) - statsHistorical := stats.NewHistoricalCommand(statsRoot.CmdClause, &globals) - statsRealtime := stats.NewRealtimeCommand(statsRoot.CmdClause, &globals) - kafkaRoot := kafka.NewRootCommand(loggingRoot.CmdClause, &globals) kafkaCreate := kafka.NewCreateCommand(kafkaRoot.CmdClause, &globals) kafkaList := kafka.NewListCommand(kafkaRoot.CmdClause, &globals) @@ -300,6 +296,18 @@ func Run(args []string, env config.Environment, file config.File, configFilePath kafkaUpdate := kafka.NewUpdateCommand(kafkaRoot.CmdClause, &globals) kafkaDelete := kafka.NewDeleteCommand(kafkaRoot.CmdClause, &globals) + googlepubsubRoot := googlepubsub.NewRootCommand(loggingRoot.CmdClause, &globals) + googlepubsubCreate := googlepubsub.NewCreateCommand(googlepubsubRoot.CmdClause, &globals) + googlepubsubList := googlepubsub.NewListCommand(googlepubsubRoot.CmdClause, &globals) + googlepubsubDescribe := googlepubsub.NewDescribeCommand(googlepubsubRoot.CmdClause, &globals) + googlepubsubUpdate := googlepubsub.NewUpdateCommand(googlepubsubRoot.CmdClause, &globals) + googlepubsubDelete := googlepubsub.NewDeleteCommand(googlepubsubRoot.CmdClause, &globals) + + statsRoot := stats.NewRootCommand(app, &globals) + statsRegions := stats.NewRegionsCommand(statsRoot.CmdClause, &globals) + statsHistorical := stats.NewHistoricalCommand(statsRoot.CmdClause, &globals) + statsRealtime := stats.NewRealtimeCommand(statsRoot.CmdClause, &globals) + commands := []common.Command{ configureRoot, whoamiRoot, @@ -505,6 +513,13 @@ func Run(args []string, env config.Environment, file config.File, configFilePath kafkaUpdate, kafkaDelete, + googlepubsubRoot, + googlepubsubCreate, + googlepubsubList, + googlepubsubDescribe, + googlepubsubUpdate, + googlepubsubDelete, + statsRoot, statsRegions, statsHistorical, diff --git a/pkg/app/run_test.go b/pkg/app/run_test.go index 1cb206afc..d08d11514 100644 --- a/pkg/app/run_test.go +++ b/pkg/app/run_test.go @@ -2594,6 +2594,91 @@ COMMANDS --version=VERSION Number of service version -n, --name=NAME The name of the Kafka logging object + logging googlepubsub create --name=NAME --version=VERSION --user=USER --secret-key=SECRET-KEY --topic=TOPIC --project-id=PROJECT-ID [] + Create a Google Cloud Pub/Sub logging endpoint on a Fastly service version + + -n, --name=NAME The name of the Google Cloud Pub/Sub logging + object. Used as a primary key for API access + -s, --service-id=SERVICE-ID Service ID + --version=VERSION Number of service version + --user=USER Your Google Cloud Platform service account + email address. The client_email field in your + service account authentication JSON + --secret-key=SECRET-KEY Your Google Cloud Platform account secret key. + The private_key field in your service account + authentication JSON + --topic=TOPIC The Google Cloud Pub/Sub topic to which logs + will be published + --project-id=PROJECT-ID The ID of your Google Cloud Platform project + --format=FORMAT Apache style log formatting + --format-version=FORMAT-VERSION + The version of the custom logging format used + for the configured endpoint. Can be either 2 + (default) or 1 + --placement=PLACEMENT Where in the generated VCL the logging call + should be placed, overriding any format_version + default. Can be none or waf_debug. This field + is not required and has no default value + --response-condition=RESPONSE-CONDITION + The name of an existing condition in the + configured endpoint, or leave blank to always + execute + + logging googlepubsub list --version=VERSION [] + List Google Cloud Pub/Sub endpoints on a Fastly service version + + -s, --service-id=SERVICE-ID Service ID + --version=VERSION Number of service version + + logging googlepubsub describe --version=VERSION --name=NAME [] + Show detailed information about a Google Cloud Pub/Sub logging endpoint on a + Fastly service version + + -s, --service-id=SERVICE-ID Service ID + --version=VERSION Number of service version + -n, --name=NAME The name of the Google Cloud Pub/Sub logging + object + + logging googlepubsub update --version=VERSION --name=NAME [] + Update a Google Cloud Pub/Sub logging endpoint on a Fastly service version + + -s, --service-id=SERVICE-ID Service ID + --version=VERSION Number of service version + -n, --name=NAME The name of the Google Cloud Pub/Sub logging + object + --new-name=NEW-NAME New name of the Google Cloud Pub/Sub logging + object + --user=USER Your Google Cloud Platform service account + email address. The client_email field in your + service account authentication JSON + --secret-key=SECRET-KEY Your Google Cloud Platform account secret key. + The private_key field in your service account + authentication JSON + --topic=TOPIC The Google Cloud Pub/Sub topic to which logs + will be published + --project-id=PROJECT-ID The ID of your Google Cloud Platform project + --format=FORMAT Apache style log formatting + --format-version=FORMAT-VERSION + The version of the custom logging format used + for the configured endpoint. Can be either 2 + (default) or 1 + --placement=PLACEMENT Where in the generated VCL the logging call + should be placed, overriding any format_version + default. Can be none or waf_debug. This field + is not required and has no default value + --response-condition=RESPONSE-CONDITION + The name of an existing condition in the + configured endpoint, or leave blank to always + execute + + logging googlepubsub delete --version=VERSION --name=NAME [] + Delete a Google Cloud Pub/Sub logging endpoint on a Fastly service version + + -s, --service-id=SERVICE-ID Service ID + --version=VERSION Number of service version + -n, --name=NAME The name of the Google Cloud Pub/Sub logging + object + stats regions List stats regions diff --git a/pkg/logging/googlepubsub/create.go b/pkg/logging/googlepubsub/create.go new file mode 100644 index 000000000..b6bedefa3 --- /dev/null +++ b/pkg/logging/googlepubsub/create.go @@ -0,0 +1,108 @@ +package googlepubsub + +import ( + "io" + + "github.com/fastly/cli/pkg/common" + "github.com/fastly/cli/pkg/compute/manifest" + "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/fastly" +) + +// CreateCommand calls the Fastly API to create Google Cloud Pub/Sub logging endpoints. +type CreateCommand struct { + common.Base + manifest manifest.Data + + // required + EndpointName string // Can't shaddow common.Base method Name(). + Version int + User string + SecretKey string + Topic string + ProjectID string + + // optional + Format common.OptionalString + FormatVersion common.OptionalUint + Placement common.OptionalString + ResponseCondition common.OptionalString +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent common.Registerer, globals *config.Data) *CreateCommand { + var c CreateCommand + c.Globals = globals + c.manifest.File.Read(manifest.Filename) + c.CmdClause = parent.Command("create", "Create a Google Cloud Pub/Sub logging endpoint on a Fastly service version").Alias("add") + + c.CmdClause.Flag("name", "The name of the Google Cloud Pub/Sub logging object. Used as a primary key for API access").Short('n').Required().StringVar(&c.EndpointName) + c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID) + c.CmdClause.Flag("version", "Number of service version").Required().IntVar(&c.Version) + + c.CmdClause.Flag("user", "Your Google Cloud Platform service account email address. The client_email field in your service account authentication JSON").Required().StringVar(&c.User) + c.CmdClause.Flag("secret-key", "Your Google Cloud Platform account secret key. The private_key field in your service account authentication JSON").Required().StringVar(&c.SecretKey) + c.CmdClause.Flag("topic", "The Google Cloud Pub/Sub topic to which logs will be published").Required().StringVar(&c.Topic) + c.CmdClause.Flag("project-id", "The ID of your Google Cloud Platform project").Required().StringVar(&c.ProjectID) + + c.CmdClause.Flag("format", "Apache style log formatting").Action(c.Format.Set).StringVar(&c.Format.Value) + c.CmdClause.Flag("format-version", "The version of the custom logging format used for the configured endpoint. Can be either 2 (default) or 1").Action(c.FormatVersion.Set).UintVar(&c.FormatVersion.Value) + c.CmdClause.Flag("placement", "Where in the generated VCL the logging call should be placed, overriding any format_version default. Can be none or waf_debug. This field is not required and has no default value").Action(c.Placement.Set).StringVar(&c.Placement.Value) + c.CmdClause.Flag("response-condition", "The name of an existing condition in the configured endpoint, or leave blank to always execute").Action(c.ResponseCondition.Set).StringVar(&c.ResponseCondition.Value) + + return &c +} + +// createInput transforms values parsed from CLI flags into an object to be used by the API client library. +func (c *CreateCommand) createInput() (*fastly.CreatePubsubInput, error) { + var input fastly.CreatePubsubInput + + serviceID, source := c.manifest.ServiceID() + if source == manifest.SourceUndefined { + return nil, errors.ErrNoServiceID + } + + input.Service = serviceID + input.Version = c.Version + input.Name = fastly.String(c.EndpointName) + input.User = fastly.String(c.User) + input.SecretKey = fastly.String(c.SecretKey) + input.Topic = fastly.String(c.Topic) + input.ProjectID = fastly.String(c.ProjectID) + + if c.Format.Valid { + input.Format = fastly.String(c.Format.Value) + } + + if c.FormatVersion.Valid { + input.FormatVersion = fastly.Uint(c.FormatVersion.Value) + } + + if c.ResponseCondition.Valid { + input.ResponseCondition = fastly.String(c.ResponseCondition.Value) + } + + if c.Placement.Valid { + input.Placement = fastly.String(c.Placement.Value) + } + + return &input, nil +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(in io.Reader, out io.Writer) error { + input, err := c.createInput() + if err != nil { + return err + } + + d, err := c.Globals.Client.CreatePubsub(input) + if err != nil { + return err + } + + text.Success(out, "Created Google Cloud Pub/Sub logging endpoint %s (service %s version %d)", d.Name, d.ServiceID, d.Version) + return nil +} diff --git a/pkg/logging/googlepubsub/delete.go b/pkg/logging/googlepubsub/delete.go new file mode 100644 index 000000000..37e87f9df --- /dev/null +++ b/pkg/logging/googlepubsub/delete.go @@ -0,0 +1,47 @@ +package googlepubsub + +import ( + "io" + + "github.com/fastly/cli/pkg/common" + "github.com/fastly/cli/pkg/compute/manifest" + "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/fastly" +) + +// DeleteCommand calls the Fastly API to delete Google Cloud Pub/Sub logging endpoints. +type DeleteCommand struct { + common.Base + manifest manifest.Data + Input fastly.DeletePubsubInput +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent common.Registerer, globals *config.Data) *DeleteCommand { + var c DeleteCommand + c.Globals = globals + c.manifest.File.Read(manifest.Filename) + c.CmdClause = parent.Command("delete", "Delete a Google Cloud Pub/Sub logging endpoint on a Fastly service version").Alias("remove") + c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID) + c.CmdClause.Flag("version", "Number of service version").Required().IntVar(&c.Input.Version) + c.CmdClause.Flag("name", "The name of the Google Cloud Pub/Sub logging object").Short('n').Required().StringVar(&c.Input.Name) + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(in io.Reader, out io.Writer) error { + serviceID, source := c.manifest.ServiceID() + if source == manifest.SourceUndefined { + return errors.ErrNoServiceID + } + c.Input.Service = serviceID + + if err := c.Globals.Client.DeletePubsub(&c.Input); err != nil { + return err + } + + text.Success(out, "Deleted Google Cloud Pub/Sub logging endpoint %s (service %s version %d)", c.Input.Name, c.Input.Service, c.Input.Version) + return nil +} diff --git a/pkg/logging/googlepubsub/describe.go b/pkg/logging/googlepubsub/describe.go new file mode 100644 index 000000000..526886d9b --- /dev/null +++ b/pkg/logging/googlepubsub/describe.go @@ -0,0 +1,59 @@ +package googlepubsub + +import ( + "fmt" + "io" + + "github.com/fastly/cli/pkg/common" + "github.com/fastly/cli/pkg/compute/manifest" + "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/errors" + "github.com/fastly/go-fastly/fastly" +) + +// DescribeCommand calls the Fastly API to describe a Google Cloud Pub/Sub logging endpoint. +type DescribeCommand struct { + common.Base + manifest manifest.Data + Input fastly.GetPubsubInput +} + +// NewDescribeCommand returns a usable command registered under the parent. +func NewDescribeCommand(parent common.Registerer, globals *config.Data) *DescribeCommand { + var c DescribeCommand + c.Globals = globals + c.manifest.File.Read(manifest.Filename) + c.CmdClause = parent.Command("describe", "Show detailed information about a Google Cloud Pub/Sub logging endpoint on a Fastly service version").Alias("get") + c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID) + c.CmdClause.Flag("version", "Number of service version").Required().IntVar(&c.Input.Version) + c.CmdClause.Flag("name", "The name of the Google Cloud Pub/Sub logging object").Short('n').Required().StringVar(&c.Input.Name) + return &c +} + +// Exec invokes the application logic for the command. +func (c *DescribeCommand) Exec(in io.Reader, out io.Writer) error { + serviceID, source := c.manifest.ServiceID() + if source == manifest.SourceUndefined { + return errors.ErrNoServiceID + } + c.Input.Service = serviceID + + googlepubsub, err := c.Globals.Client.GetPubsub(&c.Input) + if err != nil { + return err + } + + fmt.Fprintf(out, "Service ID: %s\n", googlepubsub.ServiceID) + fmt.Fprintf(out, "Version: %d\n", googlepubsub.Version) + fmt.Fprintf(out, "Name: %s\n", googlepubsub.Name) + fmt.Fprintf(out, "User: %s\n", googlepubsub.User) + fmt.Fprintf(out, "Secret key: %s\n", googlepubsub.SecretKey) + fmt.Fprintf(out, "Project ID: %s\n", googlepubsub.ProjectID) + fmt.Fprintf(out, "Topic: %s\n", googlepubsub.Topic) + fmt.Fprintf(out, "Format: %s\n", googlepubsub.Format) + fmt.Fprintf(out, "Format version: %d\n", googlepubsub.FormatVersion) + fmt.Fprintf(out, "Response condition: %s\n", googlepubsub.ResponseCondition) + fmt.Fprintf(out, "Placement: %s\n", googlepubsub.Placement) + + return nil +} diff --git a/pkg/logging/googlepubsub/doc.go b/pkg/logging/googlepubsub/doc.go new file mode 100644 index 000000000..21fb4feee --- /dev/null +++ b/pkg/logging/googlepubsub/doc.go @@ -0,0 +1,3 @@ +// Package googlepubsub contains commands to inspect and manipulate Fastly service Google Cloud Pub/Sub +// logging endpoints. +package googlepubsub diff --git a/pkg/logging/googlepubsub/googlepubsub_integration_test.go b/pkg/logging/googlepubsub/googlepubsub_integration_test.go new file mode 100644 index 000000000..18eb7e3a6 --- /dev/null +++ b/pkg/logging/googlepubsub/googlepubsub_integration_test.go @@ -0,0 +1,420 @@ +package googlepubsub_test + +import ( + "bytes" + "errors" + "io" + "net/http" + "strings" + "testing" + + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/mock" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/cli/pkg/update" + "github.com/fastly/go-fastly/fastly" +) + +func TestGooglePubSubCreate(t *testing.T) { + for _, testcase := range []struct { + args []string + api mock.API + wantError string + wantOutput string + }{ + { + args: []string{"logging", "googlepubsub", "create", "--service-id", "123", "--version", "1", "--name", "log", "--secret-key", "secret", "--project-id", "project", "--topic", "topic"}, + wantError: "error parsing arguments: required flag --user not provided", + }, + { + args: []string{"logging", "googlepubsub", "create", "--service-id", "123", "--version", "1", "--name", "log", "--user", "user@example.com", "--project-id", "project", "--topic", "topic"}, + wantError: "error parsing arguments: required flag --secret-key not provided", + }, + { + args: []string{"logging", "googlepubsub", "create", "--service-id", "123", "--version", "1", "--name", "log", "--user", "user@example.com", "--secret-key", "secret", "--topic", "topic"}, + wantError: "error parsing arguments: required flag --project-id not provided", + }, + { + args: []string{"logging", "googlepubsub", "create", "--service-id", "123", "--version", "1", "--name", "log", "--user", "user@example.com", "--secret-key", "secret", "--project-id", "project"}, + wantError: "error parsing arguments: required flag --topic not provided", + }, + { + args: []string{"logging", "googlepubsub", "create", "--service-id", "123", "--version", "1", "--name", "log", "--user", "user@example.com", "--secret-key", "secret", "--project-id", "project", "--topic", "topic"}, + api: mock.API{CreatePubsubFn: createGooglePubSubOK}, + wantOutput: "Created Google Cloud Pub/Sub logging endpoint log (service 123 version 1)", + }, + { + args: []string{"logging", "googlepubsub", "create", "--service-id", "123", "--version", "1", "--name", "log", "--user", "user@example.com", "--secret-key", "secret", "--project-id", "project", "--topic", "topic"}, + api: mock.API{CreatePubsubFn: createGooglePubSubError}, + wantError: errTest.Error(), + }, + } { + t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { + var ( + args = testcase.args + env = config.Environment{} + file = config.File{} + appConfigFile = "/dev/null" + clientFactory = mock.APIClient(testcase.api) + httpClient = http.DefaultClient + versioner update.Versioner = nil + in io.Reader = nil + out bytes.Buffer + ) + err := app.Run(args, env, file, appConfigFile, clientFactory, httpClient, versioner, in, &out) + testutil.AssertErrorContains(t, err, testcase.wantError) + testutil.AssertStringContains(t, out.String(), testcase.wantOutput) + }) + } +} + +func TestGooglePubSubList(t *testing.T) { + for _, testcase := range []struct { + args []string + api mock.API + wantError string + wantOutput string + }{ + { + args: []string{"logging", "googlepubsub", "list", "--service-id", "123", "--version", "1"}, + api: mock.API{ListPubsubsFn: listGooglePubSubsOK}, + wantOutput: listGooglePubSubsShortOutput, + }, + { + args: []string{"logging", "googlepubsub", "list", "--service-id", "123", "--version", "1", "--verbose"}, + api: mock.API{ListPubsubsFn: listGooglePubSubsOK}, + wantOutput: listGooglePubSubsVerboseOutput, + }, + { + args: []string{"logging", "googlepubsub", "list", "--service-id", "123", "--version", "1", "-v"}, + api: mock.API{ListPubsubsFn: listGooglePubSubsOK}, + wantOutput: listGooglePubSubsVerboseOutput, + }, + { + args: []string{"logging", "googlepubsub", "--verbose", "list", "--service-id", "123", "--version", "1"}, + api: mock.API{ListPubsubsFn: listGooglePubSubsOK}, + wantOutput: listGooglePubSubsVerboseOutput, + }, + { + args: []string{"logging", "-v", "googlepubsub", "list", "--service-id", "123", "--version", "1"}, + api: mock.API{ListPubsubsFn: listGooglePubSubsOK}, + wantOutput: listGooglePubSubsVerboseOutput, + }, + { + args: []string{"logging", "googlepubsub", "list", "--service-id", "123", "--version", "1"}, + api: mock.API{ListPubsubsFn: listGooglePubSubsError}, + wantError: errTest.Error(), + }, + } { + t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { + var ( + args = testcase.args + env = config.Environment{} + file = config.File{} + appConfigFile = "/dev/null" + clientFactory = mock.APIClient(testcase.api) + httpClient = http.DefaultClient + versioner update.Versioner = nil + in io.Reader = nil + out bytes.Buffer + ) + err := app.Run(args, env, file, appConfigFile, clientFactory, httpClient, versioner, in, &out) + testutil.AssertErrorContains(t, err, testcase.wantError) + testutil.AssertString(t, testcase.wantOutput, out.String()) + }) + } +} + +func TestGooglePubSubDescribe(t *testing.T) { + for _, testcase := range []struct { + args []string + api mock.API + wantError string + wantOutput string + }{ + { + args: []string{"logging", "googlepubsub", "describe", "--service-id", "123", "--version", "1"}, + wantError: "error parsing arguments: required flag --name not provided", + }, + { + args: []string{"logging", "googlepubsub", "describe", "--service-id", "123", "--version", "1", "--name", "logs"}, + api: mock.API{GetPubsubFn: getGooglePubSubError}, + wantError: errTest.Error(), + }, + { + args: []string{"logging", "googlepubsub", "describe", "--service-id", "123", "--version", "1", "--name", "logs"}, + api: mock.API{GetPubsubFn: getGooglePubSubOK}, + wantOutput: describeGooglePubSubOutput, + }, + } { + t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { + var ( + args = testcase.args + env = config.Environment{} + file = config.File{} + appConfigFile = "/dev/null" + clientFactory = mock.APIClient(testcase.api) + httpClient = http.DefaultClient + versioner update.Versioner = nil + in io.Reader = nil + out bytes.Buffer + ) + err := app.Run(args, env, file, appConfigFile, clientFactory, httpClient, versioner, in, &out) + testutil.AssertErrorContains(t, err, testcase.wantError) + testutil.AssertString(t, testcase.wantOutput, out.String()) + }) + } +} + +func TestGooglePubSubUpdate(t *testing.T) { + for _, testcase := range []struct { + args []string + api mock.API + wantError string + wantOutput string + }{ + { + args: []string{"logging", "googlepubsub", "update", "--service-id", "123", "--version", "1", "--new-name", "log"}, + wantError: "error parsing arguments: required flag --name not provided", + }, + { + args: []string{"logging", "googlepubsub", "update", "--service-id", "123", "--version", "1", "--name", "logs", "--new-name", "log"}, + api: mock.API{ + GetPubsubFn: getGooglePubSubError, + UpdatePubsubFn: updateGooglePubSubOK, + }, + wantError: errTest.Error(), + }, + { + args: []string{"logging", "googlepubsub", "update", "--service-id", "123", "--version", "1", "--name", "logs", "--new-name", "log"}, + api: mock.API{ + GetPubsubFn: getGooglePubSubOK, + UpdatePubsubFn: updateGooglePubSubError, + }, + wantError: errTest.Error(), + }, + { + args: []string{"logging", "googlepubsub", "update", "--service-id", "123", "--version", "1", "--name", "logs", "--new-name", "log"}, + api: mock.API{ + GetPubsubFn: getGooglePubSubOK, + UpdatePubsubFn: updateGooglePubSubOK, + }, + wantOutput: "Updated Google Cloud Pub/Sub logging endpoint log (service 123 version 1)", + }, + } { + t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { + var ( + args = testcase.args + env = config.Environment{} + file = config.File{} + appConfigFile = "/dev/null" + clientFactory = mock.APIClient(testcase.api) + httpClient = http.DefaultClient + versioner update.Versioner = nil + in io.Reader = nil + out bytes.Buffer + ) + err := app.Run(args, env, file, appConfigFile, clientFactory, httpClient, versioner, in, &out) + testutil.AssertErrorContains(t, err, testcase.wantError) + testutil.AssertStringContains(t, out.String(), testcase.wantOutput) + }) + } +} + +func TestGooglePubSubDelete(t *testing.T) { + for _, testcase := range []struct { + args []string + api mock.API + wantError string + wantOutput string + }{ + { + args: []string{"logging", "googlepubsub", "delete", "--service-id", "123", "--version", "1"}, + wantError: "error parsing arguments: required flag --name not provided", + }, + { + args: []string{"logging", "googlepubsub", "delete", "--service-id", "123", "--version", "1", "--name", "logs"}, + api: mock.API{DeletePubsubFn: deleteGooglePubSubError}, + wantError: errTest.Error(), + }, + { + args: []string{"logging", "googlepubsub", "delete", "--service-id", "123", "--version", "1", "--name", "logs"}, + api: mock.API{DeletePubsubFn: deleteGooglePubSubOK}, + wantOutput: "Deleted Google Cloud Pub/Sub logging endpoint logs (service 123 version 1)", + }, + } { + t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { + var ( + args = testcase.args + env = config.Environment{} + file = config.File{} + appConfigFile = "/dev/null" + clientFactory = mock.APIClient(testcase.api) + httpClient = http.DefaultClient + versioner update.Versioner = nil + in io.Reader = nil + out bytes.Buffer + ) + err := app.Run(args, env, file, appConfigFile, clientFactory, httpClient, versioner, in, &out) + testutil.AssertErrorContains(t, err, testcase.wantError) + testutil.AssertStringContains(t, out.String(), testcase.wantOutput) + }) + } +} + +var errTest = errors.New("fixture error") + +func createGooglePubSubOK(i *fastly.CreatePubsubInput) (*fastly.Pubsub, error) { + return &fastly.Pubsub{ + ServiceID: i.Service, + Version: i.Version, + Name: "log", + Topic: "topic", + User: "user", + SecretKey: "secret", + ProjectID: "project", + Format: `%h %l %u %t "%r" %>s %b`, + FormatVersion: 2, + ResponseCondition: "Prevent default logging", + Placement: "none", + }, nil +} + +func createGooglePubSubError(i *fastly.CreatePubsubInput) (*fastly.Pubsub, error) { + return nil, errTest +} + +func listGooglePubSubsOK(i *fastly.ListPubsubsInput) ([]*fastly.Pubsub, error) { + return []*fastly.Pubsub{ + { + ServiceID: i.Service, + Version: i.Version, + Name: "logs", + User: "user@example.com", + SecretKey: "secret", + ProjectID: "project", + Topic: "topic", + ResponseCondition: "Prevent default logging", + Format: `%h %l %u %t "%r" %>s %b`, + Placement: "none", + FormatVersion: 2, + }, + { + ServiceID: i.Service, + Version: i.Version, + Name: "analytics", + User: "user@example.com", + SecretKey: "secret", + ProjectID: "project", + Topic: "analytics", + Placement: "none", + ResponseCondition: "Prevent default logging", + Format: `%h %l %u %t "%r" %>s %b`, + FormatVersion: 2, + }, + }, nil +} + +func listGooglePubSubsError(i *fastly.ListPubsubsInput) ([]*fastly.Pubsub, error) { + return nil, errTest +} + +var listGooglePubSubsShortOutput = strings.TrimSpace(` +SERVICE VERSION NAME +123 1 logs +123 1 analytics +`) + "\n" + +var listGooglePubSubsVerboseOutput = strings.TrimSpace(` +Fastly API token not provided +Fastly API endpoint: https://api.fastly.com +Service ID: 123 +Version: 1 + Google Cloud Pub/Sub 1/2 + Service ID: 123 + Version: 1 + Name: logs + User: user@example.com + Secret key: secret + Project ID: project + Topic: topic + Format: %h %l %u %t "%r" %>s %b + Format version: 2 + Response condition: Prevent default logging + Placement: none + Google Cloud Pub/Sub 2/2 + Service ID: 123 + Version: 1 + Name: analytics + User: user@example.com + Secret key: secret + Project ID: project + Topic: analytics + Format: %h %l %u %t "%r" %>s %b + Format version: 2 + Response condition: Prevent default logging + Placement: none +`) + "\n\n" + +func getGooglePubSubOK(i *fastly.GetPubsubInput) (*fastly.Pubsub, error) { + return &fastly.Pubsub{ + ServiceID: i.Service, + Version: i.Version, + Name: "logs", + Topic: "topic", + User: "user@example.com", + SecretKey: "secret", + ProjectID: "project", + Format: `%h %l %u %t "%r" %>s %b`, + FormatVersion: 2, + ResponseCondition: "Prevent default logging", + Placement: "none", + }, nil +} + +func getGooglePubSubError(i *fastly.GetPubsubInput) (*fastly.Pubsub, error) { + return nil, errTest +} + +var describeGooglePubSubOutput = strings.TrimSpace(` +Service ID: 123 +Version: 1 +Name: logs +User: user@example.com +Secret key: secret +Project ID: project +Topic: topic +Format: %h %l %u %t "%r" %>s %b +Format version: 2 +Response condition: Prevent default logging +Placement: none +`) + "\n" + +func updateGooglePubSubOK(i *fastly.UpdatePubsubInput) (*fastly.Pubsub, error) { + return &fastly.Pubsub{ + ServiceID: i.Service, + Version: i.Version, + Name: "log", + Topic: "topic", + User: "user@example.com", + SecretKey: "secret", + ProjectID: "project", + Format: `%h %l %u %t "%r" %>s %b`, + FormatVersion: 2, + ResponseCondition: "Prevent default logging", + Placement: "none", + }, nil +} + +func updateGooglePubSubError(i *fastly.UpdatePubsubInput) (*fastly.Pubsub, error) { + return nil, errTest +} + +func deleteGooglePubSubOK(i *fastly.DeletePubsubInput) error { + return nil +} + +func deleteGooglePubSubError(i *fastly.DeletePubsubInput) error { + return errTest +} diff --git a/pkg/logging/googlepubsub/googlepubsub_test.go b/pkg/logging/googlepubsub/googlepubsub_test.go new file mode 100644 index 000000000..17541a51b --- /dev/null +++ b/pkg/logging/googlepubsub/googlepubsub_test.go @@ -0,0 +1,211 @@ +package googlepubsub + +import ( + "testing" + + "github.com/fastly/cli/pkg/common" + "github.com/fastly/cli/pkg/compute/manifest" + "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/mock" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/fastly" +) + +func TestCreateGooglePubSubInput(t *testing.T) { + for _, testcase := range []struct { + name string + cmd *CreateCommand + want *fastly.CreatePubsubInput + wantError string + }{ + { + name: "required values set flag serviceID", + cmd: createCommandRequired(), + want: &fastly.CreatePubsubInput{ + Service: "123", + Version: 2, + Name: fastly.String("log"), + User: fastly.String("user@example.com"), + SecretKey: fastly.String("secret"), + ProjectID: fastly.String("project"), + Topic: fastly.String("topic"), + }, + }, + { + name: "all values set flag serviceID", + cmd: createCommandAll(), + want: &fastly.CreatePubsubInput{ + Service: "123", + Version: 2, + Name: fastly.String("logs"), + Topic: fastly.String("topic"), + User: fastly.String("user@example.com"), + SecretKey: fastly.String("secret"), + ProjectID: fastly.String("project"), + FormatVersion: fastly.Uint(2), + Format: fastly.String(`%h %l %u %t "%r" %>s %b`), + ResponseCondition: fastly.String("Prevent default logging"), + Placement: fastly.String("none"), + }, + }, + { + name: "error missing serviceID", + cmd: createCommandMissingServiceID(), + want: nil, + wantError: errors.ErrNoServiceID.Error(), + }, + } { + t.Run(testcase.name, func(t *testing.T) { + have, err := testcase.cmd.createInput() + testutil.AssertErrorContains(t, err, testcase.wantError) + testutil.AssertEqual(t, testcase.want, have) + }) + } +} + +func TestUpdateGooglePubSubInput(t *testing.T) { + for _, testcase := range []struct { + name string + cmd *UpdateCommand + api mock.API + want *fastly.UpdatePubsubInput + wantError string + }{ + { + name: "all values set flag serviceID", + cmd: updateCommandAll(), + api: mock.API{GetPubsubFn: getGooglePubSubOK}, + want: &fastly.UpdatePubsubInput{ + Service: "123", + Version: 2, + Name: "log", + NewName: fastly.String("new1"), + User: fastly.String("new2"), + SecretKey: fastly.String("new3"), + ProjectID: fastly.String("new4"), + Topic: fastly.String("new5"), + Placement: fastly.String("new6"), + Format: fastly.String("new7"), + FormatVersion: fastly.Uint(3), + ResponseCondition: fastly.String("new8"), + }, + }, + { + name: "no updates", + cmd: updateCommandNoUpdates(), + api: mock.API{GetPubsubFn: getGooglePubSubOK}, + want: &fastly.UpdatePubsubInput{ + Service: "123", + Version: 2, + Name: "log", + NewName: fastly.String("log"), + User: fastly.String("user@example.com"), + SecretKey: fastly.String("secret"), + ProjectID: fastly.String("project"), + Topic: fastly.String("topic"), + Placement: fastly.String("none"), + Format: fastly.String(`%h %l %u %t "%r" %>s %b`), + FormatVersion: fastly.Uint(2), + ResponseCondition: fastly.String("Prevent default logging"), + }, + }, + { + name: "error missing serviceID", + cmd: updateCommandMissingServiceID(), + want: nil, + wantError: errors.ErrNoServiceID.Error(), + }, + } { + t.Run(testcase.name, func(t *testing.T) { + testcase.cmd.Base.Globals.Client = testcase.api + + have, err := testcase.cmd.createInput() + testutil.AssertErrorContains(t, err, testcase.wantError) + testutil.AssertEqual(t, testcase.want, have) + }) + } +} + +func createCommandRequired() *CreateCommand { + return &CreateCommand{ + manifest: manifest.Data{Flag: manifest.Flag{ServiceID: "123"}}, + EndpointName: "log", + Version: 2, + User: "user@example.com", + SecretKey: "secret", + ProjectID: "project", + Topic: "topic", + } +} + +func createCommandAll() *CreateCommand { + return &CreateCommand{ + manifest: manifest.Data{Flag: manifest.Flag{ServiceID: "123"}}, + EndpointName: "logs", + Version: 2, + User: "user@example.com", + ProjectID: "project", + Topic: "topic", + SecretKey: "secret", + Format: common.OptionalString{Optional: common.Optional{Valid: true}, Value: `%h %l %u %t "%r" %>s %b`}, + FormatVersion: common.OptionalUint{Optional: common.Optional{Valid: true}, Value: 2}, + ResponseCondition: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "Prevent default logging"}, + Placement: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "none"}, + } +} + +func createCommandMissingServiceID() *CreateCommand { + res := createCommandAll() + res.manifest = manifest.Data{} + return res +} + +func updateCommandNoUpdates() *UpdateCommand { + return &UpdateCommand{ + Base: common.Base{Globals: &config.Data{Client: nil}}, + manifest: manifest.Data{Flag: manifest.Flag{ServiceID: "123"}}, + EndpointName: "log", + Version: 2, + } +} + +func updateCommandAll() *UpdateCommand { + return &UpdateCommand{ + Base: common.Base{Globals: &config.Data{Client: nil}}, + manifest: manifest.Data{Flag: manifest.Flag{ServiceID: "123"}}, + EndpointName: "log", + Version: 2, + NewName: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "new1"}, + User: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "new2"}, + SecretKey: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "new3"}, + ProjectID: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "new4"}, + Topic: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "new5"}, + Placement: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "new6"}, + Format: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "new7"}, + FormatVersion: common.OptionalUint{Optional: common.Optional{Valid: true}, Value: 3}, + ResponseCondition: common.OptionalString{Optional: common.Optional{Valid: true}, Value: "new8"}, + } +} + +func updateCommandMissingServiceID() *UpdateCommand { + res := updateCommandAll() + res.manifest = manifest.Data{} + return res +} + +func getGooglePubSubOK(i *fastly.GetPubsubInput) (*fastly.Pubsub, error) { + return &fastly.Pubsub{ + ServiceID: i.Service, + Version: i.Version, + Name: "log", + ResponseCondition: "Prevent default logging", + Format: `%h %l %u %t "%r" %>s %b`, + User: "user@example.com", + SecretKey: "secret", + ProjectID: "project", + Topic: "topic", + Placement: "none", + FormatVersion: 2, + }, nil +} diff --git a/pkg/logging/googlepubsub/list.go b/pkg/logging/googlepubsub/list.go new file mode 100644 index 000000000..d6e518288 --- /dev/null +++ b/pkg/logging/googlepubsub/list.go @@ -0,0 +1,76 @@ +package googlepubsub + +import ( + "fmt" + "io" + + "github.com/fastly/cli/pkg/common" + "github.com/fastly/cli/pkg/compute/manifest" + "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/fastly" +) + +// ListCommand calls the Fastly API to list Google Cloud Pub/Sub logging endpoints. +type ListCommand struct { + common.Base + manifest manifest.Data + Input fastly.ListPubsubsInput +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent common.Registerer, globals *config.Data) *ListCommand { + var c ListCommand + c.Globals = globals + c.manifest.File.Read(manifest.Filename) + c.CmdClause = parent.Command("list", "List Google Cloud Pub/Sub endpoints on a Fastly service version") + c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID) + c.CmdClause.Flag("version", "Number of service version").Required().IntVar(&c.Input.Version) + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(in io.Reader, out io.Writer) error { + serviceID, source := c.manifest.ServiceID() + if source == manifest.SourceUndefined { + return errors.ErrNoServiceID + } + c.Input.Service = serviceID + + googlepubsubs, err := c.Globals.Client.ListPubsubs(&c.Input) + if err != nil { + return err + } + + if !c.Globals.Verbose() { + tw := text.NewTable(out) + tw.AddHeader("SERVICE", "VERSION", "NAME") + for _, googlepubsub := range googlepubsubs { + tw.AddLine(googlepubsub.ServiceID, googlepubsub.Version, googlepubsub.Name) + } + tw.Print() + return nil + } + + fmt.Fprintf(out, "Service ID: %s\n", c.Input.Service) + fmt.Fprintf(out, "Version: %d\n", c.Input.Version) + for i, googlepubsub := range googlepubsubs { + fmt.Fprintf(out, "\tGoogle Cloud Pub/Sub %d/%d\n", i+1, len(googlepubsubs)) + fmt.Fprintf(out, "\t\tService ID: %s\n", googlepubsub.ServiceID) + fmt.Fprintf(out, "\t\tVersion: %d\n", googlepubsub.Version) + fmt.Fprintf(out, "\t\tName: %s\n", googlepubsub.Name) + fmt.Fprintf(out, "\t\tUser: %s\n", googlepubsub.User) + fmt.Fprintf(out, "\t\tSecret key: %s\n", googlepubsub.SecretKey) + fmt.Fprintf(out, "\t\tProject ID: %s\n", googlepubsub.ProjectID) + fmt.Fprintf(out, "\t\tTopic: %s\n", googlepubsub.Topic) + fmt.Fprintf(out, "\t\tFormat: %s\n", googlepubsub.Format) + fmt.Fprintf(out, "\t\tFormat version: %d\n", googlepubsub.FormatVersion) + fmt.Fprintf(out, "\t\tResponse condition: %s\n", googlepubsub.ResponseCondition) + fmt.Fprintf(out, "\t\tPlacement: %s\n", googlepubsub.Placement) + + } + fmt.Fprintln(out) + + return nil +} diff --git a/pkg/logging/googlepubsub/root.go b/pkg/logging/googlepubsub/root.go new file mode 100644 index 000000000..45a40986e --- /dev/null +++ b/pkg/logging/googlepubsub/root.go @@ -0,0 +1,28 @@ +package googlepubsub + +import ( + "io" + + "github.com/fastly/cli/pkg/common" + "github.com/fastly/cli/pkg/config" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + common.Base + // no flags +} + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent common.Registerer, globals *config.Data) *RootCommand { + var c RootCommand + c.Globals = globals + c.CmdClause = parent.Command("googlepubsub", "Manipulate Fastly service version Google Cloud Pub/Sub logging endpoints") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(in io.Reader, out io.Writer) error { + panic("unreachable") +} diff --git a/pkg/logging/googlepubsub/update.go b/pkg/logging/googlepubsub/update.go new file mode 100644 index 000000000..3dd720333 --- /dev/null +++ b/pkg/logging/googlepubsub/update.go @@ -0,0 +1,144 @@ +package googlepubsub + +import ( + "io" + + "github.com/fastly/cli/pkg/common" + "github.com/fastly/cli/pkg/compute/manifest" + "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/fastly" +) + +// UpdateCommand calls the Fastly API to update Google Cloud Pub/Sub logging endpoints. +type UpdateCommand struct { + common.Base + manifest manifest.Data + + // required + EndpointName string // Can't shaddow common.Base method Name(). + Version int + + // optional + NewName common.OptionalString + User common.OptionalString + SecretKey common.OptionalString + ProjectID common.OptionalString + Topic common.OptionalString + Format common.OptionalString + FormatVersion common.OptionalUint + Placement common.OptionalString + ResponseCondition common.OptionalString +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent common.Registerer, globals *config.Data) *UpdateCommand { + var c UpdateCommand + c.Globals = globals + c.manifest.File.Read(manifest.Filename) + + c.CmdClause = parent.Command("update", "Update a Google Cloud Pub/Sub logging endpoint on a Fastly service version") + + c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID) + c.CmdClause.Flag("version", "Number of service version").Required().IntVar(&c.Version) + c.CmdClause.Flag("name", "The name of the Google Cloud Pub/Sub logging object").Short('n').Required().StringVar(&c.EndpointName) + + c.CmdClause.Flag("new-name", "New name of the Google Cloud Pub/Sub logging object").Action(c.NewName.Set).StringVar(&c.NewName.Value) + c.CmdClause.Flag("user", "Your Google Cloud Platform service account email address. The client_email field in your service account authentication JSON").Action(c.User.Set).StringVar(&c.User.Value) + c.CmdClause.Flag("secret-key", "Your Google Cloud Platform account secret key. The private_key field in your service account authentication JSON").Action(c.SecretKey.Set).StringVar(&c.SecretKey.Value) + c.CmdClause.Flag("topic", "The Google Cloud Pub/Sub topic to which logs will be published").Action(c.Topic.Set).StringVar(&c.Topic.Value) + c.CmdClause.Flag("project-id", "The ID of your Google Cloud Platform project").Action(c.ProjectID.Set).StringVar(&c.ProjectID.Value) + c.CmdClause.Flag("format", "Apache style log formatting").Action(c.Format.Set).StringVar(&c.Format.Value) + c.CmdClause.Flag("format-version", "The version of the custom logging format used for the configured endpoint. Can be either 2 (default) or 1").Action(c.FormatVersion.Set).UintVar(&c.FormatVersion.Value) + c.CmdClause.Flag("placement", "Where in the generated VCL the logging call should be placed, overriding any format_version default. Can be none or waf_debug. This field is not required and has no default value").Action(c.Placement.Set).StringVar(&c.Placement.Value) + c.CmdClause.Flag("response-condition", "The name of an existing condition in the configured endpoint, or leave blank to always execute").Action(c.ResponseCondition.Set).StringVar(&c.ResponseCondition.Value) + + return &c +} + +// createInput transforms values parsed from CLI flags into an object to be used by the API client library. +func (c *UpdateCommand) createInput() (*fastly.UpdatePubsubInput, error) { + serviceID, source := c.manifest.ServiceID() + if source == manifest.SourceUndefined { + return nil, errors.ErrNoServiceID + } + + googlepubsub, err := c.Globals.Client.GetPubsub(&fastly.GetPubsubInput{ + Service: serviceID, + Name: c.EndpointName, + Version: c.Version, + }) + if err != nil { + return nil, err + } + + input := fastly.UpdatePubsubInput{ + Service: googlepubsub.ServiceID, + Version: googlepubsub.Version, + Name: googlepubsub.Name, + NewName: fastly.String(googlepubsub.Name), + User: fastly.String(googlepubsub.User), + SecretKey: fastly.String(googlepubsub.SecretKey), + ProjectID: fastly.String(googlepubsub.ProjectID), + Topic: fastly.String(googlepubsub.Topic), + Format: fastly.String(googlepubsub.Format), + FormatVersion: fastly.Uint(googlepubsub.FormatVersion), + Placement: fastly.String(googlepubsub.Placement), + ResponseCondition: fastly.String(googlepubsub.ResponseCondition), + } + + if c.NewName.Valid { + input.NewName = fastly.String(c.NewName.Value) + } + + if c.User.Valid { + input.User = fastly.String(c.User.Value) + } + + if c.SecretKey.Valid { + input.SecretKey = fastly.String(c.SecretKey.Value) + } + + if c.Topic.Valid { + input.Topic = fastly.String(c.Topic.Value) + } + + if c.ProjectID.Valid { + input.ProjectID = fastly.String(c.ProjectID.Value) + } + + if c.Format.Valid { + input.Format = fastly.String(c.Format.Value) + } + + if c.FormatVersion.Valid { + input.FormatVersion = fastly.Uint(c.FormatVersion.Value) + } + + if c.ResponseCondition.Valid { + input.ResponseCondition = fastly.String(c.ResponseCondition.Value) + } + + if c.Placement.Valid { + input.Placement = fastly.String(c.Placement.Value) + } + + return &input, nil +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(in io.Reader, out io.Writer) error { + input, err := c.createInput() + if err != nil { + return err + } + + googlepubsub, err := c.Globals.Client.UpdatePubsub(input) + if err != nil { + return err + } + + text.Success(out, "Updated Google Cloud Pub/Sub logging endpoint %s (service %s version %d)", googlepubsub.Name, googlepubsub.ServiceID, googlepubsub.Version) + return nil +} diff --git a/pkg/mock/api.go b/pkg/mock/api.go index 6d14e203a..d521dd070 100644 --- a/pkg/mock/api.go +++ b/pkg/mock/api.go @@ -175,6 +175,12 @@ type API struct { UpdateKafkaFn func(*fastly.UpdateKafkaInput) (*fastly.Kafka, error) DeleteKafkaFn func(*fastly.DeleteKafkaInput) error + CreatePubsubFn func(*fastly.CreatePubsubInput) (*fastly.Pubsub, error) + ListPubsubsFn func(*fastly.ListPubsubsInput) ([]*fastly.Pubsub, error) + GetPubsubFn func(*fastly.GetPubsubInput) (*fastly.Pubsub, error) + UpdatePubsubFn func(*fastly.UpdatePubsubInput) (*fastly.Pubsub, error) + DeletePubsubFn func(*fastly.DeletePubsubInput) error + GetUserFn func(*fastly.GetUserInput) (*fastly.User, error) GetRegionsFn func() (*fastly.RegionsResponse, error) @@ -876,6 +882,31 @@ func (m API) DeleteKafka(i *fastly.DeleteKafkaInput) error { return m.DeleteKafkaFn(i) } +// CreatePubsub implements Interface. +func (m API) CreatePubsub(i *fastly.CreatePubsubInput) (*fastly.Pubsub, error) { + return m.CreatePubsubFn(i) +} + +// ListPubsubs implements Interface. +func (m API) ListPubsubs(i *fastly.ListPubsubsInput) ([]*fastly.Pubsub, error) { + return m.ListPubsubsFn(i) +} + +// GetPubsub implements Interface. +func (m API) GetPubsub(i *fastly.GetPubsubInput) (*fastly.Pubsub, error) { + return m.GetPubsubFn(i) +} + +// UpdatePubsub implements Interface. +func (m API) UpdatePubsub(i *fastly.UpdatePubsubInput) (*fastly.Pubsub, error) { + return m.UpdatePubsubFn(i) +} + +// DeletePubsub implements Interface. +func (m API) DeletePubsub(i *fastly.DeletePubsubInput) error { + return m.DeletePubsubFn(i) +} + // GetUser implements Interface. func (m API) GetUser(i *fastly.GetUserInput) (*fastly.User, error) { return m.GetUserFn(i)