diff --git a/cmd/ack-generate/command/apis.go b/cmd/ack-generate/command/apis.go index a9fef321..2a88ebf3 100644 --- a/cmd/ack-generate/command/apis.go +++ b/cmd/ack-generate/command/apis.go @@ -37,9 +37,8 @@ const ( ) var ( - optGenVersion string - optAPIsInputPath string - apisVersionPath string + optGenVersion string + apisVersionPath string ) // apiCmd is the command that generates service API types @@ -97,10 +96,13 @@ func generateAPIs(cmd *cobra.Command, args []string) error { if err := ensureSDKRepo(ctx, optCacheDir, optRefreshCache); err != nil { return err } + if optModelName == "" { + optModelName = svcAlias + } sdkHelper := ackmodel.NewSDKHelper(sdkDir) - sdkAPI, err := sdkHelper.API(svcAlias) + sdkAPI, err := sdkHelper.API(optModelName) if err != nil { - newSvcAlias, err := FallBackFindServiceID(sdkDir, svcAlias) + newSvcAlias, err := FallBackFindServiceID(sdkDir, optModelName) if err != nil { return err } @@ -110,7 +112,7 @@ func generateAPIs(cmd *cobra.Command, args []string) error { } } model, err := ackmodel.New( - sdkAPI, optGenVersion, optGeneratorConfigPath, ackgenerate.DefaultConfig, + sdkAPI, svcAlias, optGenVersion, optGeneratorConfigPath, ackgenerate.DefaultConfig, ) if err != nil { return err diff --git a/cmd/ack-generate/command/controller.go b/cmd/ack-generate/command/controller.go index c9058bf8..394935a1 100644 --- a/cmd/ack-generate/command/controller.go +++ b/cmd/ack-generate/command/controller.go @@ -62,10 +62,13 @@ func generateController(cmd *cobra.Command, args []string) error { if err := ensureSDKRepo(ctx, optCacheDir, optRefreshCache); err != nil { return err } + if optModelName == "" { + optModelName = svcAlias + } sdkHelper := ackmodel.NewSDKHelper(sdkDir) - sdkAPI, err := sdkHelper.API(svcAlias) + sdkAPI, err := sdkHelper.API(optModelName) if err != nil { - newSvcAlias, err := FallBackFindServiceID(sdkDir, svcAlias) + newSvcAlias, err := FallBackFindServiceID(sdkDir, optModelName) if err != nil { return err } @@ -79,7 +82,7 @@ func generateController(cmd *cobra.Command, args []string) error { return err } m, err := ackmodel.New( - sdkAPI, latestAPIVersion, optGeneratorConfigPath, ackgenerate.DefaultConfig, + sdkAPI, svcAlias, latestAPIVersion, optGeneratorConfigPath, ackgenerate.DefaultConfig, ) if err != nil { return err diff --git a/cmd/ack-generate/command/crossplane.go b/cmd/ack-generate/command/crossplane.go index 7b8d3b0d..106d3745 100644 --- a/cmd/ack-generate/command/crossplane.go +++ b/cmd/ack-generate/command/crossplane.go @@ -26,7 +26,6 @@ import ( "github.com/spf13/cobra" cpgenerate "github.com/aws-controllers-k8s/code-generator/pkg/generate/crossplane" - "github.com/aws-controllers-k8s/code-generator/pkg/model" ackmodel "github.com/aws-controllers-k8s/code-generator/pkg/model" ) @@ -56,17 +55,20 @@ func generateCrossplane(_ *cobra.Command, args []string) error { return err } svcAlias := strings.ToLower(args[0]) - sdkHelper := model.NewSDKHelper(sdkDir) + if optModelName == "" { + optModelName = svcAlias + } + sdkHelper := ackmodel.NewSDKHelper(sdkDir) sdkHelper.APIGroupSuffix = "aws.crossplane.io" - sdkAPI, err := sdkHelper.API(svcAlias) + sdkAPI, err := sdkHelper.API(optModelName) if err != nil { - newSvcAlias, err := FallBackFindServiceID(sdkDir, svcAlias) + newSvcAlias, err := FallBackFindServiceID(sdkDir, optModelName) if err != nil { return err } sdkAPI, err = sdkHelper.API(newSvcAlias) // retry with serviceID if err != nil { - return fmt.Errorf("cannot get the API model for service %s", svcAlias) + return fmt.Errorf("service %s not found", svcAlias) } } cfgPath := filepath.Join(providerDir, "apis", svcAlias, optGenVersion, "generator-config.yaml") @@ -78,7 +80,7 @@ func generateCrossplane(_ *cobra.Command, args []string) error { cfgPath = "" } m, err := ackmodel.New( - sdkAPI, optGenVersion, cfgPath, cpgenerate.DefaultConfig, + sdkAPI, svcAlias, optGenVersion, cfgPath, cpgenerate.DefaultConfig, ) if err != nil { return err diff --git a/cmd/ack-generate/command/olm.go b/cmd/ack-generate/command/olm.go index 3d5420a2..673e3110 100644 --- a/cmd/ack-generate/command/olm.go +++ b/cmd/ack-generate/command/olm.go @@ -86,10 +86,13 @@ func generateOLMAssets(cmd *cobra.Command, args []string) error { if err := ensureSDKRepo(ctx, optCacheDir, optRefreshCache); err != nil { return err } + if optModelName == "" { + optModelName = svcAlias + } sdkHelper := ackmodel.NewSDKHelper(sdkDir) - sdkAPI, err := sdkHelper.API(svcAlias) + sdkAPI, err := sdkHelper.API(optModelName) if err != nil { - newSvcAlias, err := FallBackFindServiceID(sdkDir, svcAlias) + newSvcAlias, err := FallBackFindServiceID(sdkDir, optModelName) if err != nil { return err } @@ -104,7 +107,7 @@ func generateOLMAssets(cmd *cobra.Command, args []string) error { return err } m, err := ackmodel.New( - sdkAPI, latestAPIVersion, optGeneratorConfigPath, ackgenerate.DefaultConfig, + sdkAPI, svcAlias, latestAPIVersion, optGeneratorConfigPath, ackgenerate.DefaultConfig, ) if err != nil { return err diff --git a/cmd/ack-generate/command/release.go b/cmd/ack-generate/command/release.go index 77f8d772..43ca4e31 100644 --- a/cmd/ack-generate/command/release.go +++ b/cmd/ack-generate/command/release.go @@ -74,10 +74,13 @@ func generateRelease(cmd *cobra.Command, args []string) error { if err := ensureSDKRepo(ctx, optCacheDir, optRefreshCache); err != nil { return err } + if optModelName == "" { + optModelName = svcAlias + } sdkHelper := ackmodel.NewSDKHelper(sdkDir) - sdkAPI, err := sdkHelper.API(svcAlias) + sdkAPI, err := sdkHelper.API(optModelName) if err != nil { - newSvcAlias, err := FallBackFindServiceID(sdkDir, svcAlias) + newSvcAlias, err := FallBackFindServiceID(sdkDir, optModelName) if err != nil { return err } @@ -87,7 +90,7 @@ func generateRelease(cmd *cobra.Command, args []string) error { } } m, err := ackmodel.New( - sdkAPI, "", optGeneratorConfigPath, ackgenerate.DefaultConfig, + sdkAPI, svcAlias, "", optGeneratorConfigPath, ackgenerate.DefaultConfig, ) if err != nil { return err diff --git a/cmd/ack-generate/command/root.go b/cmd/ack-generate/command/root.go index 9aa3fa92..844b3a8b 100644 --- a/cmd/ack-generate/command/root.go +++ b/cmd/ack-generate/command/root.go @@ -34,6 +34,7 @@ var ( optCacheDir string optRefreshCache bool optAWSSDKGoVersion string + optModelName string defaultTemplateDirs []string optTemplateDirs []string defaultServicesDir string @@ -121,6 +122,9 @@ func init() { rootCmd.PersistentFlags().StringVar( &optAWSSDKGoVersion, "aws-sdk-go-version", "", "Version of github.com/aws/aws-sdk-go used to generate apis and controllers files", ) + rootCmd.PersistentFlags().StringVar( + &optModelName, "model-name", "", "the name of the service model package", + ) } // Execute adds all child commands to the root command and sets flags diff --git a/pkg/generate/templateset/vars.go b/pkg/generate/templateset/vars.go index e87f386c..62bad876 100644 --- a/pkg/generate/templateset/vars.go +++ b/pkg/generate/templateset/vars.go @@ -21,9 +21,6 @@ type MetaVars struct { // alias does not match the ServiceID. e.g. The AWS Step Functions API has // a ServiceID of "SFN" and a service alias of "states"... ServiceAlias string - // ServiceID is the exact string that appears in the AWS service API's - // api-2.json descriptor file under `metadata.serviceId` - ServiceID string // ServiceIDClean is the ServiceID lowercased and stripped of any // non-alphanumeric characters ServiceIDClean string @@ -34,6 +31,9 @@ type MetaVars struct { // for custom resources, e.g. "sns.services.k8s.aws" or // "sfn.services.k8s.aws" APIGroup string + // AWSSDKModelServiceID is the exact string that appears in the AWS service API's + // api-2.json descriptor file under `metadata.serviceId` + AWSSDKModelServiceID string // SDKAPIInterfaceTypeName is the name of the interface type used by the // aws-sdk-go services/$SERVICE/api.go file SDKAPIInterfaceTypeName string diff --git a/pkg/model/model.go b/pkg/model/model.go index 1f1de5f0..cc141582 100644 --- a/pkg/model/model.go +++ b/pkg/model/model.go @@ -34,13 +34,14 @@ var ( // Model contains the ACK model for the generator to process and apply // templates against. type Model struct { - SDKAPI *SDKAPI - serviceAlias string - apiVersion string - crds []*CRD - typeDefs []*TypeDef - typeImports map[string]string - typeRenames map[string]string + SDKAPI *SDKAPI + servicePackage string + serviceAlias string + apiVersion string + crds []*CRD + typeDefs []*TypeDef + typeImports map[string]string + typeRenames map[string]string // Instructions to the code generator how to handle the API and its // resources cfg *ackgenconfig.Config @@ -51,10 +52,10 @@ type Model struct { func (m *Model) MetaVars() templateset.MetaVars { return templateset.MetaVars{ ServiceAlias: m.serviceAlias, - ServiceID: m.SDKAPI.ServiceID(), - ServiceIDClean: m.SDKAPI.ServiceIDClean(), - APIGroup: m.SDKAPI.APIGroup(), + ServiceIDClean: m.ServiceIDClean(), + APIGroup: m.APIGroup(), APIVersion: m.apiVersion, + AWSSDKModelServiceID: m.SDKAPI.AWSSDKModelServiceID(), SDKAPIInterfaceTypeName: m.SDKAPI.SDKAPIInterfaceTypeName(), CRDNames: m.crdNames(), } @@ -688,11 +689,29 @@ func (m *Model) GetConfig() *ackgenconfig.Config { return m.cfg } +// APIGroup returns the normalized Kubernetes APIGroup for the AWS service API, +// e.g. "sns.services.k8s.aws" +func (m *Model) APIGroup() string { + serviceID := m.servicePackage + suffix := "services.k8s.aws" + if m.SDKAPI.apiGroupSuffix != "" { + suffix = m.SDKAPI.apiGroupSuffix + } + return fmt.Sprintf("%s.%s", serviceID, suffix) +} + +// ServiceIDClean returns a lowercased, whitespace-stripped ServiceID +func (m *Model) ServiceIDClean() string { + serviceID := strings.ToLower(m.servicePackage) + return strings.Replace(serviceID, " ", "", -1) +} + // New returns a new Model struct for a supplied API model. // Optionally, pass a file path to a generator config file that can be used to // instruct the code generator how to handle the API properly func New( SDKAPI *SDKAPI, + servicePackage string, apiVersion string, configPath string, defaultConfig ackgenconfig.Config, @@ -702,12 +721,11 @@ func New( return nil, err } m := &Model{ - SDKAPI: SDKAPI, - // TODO(jaypipes): Handle cases where service alias and service ID - // don't match (Step Functions) - serviceAlias: SDKAPI.ServiceID(), - apiVersion: apiVersion, - cfg: &cfg, + SDKAPI: SDKAPI, + servicePackage: servicePackage, + serviceAlias: SDKAPI.AWSSDKModelServiceID(), + apiVersion: apiVersion, + cfg: &cfg, } m.ApplyShapeIgnoreRules() return m, nil diff --git a/pkg/model/multiversion/manager.go b/pkg/model/multiversion/manager.go index 14e39927..2f3cf9c0 100644 --- a/pkg/model/multiversion/manager.go +++ b/pkg/model/multiversion/manager.go @@ -51,6 +51,7 @@ func NewAPIVersionManager( sdkCacheDir string, metadataPath string, serviceAlias string, + serviceModelName string, hubVersion string, apisInfo map[string]ackmetadata.APIInfo, defaultConfig ackgenconfig.Config, @@ -94,13 +95,14 @@ func NewAPIVersionManager( return nil, err } - SDKAPI, err := SDKAPIHelper.API(serviceAlias) + SDKAPI, err := SDKAPIHelper.API(serviceModelName) if err != nil { return nil, err } i, err := ackmodel.New( SDKAPI, + serviceAlias, version.APIVersion, apiInfo.GeneratorConfigPath, defaultConfig, diff --git a/pkg/model/sdk_helper.go b/pkg/model/sdk_helper.go index 9c785f67..fab1fe74 100644 --- a/pkg/model/sdk_helper.go +++ b/pkg/model/sdk_helper.go @@ -246,8 +246,8 @@ func (a *SDKAPI) GetOutputShapeRef( } // getMemberByPath returns a ShapeRef given a root Shape and a dot-notation -// object search path. Given the explicit type check for list type members -// both ".." and "." notations work currently. +// object search path. Given the explicit type check for list type members +// both ".." and "." notations work currently. // TODO: Add support for other types such as map. func getMemberByPath( shape *awssdkmodel.Shape, @@ -353,21 +353,17 @@ func (a *SDKAPI) HasConflictingTypeName(typeName string, cfg *ackgenconfig.Confi util.InStrings(cleanTypeName, crdListResourceNames) } -// ServiceID returns the exact `metadata.serviceId` attribute for the AWS -// service APi's api-2.json file -func (a *SDKAPI) ServiceID() string { +// AWSSDKModelServiceID returns the exact `metadata.serviceId` attribute for the AWS +// service APi's api-2.json file. +// This MAY NOT MATCH the AWS SDK Go package used by the service. For example: +// AWS SDK Go uses `opensearchservice` whereas the service ID is `opensearch` +func (a *SDKAPI) AWSSDKModelServiceID() string { if a == nil || a.API == nil { return "" } return awssdkmodel.ServiceID(a.API) } -// ServiceIDClean returns a lowercased, whitespace-stripped ServiceID -func (a *SDKAPI) ServiceIDClean() string { - serviceID := strings.ToLower(a.ServiceID()) - return strings.Replace(serviceID, " ", "", -1) -} - func (a *SDKAPI) GetServiceFullName() string { if a == nil || a.API == nil { return "" @@ -375,17 +371,6 @@ func (a *SDKAPI) GetServiceFullName() string { return a.API.Metadata.ServiceFullName } -// APIGroup returns the normalized Kubernetes APIGroup for the AWS service API, -// e.g. "sns.services.k8s.aws" -func (a *SDKAPI) APIGroup() string { - serviceID := a.ServiceIDClean() - suffix := "services.k8s.aws" - if a.apiGroupSuffix != "" { - suffix = a.apiGroupSuffix - } - return fmt.Sprintf("%s.%s", serviceID, suffix) -} - // SDKAPIInterfaceTypeName returns the name of the aws-sdk-go primary API // interface type name. func (a *SDKAPI) SDKAPIInterfaceTypeName() string { diff --git a/pkg/testutil/schema_helper.go b/pkg/testutil/schema_helper.go index a4257f8b..46232ecf 100644 --- a/pkg/testutil/schema_helper.go +++ b/pkg/testutil/schema_helper.go @@ -29,6 +29,8 @@ import ( type TestingModelOptions struct { // The CR API Version. Defaults to v1alpha1 APIVersion string + // Override for the model name for the service + ServiceModelName string // The generator config file. Defaults to generator.yaml GeneratorConfigFile string // The AWS Service's API version. Defaults to 00-00-0000 @@ -36,10 +38,13 @@ type TestingModelOptions struct { } // SetDefaults sets the empty fields to a default value. -func (o *TestingModelOptions) SetDefaults() { +func (o *TestingModelOptions) SetDefaults(serviceAlias string) { if o.APIVersion == "" { o.APIVersion = "v1alpha1" } + if o.ServiceModelName == "" { + o.ServiceModelName = serviceAlias + } if o.GeneratorConfigFile == "" { o.GeneratorConfigFile = "generator.yaml" } @@ -71,10 +76,10 @@ func NewModelForServiceWithOptions(t *testing.T, serviceAlias string, options *T break } } - options.SetDefaults() + options.SetDefaults(serviceAlias) sdkHelper := model.NewSDKHelper(path) sdkHelper.WithAPIVersion(options.ServiceAPIVersion) - sdkAPI, err := sdkHelper.API(serviceAlias) + sdkAPI, err := sdkHelper.API(options.ServiceModelName) if err != nil { t.Fatal(err) } @@ -82,7 +87,7 @@ func NewModelForServiceWithOptions(t *testing.T, serviceAlias string, options *T if _, err := os.Stat(generatorConfigPath); os.IsNotExist(err) { generatorConfigPath = "" } - m, err := ackmodel.New(sdkAPI, options.APIVersion, generatorConfigPath, ackgenerate.DefaultConfig) + m, err := ackmodel.New(sdkAPI, serviceAlias, options.APIVersion, generatorConfigPath, ackgenerate.DefaultConfig) if err != nil { t.Fatal(err) } diff --git a/scripts/build-controller-release.sh b/scripts/build-controller-release.sh index d2669be0..3f4376e8 100755 --- a/scripts/build-controller-release.sh +++ b/scripts/build-controller-release.sh @@ -30,6 +30,7 @@ ACK_GENERATE_CACHE_DIR=${ACK_GENERATE_CACHE_DIR:-"$HOME/.cache/aws-controllers-k # typically at $GOPATH/src/github.com/aws-controllers-k8s/code-generator DEFAULT_ACK_GENERATE_BIN_PATH="$ROOT_DIR/../../aws-controllers-k8s/code-generator/bin/ack-generate" ACK_GENERATE_BIN_PATH=${ACK_GENERATE_BIN_PATH:-$DEFAULT_ACK_GENERATE_BIN_PATH} +ACK_GENERATE_MODEL_NAME=${ACK_GENERATE_MODEL_NAME:-""} ACK_GENERATE_API_VERSION=${ACK_GENERATE_API_VERSION:-"v1alpha1"} ACK_GENERATE_CONFIG_PATH=${ACK_GENERATE_CONFIG_PATH:-""} ACK_METADATA_CONFIG_PATH=${ACK_METADATA_CONFIG_PATH:-""} @@ -185,6 +186,9 @@ ag_args="$SERVICE $RELEASE_VERSION -o $SERVICE_CONTROLLER_SOURCE_PATH --template if [ -n "$ACK_GENERATE_CACHE_DIR" ]; then ag_args="$ag_args --cache-dir $ACK_GENERATE_CACHE_DIR" fi +if [ -n "$ACK_GENERATE_MODEL_NAME" ]; then + ag_args="$ag_args --model-name $ACK_GENERATE_MODEL_NAME" +fi if [ -n "$ACK_GENERATE_OUTPUT_PATH" ]; then ag_args="$ag_args --output $ACK_GENERATE_OUTPUT_PATH" helm_output_dir="$ACK_GENERATE_OUTPUT_PATH/helm" diff --git a/scripts/build-controller.sh b/scripts/build-controller.sh index 8d78e867..21670dfc 100755 --- a/scripts/build-controller.sh +++ b/scripts/build-controller.sh @@ -23,6 +23,7 @@ ACK_GENERATE_CACHE_DIR=${ACK_GENERATE_CACHE_DIR:-"$HOME/.cache/aws-controllers-k # typically at $GOPATH/src/github.com/aws-controllers-k8s/code-generator DEFAULT_ACK_GENERATE_BIN_PATH="$ROOT_DIR/bin/ack-generate" ACK_GENERATE_BIN_PATH=${ACK_GENERATE_BIN_PATH:-$DEFAULT_ACK_GENERATE_BIN_PATH} +ACK_GENERATE_MODEL_NAME=${ACK_GENERATE_MODEL_NAME:-""} ACK_GENERATE_API_VERSION=${ACK_GENERATE_API_VERSION:-"v1alpha1"} ACK_GENERATE_CONFIG_PATH=${ACK_GENERATE_CONFIG_PATH:-""} ACK_METADATA_CONFIG_PATH=${ACK_METADATA_CONFIG_PATH:-""} @@ -49,6 +50,12 @@ Environment variables: previously generated, the latest generated API version is used. If the service controller has yet to be generated, 'v1alpha1' is used. + ACK_GENERATE_MODEL_NAME: Overrides the name of the AWS SDK model for the + current service. If not specified, the name of the + service will be used. Most services do not require + overriding this value, but some services models + do not match the name of the service as defined in + the AWS SDK Go (eg. opensearchservice). ACK_GENERATE_CONFIG_PATH: Specify a path to the generator config YAML file to instruct the code generator for the service. Default: generator.yaml @@ -159,6 +166,11 @@ if [ -n "$ACK_GENERATE_API_VERSION" ]; then apis_args="$apis_args --version $ACK_GENERATE_API_VERSION" fi +if [ -n "$ACK_GENERATE_MODEL_NAME" ]; then + ag_args="$ag_args --model-name $ACK_GENERATE_MODEL_NAME" + apis_args="$apis_args --model-name $ACK_GENERATE_MODEL_NAME" +fi + if [ -n "$ACK_GENERATE_CONFIG_PATH" ]; then ag_args="$ag_args --generator-config-path $ACK_GENERATE_CONFIG_PATH" apis_args="$apis_args --generator-config-path $ACK_GENERATE_CONFIG_PATH"