Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let the backend engine report the current platform #2688

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
return err
}

if err = engine.Load(backendCtx); err != nil {
if _, err = engine.Load(backendCtx); err != nil {
return err
}

Expand Down
24 changes: 11 additions & 13 deletions cmd/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"fmt"
"net/http"
"os"
"runtime"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -57,8 +56,6 @@ func run(c *cli.Context) error {
hostname, _ = os.Hostname()
}

platform := runtime.GOOS + "/" + runtime.GOARCH

counter.Polling = c.Int("max-workflows")
counter.Running = 0

Expand Down Expand Up @@ -155,7 +152,15 @@ func run(c *cli.Context) error {
return err
}

agentConfig.AgentID, err = client.RegisterAgent(ctx, platform, engine.Name(), version.String(), parallel)
// load engine (e.g. init api client)
engInfo, err := engine.Load(backendCtx)
if err != nil {
log.Error().Err(err).Msg("cannot load backend engine")
return err
}
log.Debug().Msgf("loaded %s backend engine", engine.Name())

agentConfig.AgentID, err = client.RegisterAgent(ctx, engInfo.Platform, engine.Name(), version.String(), parallel)
if err != nil {
return err
}
Expand All @@ -164,7 +169,7 @@ func run(c *cli.Context) error {

labels := map[string]string{
"hostname": hostname,
"platform": platform,
"platform": engInfo.Platform,
"backend": engine.Name(),
"repo": "*", // allow all repos by default
}
Expand Down Expand Up @@ -195,13 +200,6 @@ 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++ {
i := i
go func() {
Expand All @@ -226,7 +224,7 @@ func run(c *cli.Context) error {

log.Info().Msgf(
"Starting Woodpecker agent with version '%s' and backend '%s' using platform '%s' running up to %d pipelines in parallel",
version.String(), engine.Name(), platform, parallel)
version.String(), engine.Name(), engInfo.Platform, parallel)

wg.Wait()
return nil
Expand Down
5 changes: 2 additions & 3 deletions pipeline/backend/common/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ package common

import (
"encoding/base64"
"runtime"
)

func GenerateContainerConf(commands []string) (env map[string]string, entry, cmd []string) {
func GenerateContainerConf(commands []string, goos string) (env map[string]string, entry, cmd []string) {
env = make(map[string]string)
if runtime.GOOS == "windows" {
if goos == "windows" {
env["CI_SCRIPT"] = base64.StdEncoding.EncodeToString([]byte(generateScriptWindows(commands)))
env["HOME"] = "c:\\root"
env["SHELL"] = "powershell.exe"
Expand Down
58 changes: 58 additions & 0 deletions pipeline/backend/common/script_win_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2022 Woodpecker Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package common

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestGenerateScriptWin(t *testing.T) {
testdata := []struct {
from []string
want string
}{
{
from: []string{"echo %PATH%", "go build", "go test"},
want: `
$ErrorActionPreference = 'Stop';
&cmd /c "mkdir c:\root";
if ($Env:CI_NETRC_MACHINE) {
$netrc=[string]::Format("{0}\_netrc",$Env:HOME);
"machine $Env:CI_NETRC_MACHINE" >> $netrc;
"login $Env:CI_NETRC_USERNAME" >> $netrc;
"password $Env:CI_NETRC_PASSWORD" >> $netrc;
};
[Environment]::SetEnvironmentVariable("CI_NETRC_PASSWORD",$null);
[Environment]::SetEnvironmentVariable("CI_SCRIPT",$null);

Write-Output ('+ "echo %PATH%"');
& echo %PATH%; if ($LASTEXITCODE -ne 0) {exit $LASTEXITCODE}

Write-Output ('+ "go build"');
& go build; if ($LASTEXITCODE -ne 0) {exit $LASTEXITCODE}

Write-Output ('+ "go test"');
& go test; if ($LASTEXITCODE -ne 0) {exit $LASTEXITCODE}

`,
},
}
for _, test := range testdata {
script := generateScriptWindows(test.from)
assert.EqualValues(t, test.want, script, "Want encoded script for %s", test.from)
}
}
7 changes: 2 additions & 5 deletions pipeline/backend/docker/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
)

// returns a container configuration.
func toConfig(step *types.Step) *container.Config {
func (e *docker) toConfig(step *types.Step) *container.Config {
config := &container.Config{
Image: step.Image,
Labels: map[string]string{"wp_uuid": step.UUID},
Expand All @@ -37,7 +37,7 @@ func toConfig(step *types.Step) *container.Config {
}

if len(step.Commands) != 0 {
env, entry, cmd := common.GenerateContainerConf(step.Commands)
env, entry, cmd := common.GenerateContainerConf(step.Commands, e.info.OSType)
for k, v := range env {
step.Environment[k] = v
}
Expand Down Expand Up @@ -76,9 +76,6 @@ func toHostConfig(step *types.Step) *container.HostConfig {
Sysctls: step.Sysctls,
}

// if len(step.VolumesFrom) != 0 {
// config.VolumesFrom = step.VolumesFrom
// }
if len(step.NetworkMode) != 0 {
config.NetworkMode = container.NetworkMode(step.NetworkMode)
}
Expand Down
36 changes: 26 additions & 10 deletions pipeline/backend/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"net/http"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/docker/docker/api/types"
Expand All @@ -43,6 +42,7 @@ type docker struct {
enableIPv6 bool
network string
volumes []string
info types.Info
}

const (
Expand Down Expand Up @@ -94,10 +94,10 @@ func httpClientOfOpts(dockerCertPath string, verifyTLS bool) *http.Client {
}

// Load new client for Docker Engine using environment variables.
func (e *docker) Load(ctx context.Context) error {
func (e *docker) Load(ctx context.Context) (*backend.EngineInfo, error) {
c, ok := ctx.Value(backend.CliContext).(*cli.Context)
if !ok {
return backend.ErrNoCliContextFound
return nil, backend.ErrNoCliContextFound
}

var dockerClientOpts []client.Opt
Expand All @@ -115,10 +115,15 @@ func (e *docker) Load(ctx context.Context) error {

cl, err := client.NewClientWithOpts(dockerClientOpts...)
if err != nil {
return err
return nil, err
}
e.client = cl

e.info, err = cl.Info(ctx)
if err != nil {
return nil, err
}

e.enableIPv6 = c.Bool("backend-docker-ipv6")
e.network = c.String("backend-docker-network")

Expand All @@ -137,7 +142,9 @@ func (e *docker) Load(ctx context.Context) error {
e.volumes = append(e.volumes, strings.Join(parts, ":"))
}

return nil
return &backend.EngineInfo{
Platform: e.info.OSType + "/" + normalizeArchType(e.info.Architecture),
}, nil
}

func (e *docker) SetupWorkflow(_ context.Context, conf *backend.Config, taskUUID string) error {
Expand All @@ -154,7 +161,7 @@ func (e *docker) SetupWorkflow(_ context.Context, conf *backend.Config, taskUUID
}

networkDriver := networkDriverBridge
if runtime.GOOS == "windows" {
if e.info.OSType == "windows" {
networkDriver = networkDriverNAT
}
for _, n := range conf.Networks {
Expand All @@ -172,7 +179,7 @@ func (e *docker) SetupWorkflow(_ context.Context, conf *backend.Config, taskUUID
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 := e.toConfig(step)
hostConfig := toHostConfig(step)
containerName := toContainerName(step)

Expand Down Expand Up @@ -262,9 +269,6 @@ func (e *docker) WaitStep(ctx context.Context, step *backend.Step, taskUUID stri
if err != nil {
return nil, err
}
// if info.State.Running {
// TODO
// }

return &backend.State{
Exited: true,
Expand Down Expand Up @@ -360,3 +364,15 @@ func isErrContainerNotFoundOrNotRunning(err error) bool {
// Error: No such container: ...
return err != nil && (strings.Contains(err.Error(), "No such container") || strings.Contains(err.Error(), "is not running"))
}

// normalizeArchType converts the arch type reported by docker info into
// the runtime.GOARCH format
// TODO: find out if we we need to convert other arch types too
func normalizeArchType(s string) string {
switch s {
case "x86_64":
return "amd64"
default:
return s
}
}
16 changes: 11 additions & 5 deletions pipeline/backend/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"io"
"os"
"runtime"
"strings"
"time"

Expand Down Expand Up @@ -46,6 +47,7 @@ type kube struct {
ctx context.Context
client kubernetes.Interface
config *Config
goos string
}

type Config struct {
Expand Down Expand Up @@ -104,10 +106,10 @@ func (e *kube) IsAvailable(context.Context) bool {
return len(host) > 0
}

func (e *kube) Load(context.Context) error {
func (e *kube) Load(context.Context) (*types.EngineInfo, error) {
config, err := configFromCliContext(e.ctx)
if err != nil {
return err
return nil, err
}
e.config = config

Expand All @@ -120,12 +122,16 @@ func (e *kube) Load(context.Context) error {
}

if err != nil {
return err
return nil, err
}

e.client = kubeClient

return nil
// TODO: use info resp of kubeClient to define platform var
anbraten marked this conversation as resolved.
Show resolved Hide resolved
6543 marked this conversation as resolved.
Show resolved Hide resolved
e.goos = runtime.GOOS
return &types.EngineInfo{
Platform: runtime.GOOS + "/" + runtime.GOARCH,
}, nil
}

// Setup the pipeline environment.
Expand Down Expand Up @@ -183,7 +189,7 @@ func (e *kube) SetupWorkflow(ctx context.Context, conf *types.Config, taskUUID s

// Start the pipeline step.
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, e.goos)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions pipeline/backend/kubernetes/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
"github.com/woodpecker-ci/woodpecker/pipeline/backend/types"
)

func Pod(namespace string, step *types.Step, labels, annotations map[string]string) (*v1.Pod, error) {
func Pod(namespace string, step *types.Step, labels, annotations map[string]string, goos string) (*v1.Pod, error) {
var (
vols []v1.Volume
volMounts []v1.VolumeMount
Expand Down Expand Up @@ -66,7 +66,7 @@ func Pod(namespace string, step *types.Step, labels, annotations map[string]stri
}

if len(step.Commands) != 0 {
scriptEnv, entry, cmds := common.GenerateContainerConf(step.Commands)
scriptEnv, entry, cmds := common.GenerateContainerConf(step.Commands, goos)
for k, v := range scriptEnv {
step.Environment[k] = v
}
Expand Down
6 changes: 4 additions & 2 deletions pipeline/backend/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,12 @@ func (e *local) IsAvailable(context.Context) bool {
return true
}

func (e *local) Load(context.Context) error {
func (e *local) Load(context.Context) (*types.EngineInfo, error) {
e.loadClone()

return nil
return &types.EngineInfo{
Platform: runtime.GOOS + "/" + runtime.GOARCH,
}, nil
}

// SetupWorkflow the pipeline environment.
Expand Down
7 changes: 6 additions & 1 deletion pipeline/backend/types/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type Engine interface {
IsAvailable(ctx context.Context) bool

// Load loads the backend engine.
Load(ctx context.Context) error
Load(ctx context.Context) (*EngineInfo, error)

// SetupWorkflow sets up the workflow environment.
SetupWorkflow(ctx context.Context, conf *Config, taskUUID string) error
Expand All @@ -50,3 +50,8 @@ type Engine interface {
// DestroyWorkflow destroys the workflow environment.
DestroyWorkflow(ctx context.Context, conf *Config, taskUUID string) error
}

// EngineInfo represents the reported information of a loaded engine
type EngineInfo struct {
Platform string
}