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

Ability to reference multiple types / generate resources multiple times #414

Open
Breee opened this issue Jun 2, 2024 · 6 comments
Open
Labels
enhancement New feature or request

Comments

@Breee
Copy link

Breee commented Jun 2, 2024

What problem are you facing?

  • The keycloak provider is generated via upjet
  • I'm currently facing the issue that the terraform provider uses generic types under the hood, for example for Clients
  • In reality we have OpenID Client and Saml Client and sadly no Generic Client available as resource.
  • This leads to problems when i have to create references for resources which just reference a Client, which can be both OpenId Client or Saml Client
  • The upstream Terraform provider is dying and is unmaintained

How could Upjet help solve your problem?

  • I'm looking for a way to have references to either a Generic Type or multiple Types OR just generate a resource multiple times with different Kinds + References
  • simplified example:
r.References["client_id"] = config.Reference{
	Type:  []{"github.com/crossplane-contrib/provider-keycloak/apis/openidclient/v1alpha1.Client", "github.com/crossplane-contrib/provider-keycloak/apis/samlclient/v1alpha1.Client},
	}
  • Or allow to do something like:
package v1alpha

type GenericClient interface { 
  *OpenIDClient | *SamlCLient
}
  • Also: as i see there is no working way to generate the same resource twice, which would be ugly but feasible (and loopable): Both do not work
	p.AddResourceConfigurator("keycloak_generic_protocol_mapper", func(r *config.Resource) {
		r.ShortGroup = "client"
		r.Name = "keycloak_generic_protocol_mapper"
		r.Kind = "OpenIDProtocolMapper"
		r.References["client_scope_id"] = config.Reference{
			Type: "github.com/crossplane-contrib/provider-keycloak/apis/openidclient/v1alpha1.ClientScope",
		}
	})

	p.AddResourceConfigurator("keycloak_generic_protocol_mapper", func(r *config.Resource) {
		r.ShortGroup = "client"
		r.Name = "keycloak_generic_protocol_mapper"
		r.Kind = "SamlProtocolMapper"
		r.References["client_scope_id"] = config.Reference{
			Type: "github.com/crossplane-contrib/provider-keycloak/apis/samlclient/v1alpha1.ClientScope",
		}
	})
	// Configure keycloak_generic_protocol_mapper for OpenIdProtocolMapper
	openIdConfigurator := ujconfig.ResourceConfiguratorFn(func(r *ujconfig.Resource) {
		r.ShortGroup = Group
		r.Name = "keycloak_generic_protocol_mapper"
		r.Kind = "OpenIdProtocolMapper"
		r.References["client_scope_id"] = ujconfig.Reference{
			Type: "github.com/crossplane-contrib/provider-keycloak/apis/openid/v1alpha1.ClientScope",
		}
	})
	// Configure keycloak_generic_protocol_mapper for SamlProtocolMapper
	samlConfigurator := ujconfig.ResourceConfiguratorFn(func(r *ujconfig.Resource) {
		r.ShortGroup = Group
		r.Name = "keycloak_generic_protocol_mapper"
		r.Kind = "SamlProtocolMapper"
		r.References["client_scope_id"] = ujconfig.Reference{
			Type: "github.com/crossplane-contrib/provider-keycloak/apis/saml/v1alpha1.ClientScope",
		}
	})

	p.SetResourceConfigurator("keycloak_generic_protocol_mapper", ujconfig.ResourceConfiguratorChain{openIdConfigurator, samlConfigurator})

code is also on this branch: https://github.com/crossplane-contrib/provider-keycloak/blob/dfacf3ae92d66b1df511884113858be1636b1327/config/mapper/config.go#L59

@Breee Breee added the enhancement New feature or request label Jun 2, 2024
@Breee Breee changed the title Ability to reference multiple types Ability to reference multiple types / generate resources multiple times Jun 2, 2024
@yordis
Copy link
Contributor

yordis commented Jun 11, 2024

@Breee could this help me with crossplane-contrib/provider-upjet-digitalocean#36 as well? I am trying to figure out what is the best strategy to deal with more than one type for a given resource field

@yordis
Copy link
Contributor

yordis commented Jun 11, 2024

Also Type is deprecated so it would be TerraformName

@Breee
Copy link
Author

Breee commented Jun 11, 2024

I'm not sure, maybe maintainers @muvaf or @ulucinar can tell us if that is even possible

@artemlive
Copy link

Are there any updates?
I've encountered the same problem when I have multiple types for one field.

@Breee
Copy link
Author

Breee commented Nov 5, 2024

Not yet, the Best solution I came up with is writing a custom Controller that implements both types or use a composition function that selects the Type based on some property passed.

@artemlive
Copy link

@Breee, thanks for the reply.
I'm curious, is it possible to mutate schema to make a few separate fields and, depending on the type (that can be a separate string field) use the corresponding field reference? (without compositions)
Pseudocode:

func CustomExtractor(ctx context.Context, mg resource.Managed) (string, error) {
    // Cast the resource to your specific type
    obj, ok := mg.(*MyResource)
    if !ok {
        return "", fmt.Errorf("unexpected resource type: %T", mg)
    }

    // Iterate over the responders to find the type and map it accordingly
    for _, responder := range obj.Spec.ForProvider.Create.Responders {
        switch responder.Type {
        case "team":
            return responder.TeamID, nil
        case "user":
            return responder.UserID, nil
        case "escalation":
            return responder.EscalationID, nil
        default:
            return "", fmt.Errorf("unsupported type: %s", responder.Type)
        }
    }

    return "", fmt.Errorf("no valid responder type found")
}

Sorry if it looks stupid. I'm new to upjet generators.

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

No branches or pull requests

3 participants