Skip to content

Commit 2f5642a

Browse files
Keerthan Reddy Malakmala
authored andcommitted
feat(registry): Add support for external registry
1 parent 0f6f3a3 commit 2f5642a

12 files changed

Lines changed: 615 additions & 15 deletions

File tree

pkg/conf/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const (
1616
gcsKey = "key.json"
1717
)
1818

19+
// Parameters is map which contains storage params
1920
type Parameters map[string]interface{}
2021

2122
// EnvConfig is a convenience function to process the envconfig (
@@ -43,6 +44,7 @@ func GetBuilderKey() (string, error) {
4344
return builderKey, nil
4445
}
4546

47+
// GetStorageParams returns the credentials required for connecting to object storage
4648
func GetStorageParams(env sys.Env) (Parameters, error) {
4749
params := make(map[string]interface{})
4850
files, err := ioutil.ReadDir(storageCredLocation)

pkg/controller/utils.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type UserInfo struct {
2727
Apps []string
2828
}
2929

30+
// ControllerURLStr returns the url for connecting to deis controller
3031
func ControllerURLStr(additionalPath ...string) (string, error) {
3132
host := os.Getenv(hostEnvName)
3233
port := os.Getenv(portEnvName)

pkg/gitreceive/build.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,21 @@ func build(
138138

139139
var pod *api.Pod
140140
var buildPodName string
141+
image := appName
141142
if usingDockerfile {
142143
buildPodName = dockerBuilderPodName(appName, gitSha.Short())
144+
registryLocation := conf.RegistryLocation
145+
registryEnv := make(map[string]string)
146+
if registryLocation != "on-cluster" {
147+
registryEnv, err = getRegistryDetails(kubeClient, &image, registryLocation, conf.PodNamespace, conf.RegistrySecretPrefix)
148+
if err != nil {
149+
return fmt.Errorf("error getting private registry details %s", err)
150+
}
151+
image = image + ":git-" + gitSha.Short()
152+
}
153+
registryEnv["DEIS_REGISTRY_PROXY_PORT"] = conf.RegistryProxyPort
154+
registryEnv["DEIS_REGISTRY_LOCATION"] = registryLocation
155+
143156
pod = dockerBuilderPod(
144157
conf.Debug,
145158
buildPodName,
@@ -149,7 +162,7 @@ func build(
149162
slugName,
150163
conf.StorageType,
151164
conf.DockerBuilderImage,
152-
conf.RegistryProxyPort,
165+
registryEnv,
153166
dockerBuilderImagePullPolicy,
154167
)
155168
} else {
@@ -244,7 +257,7 @@ func build(
244257

245258
log.Info("Build complete.")
246259

247-
buildHook := createBuildHook(slugBuilderInfo, gitSha, conf.Username, appName, procType, usingDockerfile)
260+
buildHook := createBuildHook(slugBuilderInfo, gitSha, conf.Username, appName, image, procType, usingDockerfile)
248261
quit := progress("...", conf.SessionIdleInterval())
249262
log.Info("Launching App...")
250263
buildHookResp, err := publishRelease(conf, builderKey, buildHook)

pkg/gitreceive/config.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ const (
1414
// builder's git-receive hook.
1515
type Config struct {
1616
// k8s service discovery env vars
17-
ControllerHost string `envconfig:"DEIS_CONTROLLER_SERVICE_HOST" required:"true"`
18-
ControllerPort string `envconfig:"DEIS_CONTROLLER_SERVICE_PORT" required:"true"`
19-
RegistryHost string `envconfig:"DEIS_REGISTRY_SERVICE_HOST" required:"true"`
20-
RegistryProxyPort string `envconfig:"DEIS_REGISTRY_PROXY_PORT" default:"5555"`
17+
ControllerHost string `envconfig:"DEIS_CONTROLLER_SERVICE_HOST" required:"true"`
18+
ControllerPort string `envconfig:"DEIS_CONTROLLER_SERVICE_PORT" required:"true"`
19+
RegistryProxyPort string `envconfig:"DEIS_REGISTRY_PROXY_PORT" default:"5555"`
20+
RegistryLocation string `envconfig:"DEIS_REGISTRY_LOCATION" default:"on-cluster"`
21+
RegistrySecretPrefix string `envconfig:"DEIS_REGISTRY_SECRET_PREFIX" default:"private-registry"`
2122

2223
GitHome string `envconfig:"GIT_HOME" required:"true"`
2324
SSHConnection string `envconfig:"SSH_CONNECTION" required:"true"`

pkg/gitreceive/controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,15 @@ func createBuildHook(
186186
slugBuilderInfo *SlugBuilderInfo,
187187
gitSha *git.SHA,
188188
username,
189-
appName string,
189+
appName, image string,
190190
procType pkg.ProcessType,
191191
usingDockerfile bool,
192192
) *pkg.BuildHook {
193193
ret := &pkg.BuildHook{
194194
Sha: gitSha.Short(),
195195
ReceiveUser: username,
196196
ReceiveRepo: appName,
197-
Image: appName,
197+
Image: image,
198198
Procfile: procType,
199199
}
200200
if !usingDockerfile {

pkg/gitreceive/controller_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ func TestCreateBuildHook(t *testing.T) {
2222

2323
slugName := appName + ":git-" + sha.Short()
2424
slugBuilderInfo := NewSlugBuilderInfo(slugName)
25-
hookUsingDockerfile := createBuildHook(slugBuilderInfo, sha, username, appName, procType, true)
25+
hookUsingDockerfile := createBuildHook(slugBuilderInfo, sha, username, appName, slugName, procType, true)
2626
assert.Equal(t, hookUsingDockerfile.Sha, sha.Short(), "git sha")
2727
assert.Equal(t, hookUsingDockerfile.ReceiveUser, username, "username")
2828
assert.Equal(t, hookUsingDockerfile.ReceiveRepo, appName, "username")
29-
assert.Equal(t, hookUsingDockerfile.Image, appName, "image")
29+
assert.Equal(t, hookUsingDockerfile.Image, slugName, "image")
3030
assert.Equal(t, hookUsingDockerfile.Procfile, procType, "procfile")
3131
assert.Equal(t, hookUsingDockerfile.Dockerfile, "true", "dockerfile field")
3232

33-
hookNoDockerfile := createBuildHook(slugBuilderInfo, sha, username, appName, procType, false)
33+
hookNoDockerfile := createBuildHook(slugBuilderInfo, sha, username, appName, slugName, procType, false)
3434
assert.Equal(t, hookNoDockerfile.Sha, sha.Short(), "git sha")
3535
assert.Equal(t, hookNoDockerfile.ReceiveUser, username, "username")
3636
assert.Equal(t, hookNoDockerfile.ReceiveRepo, appName, "username")

pkg/gitreceive/k8s_util.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ func dockerBuilderPod(
4343
tarKey,
4444
imageName,
4545
storageType,
46-
image, registryProxyPort string,
46+
image string,
47+
registryEnv map[string]string,
4748
pullPolicy api.PullPolicy,
4849
) *api.Pod {
4950

@@ -55,7 +56,10 @@ func dockerBuilderPod(
5556
addEnvToPod(pod, tarPath, tarKey)
5657
addEnvToPod(pod, "IMG_NAME", imageName)
5758
addEnvToPod(pod, builderStorage, storageType)
58-
addEnvToPod(pod, "DEIS_REGISTRY_PROXY_PORT", registryProxyPort)
59+
60+
for key, value := range registryEnv {
61+
addEnvToPod(pod, key, value)
62+
}
5963

6064
pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, api.VolumeMount{
6165
Name: dockerSocketName,

pkg/gitreceive/k8s_util_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ func TestBuildPod(t *testing.T) {
121121
{true, "test", "default", env, "tar", "img", "customimage", api.PullIfNotPresent, ""},
122122
{true, "test", "default", env, "tar", "img", "customimage", api.PullNever, ""},
123123
}
124-
124+
regEnv := map[string]string{"REG_LOC": "on-cluster"}
125125
for _, build := range dockerBuilds {
126126
pod = dockerBuilderPod(
127127
build.debug,
@@ -132,7 +132,7 @@ func TestBuildPod(t *testing.T) {
132132
build.imgName,
133133
build.storageType,
134134
build.dockerBuilderImage,
135-
"5555",
135+
regEnv,
136136
build.dockerBuilderImagePullPolicy,
137137
)
138138

@@ -145,6 +145,7 @@ func TestBuildPod(t *testing.T) {
145145

146146
checkForEnv(t, pod, "TAR_PATH", build.tarKey)
147147
checkForEnv(t, pod, "IMG_NAME", build.imgName)
148+
checkForEnv(t, pod, "REG_LOC", "on-cluster")
148149
if build.dockerBuilderImage != "" {
149150
if pod.Spec.Containers[0].Image != build.dockerBuilderImage {
150151
t.Errorf("expected %v but returned %v", build.dockerBuilderImage, pod.Spec.Containers[0].Image)

pkg/gitreceive/registry.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package gitreceive
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/json"
6+
"errors"
7+
"strings"
8+
9+
"github.com/deis/builder/pkg/k8s"
10+
"github.com/deis/builder/pkg/storage"
11+
"k8s.io/kubernetes/pkg/api"
12+
client "k8s.io/kubernetes/pkg/client/unversioned"
13+
)
14+
15+
const (
16+
registrySecret = "registry-secret"
17+
)
18+
19+
func getDetailsFromRegistrySecret(secretGetter k8s.SecretGetter, secret string) (map[string]string, error) {
20+
regSecret, err := secretGetter.Get(secret)
21+
if err != nil {
22+
return nil, err
23+
}
24+
regDetails := make(map[string]string)
25+
for key, value := range regSecret.Data {
26+
regDetails[key] = string(value)
27+
}
28+
return regDetails, nil
29+
}
30+
31+
func getDetailsFromDockerConfigSecret(secretGetter k8s.SecretGetter, secret string) (map[string]string, error) {
32+
configSecret, err := secretGetter.Get(secret)
33+
if err != nil {
34+
return nil, err
35+
}
36+
dockerConfigJSONBytes := configSecret.Data[api.DockerConfigJsonKey]
37+
var secretData map[string]interface{}
38+
if err = json.Unmarshal(dockerConfigJSONBytes, &secretData); err != nil {
39+
return nil, err
40+
}
41+
42+
var authdata map[string]interface{}
43+
var hostname string
44+
for key, value := range secretData["auths"].(map[string]interface{}) {
45+
hostname = key
46+
authdata = value.(map[string]interface{})
47+
}
48+
token := authdata["auth"].(string)
49+
decodedToken, err := base64.StdEncoding.DecodeString(token)
50+
if err != nil {
51+
return nil, err
52+
}
53+
parts := strings.SplitN(string(decodedToken), ":", 2)
54+
if len(parts) != 2 {
55+
return nil, errors.New("Invalid token in docker config secret")
56+
}
57+
user := parts[0]
58+
password := parts[1]
59+
regDetails := make(map[string]string)
60+
regDetails["DEIS_REGISTRY_USERNAME"] = user
61+
regDetails["DEIS_REGISTRY_PASSWORD"] = password
62+
regDetails["DEIS_REGISTRY_HOSTNAME"] = hostname
63+
return regDetails, nil
64+
}
65+
66+
func getRegistryDetails(kubeClient client.SecretsNamespacer, image *string, registryLocation, namespace, registrySecretPrefix string) (map[string]string, error) {
67+
registryConfigSecretInterface := kubeClient.Secrets(*image)
68+
privateRegistrySecretInterface := kubeClient.Secrets(namespace)
69+
registryEnv := make(map[string]string)
70+
var regSecretData map[string]string
71+
var err error
72+
if registryLocation == "off-cluster" {
73+
regSecretData, err = getDetailsFromRegistrySecret(privateRegistrySecretInterface, registrySecret)
74+
if err != nil {
75+
return nil, err
76+
}
77+
for key, value := range regSecretData {
78+
registryEnv["DEIS_REGISTRY_"+strings.ToUpper(key)] = value
79+
}
80+
if registryEnv["DEIS_REGISTRY_ORGANIZATION"] != "" {
81+
*image = registryEnv["DEIS_REGISTRY_ORGANIZATION"] + "/" + *image
82+
}
83+
if registryEnv["DEIS_REGISTRY_HOSTNAME"] != "" {
84+
*image = registryEnv["DEIS_REGISTRY_HOSTNAME"] + "/" + *image
85+
}
86+
} else if registryLocation == "ecr" {
87+
registryEnv, err = getDetailsFromDockerConfigSecret(registryConfigSecretInterface, registrySecretPrefix+"-"+registryLocation)
88+
if err != nil {
89+
return nil, err
90+
}
91+
92+
regSecretData, err = getDetailsFromRegistrySecret(privateRegistrySecretInterface, registrySecret)
93+
if err != nil {
94+
return nil, err
95+
}
96+
err = storage.CreateImageRepo(*image, regSecretData)
97+
if err != nil {
98+
return nil, err
99+
}
100+
hostname := strings.Replace(registryEnv["DEIS_REGISTRY_HOSTNAME"], "https://", "", 1)
101+
*image = hostname + "/" + *image
102+
103+
} else if registryLocation == "gcr" {
104+
registryEnv, err = getDetailsFromDockerConfigSecret(registryConfigSecretInterface, registrySecretPrefix+"-"+registryLocation)
105+
if err != nil {
106+
return nil, err
107+
}
108+
109+
regSecretData, err = getDetailsFromRegistrySecret(privateRegistrySecretInterface, registrySecret)
110+
if err != nil {
111+
return nil, err
112+
}
113+
var key struct {
114+
ProjectID string `json:"project_id"`
115+
}
116+
jsonKey := []byte(regSecretData["key.json"])
117+
if err := json.Unmarshal(jsonKey, &key); err != nil {
118+
return nil, err
119+
}
120+
hostname := strings.Replace(registryEnv["DEIS_REGISTRY_HOSTNAME"], "https://", "", 1)
121+
projectID := strings.Replace(key.ProjectID, ":", "/", -1)
122+
registryEnv["DEIS_REGISTRY_GCS_PROJ_ID"] = projectID
123+
*image = strings.Replace(hostname, "https://", "", 1) + "/" + projectID + "/" + *image
124+
}
125+
return registryEnv, nil
126+
}

0 commit comments

Comments
 (0)