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

[Feature Request] Functionality to Retrieve All Enumeration Values #3441

Closed
bflad opened this issue Jul 25, 2020 · 1 comment · Fixed by #3447 or #3479
Closed

[Feature Request] Functionality to Retrieve All Enumeration Values #3441

bflad opened this issue Jul 25, 2020 · 1 comment · Fixed by #3447 or #3479
Labels
feature-request A feature should be added or improved.

Comments

@bflad
Copy link
Contributor

bflad commented Jul 25, 2020

Is your feature request related to a problem? Please describe.

(The below uses CodeBuild as an example, but this applies to all AWS Go SDK service packages and type string enumerations 👍 )

AWS service teams can and often do provide enumerations of available values for API parameters. For example, given these API References:

These are equivalent (and presumably generated in the API Reference documentation) from these in the API model:

The AWS Go SDK generators currently translate these enumeration values into Go constants:

  • const (
    // EnvironmentTypeWindowsContainer is a EnvironmentType enum value
    EnvironmentTypeWindowsContainer = "WINDOWS_CONTAINER"
    // EnvironmentTypeLinuxContainer is a EnvironmentType enum value
    EnvironmentTypeLinuxContainer = "LINUX_CONTAINER"
    // EnvironmentTypeLinuxGpuContainer is a EnvironmentType enum value
    EnvironmentTypeLinuxGpuContainer = "LINUX_GPU_CONTAINER"
    // EnvironmentTypeArmContainer is a EnvironmentType enum value
    EnvironmentTypeArmContainer = "ARM_CONTAINER"
    // EnvironmentTypeWindowsServer2019Container is a EnvironmentType enum value
    EnvironmentTypeWindowsServer2019Container = "WINDOWS_SERVER_2019_CONTAINER"
    )
  • const (
    // EnvironmentVariableTypePlaintext is a EnvironmentVariableType enum value
    EnvironmentVariableTypePlaintext = "PLAINTEXT"
    // EnvironmentVariableTypeParameterStore is a EnvironmentVariableType enum value
    EnvironmentVariableTypeParameterStore = "PARAMETER_STORE"
    // EnvironmentVariableTypeSecretsManager is a EnvironmentVariableType enum value
    EnvironmentVariableTypeSecretsManager = "SECRETS_MANAGER"
    )

Downstream in Terraform and the Terraform AWS Provider, one feature we provide is the ability to invalidate an infrastructure configuration upfront (during plan time in Terraform terminology), should an argument value not be in a predetermined slice of strings (amongst many other validation features). For example:

Here is the above validation in the Terraform AWS Provider codebase:

These upfront validations are valuable to operators over finding configuration errors when making the API requests, potentially very far into creating their infrastructure or otherwise causing unexpected changes/downtime. Given the consequences, we have found over time that many operators have come to expect us to support this upfront validation at the expense of maintaining them with a slight delay as AWS service APIs support additional values.

This is super fuzzy metric (not representing reuse, etc.), but we have 483 of these string enumeration validators across our codebase today and many more places we don't support this validation where we could.

Describe the solution you'd like

We would like to reduce the manual work associated with including all known enumeration values at the time of the AWS Go SDK release in our codebase. It would be great if the AWS Go SDK service generators could output some form of retrieving all enumeration values for a given API model type.

A very naive approach could be generating a variable slice in addition to the constants, e.g.

const (
	// EnvironmentTypeWindowsContainer is a EnvironmentType enum value
	EnvironmentTypeWindowsContainer = "WINDOWS_CONTAINER"

	// EnvironmentTypeLinuxContainer is a EnvironmentType enum value
	EnvironmentTypeLinuxContainer = "LINUX_CONTAINER"

	// EnvironmentTypeLinuxGpuContainer is a EnvironmentType enum value
	EnvironmentTypeLinuxGpuContainer = "LINUX_GPU_CONTAINER"

	// EnvironmentTypeArmContainer is a EnvironmentType enum value
	EnvironmentTypeArmContainer = "ARM_CONTAINER"

	// EnvironmentTypeWindowsServer2019Container is a EnvironmentType enum value
	EnvironmentTypeWindowsServer2019Container = "WINDOWS_SERVER_2019_CONTAINER"
)

var EnvironmentTypeEnum = []string{
	EnvironmentTypeWindowsContainer,
	EnvironmentTypeLinuxContainer,
	EnvironmentTypeArmContainer,
	EnvironmentTypeWindowsServer2019Container,
}

const (
	// EnvironmentVariableTypePlaintext is a EnvironmentVariableType enum value
	EnvironmentVariableTypePlaintext = "PLAINTEXT"

	// EnvironmentVariableTypeParameterStore is a EnvironmentVariableType enum value
	EnvironmentVariableTypeParameterStore = "PARAMETER_STORE"

	// EnvironmentVariableTypeSecretsManager is a EnvironmentVariableType enum value
	EnvironmentVariableTypeSecretsManager = "SECRETS_MANAGER"
)

var EnvironmentVariableTypeEnum = []string{
	EnvironmentVariableTypePlaintext,
	EnvironmentVariableTypeParameterStore,
	EnvironmentVariableTypeSecretsManager,
}

Where downstream consumers such as our example above could be:

ValidateFunc: validation.StringInSlice(codebuild.EnvironmentVariableTypeEnum, false),

Otherwise, providing a new Go type for the enumeration with a receiver method for fetching the values, also could be an option:

const (
	// EnvironmentTypeWindowsContainer is a EnvironmentType enum value
	EnvironmentTypeWindowsContainer = "WINDOWS_CONTAINER"

	// EnvironmentTypeLinuxContainer is a EnvironmentType enum value
	EnvironmentTypeLinuxContainer = "LINUX_CONTAINER"

	// EnvironmentTypeLinuxGpuContainer is a EnvironmentType enum value
	EnvironmentTypeLinuxGpuContainer = "LINUX_GPU_CONTAINER"

	// EnvironmentTypeArmContainer is a EnvironmentType enum value
	EnvironmentTypeArmContainer = "ARM_CONTAINER"

	// EnvironmentTypeWindowsServer2019Container is a EnvironmentType enum value
	EnvironmentTypeWindowsServer2019Container = "WINDOWS_SERVER_2019_CONTAINER"
)

type EnvironmentType struct{}

func (EnvironmentType) Values() []string {
	return []string{
		EnvironmentTypeWindowsContainer,
		EnvironmentTypeLinuxContainer,
		EnvironmentTypeArmContainer,
		EnvironmentTypeWindowsServer2019Container,
	}
}

const (
	// EnvironmentVariableTypePlaintext is a EnvironmentVariableType enum value
	EnvironmentVariableTypePlaintext = "PLAINTEXT"

	// EnvironmentVariableTypeParameterStore is a EnvironmentVariableType enum value
	EnvironmentVariableTypeParameterStore = "PARAMETER_STORE"

	// EnvironmentVariableTypeSecretsManager is a EnvironmentVariableType enum value
	EnvironmentVariableTypeSecretsManager = "SECRETS_MANAGER"
)

type EnvironmentVariableType struct{}

func (EnvironmentVariableType) Values() []string {
	return []string{
		EnvironmentVariableTypePlaintext,
		EnvironmentVariableTypeParameterStore,
		EnvironmentVariableTypeSecretsManager,
	}
}

Where downstream consumers such as our example above could be:

ValidateFunc: validation.StringInSlice(codebuild.EnvironmentVariableType{}.Values(), false),

Describe alternatives you've considered

  • Creating our own generator that creates these enumeration helpers from the API models directly
  • Creating our own generator that attempts to reconstitute these enumerations from the constants
  • Manually managing these lists

Additional context

Thank you for the consideration!

@bflad bflad added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. labels Jul 25, 2020
bflad added a commit to bflad/aws-sdk-go that referenced this issue Jul 25, 2020
Reference: aws#3441

Allows consumers to easily handle operations with all elements of API enumeration types.
@jasdel
Copy link
Contributor

jasdel commented Jul 27, 2020

Thanks for creating this this feature request @bflad. Adding the ability to get a slice of enums makes sense. I think this is something we can add to the code generation for enum types. Ideally we can port this idea to the v2 SDK tool.

Var - Exposing the slice directly as a package variable is a straight forward approach, but what impact that would have on the resident member, or binary since of the compile application to put all SDKs into memory. I'm not actually tested that, but is a hunch.

Type - Creating a new type with method is probably a good way to expose these as well. This is what the v2 SDK is doing with string aliases. Using structs is alternative to string aliases. Having a Values() []string method on the type returning a slice would accomplish the goal. Using type alias or struct most likely has the least likely hood of name clashing with other generated identifier since the modeled enum shape has a unique name within the API. Either of these may instill some confusion in their usage since the type it self is not usable anywhere.

type Foo string
// or
type Foo struct{}

func (Foo) Values() []string {
     return []string{
          FooBar,
          FooBaz,
      }
}

const (
     FooBar = "Bar" // Not actually of type `Foo`
     FooBaz = "Baz"
)

Usage:

values := Foo("").Values() // Wish Go allowed scalar type zero value initialization with `{}` 
values := Foo{}.Values()

Func - The final alternative I can think of is a standalone function that returns the slice of enum values. While simpler than the type alias or struct, a function name most likely will have a higher risk of clashing with some other generated identifier since a new unique name would need to be generated that is beyond the modeled names. Potential workaround for the name collisions would probably be some non-idiomatic naming scheme, e.g. Foo_Values().

func FooValues() []string {
      return []string{
          FooBar,
          FooBaz,
      }
}

Usage:

values := FooValues()

As much as the func approach would be nice, I think the risk of name collision will be prohibitive without some unique naming scheme for the function. The V2 SDK will address this feature via methods, since its already using a type alias.

bflad added a commit to bflad/aws-sdk-go that referenced this issue Jul 29, 2020
@diehlaws diehlaws removed the needs-triage This issue or PR still needs to be triaged. label Aug 3, 2020
bflad added a commit to bflad/aws-sdk-go that referenced this issue Aug 7, 2020
bflad added a commit to bflad/aws-sdk-go that referenced this issue Aug 7, 2020
bflad added a commit to bflad/aws-sdk-go that referenced this issue Aug 7, 2020
jasdel pushed a commit to bflad/aws-sdk-go that referenced this issue Aug 10, 2020
jasdel pushed a commit to bflad/aws-sdk-go that referenced this issue Aug 10, 2020
jasdel pushed a commit to bflad/aws-sdk-go that referenced this issue Aug 11, 2020
jasdel pushed a commit that referenced this issue Aug 11, 2020
…es (#3447)

Fixes #3441 by adding a new XXX_Values function for each API enum type that returns a slice of enum values, e.g `DomainStatus_Values`.
aws-sdk-go-automation pushed a commit that referenced this issue Aug 12, 2020
===

### Service Client Updates
* `service/cloud9`: Updates service API and documentation
  * Add ConnectionType input parameter to CreateEnvironmentEC2 endpoint. New parameter enables creation of environments with SSM connection.
* `service/comprehend`: Updates service documentation
* `service/ec2`: Updates service API and documentation
  * Introduces support for IPv6-in-IPv4 IPsec tunnels. A user can now send traffic from their on-premise IPv6 network to AWS VPCs that have IPv6 support enabled.
* `service/fsx`: Updates service API and documentation
* `service/iot`: Updates service API, documentation, and paginators
  * Audit finding suppressions: Device Defender enables customers to turn off non-compliant findings for specific resources on a per check basis.
* `service/lambda`: Updates service API and examples
  * Support for creating Lambda Functions using 'java8.al2' and 'provided.al2'
* `service/transfer`: Updates service API, documentation, and paginators
  * Adds security policies to control cryptographic algorithms advertised by your server, additional characters in usernames and length increase, and FIPS compliant endpoints in the US and Canada regions.
* `service/workspaces`: Updates service API and documentation
  * Adds optional EnableWorkDocs property to WorkspaceCreationProperties in the ModifyWorkspaceCreationProperties API

### SDK Enhancements
* `codegen`: Add XXX_Values functions for getting slice of API enums by type.
  * Fixes [#3441](#3441) by adding a new XXX_Values function for each API enum type that returns a slice of enum values, e.g `DomainStatus_Values`.
* `aws/request`: Update default retry to retry "use of closed network connection" errors ([#3476](#3476))
  * Fixes [#3406](#3406)

### SDK Bugs
* `private/protocol/json/jsonutil`: Fixes a bug that truncated millisecond precision time in API response to seconds. ([#3474](#3474))
  * Fixes [#3464](#3464)
  * Fixes [#3410](#3410)
* `codegen`: Export event stream constructor for easier mocking ([#3473](#3473))
  * Fixes [#3412](#3412) by exporting the operation's EventStream type's constructor function so it can be used to fully initialize fully when mocking out behavior for API operations with event streams.
* `service/ec2`: Fix max retries with client customizations ([#3465](#3465))
  * Fixes [#3374](#3374) by correcting the EC2 API client's customization for ModifyNetworkInterfaceAttribute and AssignPrivateIpAddresses operations to use the aws.Config.MaxRetries value if set. Previously the API client's customizations would ignore MaxRetries specified in the SDK's aws.Config.MaxRetries field.
aws-sdk-go-automation added a commit that referenced this issue Aug 12, 2020
Release v1.34.3 (2020-08-12)
===

### Service Client Updates
* `service/cloud9`: Updates service API and documentation
  * Add ConnectionType input parameter to CreateEnvironmentEC2 endpoint. New parameter enables creation of environments with SSM connection.
* `service/comprehend`: Updates service documentation
* `service/ec2`: Updates service API and documentation
  * Introduces support for IPv6-in-IPv4 IPsec tunnels. A user can now send traffic from their on-premise IPv6 network to AWS VPCs that have IPv6 support enabled.
* `service/fsx`: Updates service API and documentation
* `service/iot`: Updates service API, documentation, and paginators
  * Audit finding suppressions: Device Defender enables customers to turn off non-compliant findings for specific resources on a per check basis.
* `service/lambda`: Updates service API and examples
  * Support for creating Lambda Functions using 'java8.al2' and 'provided.al2'
* `service/transfer`: Updates service API, documentation, and paginators
  * Adds security policies to control cryptographic algorithms advertised by your server, additional characters in usernames and length increase, and FIPS compliant endpoints in the US and Canada regions.
* `service/workspaces`: Updates service API and documentation
  * Adds optional EnableWorkDocs property to WorkspaceCreationProperties in the ModifyWorkspaceCreationProperties API

### SDK Enhancements
* `codegen`: Add XXX_Values functions for getting slice of API enums by type.
  * Fixes [#3441](#3441) by adding a new XXX_Values function for each API enum type that returns a slice of enum values, e.g `DomainStatus_Values`.
* `aws/request`: Update default retry to retry "use of closed network connection" errors ([#3476](#3476))
  * Fixes [#3406](#3406)

### SDK Bugs
* `private/protocol/json/jsonutil`: Fixes a bug that truncated millisecond precision time in API response to seconds. ([#3474](#3474))
  * Fixes [#3464](#3464)
  * Fixes [#3410](#3410)
* `codegen`: Export event stream constructor for easier mocking ([#3473](#3473))
  * Fixes [#3412](#3412) by exporting the operation's EventStream type's constructor function so it can be used to fully initialize fully when mocking out behavior for API operations with event streams.
* `service/ec2`: Fix max retries with client customizations ([#3465](#3465))
  * Fixes [#3374](#3374) by correcting the EC2 API client's customization for ModifyNetworkInterfaceAttribute and AssignPrivateIpAddresses operations to use the aws.Config.MaxRetries value if set. Previously the API client's customizations would ignore MaxRetries specified in the SDK's aws.Config.MaxRetries field.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A feature should be added or improved.
Projects
None yet
3 participants