Skip to content

Commit

Permalink
Add the --api-group-override command-line option to the resolver tran…
Browse files Browse the repository at this point in the history
…sformation

to be able to override the generated API group names.

- Add the --api-resolver-package command-line option to the resolver transformation
  to properly configure the package of the GetManagedResource function.

Signed-off-by: Alper Rifat Ulucinar <[email protected]>
  • Loading branch information
ulucinar committed Jan 26, 2024
1 parent 994c07a commit 46434b6
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
4 changes: 3 additions & 1 deletion cmd/resolver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ func main() {
var (
app = kingpin.New(filepath.Base(os.Args[0]), "Transformer for the generated resolvers by the crossplane-tools so that cross API-group imports are removed.").DefaultEnvars()
apiGroupSuffix = app.Flag("apiGroupSuffix", "Resource API group suffix, such as aws.upbound.io. The resource API group names are suffixed with this to get the canonical API group name.").Short('g').Required().String()
apiGroupOverride = app.Flag("apiGroupOverride", "API group overrides").Short('o').StringMap()
apiResolverPackage = app.Flag("apiResolverPackage", "The package that contains the implementation for the GetManagedResource function, such as github.com/upbound/provider-aws/internal/apis.").Short('a').Required().String()
pattern = app.Flag("pattern", "List patterns for the packages to process, such as ./...").Short('p').Default("./...").Strings()
resolverFilePattern = app.Flag("resolver", "Name of the generated resolver files to process.").Short('r').Default("zz_generated.resolvers.go").String()
ignorePackageLoadErrors = app.Flag("ignoreLoadErrors", "Ignore errors encountered while loading the packages.").Short('s').Bool()
)
kingpin.MustParse(app.Parse(os.Args[1:]))
logger := logging.NewLogrLogger(zap.New().WithName("transformer-resolver"))
r := transformers.NewResolver(afero.NewOsFs(), *apiGroupSuffix, *ignorePackageLoadErrors, logger)
r := transformers.NewResolver(afero.NewOsFs(), *apiGroupSuffix, *apiResolverPackage, *ignorePackageLoadErrors, logger, transformers.WithAPIGroupOverrides(*apiGroupOverride))
kingpin.FatalIfError(r.TransformPackages(*resolverFilePattern, *pattern...), "Failed to transform the resolver files in the specified packages.")
}
51 changes: 47 additions & 4 deletions pkg/transformers/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ type Resolver struct {
// managed resources, such as aws.upbound.io. Then a sample
// API group for a resource is ec2.aws.upbound.io.
apiGroupSuffix string
// API group overrides for the provider. Certain providers need
// to rename the short API group names they use, breaking the
// convention that the short group name matches the package name.
// An example is upbound/provider-azure, where the ResourceGroup.azure
// resource's short API group is the empty string. This map allows such
// providers to control the names of the generated API group names by this
// Resolver transformer.
apiGroupOverrides map[string]string
// the API resolver package that contains the
// `GetManagedResource("group", "version", "kind", "listKind")`
// function. This function is used to initialize a managed resource and
// its list type, owned by the provider, with the given API group, version,
// kind and list kind. Signature of the resolver function is as follows:
// func GetManagedResource(group, version, kind, listKind string) (xpresource.Managed, xpresource.ManagedList, error)
apiResolverPackage string
// When set, any errors encountered while loading the source packages is
// silently ignored if a logger is not configured,
// or logged via the configured logger.
Expand All @@ -54,13 +69,14 @@ type Resolver struct {
}

// NewResolver initializes a new Resolver with the specified configuration.
func NewResolver(fs afero.Fs, apiGroupSuffix string, ignorePackageLoadErrors bool, logger logging.Logger, opts ...ResolverOption) *Resolver {
func NewResolver(fs afero.Fs, apiGroupSuffix, apiResolverPackage string, ignorePackageLoadErrors bool, logger logging.Logger, opts ...ResolverOption) *Resolver {
if logger == nil {
logger = logging.NewNopLogger()
}
r := &Resolver{
fs: fs,
apiGroupSuffix: apiGroupSuffix,
apiResolverPackage: apiResolverPackage,
ignorePackageLoadErrors: ignorePackageLoadErrors,
logger: logger,
config: &packages.Config{
Expand All @@ -83,6 +99,17 @@ func WithLoaderConfig(c *packages.Config) ResolverOption {
}
}

// WithAPIGroupOverrides configures the API group overrides for a Resolver.
// Certain providers need to rename the short API group names they use,
// breaking the convention that the short group name matches the package name.
// An example is upbound/provider-azure, where the ResourceGroup.azure
// resource's short API group is the empty string.
func WithAPIGroupOverrides(overrides map[string]string) ResolverOption {
return func(r *Resolver) {
r.apiGroupOverrides = overrides
}
}

// TransformPackages applies the dynamic resolver transformation to
// the resolver modules loaded from the specified patterns and
// implemented in the specified resolver files. If `r.ignorePackageLoadErrors`
Expand Down Expand Up @@ -324,6 +351,8 @@ func (r *Resolver) transformResolverFile(fset *token.FileSet, node *ast.File, fi
version = tokens[len(tokens)-1]
// e.g., ec2.aws.upbound.io
group = fmt.Sprintf("%s.%s", tokens[len(tokens)-2], apiGroupSuffix)
// apply any configured group name overrides
group = r.overrideGroupName(group)
// extract the kind and list kind names from the field
// selector.
if sexpr.Sel != nil {
Expand All @@ -346,6 +375,8 @@ func (r *Resolver) transformResolverFile(fset *token.FileSet, node *ast.File, fi
version = tokens[len(tokens)-2]
// e.g., cur.aws.upbound.io
group = fmt.Sprintf("%s.%s", tokens[len(tokens)-3], apiGroupSuffix)
// apply any configured group name overrides
group = r.overrideGroupName(group)
if ident, ok := cl.Type.(*ast.Ident); ok {
if key == "List" {
listKind = ident.Name
Expand Down Expand Up @@ -389,7 +420,7 @@ func (r *Resolver) transformResolverFile(fset *token.FileSet, node *ast.File, fi

// get the statements including the import statements we need to make
// calls to the type registry.
mrImports, stmts := getManagedResourceStatements(group, version, kind, listKind)
mrImports, stmts := getManagedResourceStatements(group, version, kind, listKind, r.apiResolverPackage)
// insert the statements that implement type registry lookups
if !insertStatements(stmts, block, assign) {
inspectErr = errors.Errorf("failed to insert the type registry lookup statements for Group: %q, Version: %q, Kind: %q, List Kind: %q", group, version, kind, listKind)
Expand Down Expand Up @@ -532,7 +563,7 @@ func addMRVariableDeclarations(f *ast.File) map[string]string {
}
}

func getManagedResourceStatements(group, version, kind, listKind string) (map[string]string, []ast.Stmt) {
func getManagedResourceStatements(group, version, kind, listKind, apiResolverPackage string) (map[string]string, []ast.Stmt) {
// prepare the assignment statement:
// `m, l, err = apisresolver.GetManagedResource("group", "version", "kind", "listKind")`
assignStmt := &ast.AssignStmt{
Expand Down Expand Up @@ -590,6 +621,18 @@ func getManagedResourceStatements(group, version, kind, listKind string) (map[st
},
}
return map[string]string{
`"github.com/upbound/provider-aws/internal/apis"`: "apisresolver",
// TODO: we may need to parameterize the import alias in the future, if
// any provider that uses the transformer has an import alias collision
// which is not very likely.
fmt.Sprintf(`"%s"`, apiResolverPackage): "apisresolver",
}, []ast.Stmt{assignStmt, ifStmt}
}

func (r *Resolver) overrideGroupName(group string) string {
g, ok := r.apiGroupOverrides[group]
// we need to allow overrides with an empty string
if !ok {
return group
}
return g
}

0 comments on commit 46434b6

Please sign in to comment.