Skip to content

Commit 93eae9a

Browse files
author
Keerthan Mala
committed
feat(storage): implement separate storage layer
1 parent f8ce7d7 commit 93eae9a

17 files changed

Lines changed: 750 additions & 109 deletions

File tree

boot.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"github.com/deis/builder/pkg/gitreceive"
1414
"github.com/deis/builder/pkg/healthsrv"
1515
"github.com/deis/builder/pkg/sshd"
16-
"github.com/deis/builder/pkg/storage"
16+
"github.com/deis/builder/pkg/storage/driver/factory"
1717
"github.com/deis/builder/pkg/sys"
1818
pkglog "github.com/deis/pkg/log"
1919
kcl "k8s.io/kubernetes/pkg/client/unversioned"
@@ -49,16 +49,21 @@ func main() {
4949
pkglog.Err("getting config for %s [%s]", serverConfAppName, err)
5050
os.Exit(1)
5151
}
52-
env := sys.RealEnv()
53-
fs := sys.RealFS()
52+
5453
pushLock := sshd.NewInMemoryRepositoryLock()
5554
circ := sshd.NewCircuit()
5655

57-
s3Client, err := storage.GetClient(cnf.HealthSrvTestStorageRegion, fs, env)
56+
storageParams, err := conf.GetStorageParams()
5857
if err != nil {
59-
log.Printf("Error getting s3 client (%s)", err)
58+
log.Printf("Error getting storage parameters (%s)", err)
6059
os.Exit(1)
6160
}
61+
storageDriver, err := factory.Create(cnf.StorageType, storageParams)
62+
if err != nil {
63+
log.Printf("Error creating storage driver (%s)", err)
64+
os.Exit(1)
65+
}
66+
6267
kubeClient, err := kcl.NewInCluster()
6368
if err != nil {
6469
log.Printf("Error getting kubernetes client [%s]", err)
@@ -67,7 +72,7 @@ func main() {
6772
log.Printf("Starting health check server on port %d", cnf.HealthSrvPort)
6873
healthSrvCh := make(chan error)
6974
go func() {
70-
if err := healthsrv.Start(cnf.HealthSrvPort, kubeClient.Namespaces(), s3Client, circ); err != nil {
75+
if err := healthsrv.Start(cnf.HealthSrvPort, kubeClient.Namespaces(), storageDriver, circ); err != nil {
7176
healthSrvCh <- err
7277
}
7378
}()
@@ -111,8 +116,18 @@ func main() {
111116
cnf.CheckDurations()
112117
fs := sys.RealFS()
113118
env := sys.RealEnv()
119+
storageParams, err := conf.GetStorageParams()
120+
if err != nil {
121+
log.Printf("Error getting storage parameters (%s)", err)
122+
os.Exit(1)
123+
}
124+
storageDriver, err := factory.Create(cnf.StorageType, storageParams)
125+
if err != nil {
126+
log.Printf("Error creating storage driver (%s)", err)
127+
os.Exit(1)
128+
}
114129

115-
if err := gitreceive.Run(cnf, fs, env); err != nil {
130+
if err := gitreceive.Run(cnf, fs, env, storageDriver); err != nil {
116131
log.Printf("Error running git receive hook [%s]", err)
117132
os.Exit(1)
118133
}

pkg/conf/config.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ import (
88
)
99

1010
const (
11-
builderKeyLocation = "/var/run/secrets/api/auth/builder-key"
11+
builderKeyLocation = "/var/run/secrets/api/auth/builder-key"
12+
storageCredLocation = "/var/run/secrets/deis/builder/creds/"
1213
)
1314

15+
type Parameters map[string]string
16+
1417
// EnvConfig is a convenience function to process the envconfig (
1518
// https://github.com/kelseyhightower/envconfig) based configuration environment variables into
1619
// conf. Additional notes:
@@ -35,3 +38,24 @@ func GetBuilderKey() (string, error) {
3538
builderKey := string(builderKeyBytes)
3639
return builderKey, nil
3740
}
41+
42+
func GetStorageParams() (Parameters, error) {
43+
params := make(map[string]string)
44+
files, err := ioutil.ReadDir(storageCredLocation)
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
for _, file := range files {
50+
data, err := ioutil.ReadFile(storageCredLocation + file.Name())
51+
if err != nil {
52+
return nil, err
53+
}
54+
if file.Name() == "key.json" {
55+
params["keyfile"] = storageCredLocation + file.Name()
56+
} else {
57+
params[file.Name()] = string(data)
58+
}
59+
}
60+
return params, nil
61+
}

pkg/gitreceive/build.go

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/deis/pkg/log"
1919
"gopkg.in/yaml.v2"
2020

21+
storagedriver "github.com/deis/builder/pkg/storage/driver"
2122
"k8s.io/kubernetes/pkg/api"
2223
client "k8s.io/kubernetes/pkg/client/unversioned"
2324
)
@@ -41,7 +42,7 @@ func run(cmd *exec.Cmd) error {
4142
return cmd.Run()
4243
}
4344

44-
func build(conf *Config, s3Client *storage.Client, kubeClient *client.Client, fs sys.FS, env sys.Env, builderKey, rawGitSha string) error {
45+
func build(conf *Config, storageDriver storagedriver.StorageDriver, kubeClient *client.Client, fs sys.FS, env sys.Env, builderKey, rawGitSha string) error {
4546
repo := conf.Repository
4647
gitSha, err := git.NewSha(rawGitSha)
4748
if err != nil {
@@ -63,7 +64,7 @@ func build(conf *Config, s3Client *storage.Client, kubeClient *client.Client, fs
6364
return fmt.Errorf("unable to create tmpdir %s (%s)", buildDir, err)
6465
}
6566

66-
slugBuilderInfo := NewSlugBuilderInfo(s3Client.Endpoint, conf.Bucket, appName, slugName, gitSha)
67+
slugBuilderInfo := storage.NewSlugBuilderInfo(slugName)
6768

6869
// Get the application config from the controller, so we can check for a custom buildpack URL
6970
appConf, err := getAppConfig(conf, builderKey, conf.Username, appName)
@@ -100,18 +101,15 @@ func build(conf *Config, s3Client *storage.Client, kubeClient *client.Client, fs
100101
bType := getBuildTypeForDir(tmpDir)
101102
usingDockerfile := bType == buildTypeDockerfile
102103

103-
if err := storage.CreateBucket(s3Client, conf.Bucket); err != nil {
104-
log.Warn("create bucket error: %+v", err)
105-
}
106-
107-
appTgzReader, err := os.Open(absAppTgz)
104+
appTgzdata, err := ioutil.ReadFile(absAppTgz)
108105
if err != nil {
109-
return fmt.Errorf("opening %s for read (%s)", appTgz, err)
106+
return fmt.Errorf("error while reading file %s: (%s)", appTgz, err)
110107
}
111108

112-
log.Debug("Uploading tar to %s/%s/%s", s3Client.Endpoint.FullURL(), conf.Bucket, slugBuilderInfo.TarKey())
113-
if err := storage.UploadObject(s3Client, conf.Bucket, slugBuilderInfo.TarKey(), appTgzReader); err != nil {
114-
return fmt.Errorf("uploading %s to %s/%s (%v)", absAppTgz, conf.Bucket, slugBuilderInfo.TarKey(), err)
109+
//log.Debug("Uploading tar to %s/%s/%s", s3Client.Endpoint.FullURL(), conf.Bucket, slugBuilderInfo.TarKey())
110+
111+
if err := storageDriver.PutContent(slugBuilderInfo.TarKey(), appTgzdata); err != nil {
112+
return fmt.Errorf("uploading %s to %s (%v)", absAppTgz, slugBuilderInfo.TarKey(), err)
115113
}
116114

117115
creds := storage.CredsOK(fs)
@@ -126,7 +124,7 @@ func build(conf *Config, s3Client *storage.Client, kubeClient *client.Client, fs
126124
buildPodName,
127125
conf.PodNamespace,
128126
appConf.Values,
129-
slugBuilderInfo.TarURL(),
127+
slugBuilderInfo.TarKey(),
130128
slugName,
131129
conf.StorageRegion,
132130
conf.DockerBuilderImage,
@@ -139,10 +137,11 @@ func build(conf *Config, s3Client *storage.Client, kubeClient *client.Client, fs
139137
buildPodName,
140138
conf.PodNamespace,
141139
appConf.Values,
142-
slugBuilderInfo.TarURL(),
143-
slugBuilderInfo.PushURL(),
140+
slugBuilderInfo.TarKey(),
141+
slugBuilderInfo.PushKey(),
144142
buildPackURL,
145143
conf.SlugBuilderImage,
144+
conf.StorageType,
146145
)
147146
}
148147

@@ -211,17 +210,15 @@ func build(conf *Config, s3Client *storage.Client, kubeClient *client.Client, fs
211210
log.Debug("Done")
212211

213212
log.Debug(
214-
"Polling the S3 server every %s for %s for the resultant slug at %s/%s",
213+
"Polling the S3 server every %s for %s for the resultant slug at %s",
215214
conf.ObjectStorageTickDuration(),
216215
conf.ObjectStorageWaitDuration(),
217-
conf.Bucket,
218216
slugBuilderInfo.AbsoluteSlugObjectKey(),
219217
)
220218
// poll the s3 server to ensure the slug exists
221219
if !usingDockerfile {
222220
if err := storage.WaitForObject(
223-
s3Client,
224-
conf.Bucket,
221+
storageDriver,
225222
slugBuilderInfo.AbsoluteSlugObjectKey(),
226223
conf.ObjectStorageTickDuration(),
227224
conf.ObjectStorageWaitDuration(),
@@ -232,8 +229,7 @@ func build(conf *Config, s3Client *storage.Client, kubeClient *client.Client, fs
232229

233230
procType := pkg.ProcessType{}
234231
if bType == buildTypeProcfile {
235-
getter := &storage.RealObjectGetter{Client: s3Client.Client}
236-
if procType, err = getProcFile(getter, tmpDir, conf.Bucket, slugBuilderInfo.AbsoluteProcfileKey()); err != nil {
232+
if procType, err = getProcFile(storageDriver, tmpDir, slugBuilderInfo.AbsoluteProcfileKey()); err != nil {
237233
return err
238234
}
239235
}
@@ -276,7 +272,7 @@ func prettyPrintJSON(data interface{}) (string, error) {
276272
return string(formatted.Bytes()), nil
277273
}
278274

279-
func getProcFile(getter storage.ObjectGetter, dirName, bucketName, procfileKey string) (pkg.ProcessType, error) {
275+
func getProcFile(storageDriver storagedriver.StorageDriver, dirName, procfileKey string) (pkg.ProcessType, error) {
280276
procType := pkg.ProcessType{}
281277
if _, err := os.Stat(fmt.Sprintf("%s/Procfile", dirName)); err == nil {
282278
rawProcFile, err := ioutil.ReadFile(fmt.Sprintf("%s/Procfile", dirName))
@@ -289,12 +285,12 @@ func getProcFile(getter storage.ObjectGetter, dirName, bucketName, procfileKey s
289285
return procType, nil
290286
}
291287
log.Debug("Procfile not present. Getting it from the buildpack")
292-
rawProcFile, err := storage.DownloadObject(getter, bucketName, procfileKey)
288+
rawProcFile, err := storageDriver.GetContent(procfileKey)
293289
if err != nil {
294-
return nil, fmt.Errorf("error in reading %s/%s (%s)", bucketName, procfileKey, err)
290+
return nil, fmt.Errorf("error in reading %s (%s)", procfileKey, err)
295291
}
296292
if err := yaml.Unmarshal(rawProcFile, &procType); err != nil {
297-
return nil, fmt.Errorf("procfile %s/%s is malformed (%s)", bucketName, procfileKey, err)
293+
return nil, fmt.Errorf("procfile %s is malformed (%s)", procfileKey, err)
298294
}
299295
return procType, nil
300296
}

pkg/gitreceive/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ type Config struct {
3232
BuilderPodWaitDurationMSec int `envconfig:"BUILDER_POD_WAIT_DURATION" default:"900000"` // 15 minutes
3333
ObjectStorageTickDurationMSec int `envconfing:"OBJECT_STORAGE_TICK_DURATION" default:"500"`
3434
ObjectStorageWaitDurationMSec int `envconfig:"OBJECT_STORAGE_WAIT_DURATION" default:"300000"` // 5 minutes
35-
Bucket string `envconfig:"BUCKET" default:"git"`
3635
SlugBuilderImage string `envconfig:"SLUGBUILDER_IMAGE_NAME" default:"quay.io/deisci/slugbuilder:v2-beta"`
3736
DockerBuilderImage string `envconfig:"DOCKERBUILDER_IMAGE_NAME" default:"quay.io/deisci/dockerbuilder:v2-beta"`
37+
StorageType string `envconfig:"BUILDER_STORAGE" default:"minio"`
3838
}
3939

4040
// App returns the application name represented by c. The app name is the same as c.Repository

pkg/gitreceive/controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func createBuildHook(
168168
if !usingDockerfile {
169169
ret.Dockerfile = ""
170170
// need this to tell the controller what URL to give the slug runner
171-
ret.Image = slugBuilderInfo.AbsoluteSlugURL()
171+
ret.Image = slugBuilderInfo.AbsoluteSlugObjectKey()
172172
} else {
173173
ret.Dockerfile = "true"
174174
}

pkg/gitreceive/k8s_util.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const (
1818
tarURLKey = "TAR_URL"
1919
putURLKey = "put_url"
2020
debugKey = "DEBUG"
21-
minioUser = "minio-user"
21+
minioUser = "objectstorage-keyfile"
2222
dockerSocketName = "docker-socket"
2323
dockerSocketPath = "/var/run/docker.sock"
2424
)
@@ -63,14 +63,15 @@ func dockerBuilderPod(debug, withAuth bool, name, namespace string, env map[stri
6363
return &pod
6464
}
6565

66-
func slugbuilderPod(debug, withAuth bool, name, namespace string, env map[string]interface{}, tarURL, putURL, buildpackURL, slugBuilderImage string) *api.Pod {
66+
func slugbuilderPod(debug, withAuth bool, name, namespace string, env map[string]interface{}, tarKey, putURL, buildpackURL, slugBuilderImage, storageType string) *api.Pod {
6767
pod := buildPod(debug, withAuth, name, namespace, env)
6868

6969
pod.Spec.Containers[0].Name = slugBuilderName
7070
pod.Spec.Containers[0].Image = slugBuilderImage
7171

72-
addEnvToPod(pod, tarURLKey, tarURL)
72+
addEnvToPod(pod, tarURLKey, tarKey)
7373
addEnvToPod(pod, putURLKey, putURL)
74+
addEnvToPod(pod, "BUILDER_STORAGE", storageType)
7475

7576
if buildpackURL != "" {
7677
addEnvToPod(pod, "BUILDPACK_URL", buildpackURL)
@@ -112,7 +113,7 @@ func buildPod(debug, withAuth bool, name, namespace string, env map[string]inter
112113
pod.Spec.Containers[0].VolumeMounts = []api.VolumeMount{
113114
api.VolumeMount{
114115
Name: minioUser,
115-
MountPath: "/var/run/secrets/object/store",
116+
MountPath: "/var/run/secrets/deis/objectstore/creds",
116117
ReadOnly: true,
117118
},
118119
}

pkg/gitreceive/run.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ import (
66
"os"
77
"strings"
88

9-
"github.com/deis/builder/pkg/storage"
9+
builderconf "github.com/deis/builder/pkg/conf"
10+
storagedriver "github.com/deis/builder/pkg/storage/driver"
1011
"github.com/deis/builder/pkg/sys"
1112
"github.com/deis/pkg/log"
1213

13-
builderconf "github.com/deis/builder/pkg/conf"
14-
1514
client "k8s.io/kubernetes/pkg/client/unversioned"
1615
)
1716

@@ -25,19 +24,14 @@ func readLine(line string) (string, string, string, error) {
2524

2625
// Run runs the git-receive hook. This func is effectively the main for the git-receive hook,
2726
// although it is called from the main in boot.go.
28-
func Run(conf *Config, fs sys.FS, env sys.Env) error {
27+
func Run(conf *Config, fs sys.FS, env sys.Env, storageDriver storagedriver.StorageDriver) error {
2928
log.Debug("Running git hook")
3029

3130
builderKey, err := builderconf.GetBuilderKey()
3231
if err != nil {
3332
return err
3433
}
3534

36-
s3Client, err := storage.GetClient(conf.StorageRegion, fs, env)
37-
if err != nil {
38-
return fmt.Errorf("configuring S3 client (%s)", err)
39-
}
40-
4135
kubeClient, err := client.NewInCluster()
4236
if err != nil {
4337
return fmt.Errorf("couldn't reach the api server (%s)", err)
@@ -59,7 +53,7 @@ func Run(conf *Config, fs sys.FS, env sys.Env) error {
5953
}
6054
// if we're processing a receive-pack on an existing repo, run a build
6155
if strings.HasPrefix(conf.SSHOriginalCommand, "git-receive-pack") {
62-
if err := build(conf, s3Client, kubeClient, fs, env, builderKey, newRev); err != nil {
56+
if err := build(conf, storageDriver, kubeClient, fs, env, builderKey, newRev); err != nil {
6357
return err
6458
}
6559
}

pkg/gitreceive/slug_builder_info.go

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ package gitreceive
22

33
import (
44
"fmt"
5-
6-
"github.com/deis/builder/pkg/gitreceive/git"
7-
"github.com/deis/builder/pkg/storage"
85
)
96

107
const (
@@ -15,50 +12,32 @@ const (
1512
// slug builder.
1613
type SlugBuilderInfo struct {
1714
pushKey string
18-
pushURL string
1915
tarKey string
20-
tarURL string
2116
}
2217

2318
// NewSlugBuilderInfo creates and populates a new SlugBuilderInfo based on the given data
24-
func NewSlugBuilderInfo(s3Endpoint *storage.Endpoint, bucket, appName, slugName string, gitSha *git.SHA) *SlugBuilderInfo {
19+
func NewSlugBuilderInfo(slugName string) *SlugBuilderInfo {
2520
tarKey := fmt.Sprintf("home/%s/tar", slugName)
26-
// this is where the controller tells slugrunner to download the slug from, so we have to
27-
// tell slugbuilder to upload it to here
28-
pushKey := fmt.Sprintf("home/%s:git-%s/push", appName, gitSha.Short())
21+
// this is where workflow tells slugrunner to download the slug from, so we have to tell slugbuilder to upload it to here
22+
pushKey := fmt.Sprintf("home/%s/push", slugName)
2923

3024
return &SlugBuilderInfo{
3125
pushKey: pushKey,
32-
pushURL: fmt.Sprintf("%s/%s/%s", s3Endpoint.FullURL(), bucket, pushKey),
3326
tarKey: tarKey,
34-
tarURL: fmt.Sprintf("%s/%s/%s", s3Endpoint.FullURL(), bucket, tarKey),
3527
}
3628
}
3729

3830
// PushKey returns the object storage key that the slug builder will store the slug in.
3931
// The returned value only contains the path to the folder, not including the final filename.
4032
func (s SlugBuilderInfo) PushKey() string { return s.pushKey }
4133

42-
// PushURL returns the complete object storage URL that the slug builder will store the slug in.
43-
// The returned value only contains the URL to the folder, not including the final filename.
44-
func (s SlugBuilderInfo) PushURL() string { return s.pushURL }
45-
4634
// TarKey returns the object storage key from which the slug builder will download for the tarball
4735
// (from which it uses to build the slug). The returned value only contains the path to the
4836
// folder, not including the final filename.
4937
func (s SlugBuilderInfo) TarKey() string { return s.tarKey }
5038

51-
// TarURL returns the complete object storage URL that the slug builder will download the tarball
52-
// from. The returned value only contains the URL to the folder, not including the final filename.
53-
func (s SlugBuilderInfo) TarURL() string { return s.tarURL }
54-
5539
// AbsoluteSlugObjectKey returns the PushKey plus the final filename of the slug.
5640
func (s SlugBuilderInfo) AbsoluteSlugObjectKey() string { return s.PushKey() + "/" + slugTGZName }
5741

5842
// AbsoluteProcfileKey returns the PushKey plus the standard procfile name.
5943
func (s SlugBuilderInfo) AbsoluteProcfileKey() string { return s.PushKey() + "/Procfile" }
60-
61-
// AbsoluteSlugURL returns the PushURL plus the final filename of the slug.
62-
func (s SlugBuilderInfo) AbsoluteSlugURL() string {
63-
return s.PushURL() + "/" + slugTGZName
64-
}

0 commit comments

Comments
 (0)