Implementing dynamic resource provider for several...
# general
r
Implementing dynamic resource provider for several resources and sharing configuration? Any best practices for that?
I’m currently looking into implementing a custom resource with a dynamic resource provider for setting up mssql users, logins and grants for a database. Now I’m wondering how to structure this in terms of flexibility/composability (one user, two grants) and in terms of configuration. Is there always a 1-to-1 relation between resource and provider when working with dynamicproviders? I know I can pass an instance when creating a resource. But should I do so or have one provider for each resource? Regarding that, there is also the question of configuring: I thought about handing in a connection string for the whole server that is required to perform those actions with the node mssql module. How to deal with that case if I want to create several resources in the same server? Should I instantiate the provider from my script with the credentials and pass it into my resources?
My idea was to be able to instantiate one
provider
in my pulumi program passing the configuration (as you would do it with a
kubernetes
provider - using the connection string in my case) and then instantiating several resources like
User
,
Grant
that use this provider. Is there a way to do this like we do it with the third param of the resource constructor (
ComponentResourceOptions
)? For the dynamic resource provider it looks a bit more like a 1-to-1 mapping between resource and provider. Are there samples for such a setup or is my case already getting more complicated that I should consider building it as a binary provider or use a simpler concept if going the dynamic way?
c
If this is something you plan to reuse, binary provider is the recommended path.
r
Sure. For now I thought to start small and just use it in the one project. Still, are there any dynamic resources that rely on some shared provider that holds the configuration?
g
I'm not sure which language you are using but I hit an issue with my Python-based DynamicProvider because Pulumi will attempt to serialize it. I believe serialization is needed so that an object which is removed from the plan can be removed using information only available in the stored state. That said, you could create a single version of the DynamicProvider object and reuse it. Just ensure the class is serializable with whatever package is used for your language. The Typescript examples at https://www.pulumi.com/docs/intro/concepts/programming-model/#dynamic-provider-examples appear to do this.
r
I’m using node/typescript. Thanks for that hint regarding serialization. This was also a thing I wondered about, how to delete something if the information to do so is in the provider is no longer there. But this makes sense.
The examples listed still use just one provider and even hardcode it in the constructor definition of the
Resource
. (see
super(myprovider, ...)
.
g
Yes, but I don't see why you couldn't pass that object in with the other constructor arguments.
f
To answer a few other questions from above...
Should I instantiate the provider from my script with the credentials and pass it into my resources?
Use environment variables if possible, otherwise you could save the credentials as pulumi config and pass them into the props when creating each custom resource.
Is there always a 1-to-1 relation between resource and provider when working with dynamicproviders?
I believe this is the case, yes. You might be able to get away using case statements checking on the resource type but wouldn't be elegant.
r
I’m thinking about something like that:
Copy code
const mssqlProvider = new MssqlProvider(connstr);
const user = new MssqlUser(username, { ... }, {provider: mssqlProvider};
const grant = new MssqlGrant(grantname, { username: user.name, ... }, {provider: mssqlProvider};
So I want to specify the connectionString once and reuse it as I do with a
kubernetesProvider
too.
ah, right. The
CustomResourceOptions
already allow specifying a provider, but this somehow conflicts with the one passed as first argument?!
super(myprovider, name, { myStringOutput: undefined, myNumberOutput: undefined, ...props }, opts);
@future-barista-68134 Sure. I won’t hardcode the credentials but either use the output of the
azure.sql.SqlServer
I created one step before (which in turn relies on a random generated password).
f
I see, this is approaching the limits of the dynamic provider. The wrinkle here that may make this hard to do, is that the auth information is coming from a resource. FYI, here's a more advanced example you can look at that uses config: https://github.com/ellismg/github-webhooks-serverless/blob/master/github.ts.
try using the pattern above... use the function in your config code to set a variable that's used in the definition of the dynamic provider to do auth.
r
Thanks. So this seems okay if you think of a dynamic provider to be used only once, so it may reference some program-global variable for getting its config.
Still wondering a bit about the CustomResourceOptions as they also have a
provider
field but this doesn’t seem to be used in the dynamic case.
f
yeah not used in the dynamic case and I think you'll get in trouble using it since it's included as part of the constructor
So this seems okay if you think of a dynamic provider to be used only once, so it may reference some program-global variable for getting its config.
You'd be able to create multiple resources, using the same auth this way, yeah