<@U012UJTT55M> I will start a new thread here. Wi...
# typescript
a
@little-cartoon-10569 I will start a new thread here. With
awsx.ecs.FargateService
under
FargateTaskDefinitionArgs
then under
Container
you will see an option called Secrets. This type definition can be found under:
<node>@pulumi/aws/ecs/container.d.ts/Secret
. On my file it is around line 198. I will also add my deps here as well so you can get the exact versions. NOTE: I moved pulumi back down( this does not change anything in the code, .40 awsx is the same as 1.0.0 awsx/classic that we talked about yesterday.)
Copy code
"dependencies": {
    "@pulumi/pulumi": "^3.0.0",
    "@pulumi/aws": "^5.0.0",
    "@pulumi/awsx": "^0.40.0"
  },
Secret interface definition.
Copy code
export interface Secret {
    /**
     * The name of the secret.
     */
    name: pulumi.Input<string>;
    /**
     * The secret to expose to the container. The supported values are either the full ARN of the
     * AWS Secrets Manager secret or the full ARN of the parameter in the AWS Systems Manager
     * Parameter Store.
     *
     * Note: If the AWS Systems Manager Parameter Store parameter exists in the same Region as the
     * task you are launching, then you can use either the full ARN or name of the parameter. If the
     * parameter exists in a different Region, then the full ARN must be specified.
     */
    valueFrom: pulumi.Input<string>;
}
Previously we used this same concept of secrets inside a .ecs_taskdefinition yaml file and passed in a name and an ARN to a secret value from ssm. I am currently trying to move our infra to pulumi. (I am coming from python to typescript, so assume I know nothing about proper typescript) To make things simple, I will refer to my two projects as infra (all of our share none service specific code goes here) and ms (service level pulumi code that is only meant for that service) on infra we have one stack called base. In this stack a create base common shared secrets, that do not change from environment to environment. I create an ssm entry and set it to the value that is in my pulumi config, then I populate an array of
aws.ecs.Secret
(mentioned above) with the name that I want the variable to be in the container (name) and the arn of the param. I then export this
aws.ecs.Secret[]
for later stack reference. I then do the exact same thing for the envSecrets in infra on the dev stack. These values are things like DB connection strings that need the same variable name in the container, but have different values per env. These values use the env name (dev, stage, prod) so the values can be different per environment. Then I export a similar
aws.ecs.Secret[]
. I now have two different stacks (base and dev) each with different secret arrays on infra. On ms I then import that with a stack reference AS
pulumi.Output<aws.ecs.Secret[])
I do this because later I have to use apply to merge the two arrays together. This is really messy and frankly bad code. It assumes that I will always be handed the proper data, I genericly hate using
as
like this. And then merging the two arrays the way you have to is not ideal. I do it this way though because
FargateTaskDefinitionArgs
/
Container
/
secrets
is expecting only the type of `pulumi.Input<aws.ecs.Secret[]>
Copy code
const baseSecretArns = baseStackRef.getOutput('baseSecrets') as pulumi.Output<aws.ecs.Secret[]>; //Please don't do this. 
  const envSecretArns = envStackRef.getOutput(`envSecrets`) as pulumi.Output<aws.ecs.Secret[]>;
  
	const secrets: pulumi.Output<aws.ecs.Secret[]> = pulumi
    .all([baseSecretArns, envSecretArns])
    .apply(([base, env]) => {
      return base.concat(env);
    });
The end goal, I would like to have both of the arrays combined on the infra side and stored as an export per environment (dev, stage, prod), that way when I do an env stack reference on ms I will get one big
pulumi.Output<aws.ecs.Secret[]>
that I can just pass into secrets. So every environment will grab the base secrets array that has already been made and add it to their own array. The nice thing here is, when I do the stack reference I will not need to do the as, because pulumi can infere the type when I pass it in. So the code is cleaner and I can avoid that as statement on ms. The challenge that I face is, on infra, when I cam creating the env variables on the dev stack, I can not find a good way to "import" the config values of the base stack. I think I can do a stack reference into my env stack and just pull the base secrets array in. However, that is going to give me a pulumi.Output<T> I am not sure how to pull T out, unless .apply is the right way to do that, then I will just do that. What I mean is, I can not combine pulumi.Output<aws.ecs.Secret[]> with aws.ecs.Secret[]. The type are not compatible. I just thought about this though as I have typed all this out, I am going to have trouble when I update anything in the base stack, EVERY stack in my infra will need to run an update to pull the latest values.... I think I might just need a different way to think about this problem ultimately. Maybe a better route is to keep environment specific variables in ms. This will be annoying because if one of those env specific variables needs updated, like a DB connection string, it is going to have to be updated on every project.
l
Nice write-up! I see a few things to talk about, but I promise I'll try to focus on just problem you're currently trying to solve. Yesterday, I really muddled the waters by getting distracted.
Assuming that the infra/dev stack can be absolutely guaranteed that the infra/base stack has already been upped, then I suggest importing the base env secrets stack reference into dev, and exporting both the dev and base+dev secrets from there.
If you do that, does the problem become: "how do I merge Output<aws.ecs.Secret[]> with aws.ecs.Secret[]?"?
a
It does, there is also another problem too, if I do merge base in the dev stack and update base, ALLLL stack will need to be updated, not exactly a problem, but it can be missed pretty easy by someone coming in.
I would like to know how to merge them regardless.
l
Yes, there's a separate question of how to lay out resources across stacks and projects. Maybe that deserves its own question later.
If I was writing a method/function in typescript to do what you're describing, I'd go generic and write a function to merge two Input<T[]> objects, but we can get to that later.
Untitled.ts
a
I am begining to think the only option is to import them both into ms to make the merge there. I am at least guaranteed that I am always pulling the latest values from the base and env stack, and I am not going to have to worry if dev does not have the latest base stack
l
Yes. If deployment order is important, then you should do that. The function above can be run anywhere.
a
I think I need to do that on the MS side then. I think I am trying to over engineer this. I have to share this file with others when I get it done, because they are having the same problem, so I want this to be really easy for them to use. I thought it would be ideal for it to just return everything it needs in one go. without a bunch of manipulation. The bad part is, there is not way for you to be picky in what you select from an export, so on the ms side, am going to have to do a for each loop over what variables they need for that specific project, and pull them out, I can probably do that in the snnipits you sent pretty easy actually. So maybe it really is best to do it this way.
l
It sounds like the specific project is the place to decide what properties it needs. Base projects shouldn't know much about specific projects, if possible.
I also think you might be able to change your project / stack structure to make things easier. It is very rare to have dependencies between stacks on the same project. Across all the clients and projects I've worked with, I have one, and I hate it.
a
Okay, sounds like I would hate my life. So you use apply to "pull" objects out of outputs basically, in lay man terms.
l
Yes. But you need to remember that they remain in Outputs.
a
they remain outputs when they come out of the function right?
l
Yes. That's not a problem if they're being passed into other resource constructors though, which they almost always are.
a
Awesome! Now that we cleared that all up, I guess a bigger question is, am I even going about this the right way? Is this approach sane?
I am the only DevOps on the team, so I have no one to bounce this off of to have them tell me I am an idiot lol
l
The project layout? Maybe a new question, specific to that? You should be able to re-use chunks of the first post in this thread 🙂
s/I am the only DevOps on the team/I am the only infrastructure coder on the team/
DevOps is a philosophy, like Agile. You're not the only Agile on a team, and you can't be the only DevOps on a team.
a
That is True, I am the only engineer that knows anything about this thuogh.
l
You could put deployment version numbers in stacks, or something like that. Then assert on them in all projects.
(In ms project) If base version > dev version then throw exception "Someone forgot to deploy infra/dev, they owe you coffee!"
Not the best solution, but it would work without re-engineering.
a
HAHAHA That could work, but I think what we talked about before is better. Just not as clean as I want it to be. I need to figure out how to wrap this in a pretty bow to share now.
l
I don't think it's an either/or. If there's a risk of a bad deployment order, then you need to build safety in. If you re-engineer to remove that risk, then you won't have to.