diff --git a/cmd/controller-bootstrap/command/apiutil.go b/cmd/controller-bootstrap/command/apiutil.go index 703fee5..78f128b 100644 --- a/cmd/controller-bootstrap/command/apiutil.go +++ b/cmd/controller-bootstrap/command/apiutil.go @@ -98,6 +98,12 @@ func getServiceResources() (*metaVars, error) { return nil, err } + // Propagate the explicit --model-name override (if any) so the generated + // generator.yaml emits a model_name field. We use the raw flag value rather + // than the service-alias fallback: model_name only needs to be written when + // it actually differs from the alias. + svcVars.ServiceModelName = strings.ToLower(optModelName) + return svcVars, nil } diff --git a/cmd/controller-bootstrap/command/common.go b/cmd/controller-bootstrap/command/common.go index af42bc3..7504f4b 100644 --- a/cmd/controller-bootstrap/command/common.go +++ b/cmd/controller-bootstrap/command/common.go @@ -87,7 +87,10 @@ func ensureDir(fp string) (bool, error) { // isDirWriteable returns true if the supplied directory path is writeable, // false otherwise func isDirWriteable(fp string) bool { - testPath := filepath.Join(fp, "test") + // Use a dotted, unlikely-to-collide probe name. A plain "test" name + // collides with the test/ directory present in ACK controller repos, + // causing os.Create to fail and falsely report the dir as unwriteable. + testPath := filepath.Join(fp, ".ack-write-test") f, err := os.Create(testPath) if err != nil { return false @@ -97,6 +100,21 @@ func isDirWriteable(fp string) bool { return true } +// cloneSDKRepo clones the aws-sdk-go-v2 repository into the given directory. +// It is used by the per-service branch in generateController to clone the repo +// before calling ensureSDKRepoPerServiceTag. +func cloneSDKRepo(ctx context.Context, sdkDir string) error { + err := util.CloneRepository(ctx, sdkDir, sdkRepoURL) + if err != nil { + if errors.Is(err, context.DeadlineExceeded) { + err = fmt.Errorf("%w: took too long to clone aws sdk repo, "+ + "please consider manually 'git clone %s' to cache dir %s", err, sdkRepoURL, sdkDir) + } + return fmt.Errorf("cannot clone repository: %v", err) + } + return nil +} + // ensureSDKRepo ensures that we have a git clone'd copy of the aws-sdk-go // repository, which we use model JSON files from. Upon successful return of // this function, the sdkDir global variable will be set to the directory where @@ -181,3 +199,36 @@ func ensureSemverPrefix(s string) string { func getSDKVersion() string { return optAWSSDKGoVersion } + +// ensureSDKRepoPerServiceTag fetches and checks out a per-service git tag +// in the already-cloned aws-sdk-go-v2 repository. The per-service tag format +// is service/{serviceAlias}/{serviceSDKVersion}. +func ensureSDKRepoPerServiceTag( + ctx context.Context, + cacheDir string, + serviceAlias string, + serviceSDKVersion string, +) (string, error) { + srcPath := filepath.Join(cacheDir, "src") + sdkDir := filepath.Join(srcPath, "aws-sdk-go-v2") + + tag := fmt.Sprintf("service/%s/%s", serviceAlias, ensureSemverPrefix(serviceSDKVersion)) + + // Fetch the tag if not already present locally + if !util.HasTag(sdkDir, tag) { + fetchCtx, cancel := context.WithTimeout(ctx, defaultGitFetchTimeout) + defer cancel() + err := util.FetchRepositoryTag(fetchCtx, sdkDir, tag) + if err != nil { + return "", fmt.Errorf("cannot fetch per-service tag %s: %v", tag, err) + } + } + + // Checkout the per-service tag + err := util.CheckoutRepositoryTag(sdkDir, tag) + if err != nil { + return "", fmt.Errorf("cannot checkout per-service tag %s: %v", tag, err) + } + + return sdkDir, nil +} diff --git a/cmd/controller-bootstrap/command/generate.go b/cmd/controller-bootstrap/command/generate.go index 816568f..4d3ba12 100644 --- a/cmd/controller-bootstrap/command/generate.go +++ b/cmd/controller-bootstrap/command/generate.go @@ -29,9 +29,10 @@ import ( type templateVars struct { *metaVars - AWSSDKGoVersion string - RuntimeVersion string - TestInfraCommitSHA string + AWSSDKGoVersion string + AWSServiceSDKVersion string + RuntimeVersion string + TestInfraCommitSHA string } var ( @@ -70,28 +71,54 @@ func generateController(cmd *cobra.Command, args []string) (err error) { if err := validateArgs(); err != nil { return err } + if controllerExists() { return ErrServiceControllerExists } ctx, cancel := contextWithSigterm(context.Background()) defer cancel() - var sdkDirPath string - if sdkDirPath, err = ensureSDKRepo(ctx, defaultCacheACKDir, true); err != nil { - return err - } - sdkDir = sdkDirPath + if optAWSServiceSDKVersion != "" { + // Per-service branch: clone SDK repo then checkout per-service tag directly + srcPath := filepath.Join(defaultCacheACKDir, "src") + if err = os.MkdirAll(srcPath, os.ModePerm); err != nil { + return err + } + repoDir := filepath.Join(srcPath, "aws-sdk-go-v2") + if _, statErr := os.Stat(repoDir); os.IsNotExist(statErr) { + cloneCtx, cloneCancel := context.WithTimeout(ctx, defaultGitCloneTimeout) + defer cloneCancel() + if cloneErr := cloneSDKRepo(cloneCtx, repoDir); cloneErr != nil { + return cloneErr + } + } + + serviceModelName := strings.ToLower(optServiceAlias) + sdkDirPath, psErr := ensureSDKRepoPerServiceTag(ctx, defaultCacheACKDir, serviceModelName, optAWSServiceSDKVersion) + if psErr != nil { + return psErr + } + sdkDir = sdkDirPath + } else { + // Core branch: use ensureSDKRepo with core tag (existing behavior) + var sdkDirPath string + if sdkDirPath, err = ensureSDKRepo(ctx, defaultCacheACKDir, true); err != nil { + return err + } + sdkDir = sdkDirPath + } svcVars, err := getServiceResources() if err != nil { return err } tplVars := &templateVars{ - metaVars: svcVars, - AWSSDKGoVersion: optAWSSDKGoVersion, - RuntimeVersion: optRuntimeVersion, - TestInfraCommitSHA: optTestInfraCommitSHA, + metaVars: svcVars, + AWSSDKGoVersion: optAWSSDKGoVersion, + AWSServiceSDKVersion: optAWSServiceSDKVersion, + RuntimeVersion: optRuntimeVersion, + TestInfraCommitSHA: optTestInfraCommitSHA, } var tplPaths []string @@ -114,8 +141,11 @@ func validateArgs() error { if optRuntimeVersion == "" { return ErrRuntimeVersionNotFound } - if optAWSSDKGoVersion == "" { - return ErrAWSSDKGoVersionNotFound + if optAWSSDKGoVersion == "" && optAWSServiceSDKVersion == "" { + return fmt.Errorf("at least one of --aws-sdk-go-version or --aws-service-sdk-version is required") + } + if optAWSSDKGoVersion != "" && optAWSServiceSDKVersion != "" { + return fmt.Errorf("--aws-sdk-go-version and --aws-service-sdk-version are mutually exclusive; provide only one") } if optOutputPath == "" { return ErrOutputPathNotFound diff --git a/cmd/controller-bootstrap/command/root.go b/cmd/controller-bootstrap/command/root.go index 3d0a829..1c0e930 100644 --- a/cmd/controller-bootstrap/command/root.go +++ b/cmd/controller-bootstrap/command/root.go @@ -27,17 +27,18 @@ const ( ) var ( - optRuntimeVersion string - optAWSSDKGoVersion string - optTestInfraCommitSHA string - optModelName string - optRefreshCache bool - optServiceAlias string - optDryRun bool - optOutputPath string - sdkDir string - defaultCacheACKDir string - defaultTemplatesDir string + optRuntimeVersion string + optAWSSDKGoVersion string + optAWSServiceSDKVersion string + optTestInfraCommitSHA string + optModelName string + optRefreshCache bool + optServiceAlias string + optDryRun bool + optOutputPath string + sdkDir string + defaultCacheACKDir string + defaultTemplatesDir string ) // rootCmd represents the base command when called without any subcommands @@ -74,6 +75,10 @@ func init() { templateCmd.PersistentFlags().StringVar( &optModelName, "model-name", "", "Optional: service model name of the corresponding service alias", ) + templateCmd.PersistentFlags().StringVar( + &optAWSServiceSDKVersion, "aws-service-sdk-version", "", + "Per-service SDK version for fetching model from per-service tag", + ) templateCmd.PersistentFlags().BoolVar( &optRefreshCache, "refresh-cache", true, "Optional: if true, and aws-sdk-go repo is already cloned, will git pull the latest aws-sdk-go commit", ) @@ -87,7 +92,6 @@ func init() { &optOutputPath, "output-path", "", "Path to ACK service controller directory to bootstrap", ) templateCmd.MarkPersistentFlagRequired("ack-runtime-version") - templateCmd.MarkPersistentFlagRequired("aws-sdk-go-version") templateCmd.MarkPersistentFlagRequired("test-infra-commit-sha") rootCmd.MarkPersistentFlagRequired("aws-service-alias") rootCmd.MarkPersistentFlagRequired("output-path") diff --git a/templates/generator.yaml.tpl b/templates/generator.yaml.tpl index 2c444f9..2895234 100644 --- a/templates/generator.yaml.tpl +++ b/templates/generator.yaml.tpl @@ -4,5 +4,6 @@ ignore: - {{ $crdName }} {{- end }} {{- if not (eq .ServiceModelName "") }} -model_name: {{ .ServiceModelName }} +sdk_names: + model_name: {{ .ServiceModelName }} {{- end }}