mirror of
https://github.com/imjasonh/kontain.me
synced 2026-07-18 14:47:48 +00:00
better errors, better logging, moar packages
This commit is contained in:
parent
4ef0aafc7b
commit
719a5559e9
6 changed files with 97 additions and 37 deletions
|
|
@ -17,7 +17,8 @@ import (
|
|||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/imjasonh/kontain.me/pkg"
|
||||
"github.com/imjasonh/kontain.me/pkg/run"
|
||||
"github.com/imjasonh/kontain.me/pkg/serve"
|
||||
"golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
|
|
@ -71,9 +72,9 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
case strings.Contains(path, "/manifests/"):
|
||||
s.serveBuildpackManifest(w, r)
|
||||
case strings.Contains(path, "/blobs/"):
|
||||
pkg.ServeBlob(w, r)
|
||||
serve.Blob(w, r)
|
||||
default:
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
serve.Error(w, serve.ErrNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +83,7 @@ func (s *server) serveBuildpackManifest(w http.ResponseWriter, r *http.Request)
|
|||
src, layers, err := s.prepareWorkspace()
|
||||
if err != nil {
|
||||
s.error.Println("ERROR:", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
serve.Error(w, err)
|
||||
return
|
||||
}
|
||||
// Clean up workspace.
|
||||
|
|
@ -113,7 +114,7 @@ func (s *server) serveBuildpackManifest(w http.ResponseWriter, r *http.Request)
|
|||
image, err := s.fetchAndBuild(src, layers, repo, revision)
|
||||
if err != nil {
|
||||
s.error.Println("ERROR:", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
serve.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -121,10 +122,10 @@ func (s *server) serveBuildpackManifest(w http.ResponseWriter, r *http.Request)
|
|||
img, err := s.getImage(image)
|
||||
if err != nil {
|
||||
s.error.Println("ERROR:", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
serve.Error(w, err)
|
||||
return
|
||||
}
|
||||
pkg.ServeManifest(w, img)
|
||||
serve.Manifest(w, img)
|
||||
}
|
||||
|
||||
func (s *server) prepareWorkspace() (string, string, error) {
|
||||
|
|
@ -141,7 +142,7 @@ func (s *server) prepareWorkspace() (string, string, error) {
|
|||
}
|
||||
}
|
||||
}`, auth)
|
||||
if err := pkg.Run(s.info.Writer(), "mkdir -p ~/.docker/ && cat << EOF > ~/.docker/config.json\n"+string(configJSON)+"\nEOF"); err != nil {
|
||||
if err := run.Do(s.info.Writer(), "mkdir -p ~/.docker/ && cat << EOF > ~/.docker/config.json\n"+string(configJSON)+"\nEOF"); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +172,14 @@ func (s *server) fetchAndBuild(src, layers, repo, revision string) (string, erro
|
|||
image := fmt.Sprintf("gcr.io/%s/built-%d", projectID, time.Now().Unix)
|
||||
source := fmt.Sprintf("https://github.com/%s/archive/%s.tar.gz", repo, revision)
|
||||
|
||||
if resp, err := http.Head(source); err != nil {
|
||||
return "", err
|
||||
} else if resp.StatusCode == http.StatusNotFound {
|
||||
return "", serve.ErrNotFound
|
||||
} else if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("HEAD %s (%d): %s", source, resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
for _, cmd := range []string{
|
||||
fmt.Sprintf("chown -R %d:%d %s", os.Geteuid(), os.Getgid(), src),
|
||||
fmt.Sprintf("chown -R %d:%d %s", os.Geteuid(), os.Getgid(), layers),
|
||||
|
|
@ -181,7 +190,7 @@ func (s *server) fetchAndBuild(src, layers, repo, revision string) (string, erro
|
|||
fmt.Sprintf("/lifecycle/builder -layers=%s -app=%s -group=%s/group.toml -plan=%s/plan.toml", layers, src, layers, layers),
|
||||
fmt.Sprintf("/lifecycle/exporter -layers=%s -helpers=true -app=%s -image=%s -group=%s/group.toml %s", layers, src, base, layers, image),
|
||||
} {
|
||||
if err := pkg.Run(s.info.Writer(), cmd); err != nil {
|
||||
if err := run.Do(s.info.Writer(), cmd); err != nil {
|
||||
return "", fmt.Errorf("Running %q: %v", cmd, err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ import (
|
|||
"github.com/google/go-containerregistry/pkg/v1/random"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/ko/pkg/build"
|
||||
"github.com/imjasonh/kontain.me/pkg"
|
||||
"github.com/imjasonh/kontain.me/pkg/run"
|
||||
"github.com/imjasonh/kontain.me/pkg/serve"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
@ -82,9 +83,9 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
s.serveKoManifest(w, r)
|
||||
case strings.HasPrefix(path, "random/blobs/"),
|
||||
strings.HasPrefix(path, "ko/") && strings.Contains(path, "/blobs/"):
|
||||
pkg.ServeBlob(w, r)
|
||||
serve.Blob(w, r)
|
||||
default:
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
serve.Error(w, serve.ErrNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -108,9 +109,9 @@ func (s *server) serveKoManifest(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// go get the package.
|
||||
s.info.Printf("go get %s...", ip)
|
||||
if err := pkg.Run(s.info.Writer(), fmt.Sprintf("go get %s", ip)); err != nil {
|
||||
if err := run.Do(s.info.Writer(), fmt.Sprintf("go get %s", ip)); err != nil {
|
||||
s.error.Printf("ERROR (go get): %s", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
serve.Error(w, err)
|
||||
return
|
||||
}
|
||||
// TODO: Check image tag for version, resolve branches -> commits and redirect to img:<commit>
|
||||
|
|
@ -124,22 +125,22 @@ func (s *server) serveKoManifest(w http.ResponseWriter, r *http.Request) {
|
|||
)
|
||||
if err != nil {
|
||||
s.error.Printf("ERROR (build.NewGo): %s", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
serve.Error(w, serve.ErrInvalid)
|
||||
return
|
||||
}
|
||||
if !g.IsSupportedReference(ip) {
|
||||
s.error.Printf("ERROR (IsSupportedReference): %s", err)
|
||||
http.Error(w, fmt.Sprintf("%q is not a supported reference", ip), http.StatusBadRequest)
|
||||
serve.Error(w, serve.ErrInvalid)
|
||||
return
|
||||
}
|
||||
s.info.Printf("ko build %s...", ip)
|
||||
img, err := g.Build(ip)
|
||||
if err != nil {
|
||||
s.error.Printf("ERROR (ko build): %s", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
serve.Error(w, serve.ErrInvalid)
|
||||
return
|
||||
}
|
||||
pkg.ServeManifest(w, img)
|
||||
serve.Manifest(w, img)
|
||||
}
|
||||
|
||||
// Capture up to 99 layers of up to 99.9MB each.
|
||||
|
|
@ -163,8 +164,8 @@ func (s *server) serveRandomManifest(w http.ResponseWriter, r *http.Request) {
|
|||
img, err := random.Image(size, num)
|
||||
if err != nil {
|
||||
s.error.Printf("ERROR (random.Image): %s", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
serve.Error(w, err)
|
||||
return
|
||||
}
|
||||
pkg.ServeManifest(w, img)
|
||||
serve.Manifest(w, img)
|
||||
}
|
||||
|
|
|
|||
14
deploy.sh
14
deploy.sh
|
|
@ -1,11 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
#KO_DOCKER_REPO=gcr.io/kontainme ko publish -P ./cmd/ko && \
|
||||
#gcloud --project=kontainme beta run deploy app \
|
||||
# --image=gcr.io/kontainme/github.com/imjasonh/kontain.me/cmd/ko \
|
||||
# --memory=2Gi \
|
||||
# --concurrency=1 \
|
||||
# --region=us-central1
|
||||
set -euxo pipefail
|
||||
|
||||
KO_DOCKER_REPO=gcr.io/kontainme ko publish -P ./cmd/ko && \
|
||||
gcloud --project=kontainme beta run deploy app \
|
||||
--image=gcr.io/kontainme/github.com/imjasonh/kontain.me/cmd/ko \
|
||||
--memory=2Gi \
|
||||
--concurrency=1 \
|
||||
--region=us-central1
|
||||
|
||||
KO_DOCKER_REPO=gcr.io/kontainme ko publish -P ./cmd/buildpack && \
|
||||
gcloud --project=kontainme beta run deploy buildpack \
|
||||
|
|
|
|||
13
pkg/run/run.go
Normal file
13
pkg/run/run.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package run
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func Do(stdout io.Writer, command string) error {
|
||||
cmd := exec.Command("/bin/sh", "-c", "set -ex && "+command)
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stdout
|
||||
return cmd.Run()
|
||||
}
|
||||
43
pkg/serve/error.go
Normal file
43
pkg/serve/error.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package serve
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("repository or commit not found")
|
||||
ErrInvalid = errors.New("requested manifest is invalid")
|
||||
)
|
||||
|
||||
func Error(w http.ResponseWriter, err error) {
|
||||
code := "INTERNAL_ERROR"
|
||||
httpCode := http.StatusInternalServerError
|
||||
|
||||
if err == ErrNotFound {
|
||||
code = "MANIFEST_UNKNOWN"
|
||||
httpCode = http.StatusNotFound
|
||||
} else if err == ErrInvalid {
|
||||
code = "NAME_INVALID"
|
||||
httpCode = http.StatusBadRequest
|
||||
}
|
||||
|
||||
http.Error(w, "", httpCode)
|
||||
json.NewEncoder(w).Encode(&resp{
|
||||
Errors: []e{{
|
||||
Code: code,
|
||||
Message: err.Error(),
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
type resp struct {
|
||||
Errors []e `json:"errors"`
|
||||
}
|
||||
|
||||
type e struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package pkg
|
||||
package serve
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
|
|
@ -18,14 +17,7 @@ import (
|
|||
|
||||
const bucket = "kontainme"
|
||||
|
||||
func Run(stdout io.Writer, command string) error {
|
||||
cmd := exec.Command("/bin/sh", "-c", command)
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stdout
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func ServeBlob(w http.ResponseWriter, r *http.Request) {
|
||||
func Blob(w http.ResponseWriter, r *http.Request) {
|
||||
// Extract requested blob digest and redirect to serve it from GCS.
|
||||
// If it doesn't exist, this will return 404.
|
||||
parts := strings.Split(r.URL.Path, "/")
|
||||
|
|
@ -69,7 +61,7 @@ func writeBlob(h v1.Hash, rc io.ReadCloser) error {
|
|||
|
||||
// ServeManifest writes config and layer blobs for the image, then serves the
|
||||
// manifest contents pointing to those blobs.
|
||||
func ServeManifest(w http.ResponseWriter, img v1.Image) {
|
||||
func Manifest(w http.ResponseWriter, img v1.Image) {
|
||||
// Write config blob for later serving.
|
||||
ch, err := img.ConfigName()
|
||||
if err != nil {
|
||||
Loading…
Add table
Add a link
Reference in a new issue