A stack config typically looks like this (ignoring...
# general
l
A stack config typically looks like this (ignoring structured config for the moment):
Copy code
config:
  <your-project-name>:<key>: <value>
Providers often look up their config with another "project-name", e.g.:
Copy code
config:
  aws:region: eu-west-1
  <your-project-name>:<key>: <value>
If I create an abstraction in a reusable library, I could for example use a separate project key to store all the config for my component.
Copy code
config:
  aws:region: eu-west-1
  <your-project-name>:<key>: <value>
  <my-component-name>:<key1>: <value1>
  <my-component-name>:<key2>: <value2>
Do other Pulumi developers use this ability for such use cases? Would this be a good pattern to use, or rather an anti-pattern?
l
I consider that an anti-pattern. Configuration for a component should be passed into it in all cases. It's the only way to ensure proper testability.
The only thing that should ever read config is your top level project / program. It should pass the correct config into components via args.
This is one of the many good lessons we can take from the rise of Functional Programming 🙂
l
@little-cartoon-10569 to prevent confusion, I wouldn't force this to be single/only way of configuring a component. If component config comes from the stack config, I would provide an additional function next to my component, like
getComponentConfig()
which in its implementation would e.g. call
pulumi.getConfig('my-component-name').require(...)
(or
requireObject
)
l
Ok. Still, it won't work in a unit test, where you can't call
pulumi.getConfig()
at all, because you're not in a Pulumi runtime.
Plus, it's less readable. Two source of configuration (args and mysterious-injected-config-properties) makes for side effects, and difficulty faking in test circumstances.
l
But the call to
pulumi.getConfig()
wouldn't be inside my component implementation, this would be in the
getComponentConfig
function which is next to my component class.
l
So in your test code, you'll need to implement
getComponentConfig()
to inject values?
l
What you are hinting at is this:
Copy code
config = {
  key: value
}
component = new package.ComponentResource('name', config)
What I am hinting at is this:
Copy code
config = package.getComponentConfig() // <- only this reads from stack config with a separate key
component = new package.ComponentResource('name', config)
So you see that
package
exposes two items: the config helper function and my component resource, which still is decoupled from how config is passed. Actually, it exposes 3 items: I missed the
args
interface type, e.g.
ComponentArgs
my test code for my component resource is not coupled to the config at all.
So with that confusion (hopefully aside) and more looking at the config helper function, would you "namespace" the config for your abstraction in another top level key, like e.g. the AWS provider does by putting config under the
aws
top level key
l
Yes, that sounds useful. I don't currently ever need to do that, since the config is always project/program specific. For example, in some cases the component's config would be hard-coded in the program; in some cases it would be derived from an existing config value. If the dev was expect to provide a well-known set of config values for my component, it implies that each program that uses the component would have to document any deviations from that well-known config structure.
For example, if your component needs a value and gets it it in
getComponentConfig()
, and the program needs the same value for itself (independent of the component), then you really need the same value to be defined twice in your config...
l
True, but in our setup, we distinguish between "real" config and info which comes from the environment. We have a standard approach to that.
l
Then this is a good solution. The namespace is owned by the component (or at least, the library that provides the component). That makes sense.
👌🏼 1
w
What you're describing sounds like the way dotnet configuration works, where libraries can read the config via the passed config root, and access the part scoped to their specific name.
e.g. here I'm configuring the
Serilog
logger library with its own section which is wired up here
👍 1