Commit 0e2ae000 authored by Tomasz Maczukin's avatar Tomasz Maczukin Committed by Kamil Trzciński

Make k8s object names DNS-1123 compatible

parent 510e9be4
......@@ -393,6 +393,10 @@ type dockerConfigEntry struct {
Username, Password string
}
func (s *executor) projectUniqueName() string {
return makeDNS1123Compatible(s.Build.ProjectUniqueName())
}
func (s *executor) setupCredentials() error {
authConfigs := make(map[string]dockerConfigEntry)
......@@ -417,7 +421,7 @@ func (s *executor) setupCredentials() error {
}
secret := api.Secret{}
secret.GenerateName = s.Build.ProjectUniqueName()
secret.GenerateName = s.projectUniqueName()
secret.Namespace = s.configurationOverwrites.namespace
secret.Type = api.SecretTypeDockercfg
secret.Data = map[string][]byte{}
......@@ -461,7 +465,7 @@ func (s *executor) setupBuildPod() error {
pod, err := s.kubeClient.CoreV1().Pods(s.configurationOverwrites.namespace).Create(&api.Pod{
ObjectMeta: metav1.ObjectMeta{
GenerateName: s.Build.ProjectUniqueName(),
GenerateName: s.projectUniqueName(),
Namespace: s.configurationOverwrites.namespace,
Labels: labels,
Annotations: annotations,
......
......@@ -892,15 +892,16 @@ func TestSetupCredentials(t *testing.T) {
version, _ := testVersionAndCodec()
type testDef struct {
Credentials []common.Credentials
VerifyFn func(*testing.T, testDef, *api.Secret)
RunnerCredentials *common.RunnerCredentials
Credentials []common.Credentials
VerifyFn func(*testing.T, testDef, *api.Secret)
}
tests := []testDef{
{
tests := map[string]testDef{
"no credentials": {
// don't execute VerifyFn
VerifyFn: nil,
},
{
"registry credentials": {
Credentials: []common.Credentials{
{
Type: "registry",
......@@ -914,7 +915,7 @@ func TestSetupCredentials(t *testing.T) {
assert.NotEmpty(t, secret.Data[api.DockerConfigKey])
},
},
{
"other credentials": {
Credentials: []common.Credentials{
{
Type: "other",
......@@ -926,6 +927,22 @@ func TestSetupCredentials(t *testing.T) {
// don't execute VerifyFn
VerifyFn: nil,
},
"non-DNS-1123-compatible-token": {
RunnerCredentials: &common.RunnerCredentials{
Token: "ToK3_?OF",
},
Credentials: []common.Credentials{
{
Type: "registry",
URL: "http://example.com",
Username: "user",
Password: "password",
},
},
VerifyFn: func(t *testing.T, test testDef, secret *api.Secret) {
assertDNS1123Compatibility(t, secret.GetGenerateName())
},
},
}
executed := false
......@@ -962,39 +979,50 @@ func TestSetupCredentials(t *testing.T) {
}
}
for _, test := range tests {
ex := executor{
kubeClient: testKubernetesClient(version, fake.CreateHTTPClient(fakeClientRoundTripper(test))),
options: &kubernetesOptions{},
AbstractExecutor: executors.AbstractExecutor{
Config: common.RunnerConfig{
RunnerSettings: common.RunnerSettings{
Kubernetes: &common.KubernetesConfig{
Namespace: "default",
for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
ex := executor{
kubeClient: testKubernetesClient(version, fake.CreateHTTPClient(fakeClientRoundTripper(test))),
options: &kubernetesOptions{},
AbstractExecutor: executors.AbstractExecutor{
Config: common.RunnerConfig{
RunnerSettings: common.RunnerSettings{
Kubernetes: &common.KubernetesConfig{
Namespace: "default",
},
},
},
},
BuildShell: &common.ShellConfiguration{},
Build: &common.Build{
JobResponse: common.JobResponse{
Variables: []common.JobVariable{},
Credentials: test.Credentials,
BuildShell: &common.ShellConfiguration{},
Build: &common.Build{
JobResponse: common.JobResponse{
Variables: []common.JobVariable{},
Credentials: test.Credentials,
},
Runner: &common.RunnerConfig{},
},
Runner: &common.RunnerConfig{},
},
},
}
}
executed = false
err := ex.prepareOverwrites(make(common.JobVariables, 0))
assert.NoError(t, err)
err = ex.setupCredentials()
assert.NoError(t, err)
if test.VerifyFn != nil {
assert.True(t, executed)
} else {
assert.False(t, executed)
}
if test.RunnerCredentials != nil {
ex.Build.Runner = &common.RunnerConfig{
RunnerCredentials: *test.RunnerCredentials,
}
}
executed = false
err := ex.prepareOverwrites(make(common.JobVariables, 0))
assert.NoError(t, err)
err = ex.setupCredentials()
assert.NoError(t, err)
if test.VerifyFn != nil {
assert.True(t, executed)
} else {
assert.False(t, executed)
}
})
}
}
......@@ -1368,6 +1396,21 @@ func TestSetupBuildPod(t *testing.T) {
assert.Equal(t, []string{"argument1", "argument2"}, pod.Spec.Containers[4].Args)
},
},
"non-DNS-1123-compatible-token": {
RunnerConfig: common.RunnerConfig{
RunnerCredentials: common.RunnerCredentials{
Token: "ToK3_?OF",
},
RunnerSettings: common.RunnerSettings{
Kubernetes: &common.KubernetesConfig{
Namespace: "default",
},
},
},
VerifyFn: func(t *testing.T, test setupBuildPodTestDef, pod *api.Pod) {
assertDNS1123Compatibility(t, pod.GetGenerateName())
},
},
}
for testName, test := range tests {
......
......@@ -5,6 +5,8 @@ import (
"fmt"
"io"
"net/http"
"regexp"
"strings"
"time"
"golang.org/x/net/context"
......@@ -18,6 +20,12 @@ import (
"gitlab.com/gitlab-org/gitlab-runner/common"
)
const (
DNS1123NameMaximumLength = 63
DNS1123NotAllowedCharacters = "[^-a-z0-9]"
DNS1123NotAllowedStartCharacters = "^[^a-z0-9]+"
)
type kubeConfigProvider func() (*restclient.Config, error)
var (
......@@ -256,3 +264,19 @@ func buildVariables(bv common.JobVariables) []api.EnvVar {
}
return e
}
func makeDNS1123Compatible(name string) string {
name = strings.ToLower(name)
nameNotAllowedChars := regexp.MustCompile(DNS1123NotAllowedCharacters)
name = nameNotAllowedChars.ReplaceAllString(name, "")
nameNotAllowedStartChars := regexp.MustCompile(DNS1123NotAllowedStartCharacters)
name = nameNotAllowedStartChars.ReplaceAllString(name, "")
if len(name) > DNS1123NameMaximumLength {
name = name[0:DNS1123NameMaximumLength]
}
return name
}
......@@ -6,6 +6,7 @@ import (
"io"
"io/ioutil"
"net/http"
"regexp"
"strings"
"testing"
......@@ -400,3 +401,31 @@ func testVersionAndCodec() (version string, codec runtime.Codec) {
return
}
func assertDNS1123Compatibility(t *testing.T, name string) {
dns1123MaxLength := 63
dns1123FormatRegexp := regexp.MustCompile("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$")
assert.True(t, len(name) <= dns1123MaxLength, "Name length needs to be shorter than %d", dns1123MaxLength)
assert.Regexp(t, dns1123FormatRegexp, name, "Name needs to be in DNS-1123 allowed format")
}
func TestMakeDNS1123Compatible(t *testing.T) {
examples := []struct {
name string
expected string
}{
{name: "tOk3_?ofTHE-Runner", expected: "tok3ofthe-runner"},
{name: "----tOk3_?ofTHE-Runner", expected: "tok3ofthe-runner"},
{name: "very-long-token-----------------------------------------------end", expected: "very-long-token-----------------------------------------------e"},
}
for _, example := range examples {
t.Run(example.name, func(t *testing.T) {
name := makeDNS1123Compatible(example.name)
assert.Equal(t, example.expected, name)
assertDNS1123Compatibility(t, name)
})
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment