Use current deployment context in SCRIPT_RUN stage
What would you like to be added: Use current deployment context (like DeploymentTrigger, DeploymentStatus, etc.) in SCRIPT_RUN stage. refs: https://pipecd.dev/docs-v0.46.x/user-guide/managing-application/customizing-deployment/script-run/
Why is this needed: Since we don't know about the current deployment, it is difficult to write a script for customization of the deployment process.
This is similar to GitHubAction, where we can access job and step contexts through a defined property. refs: https://docs.github.com/en/actions/learn-github-actions/contexts#job-context
We look forward to this feature!
In our use case, we want to get the Summary including a docker image tag and deployment ID.
@minhquang4334 @peaceiris Sorry for the late response 🙏
We can realize it by adding the default environment variable for SR_XX (like SR_DEPLOYMENT_ID).
How about this?
apiVersion: pipecd.dev/v1beta1
kind: KubernetesApp
spec:
name: script-run
labels:
env: example
team: product
pipeline:
stages:
- name: K8S_CANARY_ROLLOUT
with:
replicas: 10%
- name: WAIT
with:
duration: 10s
- name: SCRIPT_RUN
with:
run: |
echo $SR_DEPLOYMENT_ID
- name: K8S_PRIMARY_ROLLOUT
- name: K8S_CANARY_CLEAN
environment variable for SR_XX (like SR_DEPLOYMENT_ID).
LGTM ʕ◔ϖ◔ʔ
We can realize it by adding the default environment variable for SR_XX (like SR_DEPLOYMENT_ID).
LGTM 🐳 @ffjlabo
Thanks, both 👍 I will try it.
Also, I received a comment from @khanhtc1202 about the implementation. We should check whether the env values are shared by multiple deployments.
So at first, I will investigate it :)
After the investigation, I found out the way is possible. 👍 I will implement it later.
Detail
As the official document, os/exec package executes the command as a new process.
Package exec runs external commands. It wraps os.StartProcess to make it easier to remap stdin and stdout, connect I/O with pipes, and do other adjustments. https://pkg.go.dev/os/exec
Proceses usually have their own environment variable and separate them.
Also, I tested the behavior using the code below, and it works as I expected.
package main
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"golang.org/x/sync/errgroup"
)
func main() {
// This example shows that each exec.Cmd doesn't share the env value.
// Scenario:
// When executing "echo $DEPLOYMENT_ID" asynchronously with two exec.Cmd,
// The one is executed after 10s with "sleep 10", the other without any waiting time.
// Result:
// The output of the first command is "one" and the second is "two". Not shared.
/*
% go run main.go
===== D2 ======
output: two
err:
===== D1 (execute after 5s) ======
output: one
err:
*/
eg, _ := errgroup.WithContext(context.TODO())
eg.Go(func() error {
var outBuf, errBuf bytes.Buffer
cmd := exec.Command("/bin/sh", "-l", "-c", "sleep 5 && echo $DEPLOYMENT_ID")
cmd.Env = append(os.Environ(), "DEPLOYMENT_ID=one")
cmd.Stdout = &outBuf
cmd.Stderr = &errBuf
if err := cmd.Run(); err != nil {
return err
}
fmt.Println("===== D1 (execute after 5s) ======")
fmt.Println("output:", outBuf.String())
fmt.Println("err:", errBuf.String())
return nil
})
eg.Go(func() error {
var outBuf, errBuf bytes.Buffer
cmd := exec.Command("/bin/sh", "-l", "-c", "echo $DEPLOYMENT_ID")
cmd.Env = append(os.Environ(), "DEPLOYMENT_ID=two")
cmd.Stdout = &outBuf
cmd.Stderr = &errBuf
if err := cmd.Run(); err != nil {
return err
}
fmt.Println("===== D2 ======")
fmt.Println("output:", outBuf.String())
fmt.Println("err:", errBuf.String())
return nil
})
if err := eg.Wait(); err != nil {
fmt.Printf("error :%v\n", err)
}
}