Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service ID lookup to include fallback to environment variable #320

Merged
merged 2 commits into from Jun 28, 2021

Conversation

Integralist
Copy link
Collaborator

@Integralist Integralist commented Jun 23, 2021

Problem: a Service ID must be explicitly set on each CLI invocation using the --service-id flag which is tedious.
Solution: add an env var lookup between the flag and file lookup options.
Notes: to avoid having to duplicate the updated flag description (which is where I wanted to highlight to the user the lookup options) I've moved the flag to a separate function that each command calls.

Addresses: #301

@Integralist Integralist added the enhancement New feature or request label Jun 23, 2021
@Integralist Integralist requested review from a team and triblondon and removed request for a team June 23, 2021 16:13
Copy link
Collaborator Author

@Integralist Integralist left a comment

Choose a reason for hiding this comment

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

@triblondon hopefully this helps...

@@ -35,7 +35,7 @@ func NewCreateCommand(parent cmd.Registerer, globals *config.Data) *CreateComman
c.manifest.File.SetOutput(c.Globals.Output)
c.manifest.File.Read(manifest.Filename)
c.CmdClause = parent.Command("create", "Create a backend on a Fastly service version").Alias("add")
c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID)
c.RegisterServiceIDFlag(&c.manifest.Flag.ServiceID)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  1. Example of new register function.

@@ -16,6 +16,14 @@ import (
"github.com/fastly/kingpin"
)

// RegisterServiceIDFlag defines a --service-id flag that will attempt to
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  1. Implementation of new register function.

@@ -80,6 +84,10 @@ func (d *Data) ServiceID() (string, Source) {
return d.Flag.ServiceID, SourceFlag
}

if sid := os.Getenv(env.ServiceID); sid != "" {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  1. New env var lookup option.

@@ -159,3 +160,42 @@ func TestManifestPrepend(t *testing.T) {
t.Fatal(err)
}
}

func TestDataServiceID(t *testing.T) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  1. Tests for the lookup behaviour.

@@ -10,4 +10,7 @@ const (

// Endpoint is the env var we look in for the API endpoint.
Endpoint = "FASTLY_API_ENDPOINT"

// ServiceID is the env var we look in for the required Service ID.
ServiceID = "FASTLY_SERVICE_ID"
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  1. The new env var.

@Integralist Integralist merged commit 4e2dbff into main Jun 28, 2021
@Integralist Integralist deleted the integralist/service-id-env branch June 28, 2021 08:19
c.CmdClause.Flag("service-id", "Service ID").Short('s').Required().StringVar(&c.manifest.Flag.ServiceID)
c.RegisterServiceIDFlag(&c.manifest.Flag.ServiceID)
Copy link
Contributor

Choose a reason for hiding this comment

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

This represents a change in behavior — a previously Required flag is no longer required. It's not a... huge? problem, but it does have an IMO noticeable negative effect on user experience. If a command or subcommand requires a service ID, and I forget to provide one by any means, it's much better to get an error message from the CLI telling me I omitted a required parameter than from the API (or whatever) telling me my request was invalid.

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand that adding the fastly.toml option makes it tricky, but IMO validating required flags/params at the CLI layer is actually reasonably important...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it's much better to get an error message from the CLI telling me I omitted a required parameter than from the API (or whatever) telling me my request was invalid.

It's not the API telling you the Service ID is missing, but the CLI.

In each command's Exec function we call a function which subsequently triggers:

cli/pkg/cmd/cmd.go

Lines 125 to 128 in a869c58

serviceID, source := opts.Manifest.ServiceID()
if source == manifest.SourceUndefined {
return serviceID, serviceVersion, errors.ErrNoServiceID
}

The logic for the ServiceID function was updated as part of this PR to include an env var lookup:

// ServiceID yields a ServiceID.
func (d *Data) ServiceID() (string, Source) {
if d.Flag.ServiceID != "" {
return d.Flag.ServiceID, SourceFlag
}
if sid := os.Getenv(env.ServiceID); sid != "" {
return sid, SourceEnv
}
if d.File.ServiceID != "" {
return d.File.ServiceID, SourceFile
}
return "", SourceUndefined
}
.

The --service-id is not required in the sense that you aren't required to set the flag if you've got either the appropriate environment variable set, or you have a fastly.toml file.

The problem is that even when using something like Envar to enable a failover to an environment variable (if set by the user), the help output would (unless I'm mistaken) still indicate that the flag itself was required, and that's not strictly speaking true (the Service ID is what's required, but how you provide it is flexible).

This is made harder due to the additional need to fallback to the fastly.toml manifest file.

An alternative, would be to move the fallback logic from our CLI into our fork of Kingpin so that we implement something similar to Envar but which worked specifically for our use case. For example implementing a Fallback chained function like:

- c.CmdClause.Flag("service-id", "Service ID").Short('s').Envar(env.ServiceID).Required().StringVar(&c.Input.ServiceID)
+ c.CmdClause.Flag("service-id", "Service ID").Short('s').Fallback(...).Required().StringVar(&c.Input.ServiceID)

...where Fallback() excepted a slice of func types that could be executed in order. That way you still get the help output to show --service-id is required, and then you could omit the flag and have it failover to one of the alternatives. I still don't like the fact that it might confuse users who see the help output tell them the flag is required and so they don't question it and feel obliged to always provide the flag.

It would be nice to signify that a 'value' is required without coupling it to a flag. AFAIK this sort of thing would be communicated via man cli but as we're not generating a manual we have to rely on the Kingpin parser to indicate what data is required on a per command basis. So having it indicated via a flag is easier in that sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see I see, so the Required bit in the clause is specifically expressing the semantic of: the literal flag must be provided. That's no good. It would be better if we could catch that during some kind of validation phase, before we got into the command code itself, but IMO that's "nice to have" rather than "important". Thanks for the detailed explanation 👍

An alternative . . .

Sure! An additional alternative — based on my intuition and not verified to actually be viable — might be to leverage the Pre-whatever hooks of the CmdClause to do this and perhaps additional validation as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

might be to leverage the Pre-whatever hooks of the CmdClause to do this and perhaps additional validation as well.

ah ok, I'm still very green when it comes to Kingpin so there could well be something for me to explore there 👍🏻

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looks like from a brief investigation that none of the PreActions are able to execute before the Required() validation (once the command has a flag defined as required that validation completes first). So at this point I don't think I want to spend too much more time on this. Would be good to revisit but only when it's more of a priority.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, no, I agree you can't use Required. I was suggesting to drop all the Requireds (as you have done) and use the PreAction "stage" as a way to perform validation of flags, rather than in the command function itself. But again I haven't verified this will work and I don't think it's critical!! Just a suggestion for the great and unknowable future ⛵

Integralist added a commit that referenced this pull request Jun 28, 2021
* failover to env var

* move manifest read up a line
Integralist added a commit that referenced this pull request Jun 28, 2021
* failover to env var

* move manifest read up a line
Integralist added a commit that referenced this pull request Jun 28, 2021
* failover to env var

* move manifest read up a line
Integralist added a commit that referenced this pull request Jun 29, 2021
* Service ID lookup to include fallback to environment variable (#320)

* failover to env var

* move manifest read up a line

* fix snippet list

* add new test scenarios for snippet describe

* fix snippet update

* ignore vendor directory

* fix code to use go go-fastly 3.7.1

* update to latest go-fastly version 3.8.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants