Skip to content

Commit 58c0e62

Browse files
arschlesAaron Schlesinger
authored andcommitted
ref(gitreceive): complete builder shell-to-go refactor
1 parent 266c133 commit 58c0e62

16 files changed

Lines changed: 218 additions & 651 deletions

pkg/gitreceive/build.go

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,11 @@ func build(conf *Config, newRev string) error {
4747
// PUSH_URL=$HTTP_PREFIX://$S3EP/git/home/${SLUG_NAME}/push
4848
storage, err := getStorageConfig()
4949
if err != nil {
50-
log.Err(err.Error())
51-
os.Exit(1)
50+
return err
5251
}
5352
creds, err := getStorageCreds()
5453
if err == errMissingKey || err == errMissingSecret {
55-
log.Err(err.Error())
56-
os.Exit(1)
54+
return err
5755
}
5856

5957
// #!/usr/bin/env bash
@@ -139,8 +137,7 @@ func build(conf *Config, newRev string) error {
139137
metaName := strings.Replace(slugName, ":", "-", -1)
140138
tmpImage := fmt.Sprintf("%s:%s/%s", conf.RegistryHost, conf.RegistryPort, conf.ImageName)
141139
if err := os.MkdirAll(buildDir, os.ModeDir); err != nil {
142-
log.Err("making the build directory %s (%s)", buildDir, err)
143-
os.Exit(1)
140+
return fmt.Errorf("making the build directory %s (%s)", buildDir, err)
144141
}
145142
tmpDir := os.TempDir()
146143

@@ -156,17 +153,15 @@ func build(conf *Config, newRev string) error {
156153
cmd.Stdout = os.Stdout
157154
cmd.Stderr = os.Stderr
158155
if err := cmd.Run(); err != nil {
159-
log.Err("running %s", strings.Join(cmd.Args, " "))
160-
os.Exit(1)
156+
return fmt.Errorf("running %s", strings.Join(cmd.Args, " "))
161157
}
162158
// tar -xzf ${APP_NAME}.tar.gz -C $TMP_DIR/
163159
tarCmd := exec.Command("tar", "-xzf", fmt.Sprintf("%s.tar.gz", appName), "-C", fmt.Sprintf("%s/", tmpDir))
164160
tarCmd.Dir = repoDir
165161
tarCmd.Stdout = os.Stdout
166162
tarCmd.Stderr = os.Stderr
167163
if err := tarCmd.Run(); err != nil {
168-
log.Err("running %s", strings.Join(cmd.Args, " "))
169-
os.Exit(1)
164+
return fmt.Errorf("running %s", strings.Join(cmd.Args, " "))
170165
}
171166

172167
// USING_DOCKERFILE=true
@@ -184,8 +179,7 @@ func build(conf *Config, newRev string) error {
184179
}
185180
procFile, err := pkg.YamlToJSON(rawProcFile)
186181
if err != nil {
187-
log.Err("procfile %s/Procfile is not valid JSON [%s]", tmpDir, err)
188-
os.Exit(1)
182+
return fmt.Errorf("procfile %s/Procfile is not valid JSON [%s]", tmpDir, err)
189183
}
190184

191185
// if [[ ! -f /var/run/secrets/object/store/access-key-id ]]; then
@@ -226,14 +220,12 @@ func build(conf *Config, newRev string) error {
226220
}
227221
} else if err != nil {
228222
// unexpected error, fail
229-
log.Err("unexpected error (%s)", err)
230-
os.Exit(1)
223+
return fmt.Errorf("unexpected error (%s)", err)
231224
}
232225

233226
fileBytes, err := ioutil.ReadFile(srcManifest)
234227
if err != nil {
235-
log.Err("reading kubernetes manifest %s (%s)", srcManifest, err)
236-
os.Exit(1)
228+
return fmt.Errorf("reading kubernetes manifest %s (%s)", srcManifest, err)
237229
}
238230

239231
// sed -i -- "s#repo_name#$META_NAME#g" /etc/${SLUG_NAME}.yaml
@@ -255,8 +247,7 @@ func build(conf *Config, newRev string) error {
255247
}
256248

257249
if err := ioutil.WriteFile(finalManifestFileName, []byte(finalManifest), os.ModePerm); err != nil {
258-
log.Err("writing final manifest %s (%s)", finalManifestFileName, err)
259-
os.Exit(1)
250+
return fmt.Errorf("writing final manifest %s (%s)", finalManifestFileName, err)
260251
}
261252
//
262253
// git archive --format=tar.gz ${GIT_SHA} > ${APP_NAME}.tar.gz
@@ -266,8 +257,7 @@ func build(conf *Config, newRev string) error {
266257
gitArchiveCmd.Stdout = os.Stdout
267258
gitArchiveCmd.Stderr = os.Stderr
268259
if err := gitArchiveCmd.Run(); err != nil {
269-
log.Err("running %s", strings.Join(cmd.Args, " "))
270-
os.Exit(1)
260+
return fmt.Errorf("running %s", strings.Join(cmd.Args, " "))
271261
}
272262

273263
//
@@ -283,8 +273,7 @@ func build(conf *Config, newRev string) error {
283273
// MC_PREFIX="mc -C $CONFIG_DIR --quiet"
284274
configDir := "/var/minio-conf"
285275
if err := os.MkdirAll(configDir, os.ModePerm); err != nil {
286-
log.Err("creating minio config file (%s)", err)
287-
os.Exit(1)
276+
return fmt.Errorf("creating minio config file (%s)", err)
288277
}
289278
baseMinioCmd := exec.Command("mc", "-C", configDir, "--quiet")
290279
baseMinioCmd.Stderr = os.Stderr
@@ -301,8 +290,7 @@ func build(conf *Config, newRev string) error {
301290
creds.secret,
302291
)
303292
if err := configCmd.Run(); err != nil {
304-
log.Err("configuring the minio client (%s)", err)
305-
os.Exit(1)
293+
return fmt.Errorf("configuring the minio client (%s)", err)
306294
}
307295

308296
// $MC_PREFIX mb "$HTTP_PREFIX://${S3EP}/git" &>/dev/null
@@ -325,8 +313,7 @@ func build(conf *Config, newRev string) error {
325313
)
326314
cpCmd.Dir = repoDir
327315
if err := cpCmd.Run(); err != nil {
328-
log.Err("copying %s.tar.gz to %s (%s)", appName, tarURL, err)
329-
os.Exit(1)
316+
return fmt.Errorf("copying %s.tar.gz to %s (%s)", appName, tarURL, err)
330317
}
331318

332319
//
@@ -343,8 +330,7 @@ func build(conf *Config, newRev string) error {
343330
)
344331
kubectlCmd.Stderr = os.Stderr
345332
if err := kubectlCmd.Run(); err != nil {
346-
log.Err("creating builder pod (%s)", err)
347-
os.Exit(1)
333+
return fmt.Errorf("creating builder pod (%s)", err)
348334
}
349335

350336
//
@@ -369,8 +355,7 @@ func build(conf *Config, newRev string) error {
369355
var out bytes.Buffer
370356
getCmd.Stdout = &out
371357
if err := getCmd.Run(); err != nil {
372-
log.Err("running %s while determining if builder pod %s is running (%s)", buildPodName, err)
373-
os.Exit(1)
358+
return fmt.Errorf("running %s while determining if builder pod %s is running (%s)", buildPodName, err)
374359
}
375360
if strings.Contains(string(out.Bytes()), "phase: Running") {
376361
break
@@ -388,8 +373,7 @@ func build(conf *Config, newRev string) error {
388373
)
389374
logsCmd.Stdout = os.Stdout
390375
if err := logsCmd.Run(); err != nil {
391-
log.Err("running %s to get builder logs (%s)", strings.Join(logsCmd.Args, " "), err)
392-
os.Exit(1)
376+
return fmt.Errorf("running %s to get builder logs (%s)", strings.Join(logsCmd.Args, " "), err)
393377
}
394378

395379
//
@@ -438,6 +422,18 @@ func build(conf *Config, newRev string) error {
438422
// exit 1
439423
// fi
440424
//
425+
426+
cfg, err := getAppConfig(
427+
conf,
428+
getBuilderKey(),
429+
conf.Username,
430+
conf.App,
431+
)
432+
if err != nil {
433+
return fmt.Errorf("getting app config for %s (%s)", conf.App, err)
434+
os.Exit(1)
435+
}
436+
441437
// # use Procfile if provided, otherwise try default process types from ./release
442438
//
443439
// puts-step "Launching... "
@@ -450,6 +446,25 @@ func build(conf *Config, newRev string) error {
450446
// puts-warn $PUBLISH_RELEASE
451447
// exit 1
452448
// fi
449+
450+
log.Info("Launching...")
451+
452+
buildHook := &pkg.BuildHook{
453+
Sha: conf.SHA,
454+
ReceiveUser: conf.Username,
455+
ReceiveRepo: conf.Repository,
456+
Image: conf.ImageName,
457+
Procfile: procFile,
458+
Dockerfile: usingDockerfile,
459+
}
460+
buildHookResp, err := publishRelease(
461+
conf,
462+
getBuilderKey(),
463+
buildHook,
464+
)
465+
if err != nil {
466+
return fmt.Errorf("publishing release (%s)", err)
467+
}
453468
//
454469
// RELEASE=$(echo $PUBLISH_RELEASE | extract-version)
455470
// DOMAIN=$(echo $PUBLISH_RELEASE | extract-domain)
@@ -459,10 +474,30 @@ func build(conf *Config, newRev string) error {
459474
// echo
460475
// indent "To learn more, use \`deis help\` or visit http://deis.io"
461476
// echo
477+
478+
release, ok := buildHookResp.Release["version"]
479+
if !ok {
480+
return fmt.Errorf("No release returned from Deis controller")
481+
}
482+
if buildHookResp.Domains == nil || len(buildHookResp.Domains) == 0 {
483+
return fmt.Errorf("No domains returned from Deis controller")
484+
}
485+
domain := buildHookResp.Domains[0]
486+
487+
log.Info(fmt.Sprintf("http://%s", domain))
488+
log.Info("To learn more, use 'deis help' or visit http://deis.io")
489+
462490
//
463491
// # cleanup
464492
// cd $REPO_DIR
465493
// git gc &>/dev/null
466494

495+
gcCmd := exec.Command("git", "gc")
496+
gcCmd.Dir = repoDir
497+
if err := gcCmd.Run(); err != nil {
498+
return fmt.Errorf("cleaning up the repository with %s (%s)", strings.Join(gcCmd.Args, " "), err)
499+
// TODO: is it ok not to exit even if the repo was not cleaned up
500+
}
501+
467502
return nil
468503
}

pkg/gitreceive/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ type Config struct {
1616
App string `envconfing:"app"`
1717
Fingerprint string `envconfing:"fingerprint"`
1818
ImageName string `envconfig:"image_name"`
19-
PodNamespace string `envconfig:"POD_NAMESPACE"`
19+
PodNamespace string `envconfig:"pod_namespace"`
2020
}

pkg/gitreceive/constants.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package gitreceive
2+
3+
const (
4+
contentType string = "application/json"
5+
userAgent string = "deis-builder"
6+
)

pkg/gitreceive/controller.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package gitreceive
2+
3+
import (
4+
"error"
5+
"strings"
6+
)
7+
8+
var (
9+
errControllerNotFound = errors.New("Deis controller not found. Is it running?")
10+
errControllerServiceUnavailable = errors.New("Deis controller was unavailable. Is it healthy?")
11+
)
12+
13+
type unexpectedControllerStatusCode struct {
14+
expected int
15+
actual int
16+
}
17+
18+
func (u unexpectedControllerStatusCode) Error() string {
19+
return fmt.Sprintf("Expected status code %d from Deis controller, got %d", u.expected, u.actual)
20+
}
21+
22+
func controllerURLStr(conf *Config, additionalPath ...string) string {
23+
return fmt.Sprintf("http://%s:%s/%s", conf.WorkflowHost, conf.WorkflowPort, strings.Join(additionalPath, "/"))
24+
}

pkg/gitreceive/get_app_config.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package gitreceive
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"errors"
7+
"flag"
8+
"fmt"
9+
"io/ioutil"
10+
"net/http"
11+
"os"
12+
13+
"github.com/deis/builder/pkg"
14+
)
15+
16+
func getAppConfig(conf *Config, builderKey, userName, appName string) (*pkg.Config, error) {
17+
data, err := json.Marshal(&pkg.ConfigHook{
18+
ReceiveUser: userName,
19+
ReceiveRepo: appName,
20+
})
21+
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
b := bytes.NewReader(data)
27+
url := controllerURLStr(conf, "v2", "hooks", "config")
28+
req, err := http.NewRequest("POST", url, b)
29+
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
req.Header.Add("Content-Type", contentType)
35+
req.Header.Add("Accept", contentType)
36+
req.Header.Add("User-Agent", userAgent)
37+
req.Header.Add("X-Deis-Builder-Auth", builderKey)
38+
39+
res, err := http.DefaultClient.Do(req)
40+
if err != nil {
41+
return nil, err
42+
}
43+
defer res.Body.Close()
44+
45+
if res.StatusCode == 404 {
46+
return nil, errControllerNotFound
47+
} else if res.StatusCode != 200 {
48+
return nil, unexpectedControllerStatusCode{expected: 200, actual: res.StatusCode}
49+
}
50+
51+
ret := &pkg.Config{}
52+
if err := json.NewDecoder(res.Body).Decode(ret); err != nil {
53+
return nil, err
54+
}
55+
return nil, ret
56+
}

pkg/gitreceive/publish_release.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package gitreceive
2+
3+
import (
4+
"encoding/json"
5+
"flag"
6+
"fmt"
7+
"io/ioutil"
8+
"log"
9+
"net/http"
10+
"os"
11+
"regexp"
12+
"strings"
13+
14+
"github.com/deis/builder/pkg"
15+
)
16+
17+
func publishRelease(conf *Config, builderKey string, buildHook *pkg.BuildHook) (*pkg.BuildHookResponse, error) {
18+
19+
var b bytes.Buffer
20+
if err := json.NewEncoder(&b).Encode(buildHook); err != nil {
21+
return nil, err
22+
}
23+
url := controllerURLStr(conf, "v2", "hooks", "build")
24+
req, err := http.NewRequest("POST", url, b)
25+
if err != nil {
26+
return nil, err
27+
}
28+
req.Header.Add("Content-Type", contentType)
29+
req.Header.Add("Accept", contentType)
30+
req.Header.Add("User-Agent", userAgent)
31+
req.Header.Add("X-Deis-Builder-Auth", *builderKey)
32+
33+
res, err := http.DefaultClient.Do(req)
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
defer res.Body.Close()
39+
40+
if res.StatusCode == http.StatusNotFound {
41+
return nil, errControllerNotFound
42+
} else if res.StatusCode == http.StatusServiceUnavailable {
43+
return nil, errControllerServiceUnavailable
44+
} else if res.StatusCode != 200 {
45+
return nil, unexpectedControllerStatusCode{expected: 200, actual: res.StatusCode}
46+
}
47+
48+
ret := new(pkg.BuildHookResponse)
49+
if err := json.NewDecoder(res.Body).Decode(ret); err != nil {
50+
return nil, err
51+
}
52+
53+
return ret, nil
54+
}

0 commit comments

Comments
 (0)