diff --git a/CHANGELOG.md b/CHANGELOG.md index ae7ccaaa8..11165a4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ### Bug Fixes: +- fix(compute/deploy): remove compute trial activation code because trials no longer exist ([#1730](https://github.com/fastly/cli/pull/1730)) + ### Enhancements: ### Dependencies: diff --git a/pkg/api/undocumented/undocumented.go b/pkg/api/undocumented/undocumented.go index d1ed616d1..123ceb4ee 100644 --- a/pkg/api/undocumented/undocumented.go +++ b/pkg/api/undocumented/undocumented.go @@ -16,9 +16,6 @@ import ( "github.com/fastly/cli/pkg/useragent" ) -// EdgeComputeTrial is the API endpoint for activating a compute trial. -const EdgeComputeTrial = "/customer/%s/edge-compute-trial" - // RequestTimeout is the timeout for the API network request. const RequestTimeout = 5 * time.Second diff --git a/pkg/commands/compute/deploy.go b/pkg/commands/compute/deploy.go index e7126854e..102333330 100644 --- a/pkg/commands/compute/deploy.go +++ b/pkg/commands/compute/deploy.go @@ -10,7 +10,6 @@ import ( "os" "os/signal" "path/filepath" - "strconv" "strings" "syscall" "time" @@ -21,7 +20,6 @@ import ( "github.com/fastly/go-fastly/v14/fastly" "github.com/fastly/cli/pkg/api" - "github.com/fastly/cli/pkg/api/undocumented" "github.com/fastly/cli/pkg/argparser" "github.com/fastly/cli/pkg/commands/compute/setup" "github.com/fastly/cli/pkg/debug" @@ -36,7 +34,6 @@ import ( const ( manageServiceBaseURL = "https://manage.fastly.com/configure/services/" - trialNotActivated = "Valid values for 'type' are: 'vcl'" ) // ErrPackageUnchanged is an error that indicates the package hasn't changed. @@ -178,7 +175,7 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) { } text.Break(out) - fnActivateTrial, serviceID, err := c.Setup(out) + serviceID, err := c.Setup(out) if err != nil { return err } @@ -205,7 +202,7 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) { var serviceVersion *fastly.Version if noExistingService { - serviceID, serviceVersion, err = c.NewService(manifestFilename, fnActivateTrial, spinner, in, out) + serviceID, serviceVersion, err = c.NewService(manifestFilename, spinner, in, out) if err != nil { return err } @@ -368,13 +365,10 @@ func validStatusCodeRange(status int) bool { // - Check if there is an API token missing. // - Acquire the Service ID/Version. // - Validate there is a package to deploy. -// - Determine if a trial needs to be activated on the user's account. -func (c *DeployCommand) Setup(out io.Writer) (fnActivateTrial Activator, serviceID string, err error) { - defaultActivator := func(_ string) error { return nil } - - token, s := c.Globals.Token() +func (c *DeployCommand) Setup(out io.Writer) (serviceID string, err error) { + _, s := c.Globals.Token() if s == lookup.SourceUndefined { - return defaultActivator, "", fsterr.ErrNoToken() + return "", fsterr.ErrNoToken() } // IMPORTANT: We don't handle the error when looking up the Service ID. @@ -387,7 +381,7 @@ func (c *DeployCommand) Setup(out io.Writer) (fnActivateTrial Activator, service if c.PackagePath == "" { projectName, source := c.Globals.Manifest.Name() if source == manifest.SourceUndefined { - return defaultActivator, serviceID, fsterr.ErrReadingManifest + return serviceID, fsterr.ErrReadingManifest } c.PackagePath = filepath.Join("pkg", fmt.Sprintf("%s.tar.gz", sanitize.BaseName(projectName))) } @@ -397,13 +391,10 @@ func (c *DeployCommand) Setup(out io.Writer) (fnActivateTrial Activator, service c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Package path": c.PackagePath, }) - return defaultActivator, serviceID, err + return serviceID, err } - endpoint, _ := c.Globals.APIEndpoint() - fnActivateTrial = preconfigureActivateTrial(endpoint, token, c.Globals.HTTPClient, c.Globals.Env.DebugMode) - - return fnActivateTrial, serviceID, err + return serviceID, err } // validatePackage checks the package and returns its path, which can change @@ -505,44 +496,8 @@ func packageSize(path string) (size int64, err error) { return fi.Size(), nil } -// Activator represents a function that calls an undocumented API endpoint for -// activating a Compute free trial on the given customer account. -// -// It is preconfigured with the Fastly API endpoint, a user token and a simple -// HTTP Client. -// -// This design allows us to pass an Activator rather than passing multiple -// unrelated arguments through several nested functions. -type Activator func(customerID string) error - -// preconfigureActivateTrial activates a free trial on the customer account. -func preconfigureActivateTrial(endpoint, token string, httpClient api.HTTPClient, debugMode string) Activator { - debug, _ := strconv.ParseBool(debugMode) - return func(customerID string) error { - _, err := undocumented.Call(undocumented.CallOptions{ - APIEndpoint: endpoint, - HTTPClient: httpClient, - Method: http.MethodPost, - Path: fmt.Sprintf(undocumented.EdgeComputeTrial, customerID), - Token: token, - Debug: debug, - }) - if err != nil { - apiErr, ok := err.(undocumented.APIError) - if !ok { - return err - } - // 409 Conflict == The Compute trial has already been created. - if apiErr.StatusCode != http.StatusConflict { - return fmt.Errorf("%w: %d %s", err, apiErr.StatusCode, http.StatusText(apiErr.StatusCode)) - } - } - return nil - } -} - // NewService handles creating a new service when no Service ID is found. -func (c *DeployCommand) NewService(manifestFilename string, fnActivateTrial Activator, spinner text.Spinner, in io.Reader, out io.Writer) (string, *fastly.Version, error) { +func (c *DeployCommand) NewService(manifestFilename string, spinner text.Spinner, in io.Reader, out io.Writer) (string, *fastly.Version, error) { var ( err error serviceID string @@ -589,7 +544,7 @@ func (c *DeployCommand) NewService(manifestFilename string, fnActivateTrial Acti // There is no service and so we'll do a one time creation of the service // // NOTE: we're shadowing the `serviceID` and `serviceVersion` variables. - serviceID, serviceVersion, err = createService(c.Globals, serviceName, fnActivateTrial, spinner, out) + serviceID, serviceVersion, err = createService(c.Globals, serviceName, spinner, out) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Service name": serviceName, @@ -619,13 +574,9 @@ func (c *DeployCommand) NewService(manifestFilename string, fnActivateTrial Acti } // createService creates a service to associate with the compute package. -// -// NOTE: If the creation of the service fails because the user has not -// activated a free trial, then we'll trigger the trial for their account. func createService( g *global.Data, serviceName string, - fnActivateTrial Activator, spinner text.Spinner, out io.Writer, ) (serviceID string, serviceVersion *fastly.Version, err error) { @@ -649,50 +600,6 @@ func createService( Type: fastly.ToPointer("wasm"), }) if err != nil { - if strings.Contains(err.Error(), trialNotActivated) { - user, err := apiClient.GetCurrentUser(context.TODO()) - if err != nil { - err = fmt.Errorf("unable to identify user associated with the given token: %w", err) - spinner.StopFailMessage(msg) - spinErr := spinner.StopFail() - if spinErr != nil { - return "", nil, fmt.Errorf(text.SpinnerErrWrapper, spinErr, err) - } - return serviceID, serviceVersion, fsterr.RemediationError{ - Inner: err, - Remediation: "To ensure you have access to the Compute platform we need your Customer ID. " + fsterr.AuthRemediation(), - } - } - - customerID := fastly.ToValue(user.CustomerID) - err = fnActivateTrial(customerID) - if err != nil { - err = fmt.Errorf("error creating service: you do not have the Compute free trial enabled on your Fastly account") - spinner.StopFailMessage(msg) - spinErr := spinner.StopFail() - if spinErr != nil { - return "", nil, fmt.Errorf(text.SpinnerErrWrapper, spinErr, err) - } - return serviceID, serviceVersion, fsterr.RemediationError{ - Inner: err, - Remediation: fsterr.ComputeTrialRemediation, - } - } - - errLog.AddWithContext(err, map[string]any{ - "Service Name": serviceName, - "Customer ID": customerID, - }) - - spinner.StopFailMessage(msg) - err = spinner.StopFail() - if err != nil { - return "", nil, err - } - - return createService(g, serviceName, fnActivateTrial, spinner, out) - } - spinner.StopFailMessage(msg) spinErr := spinner.StopFail() if spinErr != nil { @@ -1253,7 +1160,7 @@ func (c *DeployCommand) ExistingServiceVersion(serviceID string, out io.Writer) }) return serviceVersion, fsterr.RemediationError{ Inner: fmt.Errorf("invalid service type: %s", serviceType), - Remediation: "Ensure the provided Service ID is associated with a 'Wasm' Fastly Service and not a 'VCL' Fastly service. " + fsterr.ComputeTrialRemediation, + Remediation: "Ensure the provided Service ID is associated with a 'Wasm' Fastly Service and not a 'VCL' Fastly service.", } } diff --git a/pkg/commands/compute/deploy_test.go b/pkg/commands/compute/deploy_test.go index e6c7c911b..e4884b450 100644 --- a/pkg/commands/compute/deploy_test.go +++ b/pkg/commands/compute/deploy_test.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "net/http" - "net/url" "os" "path/filepath" "strings" @@ -90,14 +89,9 @@ func TestDeploy(t *testing.T) { originalPackageSizeLimit := compute.MaxPackageSize args := testutil.SplitArgs scenarios := []struct { - api mock.API - args []string - dontWantOutput []string - // There are two times the HTTPClient is used. - // The first is if we need to activate a free trial. - // The second is when we ping for service availability. - // In this test case the free trial activation isn't used. - // So we only define a single HTTP client call for service availability. + api mock.API + args []string + dontWantOutput []string httpClientRes []*http.Response httpClientErr []error manifest string @@ -270,85 +264,6 @@ func TestDeploy(t *testing.T) { }, wantError: fmt.Sprintf("error creating service: %s", testutil.Err.Error()), }, - // The following test mocks the service creation to fail with a specific - // error value that will result in the code trying to activate a free trial - // for the customer's account. - // - // Specifically this test will fail the initial API call to get the - // customer's details and so we expect it to return that error (as we can't - // activate a free trial without knowing the customer ID). - { - name: "service create error due to no trial activated and error getting user", - args: args("compute deploy --token 123"), - api: mock.API{ - CreateServiceFn: createServiceErrorNoTrial, - DeleteServiceFn: deleteServiceOK, - GetCurrentUserFn: getCurrentUserError, - }, - stdin: []string{ - "Y", // when prompted to create a new service - }, - wantError: fmt.Sprintf("unable to identify user associated with the given token: %s", testutil.Err.Error()), - wantOutput: []string{ - "Creating service", - }, - }, - // The following test mocks the HTTP client to return a 400 Bad Request, - // which is then coerced into a generic 'no free trial' error. - { - name: "service create error due to no trial activated and error activating trial", - args: args("compute deploy --token 123"), - api: mock.API{ - CreateServiceFn: createServiceErrorNoTrial, - DeleteServiceFn: deleteServiceOK, - GetCurrentUserFn: getCurrentUser, - }, - httpClientRes: []*http.Response{ - { - Body: io.NopCloser(strings.NewReader(testutil.Err.Error())), - Status: http.StatusText(http.StatusBadRequest), - StatusCode: http.StatusBadRequest, - }, - }, - httpClientErr: []error{ - nil, - }, - stdin: []string{ - "Y", // when prompted to create a new service - }, - wantError: "error creating service: you do not have the Compute free trial enabled on your Fastly account", - wantRemediationError: errors.ComputeTrialRemediation, - wantOutput: []string{ - "Creating service", - }, - }, - // The following test mocks the HTTP client to return a timeout error, - // which is then coerced into a generic 'no free trial' error. - { - name: "service create error due to no trial activated and activating trial timeout", - args: args("compute deploy --token 123"), - api: mock.API{ - CreateServiceFn: createServiceErrorNoTrial, - DeleteServiceFn: deleteServiceOK, - GetCurrentUserFn: getCurrentUser, - }, - httpClientRes: []*http.Response{ - nil, - }, - httpClientErr: []error{ - &url.Error{Err: context.DeadlineExceeded}, - }, - stdin: []string{ - "Y", // when prompted to create a new service - }, - wantError: "error creating service: you do not have the Compute free trial enabled on your Fastly account", - wantRemediationError: errors.ComputeTrialRemediation, - wantOutput: []string{ - "Creating service", - }, - }, - // The following test mocks the HTTP client to return successfully when - // trying to activate the free trial. { name: "service create success", args: args("compute deploy --token 123"), @@ -2354,22 +2269,6 @@ func createServiceError(_ context.Context, _ *fastly.CreateServiceInput) (*fastl return nil, testutil.Err } -// NOTE: We don't return testutil.Err but a very specific error message so that -// the Deploy logic will drop into a nested logic block. -func createServiceErrorNoTrial(_ context.Context, _ *fastly.CreateServiceInput) (*fastly.Service, error) { - return nil, fmt.Errorf("Valid values for 'type' are: 'vcl'") -} - -func getCurrentUser(_ context.Context) (*fastly.User, error) { - return &fastly.User{ - CustomerID: fastly.ToPointer("abc"), - }, nil -} - -func getCurrentUserError(_ context.Context) (*fastly.User, error) { - return nil, testutil.Err -} - func deleteServiceOK(_ context.Context, _ *fastly.DeleteServiceInput) error { return nil } diff --git a/pkg/errors/remediation_error.go b/pkg/errors/remediation_error.go index 0741c47b0..8140aac90 100644 --- a/pkg/errors/remediation_error.go +++ b/pkg/errors/remediation_error.go @@ -184,10 +184,6 @@ var ComputeBuildRemediation = strings.Join([]string{ "See more at https://www.fastly.com/documentation/reference/compute/fastly-toml", }, " ") -// ComputeTrialRemediation suggests contacting customer manager to enable the -// free trial feature flag. -var ComputeTrialRemediation = "For more help with this error see fastly.help/cli/ecp-feature" - // ProfileRemediation suggests running auth commands. func ProfileRemediation() string { if env.AuthCommandDisabled() {