This message was deleted.
# general
s
This message was deleted.
b
I have a docker container with pulumi and python installed, I mount my container on top of my repo with the pulumi code. I've been experimenting with python threads to deploy multiple services at the same time. I get random "unknown errors" during deployment with multiple threads. If I deploy them with a wait time inbetween, ir make them sequential, it is OK. This would be for the same folder, but multiple stacks in the folder,
Is something like this possible? Essentially it is python threads running check_output() calls to invoke the cli multiple times on multiple stacks in the same folder.
l
Are your built artifacts (.pyc files and so on) all in the same directory hierarchy? If you configure your builds/threads to output all built files to different locations, that would eliminate one potential source of conflicts...
b
I was wondering if making a copy of the folder at runtime, one for each thread, would allow me to run multiple concurrent threads if this is some type of limitation
I'm using typescript on the pulumi side, python for my orchestration cli
The python is installed at runtime on the container build
l
Then you could try specifying a different outDir for each bulid in your tsconfig.json file.
Since you're using Docker, you could orchestrate outside Docker, and use a different container (same image) for each deploy?
And if your outDir points to a non-bind-mounted location, you should be able to avoid that source of errors.
Not that conflicting output files is definitely the problem.. just a guess.
b
Yea, I was doing that previously with Jenkins (unfortunately), but it was hitting resource limits trying to do 15 service deploys at same time
l
You could have your Python app invoke Docker, and Jenkins just invokes a single Python app...
b
I actually don't think I have any tsconfig files in my directory tree any longer.. I have a single package.json file at top of all the sub folders with the stack TS files
l
Oh, so where do the .js files appear?
b
.ts, and they are in sub folders like: pulumi/ package.json stack1/ .gitignore index.ts Pulumi.yaml Pulumi.dev-green.yaml Pulumi.dev-blue.yaml stack2/ (Same)
so I'd have multiple threads in python CD to the same dir, then run
pulumi stack select A
,
pulumi update -y
via subprocess
l
No, I meant the .js files that tsc builds from the .ts files.
b
oh, beats me, I don't see them in the working dir
l
That may be the problem: one process is running the Pulumi app, and another one is transpiling it from .ts to .js, causing the first process to break.
That's what tsconfig.json's outDir property is for. If every process is compiling the same files to the same directory, the you may get race conditions. If they're all compiling to different directories, you may avoid that.
b
I wonder if I could either set outdir at run time, or generate a new tsconfig before launching each thread
l
Yep. Or configure outDir to be some location that's different for each thread. That's the challenge 🙂
b
I think that wouldn't be so hard, just use /tmp/{guid} or similar
is that a runtime flag option for pulumi to set outDir?
l
Not as far as I know.. it's a typescript thing, not a Pulumi thing...
b
ok yea makes sense, wonder if can set an env var or something
l
And all of this is just a maybe.. we don't know that this is what's causing the problem.. you might spend 4 hours on this and the problem hasn't been resolved 😞
Good luck!
b
Thanks, ill keep poking at it, appreciate the help!
👍 1
just FYI, tried this today and no dice, I used a quick and dirty way to do this, I used jinja CLI to update the tsconfig.json on each thread run right before running an update: this is a bit of the mixed-thread log outputs, this type of random error is what occurs when I run them too close together. This time I added a couple of commands to create a local tmp dir for each deploy, and then update the tsconfig to point to that new folder just before running pulumi up, hoping that would get each compiliation to use its own dir - didn't work 😕 if I space the threads out 30 sec apart, it is ok, but then it sorta nullifies the benefit of the threading with 15 services going up simultaneously.
Copy code
[DEBUG] MYCOMPANY SERVICE DEPLOY PULUMI CMD LIST: [
  'pulumi stack select mycompany-ecs-services.us-east-1.stage.userservice.blue', 
  'pulumi refresh --yes', 
  'pulumi config set aws:region us-east-1', 
  'mkdir tmp/HXKdIUPPXo', 
  'OUTDIR=HXKdIUPPXo jinja2 tsconfig.json.j2 > tsconfig.json', 
  'TASK_REVISION=169 pulumi update --yes'
]                   
 +  pulumi:pulumi:Stack mycompany-ecs-services-mycompany-ecs-services.us-east-1.stage.apigateway.blue create error: an unhandled error occurred: Program exited with non-zero exit code: -1
 +  pulumi:pulumi:Stack mycompany-ecs-services-mycompany-ecs-services.us-east-1.stage.apigateway.blue create 1 error

Diagnostics:
  pulumi:pulumi:Stack (mycompany-ecs-services-mycompany-ecs-services.us-east-1.stage.apigateway.blue):
    error: an unhandled error occurred: Program exited with non-zero exit code: -1
l
I wonder if AutomationAPI would be a better way to go. It does seem likely that the problem is race conditions, probably on local files; automation-api presumably handles this, since parallelism would be a key driver for adopting it. Maybe @lemon-agent-27707 would have opinions on this thread?
l
👋 If you want to use python to orchestrate updates, check out the automation api. @red-match-15116 has been working on python support. You can use it to run updates on programs written in a different language like typescript. There are a few caveats with concurrency. Inline programs written in node and python do not support concurrent updates. Go inline programs do support concurrent updates. Things like changing the selected stack and setting configuration are generally not safe to do concurrently, but we are working on improving that. TLDR python automation api should be able to run concurrent updates of multiple typescript stacks. You may need some special considerations for setup (setting up config in serial)
👍 1
b
Hi Evan, thanks! What do you mean by "inline" programs? And yes, I've seen the automation API and it does seem like a better option. I'll check it out. Also, I should switch to Go 🤣
l
An inline program is a single
main.py
file that can be executed without the CLI: https://github.com/pulumi/automation-api-examples/blob/main/python/inline_program/main.py It includes both the pulumi program as a function (the inline program) and the automation api script that drives the deployment. A local program is what we think of as a standard CLI driven pulumi program. The automation API is a python script in this example, and the program it runs is an independent pulumi project (that you could also theoretically use the CLI to run) https://github.com/pulumi/automation-api-examples/tree/main/python/local_program
b
hi @lemon-agent-27707 - thanks for this. I'm going to be starting down a new path, a complete refactor if you will.. I'd like to use the approaches described here in terms of advanced orchestration (previously using my python package and pulumi cli), but I'd like to start out using the Automation API. Is Typescript still the most "mature" in terms of the automation API? and Pulumi in general? If you were starting over today, and intend to use Pulumi + Automation API for a foundation for a new platform, would you chose Typescript? (assume that knowledge of language syntax is not a concern) thanks!
l
Personally, my favorite language for writing pulumi programs is typescript (due to the type system). My favorite language for Automation API is Go. Go naturally lends itself nicely to building http servers, nice error handling, and building CLIs (the cobra package for instance).
Go inline programs can run concurrently. Other languages can achieve the same results by opting for local programs instead of inline programs.
b
yea, after writing my orchestrator in python with
click
and making a CLI out of it, then dealing with handling threads, it made me wish I had gone with
Go
🙂 so, it's possible to write a CLI with Go and use the Automation API in Go to trigger/run stacks written in Typescript?
how is the Automation API maturity with Go ?
l
Both Go and Typescript have been out for months, have lots of users, and received many bug fixes. Python just shipped today, there will probably be a few bugs to fix here and there but the quality is high.
it's possible to write a CLI with Go and use the Automation API in Go to trigger/run stacks written in Typescript?
Yes. See this example: https://github.com/pulumi/automation-api-examples/tree/main/go/local_program The local program is written in Go here (https://github.com/pulumi/automation-api-examples/tree/main/go/local_program/fargate), but it could be any other pulumi language.
b
Awesome, thank you!
hi @lemon-agent-27707 - so I've been working on this, I hope you don't mind me asking a couple more questions. I prefer to write micro-stacks. I'm thinking that I would like to have a folder of micro-stacks, and then above that I'd like to have a folder of automation scripts. The automation scripts would basically orchestrate the deployment of an "area" which may be like ALB + ECS cluster + IAM roles + Autoscaling + Logging etc. Most of the micro-stacks are already written in Typescript. I'd like to write a CLI tool in GO + cobra to help simply the CLI aspects. My question is about the automation scripts. I'd like the CLI to be able to simply load an automation script via CLI command, something like
ops -script services-refresh -env prod -region us-west-2
so the GO would (I assume) run an inline automation program, which will then run updates on several micro stacks, probably setting some config values to them as passed in by the CLI arguments. I'd like your advice on what language you think those should be, and if they are GO, I'm assuming the GO cli can basically sub-execute the automation scripts as an inline GO program. Does that sound reasonable? I think that seems more reasonable than using a GO cli to execute inline node automation programs (or maybe it doesn't really matter). But I'd like to avoid having to bake in the automation scripts to the GO cli. I'd like the CLI to be able to be ran from inside of different repos containing this type of configuration so it is portable to many projects. Any advice is appreciated 🙏
l
Definitely! Have you had a chance to look through the go examples? There are a few interesting ones: https://github.com/pulumi/automation-api-examples/tree/main/go 1. vm manager: go cobra CLI + go inline programs 2. hybrid: go automation api script, that uses an inline program. But this program is factored into a separate module so that it can also be used with the pulumi CLI. So one thing to note is that Go automation api can only execute inline programs written in go. If you want to use another language like nodejs for your program, that would be a local program. Local programs and normal pulumi-cli-driven programs that you can use without automation api. It sounds like you want to be able to author the CLI in Go, so you would be using automation API in go. Then it sounds like you also want to be able to use the pulumi CLI with each program. That likely means you want to use local programs. In this case, it doesn't matter what language the local pulumi program is written in, I would just juse whatever you're comfortable with.
b
great, I'll check these examples out, I did look through the ones you posted previously. Am I able to load the automation scripts/commands on the fly with the CLI? As in I'll be able to run the built GO cli inside of a repo that has automation scripts sitting in it? I would imagine that the CLI would need to take the arguments passed in, and navigate to the folder containing the specified script, and then run that automation script which will in turn run the local microstacks written in typescript
l
What you do here depends on your use case, and how flexible you need to be. Are there a static set of projects that it needs to work with that are laid out in a consistent directory structure, or do you need to be able to adapt to any old pulumi program in the directory? These sort of things will influence your usage of automation api.
b
thanks, I'll read through some of these examples and play around with the automation API a bit first. Seems like I need to dive in a bit more. Basically I want an automation script to handle multple micro-stacks and facilitate moving data between them and doing some checks in between steps. I was thinking that a GO cli might be nice to handle the execution of these automation scripts, but maybe I should just invoke them directly. I really appreciate your replying 👍
138 Views