mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-16 11:25:14 +00:00
Refactor agent (#2021)
- code cleanup - init backend engine only once - pass a taskUUID to the backend --- *Sponsored by Kithara Software GmbH*
This commit is contained in:
parent
f464156917
commit
3cd78c9409
10 changed files with 110 additions and 72 deletions
|
@ -15,7 +15,6 @@
|
||||||
package agent
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/rpc"
|
"github.com/woodpecker-ci/woodpecker/pipeline/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *Runner) createLogger(_ context.Context, logger zerolog.Logger, uploads *sync.WaitGroup, work *rpc.Pipeline) pipeline.LogFunc {
|
func (r *Runner) createLogger(logger zerolog.Logger, uploads *sync.WaitGroup, work *rpc.Pipeline) pipeline.LogFunc {
|
||||||
return func(step *backend.Step, rc multipart.Reader) error {
|
return func(step *backend.Step, rc multipart.Reader) error {
|
||||||
loglogger := logger.With().
|
loglogger := logger.With().
|
||||||
Str("image", step.Image).
|
Str("image", step.Image).
|
||||||
|
@ -55,12 +54,8 @@ func (r *Runner) createLogger(_ context.Context, logger zerolog.Logger, uploads
|
||||||
log.Error().Err(err).Msg("copy limited logStream part")
|
log.Error().Err(err).Msg("copy limited logStream part")
|
||||||
}
|
}
|
||||||
|
|
||||||
loglogger.Debug().Msg("log stream copied")
|
loglogger.Debug().Msg("log stream copied, close ...")
|
||||||
|
uploads.Done()
|
||||||
defer func() {
|
|
||||||
loglogger.Debug().Msg("log stream closed")
|
|
||||||
uploads.Done()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package agent
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -140,7 +141,8 @@ func (r *Runner) Run(runnerCtx context.Context) error {
|
||||||
var uploads sync.WaitGroup
|
var uploads sync.WaitGroup
|
||||||
err = pipeline.New(work.Config,
|
err = pipeline.New(work.Config,
|
||||||
pipeline.WithContext(workflowCtx),
|
pipeline.WithContext(workflowCtx),
|
||||||
pipeline.WithLogger(r.createLogger(ctxmeta, logger, &uploads, work)),
|
pipeline.WithTaskUUID(fmt.Sprint(work.ID)),
|
||||||
|
pipeline.WithLogger(r.createLogger(logger, &uploads, work)),
|
||||||
pipeline.WithTracer(r.createTracer(ctxmeta, logger, work)),
|
pipeline.WithTracer(r.createTracer(ctxmeta, logger, work)),
|
||||||
pipeline.WithEngine(*r.engine),
|
pipeline.WithEngine(*r.engine),
|
||||||
pipeline.WithDescription(map[string]string{
|
pipeline.WithDescription(map[string]string{
|
||||||
|
|
|
@ -215,20 +215,20 @@ func run(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// load engine (e.g. init api client)
|
||||||
|
if err := engine.Load(backendCtx); err != nil {
|
||||||
|
log.Error().Err(err).Msg("cannot load backend engine")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debug().Msgf("loaded %s backend engine", engine.Name())
|
||||||
|
|
||||||
for i := 0; i < parallel; i++ {
|
for i := 0; i < parallel; i++ {
|
||||||
|
i := i
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
// load engine (e.g. init api client)
|
|
||||||
err = engine.Load(backendCtx)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("cannot load backend engine")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
r := agent.NewRunner(client, filter, hostname, counter, &engine)
|
r := agent.NewRunner(client, filter, hostname, counter, &engine)
|
||||||
|
log.Debug().Msgf("created new runner %d", i)
|
||||||
log.Debug().Msgf("loaded %s backend engine", engine.Name())
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if sigterm.IsSet() {
|
if sigterm.IsSet() {
|
||||||
|
|
|
@ -101,7 +101,9 @@ func (e *docker) Load(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *docker) Setup(_ context.Context, conf *backend.Config) error {
|
func (e *docker) SetupWorkflow(_ context.Context, conf *backend.Config, taskUUID string) error {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msg("create workflow environment")
|
||||||
|
|
||||||
for _, vol := range conf.Volumes {
|
for _, vol := range conf.Volumes {
|
||||||
_, err := e.client.VolumeCreate(noContext, volume.VolumeCreateBody{
|
_, err := e.client.VolumeCreate(noContext, volume.VolumeCreateBody{
|
||||||
Name: vol.Name,
|
Name: vol.Name,
|
||||||
|
@ -128,7 +130,9 @@ func (e *docker) Setup(_ context.Context, conf *backend.Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *docker) Exec(ctx context.Context, step *backend.Step) error {
|
func (e *docker) StartStep(ctx context.Context, step *backend.Step, taskUUID string) error {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("start step %s", step.Name)
|
||||||
|
|
||||||
config := toConfig(step)
|
config := toConfig(step)
|
||||||
hostConfig := toHostConfig(step)
|
hostConfig := toHostConfig(step)
|
||||||
containerName := toContainerName(step)
|
containerName := toContainerName(step)
|
||||||
|
@ -204,7 +208,9 @@ func (e *docker) Exec(ctx context.Context, step *backend.Step) error {
|
||||||
return e.client.ContainerStart(ctx, containerName, startOpts)
|
return e.client.ContainerStart(ctx, containerName, startOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *docker) Wait(ctx context.Context, step *backend.Step) (*backend.State, error) {
|
func (e *docker) WaitStep(ctx context.Context, step *backend.Step, taskUUID string) (*backend.State, error) {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("wait for step %s", step.Name)
|
||||||
|
|
||||||
containerName := toContainerName(step)
|
containerName := toContainerName(step)
|
||||||
|
|
||||||
wait, errc := e.client.ContainerWait(ctx, containerName, "")
|
wait, errc := e.client.ContainerWait(ctx, containerName, "")
|
||||||
|
@ -228,7 +234,9 @@ func (e *docker) Wait(ctx context.Context, step *backend.Step) (*backend.State,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *docker) Tail(ctx context.Context, step *backend.Step) (io.ReadCloser, error) {
|
func (e *docker) TailStep(ctx context.Context, step *backend.Step, taskUUID string) (io.ReadCloser, error) {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("tail logs of step %s", step.Name)
|
||||||
|
|
||||||
logs, err := e.client.ContainerLogs(ctx, toContainerName(step), logsOpts)
|
logs, err := e.client.ContainerLogs(ctx, toContainerName(step), logsOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -244,7 +252,9 @@ func (e *docker) Tail(ctx context.Context, step *backend.Step) (io.ReadCloser, e
|
||||||
return rc, nil
|
return rc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *docker) Destroy(_ context.Context, conf *backend.Config) error {
|
func (e *docker) DestroyWorkflow(_ context.Context, conf *backend.Config, taskUUID string) error {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("delete workflow environment")
|
||||||
|
|
||||||
for _, stage := range conf.Stages {
|
for _, stage := range conf.Stages {
|
||||||
for _, step := range stage.Steps {
|
for _, step := range stage.Steps {
|
||||||
containerName := toContainerName(step)
|
containerName := toContainerName(step)
|
||||||
|
|
|
@ -115,8 +115,8 @@ func (e *kube) Load(context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the pipeline environment.
|
// Setup the pipeline environment.
|
||||||
func (e *kube) Setup(ctx context.Context, conf *types.Config) error {
|
func (e *kube) SetupWorkflow(ctx context.Context, conf *types.Config, taskUUID string) error {
|
||||||
log.Trace().Msgf("Setting up Kubernetes primitives")
|
log.Trace().Str("taskUUID", taskUUID).Msgf("Setting up Kubernetes primitives")
|
||||||
|
|
||||||
for _, vol := range conf.Volumes {
|
for _, vol := range conf.Volumes {
|
||||||
pvc, err := PersistentVolumeClaim(e.config.Namespace, vol.Name, e.config.StorageClass, e.config.VolumeSize, e.config.StorageRwx)
|
pvc, err := PersistentVolumeClaim(e.config.Namespace, vol.Name, e.config.StorageClass, e.config.VolumeSize, e.config.StorageRwx)
|
||||||
|
@ -168,25 +168,27 @@ func (e *kube) Setup(ctx context.Context, conf *types.Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the pipeline step.
|
// Start the pipeline step.
|
||||||
func (e *kube) Exec(ctx context.Context, step *types.Step) error {
|
func (e *kube) StartStep(ctx context.Context, step *types.Step, taskUUID string) error {
|
||||||
pod, err := Pod(e.config.Namespace, step, e.config.PodLabels, e.config.PodAnnotations)
|
pod, err := Pod(e.config.Namespace, step, e.config.PodLabels, e.config.PodAnnotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Msgf("Creating pod: %s", pod.Name)
|
log.Trace().Str("taskUUID", taskUUID).Msgf("Creating pod: %s", pod.Name)
|
||||||
_, err = e.client.CoreV1().Pods(e.config.Namespace).Create(ctx, pod, metav1.CreateOptions{})
|
_, err = e.client.CoreV1().Pods(e.config.Namespace).Create(ctx, pod, metav1.CreateOptions{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the pipeline step to complete and returns
|
// Wait for the pipeline step to complete and returns
|
||||||
// the completion results.
|
// the completion results.
|
||||||
func (e *kube) Wait(ctx context.Context, step *types.Step) (*types.State, error) {
|
func (e *kube) WaitStep(ctx context.Context, step *types.Step, taskUUID string) (*types.State, error) {
|
||||||
podName, err := dnsName(step.Name)
|
podName, err := dnsName(step.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("Waiting for pod: %s", podName)
|
||||||
|
|
||||||
finished := make(chan bool)
|
finished := make(chan bool)
|
||||||
|
|
||||||
podUpdated := func(old, new interface{}) {
|
podUpdated := func(old, new interface{}) {
|
||||||
|
@ -239,12 +241,14 @@ func (e *kube) Wait(ctx context.Context, step *types.Step) (*types.State, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tail the pipeline step logs.
|
// Tail the pipeline step logs.
|
||||||
func (e *kube) Tail(ctx context.Context, step *types.Step) (io.ReadCloser, error) {
|
func (e *kube) TailStep(ctx context.Context, step *types.Step, taskUUID string) (io.ReadCloser, error) {
|
||||||
podName, err := dnsName(step.Name)
|
podName, err := dnsName(step.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("Tail logs of pod: %s", podName)
|
||||||
|
|
||||||
up := make(chan bool)
|
up := make(chan bool)
|
||||||
|
|
||||||
podUpdated := func(old, new interface{}) {
|
podUpdated := func(old, new interface{}) {
|
||||||
|
@ -308,7 +312,9 @@ func (e *kube) Tail(ctx context.Context, step *types.Step) (io.ReadCloser, error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy the pipeline environment.
|
// Destroy the pipeline environment.
|
||||||
func (e *kube) Destroy(_ context.Context, conf *types.Config) error {
|
func (e *kube) DestroyWorkflow(_ context.Context, conf *types.Config, taskUUID string) error {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msg("Deleting Kubernetes primitives")
|
||||||
|
|
||||||
gracePeriodSeconds := int64(0) // immediately
|
gracePeriodSeconds := int64(0) // immediately
|
||||||
dpb := metav1.DeletePropagationBackground
|
dpb := metav1.DeletePropagationBackground
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alessio/shellescape"
|
"github.com/alessio/shellescape"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/backend/types"
|
"github.com/woodpecker-ci/woodpecker/pipeline/backend/types"
|
||||||
|
@ -74,8 +75,10 @@ func (e *local) Load(context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the pipeline environment.
|
// SetupWorkflow the pipeline environment.
|
||||||
func (e *local) Setup(_ context.Context, c *types.Config) error {
|
func (e *local) SetupWorkflow(_ context.Context, conf *types.Config, taskUUID string) error {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msg("create workflow environment")
|
||||||
|
|
||||||
baseDir, err := os.MkdirTemp("", "woodpecker-local-*")
|
baseDir, err := os.MkdirTemp("", "woodpecker-local-*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -98,7 +101,7 @@ func (e *local) Setup(_ context.Context, c *types.Config) error {
|
||||||
|
|
||||||
// TODO: copy plugin-git binary to homeDir and set PATH
|
// TODO: copy plugin-git binary to homeDir and set PATH
|
||||||
|
|
||||||
workflowID, err := e.getWorkflowIDFromConfig(c)
|
workflowID, err := e.getWorkflowIDFromConfig(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -108,8 +111,10 @@ func (e *local) Setup(_ context.Context, c *types.Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec the pipeline step.
|
// StartStep the pipeline step.
|
||||||
func (e *local) Exec(ctx context.Context, step *types.Step) error {
|
func (e *local) StartStep(ctx context.Context, step *types.Step, taskUUID string) error {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("start step %s", step.Name)
|
||||||
|
|
||||||
state, err := e.getWorkflowStateFromStep(step)
|
state, err := e.getWorkflowStateFromStep(step)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -163,9 +168,11 @@ func (e *local) Exec(ctx context.Context, step *types.Step) error {
|
||||||
return cmd.Start()
|
return cmd.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the pipeline step to complete and returns
|
// WaitStep for the pipeline step to complete and returns
|
||||||
// the completion results.
|
// the completion results.
|
||||||
func (e *local) Wait(_ context.Context, step *types.Step) (*types.State, error) {
|
func (e *local) WaitStep(_ context.Context, step *types.Step, taskUUID string) (*types.State, error) {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("wait for step %s", step.Name)
|
||||||
|
|
||||||
state, err := e.getWorkflowStateFromStep(step)
|
state, err := e.getWorkflowStateFromStep(step)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -192,14 +199,17 @@ func (e *local) Wait(_ context.Context, step *types.Step) (*types.State, error)
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tail the pipeline step logs.
|
// TailStep the pipeline step logs.
|
||||||
func (e *local) Tail(context.Context, *types.Step) (io.ReadCloser, error) {
|
func (e *local) TailStep(_ context.Context, step *types.Step, taskUUID string) (io.ReadCloser, error) {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("tail logs of step %s", step.Name)
|
||||||
return e.output, nil
|
return e.output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy the pipeline environment.
|
// DestroyWorkflow the pipeline environment.
|
||||||
func (e *local) Destroy(_ context.Context, c *types.Config) error {
|
func (e *local) DestroyWorkflow(_ context.Context, conf *types.Config, taskUUID string) error {
|
||||||
state, err := e.getWorkflowStateFromConfig(c)
|
log.Trace().Str("taskUUID", taskUUID).Msgf("delete workflow environment")
|
||||||
|
|
||||||
|
state, err := e.getWorkflowStateFromConfig(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -209,7 +219,7 @@ func (e *local) Destroy(_ context.Context, c *types.Config) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
workflowID, err := e.getWorkflowIDFromConfig(c)
|
workflowID, err := e.getWorkflowIDFromConfig(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/melbahja/goph"
|
"github.com/melbahja/goph"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/backend/common"
|
"github.com/woodpecker-ci/woodpecker/pipeline/backend/common"
|
||||||
|
@ -79,13 +80,15 @@ func (e *ssh) Load(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the pipeline environment.
|
// SetupWorkflow create the workflow environment.
|
||||||
func (e *ssh) Setup(_ context.Context, _ *types.Config) error {
|
func (e *ssh) SetupWorkflow(context.Context, *types.Config, string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec the pipeline step.
|
// StartStep start the step.
|
||||||
func (e *ssh) Exec(ctx context.Context, step *types.Step) error {
|
func (e *ssh) StartStep(ctx context.Context, step *types.Step, taskUUID string) error {
|
||||||
|
log.Trace().Str("taskUUID", taskUUID).Msgf("Start step %s", step.Name)
|
||||||
|
|
||||||
// Get environment variables
|
// Get environment variables
|
||||||
var command []string
|
var command []string
|
||||||
for a, b := range step.Environment {
|
for a, b := range step.Environment {
|
||||||
|
@ -124,21 +127,21 @@ func (e *ssh) Exec(ctx context.Context, step *types.Step) error {
|
||||||
return e.cmd.Start()
|
return e.cmd.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the pipeline step to complete and returns
|
// WaitStep for the pipeline step to complete and returns
|
||||||
// the completion results.
|
// the completion results.
|
||||||
func (e *ssh) Wait(context.Context, *types.Step) (*types.State, error) {
|
func (e *ssh) WaitStep(context.Context, *types.Step, string) (*types.State, error) {
|
||||||
return &types.State{
|
return &types.State{
|
||||||
Exited: true,
|
Exited: true,
|
||||||
}, e.cmd.Wait()
|
}, e.cmd.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tail the pipeline step logs.
|
// TailStep the pipeline step logs.
|
||||||
func (e *ssh) Tail(context.Context, *types.Step) (io.ReadCloser, error) {
|
func (e *ssh) TailStep(context.Context, *types.Step, string) (io.ReadCloser, error) {
|
||||||
return e.output, nil
|
return e.output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy the pipeline environment.
|
// DestroyWorkflow delete the workflow environment.
|
||||||
func (e *ssh) Destroy(context.Context, *types.Config) error {
|
func (e *ssh) DestroyWorkflow(context.Context, *types.Config, string) error {
|
||||||
e.client.Close()
|
e.client.Close()
|
||||||
sftp, err := e.client.NewSftp()
|
sftp, err := e.client.NewSftp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,25 +11,25 @@ type Engine interface {
|
||||||
// Name returns the name of the backend.
|
// Name returns the name of the backend.
|
||||||
Name() string
|
Name() string
|
||||||
|
|
||||||
// Check if the backend is available.
|
// IsAvailable check if the backend is available.
|
||||||
IsAvailable(context.Context) bool
|
IsAvailable(ctx context.Context) bool
|
||||||
|
|
||||||
// Load the backend engine.
|
// Load the backend engine.
|
||||||
Load(context.Context) error
|
Load(ctx context.Context) error
|
||||||
|
|
||||||
// Setup the pipeline environment.
|
// SetupWorkflow the workflow environment.
|
||||||
Setup(context.Context, *Config) error
|
SetupWorkflow(ctx context.Context, conf *Config, taskUUID string) error
|
||||||
|
|
||||||
// Exec start the pipeline step.
|
// StartStep start the workflow step.
|
||||||
Exec(context.Context, *Step) error
|
StartStep(ctx context.Context, step *Step, taskUUID string) error
|
||||||
|
|
||||||
// Wait for the pipeline step to complete and returns
|
// WaitStep for the workflow step to complete and returns
|
||||||
// the completion results.
|
// the completion results.
|
||||||
Wait(context.Context, *Step) (*State, error)
|
WaitStep(ctx context.Context, step *Step, taskUUID string) (*State, error)
|
||||||
|
|
||||||
// Tail the pipeline step logs.
|
// TailStep the workflow step logs.
|
||||||
Tail(context.Context, *Step) (io.ReadCloser, error)
|
TailStep(ctx context.Context, step *Step, taskUUID string) (io.ReadCloser, error)
|
||||||
|
|
||||||
// Destroy the pipeline environment.
|
// DestroyWorkflow the workflow environment.
|
||||||
Destroy(context.Context, *Config) error
|
DestroyWorkflow(ctx context.Context, conf *Config, taskUUID string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,3 +42,9 @@ func WithDescription(desc map[string]string) Option {
|
||||||
r.Description = desc
|
r.Description = desc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithTaskUUID(uuid string) Option {
|
||||||
|
return func(r *Runtime) {
|
||||||
|
r.taskUUID = uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
@ -16,6 +17,8 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/pipeline/multipart"
|
"github.com/woodpecker-ci/woodpecker/pipeline/multipart"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: move runtime into "runtime" subpackage
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// State defines the pipeline and process state.
|
// State defines the pipeline and process state.
|
||||||
State struct {
|
State struct {
|
||||||
|
@ -45,6 +48,8 @@ type Runtime struct {
|
||||||
tracer Tracer
|
tracer Tracer
|
||||||
logger Logger
|
logger Logger
|
||||||
|
|
||||||
|
taskUUID string
|
||||||
|
|
||||||
Description map[string]string // The runtime descriptors.
|
Description map[string]string // The runtime descriptors.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +60,7 @@ func New(spec *backend.Config, opts ...Option) *Runtime {
|
||||||
r.Description = map[string]string{}
|
r.Description = map[string]string{}
|
||||||
r.spec = spec
|
r.spec = spec
|
||||||
r.ctx = context.Background()
|
r.ctx = context.Background()
|
||||||
|
r.taskUUID = uuid.New().String()
|
||||||
for _, opts := range opts {
|
for _, opts := range opts {
|
||||||
opts(r)
|
opts(r)
|
||||||
}
|
}
|
||||||
|
@ -69,7 +75,7 @@ func (r *Runtime) MakeLogger() zerolog.Logger {
|
||||||
return logCtx.Logger()
|
return logCtx.Logger()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts the execution of the pipeline and waits for it to complete
|
// Starts the execution of an workflow and waits for it to complete
|
||||||
func (r *Runtime) Run(runnerCtx context.Context) error {
|
func (r *Runtime) Run(runnerCtx context.Context) error {
|
||||||
logger := r.MakeLogger()
|
logger := r.MakeLogger()
|
||||||
logger.Debug().Msgf("Executing %d stages, in order of:", len(r.spec.Stages))
|
logger.Debug().Msgf("Executing %d stages, in order of:", len(r.spec.Stages))
|
||||||
|
@ -86,13 +92,13 @@ func (r *Runtime) Run(runnerCtx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := r.engine.Destroy(runnerCtx, r.spec); err != nil {
|
if err := r.engine.DestroyWorkflow(runnerCtx, r.spec, r.taskUUID); err != nil {
|
||||||
logger.Error().Err(err).Msg("could not destroy engine")
|
logger.Error().Err(err).Msg("could not destroy engine")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.started = time.Now().Unix()
|
r.started = time.Now().Unix()
|
||||||
if err := r.engine.Setup(r.ctx, r.spec); err != nil {
|
if err := r.engine.SetupWorkflow(r.ctx, r.spec, r.taskUUID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,13 +221,13 @@ func (r *Runtime) execAll(steps []*backend.Step) <-chan error {
|
||||||
|
|
||||||
// Executes the step and returns the state and error.
|
// Executes the step and returns the state and error.
|
||||||
func (r *Runtime) exec(step *backend.Step) (*backend.State, error) {
|
func (r *Runtime) exec(step *backend.Step) (*backend.State, error) {
|
||||||
if err := r.engine.Exec(r.ctx, step); err != nil {
|
if err := r.engine.StartStep(r.ctx, step, r.taskUUID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
if r.logger != nil {
|
if r.logger != nil {
|
||||||
rc, err := r.engine.Tail(r.ctx, step)
|
rc, err := r.engine.TailStep(r.ctx, step, r.taskUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -246,7 +252,7 @@ func (r *Runtime) exec(step *backend.Step) (*backend.State, error) {
|
||||||
// Some pipeline backends, such as local, will close the pipe from Tail on Wait,
|
// Some pipeline backends, such as local, will close the pipe from Tail on Wait,
|
||||||
// so first make sure all reading has finished.
|
// so first make sure all reading has finished.
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
waitState, err := r.engine.Wait(r.ctx, step)
|
waitState, err := r.engine.WaitStep(r.ctx, step, r.taskUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, context.Canceled) {
|
if errors.Is(err, context.Canceled) {
|
||||||
return waitState, ErrCancel
|
return waitState, ErrCancel
|
||||||
|
|
Loading…
Reference in a new issue