runservice: implement docker registry auth
By now just support default username/password login In future also support additional container registries with their own credential helpers
This commit is contained in:
parent
298ffc3529
commit
634a8a543c
@ -59,15 +59,31 @@ const (
|
|||||||
RuntimeTypePod RuntimeType = "pod"
|
RuntimeTypePod RuntimeType = "pod"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RegistryAuthType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RegistryAuthTypeDefault RegistryAuthType = "default"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RegistryAuth struct {
|
||||||
|
Type RegistryAuthType `yaml:"type"`
|
||||||
|
|
||||||
|
// default auth
|
||||||
|
Username Value `yaml:"username"`
|
||||||
|
Password Value `yaml:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
Type RuntimeType `yaml:"type,omitempty"`
|
Type RuntimeType `yaml:"type,omitempty"`
|
||||||
Arch common.Arch `yaml:"arch,omitempty"`
|
Auth *RegistryAuth `yaml:"auth"`
|
||||||
Containers []*Container `yaml:"containers,omitempty"`
|
Arch common.Arch `yaml:"arch,omitempty"`
|
||||||
|
Containers []*Container `yaml:"containers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Container struct {
|
type Container struct {
|
||||||
Image string `yaml:"image,omitempty"`
|
Image string `yaml:"image,omitempty"`
|
||||||
|
Auth *RegistryAuth `yaml:"auth"`
|
||||||
Environment map[string]Value `yaml:"environment,omitempty"`
|
Environment map[string]Value `yaml:"environment,omitempty"`
|
||||||
User string `yaml:"user"`
|
User string `yaml:"user"`
|
||||||
Privileged bool `yaml:"privileged"`
|
Privileged bool `yaml:"privileged"`
|
||||||
@ -539,6 +555,22 @@ func ParseConfig(configData []byte) (*Config, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set auth type to default if not specified
|
||||||
|
for _, runtime := range config.Runtimes {
|
||||||
|
if runtime.Auth != nil {
|
||||||
|
if runtime.Auth.Type == "" {
|
||||||
|
runtime.Auth.Type = RegistryAuthTypeDefault
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, container := range runtime.Containers {
|
||||||
|
if container.Auth != nil {
|
||||||
|
if container.Auth.Type == "" {
|
||||||
|
container.Auth.Type = RegistryAuthTypeDefault
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &config, checkConfig(&config)
|
return &config, checkConfig(&config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +134,16 @@ func TestParseOutput(t *testing.T) {
|
|||||||
runtimes:
|
runtimes:
|
||||||
runtime01:
|
runtime01:
|
||||||
type: pod
|
type: pod
|
||||||
|
auth:
|
||||||
|
username: username
|
||||||
|
password:
|
||||||
|
from_variable: password
|
||||||
containers:
|
containers:
|
||||||
- image: image01
|
- image: image01
|
||||||
|
auth:
|
||||||
|
username:
|
||||||
|
from_variable: username2
|
||||||
|
password: password2
|
||||||
environment:
|
environment:
|
||||||
ENV01: ENV01
|
ENV01: ENV01
|
||||||
ENVFROMVARIABLE01:
|
ENVFROMVARIABLE01:
|
||||||
@ -179,10 +187,20 @@ func TestParseOutput(t *testing.T) {
|
|||||||
"runtime01": &Runtime{
|
"runtime01": &Runtime{
|
||||||
Name: "runtime01",
|
Name: "runtime01",
|
||||||
Type: "pod",
|
Type: "pod",
|
||||||
|
Auth: &RegistryAuth{
|
||||||
|
Type: RegistryAuthTypeDefault,
|
||||||
|
Username: Value{Type: ValueTypeString, Value: "username"},
|
||||||
|
Password: Value{Type: ValueTypeFromVariable, Value: "password"},
|
||||||
|
},
|
||||||
Arch: "",
|
Arch: "",
|
||||||
Containers: []*Container{
|
Containers: []*Container{
|
||||||
&Container{
|
&Container{
|
||||||
Image: "image01",
|
Image: "image01",
|
||||||
|
Auth: &RegistryAuth{
|
||||||
|
Type: RegistryAuthTypeDefault,
|
||||||
|
Username: Value{Type: ValueTypeFromVariable, Value: "username2"},
|
||||||
|
Password: Value{Type: ValueTypeString, Value: "password2"},
|
||||||
|
},
|
||||||
Environment: map[string]Value{
|
Environment: map[string]Value{
|
||||||
"ENV01": Value{Type: ValueTypeString, Value: "ENV01"},
|
"ENV01": Value{Type: ValueTypeString, Value: "ENV01"},
|
||||||
"ENVFROMVARIABLE01": Value{Type: ValueTypeFromVariable, Value: "variable01"},
|
"ENVFROMVARIABLE01": Value{Type: ValueTypeFromVariable, Value: "variable01"},
|
||||||
|
@ -38,6 +38,24 @@ func genRuntime(c *config.Config, runtimeName string, variables map[string]strin
|
|||||||
Privileged: cc.Privileged,
|
Privileged: cc.Privileged,
|
||||||
Entrypoint: cc.Entrypoint,
|
Entrypoint: cc.Entrypoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set container auth
|
||||||
|
if cc.Auth != nil {
|
||||||
|
container.Auth = &rstypes.RegistryAuth{
|
||||||
|
Type: rstypes.RegistryAuthType(cc.Auth.Type),
|
||||||
|
Username: genValue(cc.Auth.Username, variables),
|
||||||
|
Password: genValue(cc.Auth.Password, variables),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if container auth is nil use runtime auth
|
||||||
|
if container.Auth == nil && ce.Auth != nil {
|
||||||
|
container.Auth = &rstypes.RegistryAuth{
|
||||||
|
Type: rstypes.RegistryAuthType(ce.Auth.Type),
|
||||||
|
Username: genValue(ce.Auth.Username, variables),
|
||||||
|
Password: genValue(ce.Auth.Password, variables),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
containers = append(containers, container)
|
containers = append(containers, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,13 +702,23 @@ func TestGenRunConfig(t *testing.T) {
|
|||||||
"runtime01": &config.Runtime{
|
"runtime01": &config.Runtime{
|
||||||
Name: "runtime01",
|
Name: "runtime01",
|
||||||
Type: "pod",
|
Type: "pod",
|
||||||
|
Auth: &config.RegistryAuth{
|
||||||
|
Type: config.RegistryAuthTypeDefault,
|
||||||
|
Username: config.Value{Type: config.ValueTypeString, Value: "username"},
|
||||||
|
Password: config.Value{Type: config.ValueTypeFromVariable, Value: "password"},
|
||||||
|
},
|
||||||
Arch: "",
|
Arch: "",
|
||||||
Containers: []*config.Container{
|
Containers: []*config.Container{
|
||||||
&config.Container{
|
&config.Container{
|
||||||
Image: "image01",
|
Image: "image01",
|
||||||
Environment: map[string]config.EnvVar{
|
Auth: &config.RegistryAuth{
|
||||||
"ENV01": config.EnvVar{Type: config.EnvVarTypeString, Value: "ENV01"},
|
Type: config.RegistryAuthTypeDefault,
|
||||||
"ENVFROMVARIABLE01": config.EnvVar{Type: config.EnvVarTypeFromVariable, Value: "variable01"},
|
Username: config.Value{Type: config.ValueTypeFromVariable, Value: "registry_username"},
|
||||||
|
Password: config.Value{Type: config.ValueTypeString, Value: "password2"},
|
||||||
|
},
|
||||||
|
Environment: map[string]config.Value{
|
||||||
|
"ENV01": config.Value{Type: config.ValueTypeString, Value: "ENV01"},
|
||||||
|
"ENVFROMVARIABLE01": config.Value{Type: config.ValueTypeFromVariable, Value: "variable01"},
|
||||||
},
|
},
|
||||||
User: "",
|
User: "",
|
||||||
},
|
},
|
||||||
@ -719,9 +729,9 @@ func TestGenRunConfig(t *testing.T) {
|
|||||||
"task01": &config.Task{
|
"task01": &config.Task{
|
||||||
Name: "task01",
|
Name: "task01",
|
||||||
Runtime: "runtime01",
|
Runtime: "runtime01",
|
||||||
Environment: map[string]config.EnvVar{
|
Environment: map[string]config.Value{
|
||||||
"ENV01": config.EnvVar{Type: config.EnvVarTypeString, Value: "ENV01"},
|
"ENV01": config.Value{Type: config.ValueTypeString, Value: "ENV01"},
|
||||||
"ENVFROMVARIABLE01": config.EnvVar{Type: config.EnvVarTypeFromVariable, Value: "variable01"},
|
"ENVFROMVARIABLE01": config.Value{Type: config.ValueTypeFromVariable, Value: "variable01"},
|
||||||
},
|
},
|
||||||
WorkingDir: "",
|
WorkingDir: "",
|
||||||
Shell: "",
|
Shell: "",
|
||||||
@ -747,9 +757,9 @@ func TestGenRunConfig(t *testing.T) {
|
|||||||
Name: "command03",
|
Name: "command03",
|
||||||
},
|
},
|
||||||
Command: "command03",
|
Command: "command03",
|
||||||
Environment: map[string]config.EnvVar{
|
Environment: map[string]config.Value{
|
||||||
"ENV01": config.EnvVar{Type: config.EnvVarTypeString, Value: "ENV01"},
|
"ENV01": config.Value{Type: config.ValueTypeString, Value: "ENV01"},
|
||||||
"ENVFROMVARIABLE01": config.EnvVar{Type: config.EnvVarTypeFromVariable, Value: "variable01"},
|
"ENVFROMVARIABLE01": config.Value{Type: config.ValueTypeFromVariable, Value: "variable01"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -779,7 +789,8 @@ func TestGenRunConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
variables: map[string]string{
|
variables: map[string]string{
|
||||||
"variable01": "VARVALUE01",
|
"variable01": "VARVALUE01",
|
||||||
|
"registry_username": "yourregistryusername",
|
||||||
},
|
},
|
||||||
out: map[string]*rstypes.RunConfigTask{
|
out: map[string]*rstypes.RunConfigTask{
|
||||||
uuid.New("element01").String(): &rstypes.RunConfigTask{
|
uuid.New("element01").String(): &rstypes.RunConfigTask{
|
||||||
@ -789,6 +800,11 @@ func TestGenRunConfig(t *testing.T) {
|
|||||||
Containers: []*rstypes.Container{
|
Containers: []*rstypes.Container{
|
||||||
{
|
{
|
||||||
Image: "image01",
|
Image: "image01",
|
||||||
|
Auth: &rstypes.RegistryAuth{
|
||||||
|
Type: rstypes.RegistryAuthTypeDefault,
|
||||||
|
Username: "yourregistryusername",
|
||||||
|
Password: "password2",
|
||||||
|
},
|
||||||
Environment: map[string]string{
|
Environment: map[string]string{
|
||||||
"ENV01": "ENV01",
|
"ENV01": "ENV01",
|
||||||
"ENVFROMVARIABLE01": "VARVALUE01",
|
"ENVFROMVARIABLE01": "VARVALUE01",
|
||||||
@ -809,6 +825,161 @@ func TestGenRunConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "test runtime auth used for container nil auth",
|
||||||
|
in: &config.Config{
|
||||||
|
Runtimes: map[string]*config.Runtime{
|
||||||
|
"runtime01": &config.Runtime{
|
||||||
|
Name: "runtime01",
|
||||||
|
Type: "pod",
|
||||||
|
Auth: &config.RegistryAuth{
|
||||||
|
Type: config.RegistryAuthTypeDefault,
|
||||||
|
Username: config.Value{Type: config.ValueTypeString, Value: "username"},
|
||||||
|
Password: config.Value{Type: config.ValueTypeFromVariable, Value: "password"},
|
||||||
|
},
|
||||||
|
Arch: "",
|
||||||
|
Containers: []*config.Container{
|
||||||
|
&config.Container{
|
||||||
|
Image: "image01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tasks: map[string]*config.Task{
|
||||||
|
"task01": &config.Task{
|
||||||
|
Name: "task01",
|
||||||
|
Runtime: "runtime01",
|
||||||
|
Steps: []interface{}{
|
||||||
|
&config.RunStep{
|
||||||
|
Step: config.Step{
|
||||||
|
Type: "run",
|
||||||
|
Name: "command01",
|
||||||
|
},
|
||||||
|
Command: "command01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Pipelines: map[string]*config.Pipeline{
|
||||||
|
"pipeline01": &config.Pipeline{
|
||||||
|
Name: "pipeline01",
|
||||||
|
Elements: map[string]*config.Element{
|
||||||
|
"element01": &config.Element{
|
||||||
|
Name: "element01",
|
||||||
|
Task: "task01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variables: map[string]string{
|
||||||
|
"variable01": "VARVALUE01",
|
||||||
|
"password": "yourregistrypassword",
|
||||||
|
},
|
||||||
|
out: map[string]*rstypes.RunConfigTask{
|
||||||
|
uuid.New("element01").String(): &rstypes.RunConfigTask{
|
||||||
|
ID: uuid.New("element01").String(),
|
||||||
|
Name: "element01", Depends: []*rstypes.RunConfigTaskDepend{},
|
||||||
|
Runtime: &rstypes.Runtime{Type: rstypes.RuntimeType("pod"),
|
||||||
|
Containers: []*rstypes.Container{
|
||||||
|
{
|
||||||
|
Image: "image01",
|
||||||
|
Auth: &rstypes.RegistryAuth{
|
||||||
|
Type: rstypes.RegistryAuthTypeDefault,
|
||||||
|
Username: "username",
|
||||||
|
Password: "yourregistrypassword",
|
||||||
|
},
|
||||||
|
Environment: map[string]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Environment: map[string]string{},
|
||||||
|
Steps: []interface{}{
|
||||||
|
&rstypes.RunStep{Step: rstypes.Step{Type: "run", Name: "command01"}, Command: "command01", Environment: map[string]string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test runtime auth not used for container with auth",
|
||||||
|
in: &config.Config{
|
||||||
|
Runtimes: map[string]*config.Runtime{
|
||||||
|
"runtime01": &config.Runtime{
|
||||||
|
Name: "runtime01",
|
||||||
|
Type: "pod",
|
||||||
|
Auth: &config.RegistryAuth{
|
||||||
|
Type: config.RegistryAuthTypeDefault,
|
||||||
|
Username: config.Value{Type: config.ValueTypeString, Value: "username"},
|
||||||
|
Password: config.Value{Type: config.ValueTypeFromVariable, Value: "password"},
|
||||||
|
},
|
||||||
|
Arch: "",
|
||||||
|
Containers: []*config.Container{
|
||||||
|
&config.Container{
|
||||||
|
Image: "image01",
|
||||||
|
Auth: &config.RegistryAuth{
|
||||||
|
Type: config.RegistryAuthTypeDefault,
|
||||||
|
Username: config.Value{Type: config.ValueTypeFromVariable, Value: "registry_username"},
|
||||||
|
Password: config.Value{Type: config.ValueTypeString, Value: "password2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tasks: map[string]*config.Task{
|
||||||
|
"task01": &config.Task{
|
||||||
|
Name: "task01",
|
||||||
|
Runtime: "runtime01",
|
||||||
|
Steps: []interface{}{
|
||||||
|
&config.RunStep{
|
||||||
|
Step: config.Step{
|
||||||
|
Type: "run",
|
||||||
|
Name: "command01",
|
||||||
|
},
|
||||||
|
Command: "command01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Pipelines: map[string]*config.Pipeline{
|
||||||
|
"pipeline01": &config.Pipeline{
|
||||||
|
Name: "pipeline01",
|
||||||
|
Elements: map[string]*config.Element{
|
||||||
|
"element01": &config.Element{
|
||||||
|
Name: "element01",
|
||||||
|
Task: "task01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variables: map[string]string{
|
||||||
|
"variable01": "VARVALUE01",
|
||||||
|
"registry_username": "yourregistryusername",
|
||||||
|
},
|
||||||
|
out: map[string]*rstypes.RunConfigTask{
|
||||||
|
uuid.New("element01").String(): &rstypes.RunConfigTask{
|
||||||
|
ID: uuid.New("element01").String(),
|
||||||
|
Name: "element01", Depends: []*rstypes.RunConfigTaskDepend{},
|
||||||
|
Runtime: &rstypes.Runtime{Type: rstypes.RuntimeType("pod"),
|
||||||
|
Containers: []*rstypes.Container{
|
||||||
|
{
|
||||||
|
Image: "image01",
|
||||||
|
Auth: &rstypes.RegistryAuth{
|
||||||
|
Type: rstypes.RegistryAuthTypeDefault,
|
||||||
|
Username: "yourregistryusername",
|
||||||
|
Password: "password2",
|
||||||
|
},
|
||||||
|
Environment: map[string]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Environment: map[string]string{},
|
||||||
|
Steps: []interface{}{
|
||||||
|
&rstypes.RunStep{Step: rstypes.Step{Type: "run", Name: "command01"}, Command: "command01", Environment: map[string]string{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -118,7 +118,7 @@ func (d *DockerDriver) NewPod(ctx context.Context, podConfig *PodConfig, out io.
|
|||||||
|
|
||||||
// by default always try to pull the image so we are sure only authorized users can fetch them
|
// by default always try to pull the image so we are sure only authorized users can fetch them
|
||||||
// see https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages
|
// see https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages
|
||||||
reader, err := d.client.ImagePull(ctx, containerConfig.Image, types.ImagePullOptions{})
|
reader, err := d.client.ImagePull(ctx, containerConfig.Image, types.ImagePullOptions{RegistryAuth: containerConfig.RegistryAuth})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -487,17 +487,23 @@ func (e *Executor) setupTask(ctx context.Context, rt *runningTask) error {
|
|||||||
|
|
||||||
log.Debugf("starting pod")
|
log.Debugf("starting pod")
|
||||||
|
|
||||||
|
registryAuth, err := registryAuthToken(et.Containers[0].Auth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
podConfig := &driver.PodConfig{
|
podConfig := &driver.PodConfig{
|
||||||
Labels: createTaskLabels(et.ID),
|
Labels: createTaskLabels(et.ID),
|
||||||
InitVolumeDir: toolboxContainerDir,
|
InitVolumeDir: toolboxContainerDir,
|
||||||
Containers: []*driver.ContainerConfig{
|
Containers: []*driver.ContainerConfig{
|
||||||
{
|
{
|
||||||
Image: et.Containers[0].Image,
|
Image: et.Containers[0].Image,
|
||||||
Cmd: cmd,
|
Cmd: cmd,
|
||||||
Env: et.Containers[0].Environment,
|
Env: et.Containers[0].Environment,
|
||||||
WorkingDir: et.WorkingDir,
|
WorkingDir: et.WorkingDir,
|
||||||
User: et.Containers[0].User,
|
User: et.Containers[0].User,
|
||||||
Privileged: et.Containers[0].Privileged,
|
Privileged: et.Containers[0].Privileged,
|
||||||
|
RegistryAuth: registryAuth,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -515,7 +521,7 @@ func (e *Executor) setupTask(ctx context.Context, rt *runningTask) error {
|
|||||||
outf.WriteString("Starting pod.\n")
|
outf.WriteString("Starting pod.\n")
|
||||||
pod, err := e.driver.NewPod(ctx, podConfig, outf)
|
pod, err := e.driver.NewPod(ctx, podConfig, outf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
outf.WriteString("Pod failed to start.\n")
|
outf.WriteString(fmt.Sprintf("Pod failed to start. Error: %s\n", err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
outf.WriteString("Pod started.\n")
|
outf.WriteString("Pod started.\n")
|
||||||
|
47
internal/services/runservice/executor/registry.go
Normal file
47
internal/services/runservice/executor/registry.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2019 Sorint.lab
|
||||||
|
//
|
||||||
|
// 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 executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/sorintlab/agola/internal/services/runservice/types"
|
||||||
|
|
||||||
|
dtypes "github.com/docker/docker/api/types"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func registryAuthToken(auth *types.RegistryAuth) (string, error) {
|
||||||
|
if auth == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch auth.Type {
|
||||||
|
case types.RegistryAuthTypeDefault:
|
||||||
|
authConfig := dtypes.AuthConfig{
|
||||||
|
Username: auth.Username,
|
||||||
|
Password: auth.Password,
|
||||||
|
}
|
||||||
|
authConfigj, err := json.Marshal(authConfig)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return base64.URLEncoding.EncodeToString(authConfigj), nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "", errors.Errorf("unsupported registry auth type %q", auth.Type)
|
||||||
|
}
|
||||||
|
}
|
@ -332,6 +332,20 @@ const (
|
|||||||
RuntimeTypePod RuntimeType = "pod"
|
RuntimeTypePod RuntimeType = "pod"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RegistryAuthType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RegistryAuthTypeDefault RegistryAuthType = "default"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RegistryAuth struct {
|
||||||
|
Type RegistryAuthType `yaml:"type"`
|
||||||
|
|
||||||
|
// default auth
|
||||||
|
Username string `yaml:"username"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
Type RuntimeType `json:"type,omitempty"`
|
Type RuntimeType `json:"type,omitempty"`
|
||||||
Containers []*Container `json:"containers,omitempty"`
|
Containers []*Container `json:"containers,omitempty"`
|
||||||
@ -478,6 +492,7 @@ type ExecutorTaskStepStatus struct {
|
|||||||
|
|
||||||
type Container struct {
|
type Container struct {
|
||||||
Image string `json:"image,omitempty"`
|
Image string `json:"image,omitempty"`
|
||||||
|
Auth *RegistryAuth `json:"auth,omitempty"`
|
||||||
Environment map[string]string `json:"environment,omitempty"`
|
Environment map[string]string `json:"environment,omitempty"`
|
||||||
User string `json:"user,omitempty"`
|
User string `json:"user,omitempty"`
|
||||||
Privileged bool `json:"privileged"`
|
Privileged bool `json:"privileged"`
|
||||||
|
Loading…
Reference in New Issue
Block a user