func Help() { fmt.Fprintf(os.Stderr, "Jetpack version %v\nUsage: %v [OPTION...] COMMAND [ARGS...]\nCommands:\n", jetpack.Version(), AppName) cmds := make([][]string, len(Commands)) i := 0 for _, cmd := range Commands { cmds[i] = []string{"", AppName + " " + cmd.Usage, cmd.Synopsis} i++ } doListF(os.Stderr, "", cmds) fmt.Fprintln(os.Stderr, "Global options:") flag.PrintDefaults() }
func doServeMetadata(r *http.Request) (int, []byte) { if r.URL.Path == "/" { // Root URL. We introduce ourselves, no questions asked. return http.StatusOK, []byte(fmt.Sprintf("Jetpack metadata service version %v\n", jetpack.Version())) } path, token := extractToken(r.URL.Path) r.RequestURI = path // Strip token from future logs if path == "/_info" { if !jetpack.VerifyMetadataToken(uuid.NIL, token) { return resp403() } r.URL.User = url.User("host") if body, err := json.Marshal(&Info); err != nil { return resp500(err) } else { return http.StatusOK, body } } // All other requests should be coming from a pod. pod := getPod(clientIP(r)) if pod == nil { return http.StatusTeapot, []byte("You are not a real pod. For you, I am a teapot.") } // hack hack hack r.URL.User = url.User(pod.UUID.String()) if !jetpack.VerifyMetadataToken(pod.UUID, token) { return http.StatusTeapot, []byte("You are not a real pod. For you, I am a teapot.") } if !strings.HasPrefix(path, "/acMetadata/v1/") { // Not a metadata service request. return resp404() } path = path[len("/acMetadata/v1/"):] switch { case path == "pod/uuid": return resp200(pod.UUID) case path == "pod/manifest": // Pod manifest if manifestJSON, err := json.Marshal(pod.Manifest); err != nil { panic(err) } else { return http.StatusOK, manifestJSON } case path == "pod/hmac/sign": content := r.FormValue("content") if content == "" { return http.StatusBadRequest, []byte("content form value not found\n") } h := hmac.New(sha512.New, SigningKey) h.Write(pod.UUID) h.Write([]byte(content)) return resp200(hex.EncodeToString(h.Sum(nil))) case path == "pod/hmac/verify": uuid := uuid.Parse(r.FormValue("uid")) if uuid == nil { return http.StatusBadRequest, []byte(fmt.Sprintf("Invalid UUID: %#v\n", r.FormValue("uid"))) } sig, err := hex.DecodeString(r.FormValue("signature")) if err != nil { return http.StatusBadRequest, []byte(fmt.Sprintf("Invalid signature: %#v\n", r.FormValue("signature"))) } content := r.FormValue("content") if content == "" { return http.StatusBadRequest, []byte("content form value not found\n") } h := hmac.New(sha512.New, SigningKey) h.Write(uuid) h.Write([]byte(content)) if hmac.Equal(sig, h.Sum(nil)) { return http.StatusOK, nil } else { return http.StatusForbidden, nil } case path == "pod/annotations" || path == "pod/annotations/": anns := make([]string, len(pod.Manifest.Annotations)) for i, ann := range pod.Manifest.Annotations { anns[i] = string(ann.Name) } return resp200(strings.Join(anns, "\n")) case strings.HasPrefix(path, "pod/annotations/"): // Pod annotation. 404 on nonexistent one. annName := path[len("pod/annotations/"):] if val, ok := pod.Manifest.Annotations.Get(annName); ok { return resp200(val) } else { return resp404() } case strings.HasPrefix(path, "apps/"): // App metadata. subpath := path[len("apps/"):] for _, app := range pod.Manifest.Apps { appPrefix := string(app.Name) + "/" if strings.HasPrefix(subpath, appPrefix) { switch appPath := subpath[len(appPrefix):]; appPath { case "image/id": return resp200(app.Image.ID) case "image/manifest": if img, err := Host.GetImage(app.Image.ID, "", nil); err != nil { panic(err) } else if manifestJSON, err := json.Marshal(img.Manifest); err != nil { panic(err) } else { return http.StatusOK, manifestJSON } case "annotations", "annotations/": anns := make([]string, len(app.Annotations)) for i, ann := range app.Annotations { anns[i] = string(ann.Name) } return resp200(strings.Join(anns, "\n")) default: if strings.HasPrefix(appPath, "annotations/") { annName := appPath[len("annotations/"):] if val, ok := app.Annotations.Get(annName); ok { return resp200(val) } else if img, err := Host.GetImage(app.Image.ID, "", nil); err != nil { panic(err) } else if val, ok := img.Manifest.Annotations.Get(annName); ok { return resp200(val) } } } } } return resp404() default: return resp404() } }
func cmdVersion([]string) error { fmt.Println(jetpack.Version()) return nil }
func main() { flag.Parse() Info.Pid = os.Getpid() Info.Uid = -1 Info.Gid = -1 Info.Version = jetpack.Version() if host, err := jetpack.NewHost(); err != nil { log.Fatalln("Error initializing host:", err) } else { Host = host } if hostip, _, err := Host.HostIP(); err != nil { panic(err) } else { Info.IP = hostip.String() } Info.Port = jetpack.Config().MustGetInt("mds.port") if s, err := hex.DecodeString(jetpack.Config().MustGet("mds.signing-key")); err != nil { panic(err) } else { SigningKey = s } switch lfPath, _ := jetpack.Config().Get("mds.logfile"); lfPath { case "-", "": log.SetOutput(os.Stderr) case "none", "/dev/null": log.SetOutput(ioutil.Discard) default: if lf, err := os.OpenFile(lfPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640); err != nil { log.Fatalf("Cannot open log file %#v: %v", lfPath, err) } else { log.SetOutput(lf) defer lf.Close() } } if pfPath, ok := jetpack.Config().Get("mds.pidfile"); ok { if err := ioutil.WriteFile(pfPath, []byte(fmt.Sprintln(os.Getpid())), 0644); err != nil { log.Fatalf("Cannot write pidfile %#v: %v", pfPath, err) } } addr := fmt.Sprintf("%v:%d", Info.IP, Info.Port) listener, err := net.Listen("tcp", addr) if err != nil { log.Fatalf("Cannot listen on %v: %v", addr, err) } if !jetpack.Config().GetBool("mds.keep-uid", false) { uid, gid := jetpack.MDSUidGid() if err := unix.Setgroups(nil); err != nil { log.Fatal("Cannot clear groups:", err) } if err := unix.Setresgid(gid, gid, gid); err != nil { log.Fatal("Cannot drop gid:", err) } if err := unix.Setresuid(uid, uid, uid); err != nil { log.Fatal("Cannot drop uid:", err) } } Info.Uid = os.Getuid() Info.Gid = os.Getgid() log.Println("Listening on:", addr) log.Fatal(http.Serve(listener, http.HandlerFunc(ServeMetadata))) }