https://pulumi.com logo
Title
p

polite-napkin-90098

05/11/2023, 3:49 PM
Wotcha, I've written a bunch of stacks to deploy a Fargate application. Starting with a VPC stack to make subnets, internet and NAT gateways and VPC endpoints, then a fargate stack to make the ECS cluster, and a series of stacks to make the services running on them, also some ancillary services to make certs, ALBs, RDS, Elasticache. I found myself setting the awsConfig options for the aws provider (and aws native provider) and thought it would be nice if that config was done in only one place so changing it required less effort. I thus exported the config from the vpc stack(s) thusly:
import * as values from './src/config/values';
// export aws config options.
export const awsConfigOptions = values.awsConfigOptions;
where values has
// export aws config object.
export const awsConfigOptions = {
  // aws region.
  region: <aws.Region>awsConfig.require('region'),
  // allow EC2 instance metadata authentication.
  skipMetadataApiCheck: awsConfig.requireBoolean('skipMetadataApiCheck'),
  // also for EC2 metadata auth.
  skipCredentialsValidation: awsConfig.requireBoolean('skipCredentialsValidation'),
  // assume role.
  assumeRole: <aws.types.input.ProviderAssumeRole>awsConfig.requireObject('assumeRole'),
}
and the config for each stack could be sensibly set the
pulumi config set
I then imported the exported config into the descendent stacks thusly: in a file called src/stacks/vpc.ts
const config = new pulumi.Config()

const vpcStack = new pulumi.StackReference(config.require('vpcStackName'));

// get the awsConfig from the vpcStackName

const awsConfig = vpcStack.requireOutput('awsConfigOptions');
to use this I found I needed an apply to convert the Output back to a string so:
export const awsProvider = awsConfig.apply((awsC) => {
  return new aws.Provider(`${stackName}-awsProvider`, {
    ...awsC,
  });
});
then I used that as a provider in my stack files which generate the resources with another apply thusly
// Make all the AWS parameter store secure strings for the api deployments.
import * as pulumi from '@pulumi/pulumi';
import * as aws from '@pulumi/aws';
import { awsProvider, vpcId } from '../src/stacks/vpc';
import { albStack } from '../src/stacks/alb';
import { stackName } from '../src/config/values';

const nom = stackName.split('-')[0];

export const targetGroups = (hostHeader: string) => {
  const tGroups = awsProvider.apply(prov => { 
    const reactTarget = new aws.lb.TargetGroup(name,
      ...
     }, {provider: prov}); 
  });
};
So this kinda worked, but when running up it would often get things wrong in the preview, as in say it was going to delete things and then update them, or say it would update things and then not. My colleague who understands apply and promise somewhat better than me, spent some hours working on trying to fix it and claims that it isn't possible and there is nothing we can do but set the config options in every stack. Is he right?
l

little-cartoon-10569

05/11/2023, 8:53 PM
It was true. But a recent update allows stack outputs to retrieved as non-futures, which will allow this. See
getOutputDetails()
here: https://www.pulumi.com/docs/intro/concepts/stack/#reading-outputs-from-stack-references
That said, this might not be the best solution. It might be better to provide a non-Pulumi solution for this. Really-really-shared configuration, that applies across multiple projects (as opposed to stacks within a project) may be better solved with properly-global configuration, which Pulumi doesn't provide.
p

polite-napkin-90098

05/11/2023, 9:02 PM
thanks for the link @little-cartoon-10569 yes the stacks I mention are in their own projects, so I am looking at passing config across projects, I guess it could be global, especially as we're only in a single cloud at the moment, but having it being inheritable so e.g. all the AWS stacks inherit it from their parent stack and the Google stacks from theirs. I'll have a read of that link and see if it helps me.
l

little-cartoon-10569

05/11/2023, 9:05 PM
You can have a global project whose stacks do nothing but provide configuration for other projects (usually, grabbing config from a stack of the same name). However, you can do exactly that with a solution that does not depend on the Pulumi service, thus cutting out web traffic and potential for failure
Inheritance (at least, OO-style inheritance) isn't the right solution here: both composition and injection are more appropriate.