From aef560a01afcc6e362ea9f29585267c2711836c1 Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Thu, 26 Feb 2015 11:51:26 -0800 Subject: [PATCH 1/3] contrib/podex: split manifest generation --- contrib/podex/podex.go | 83 +++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/contrib/podex/podex.go b/contrib/podex/podex.go index e5ccd4c2c74..8f1b2d449f9 100644 --- a/contrib/podex/podex.go +++ b/contrib/podex/podex.go @@ -45,9 +45,9 @@ import ( const usage = "podex [-format=yaml|json] [-type=pod|container] [-id NAME] IMAGES..." -var manifestFormat = flag.String("format", "yaml", "manifest format to output, `yaml` or `json`") -var manifestType = flag.String("type", "pod", "manifest type to output, `pod` or `container`") -var manifestName = flag.String("name", "", "manifest name, default to image base name") +var flManifestFormat = flag.String("format", "yaml", "manifest format to output, `yaml` or `json`") +var flManifestType = flag.String("type", "pod", "manifest type to output, `pod` or `container`") +var flManifestName = flag.String("name", "", "manifest name, default to image base name") func init() { flag.Usage = func() { @@ -63,24 +63,10 @@ type image struct { Tag string } -func main() { - flag.Parse() - - if flag.NArg() < 1 { - flag.Usage() - log.Fatal("pod: missing image argument") - } - if *manifestName == "" { - if flag.NArg() > 1 { - flag.Usage() - log.Fatal("podex: -id arg is required when passing more than one image") - } - _, _, *manifestName, _ = splitDockerImageName(flag.Arg(0)) - } - +func getManifest(manifestName, manifestType, manifestFormat string, images ...string) (io.Reader, error) { podContainers := []goyaml.MapSlice{} - for _, imageName := range flag.Args() { + for _, imageName := range images { host, namespace, repo, tag := splitDockerImageName(imageName) container := goyaml.MapSlice{ @@ -91,13 +77,13 @@ func main() { img, err := getImageMetadata(host, namespace, repo, tag) if err != nil { - log.Fatalf("failed to get image metadata %q: %v", imageName, err) + return nil, fmt.Errorf("failed to get image metadata %q: %v", imageName, err) } portSlice := []goyaml.MapSlice{} for p := range img.ContainerConfig.ExposedPorts { port, err := strconv.Atoi(p.Port()) if err != nil { - log.Fatalf("failed to parse port %q: %v", p.Port(), err) + return nil, fmt.Errorf("failed to parse port %q: %v", p.Port(), err) } portEntry := goyaml.MapSlice{{ Key: "name", @@ -125,15 +111,15 @@ func main() { var data interface{} - switch *manifestType { + switch manifestType { case "container": containerManifest = append(goyaml.MapSlice{ - {Key: "id", Value: *manifestName}, + {Key: "id", Value: manifestName}, }, containerManifest...) data = containerManifest case "pod": data = goyaml.MapSlice{ - {Key: "id", Value: *manifestName}, + {Key: "id", Value: manifestName}, {Key: "kind", Value: "Pod"}, {Key: "apiVersion", Value: "v1beta1"}, {Key: "desiredState", Value: goyaml.MapSlice{ @@ -141,32 +127,61 @@ func main() { }}, } default: - flag.Usage() - log.Fatalf("unsupported manifest type %q", *manifestType) + return nil, fmt.Errorf("unsupported manifest type %q", manifestFormat) } yamlBytes, err := goyaml.Marshal(data) if err != nil { - log.Fatalf("failed to marshal container manifest: %v", err) + return nil, fmt.Errorf("failed to marshal container manifest: %v", err) } - switch *manifestFormat { + switch manifestFormat { case "yaml": - os.Stdout.Write(yamlBytes) + return bytes.NewBuffer(yamlBytes), nil case "json": jsonBytes, err := yaml.YAMLToJSON(yamlBytes) if err != nil { - log.Fatalf("failed to marshal container manifest into JSON: %v", err) + return nil, fmt.Errorf("failed to marshal container manifest into JSON: %v", err) } var jsonPretty bytes.Buffer if err := json.Indent(&jsonPretty, jsonBytes, "", " "); err != nil { - log.Fatalf("failed to indent json %q: %v", string(jsonBytes), err) + return nil, fmt.Errorf("failed to indent json %q: %v", string(jsonBytes), err) } - io.Copy(os.Stdout, &jsonPretty) + return &jsonPretty, nil default: - flag.Usage() - log.Fatalf("unsupported manifest format %q", *manifestFormat) + return nil, fmt.Errorf("unsupported manifest format %q", manifestFormat) } + +} + +func main() { + flag.Parse() + + if flag.NArg() < 1 { + flag.Usage() + log.Fatal("pod: missing image argument") + } + if *flManifestName == "" { + if flag.NArg() > 1 { + flag.Usage() + log.Fatal("podex: -id arg is required when passing more than one image") + } + _, _, *flManifestName, _ = splitDockerImageName(flag.Arg(0)) + } + if *flManifestType != "pod" && *flManifestType != "container" { + flag.Usage() + log.Fatalf("unsupported manifest type %q", *flManifestType) + } + if *flManifestFormat != "yaml" && *flManifestFormat != "json" { + flag.Usage() + log.Fatalf("unsupported manifest format %q", *flManifestFormat) + } + + manifest, err := getManifest(*flManifestName, *flManifestType, *flManifestFormat, flag.Args()...) + if err != nil { + log.Fatalf("failed to generate %q manifest for %v: %v", *flManifestType, flag.Args(), err) + } + io.Copy(os.Stdout, manifest) } // splitDockerImageName split a docker image name of the form [HOST/][NAMESPACE/]REPOSITORY[:TAG] From bdaaa0f14372d2836e9672017716541474db16ee Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Thu, 26 Feb 2015 12:17:45 -0800 Subject: [PATCH 2/3] podex: add daemon mode --- contrib/podex/podex.go | 78 ++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/contrib/podex/podex.go b/contrib/podex/podex.go index 8f1b2d449f9..82f9e51cda6 100644 --- a/contrib/podex/podex.go +++ b/contrib/podex/podex.go @@ -48,6 +48,7 @@ const usage = "podex [-format=yaml|json] [-type=pod|container] [-id NAME] IMAGES var flManifestFormat = flag.String("format", "yaml", "manifest format to output, `yaml` or `json`") var flManifestType = flag.String("type", "pod", "manifest type to output, `pod` or `container`") var flManifestName = flag.String("name", "", "manifest name, default to image base name") +var flDaemon = flag.Bool("daemon", false, "daemon mode") func init() { flag.Usage = func() { @@ -63,6 +64,53 @@ type image struct { Tag string } +func main() { + flag.Parse() + + if *flDaemon { + http.HandleFunc("/pods/", func(w http.ResponseWriter, r *http.Request) { + image := strings.TrimPrefix(r.URL.Path, "/pods/") + _, _, manifestName, _ := splitDockerImageName(image) + manifest, err := getManifest(manifestName, "pod", "json", image) + if err != nil { + errMessage := fmt.Sprintf("failed to generate pod manifest for image %q: %v", image, err) + log.Print(errMessage) + http.Error(w, errMessage, http.StatusInternalServerError) + return + } + io.Copy(w, manifest) + }) + log.Fatal(http.ListenAndServe(":8080", nil)) + } + + if flag.NArg() < 1 { + flag.Usage() + log.Fatal("pod: missing image argument") + } + if *flManifestName == "" { + if flag.NArg() > 1 { + flag.Usage() + log.Fatal("podex: -id arg is required when passing more than one image") + } + _, _, *flManifestName, _ = splitDockerImageName(flag.Arg(0)) + } + if *flManifestType != "pod" && *flManifestType != "container" { + flag.Usage() + log.Fatalf("unsupported manifest type %q", *flManifestType) + } + if *flManifestFormat != "yaml" && *flManifestFormat != "json" { + flag.Usage() + log.Fatalf("unsupported manifest format %q", *flManifestFormat) + } + + manifest, err := getManifest(*flManifestName, *flManifestType, *flManifestFormat, flag.Args()...) + if err != nil { + log.Fatalf("failed to generate %q manifest for %v: %v", *flManifestType, flag.Args(), err) + } + io.Copy(os.Stdout, manifest) +} + +// getManifest infers a pod (or container) manifest for a list of docker images. func getManifest(manifestName, manifestType, manifestFormat string, images ...string) (io.Reader, error) { podContainers := []goyaml.MapSlice{} @@ -154,36 +202,6 @@ func getManifest(manifestName, manifestType, manifestFormat string, images ...st } -func main() { - flag.Parse() - - if flag.NArg() < 1 { - flag.Usage() - log.Fatal("pod: missing image argument") - } - if *flManifestName == "" { - if flag.NArg() > 1 { - flag.Usage() - log.Fatal("podex: -id arg is required when passing more than one image") - } - _, _, *flManifestName, _ = splitDockerImageName(flag.Arg(0)) - } - if *flManifestType != "pod" && *flManifestType != "container" { - flag.Usage() - log.Fatalf("unsupported manifest type %q", *flManifestType) - } - if *flManifestFormat != "yaml" && *flManifestFormat != "json" { - flag.Usage() - log.Fatalf("unsupported manifest format %q", *flManifestFormat) - } - - manifest, err := getManifest(*flManifestName, *flManifestType, *flManifestFormat, flag.Args()...) - if err != nil { - log.Fatalf("failed to generate %q manifest for %v: %v", *flManifestType, flag.Args(), err) - } - io.Copy(os.Stdout, manifest) -} - // splitDockerImageName split a docker image name of the form [HOST/][NAMESPACE/]REPOSITORY[:TAG] func splitDockerImageName(imageName string) (host, namespace, repo, tag string) { hostNamespaceImage := strings.Split(imageName, "/") From 478257a259b3817a1364d183963b773691b8ea49 Mon Sep 17 00:00:00 2001 From: Johan Euphrosine Date: Thu, 26 Feb 2015 13:30:48 -0800 Subject: [PATCH 3/3] contrib/podex: add http status code handling --- contrib/podex/podex.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/podex/podex.go b/contrib/podex/podex.go index 82f9e51cda6..ce270c24942 100644 --- a/contrib/podex/podex.go +++ b/contrib/podex/podex.go @@ -262,8 +262,12 @@ func getImageMetadata(host, namespace, repo, tag string) (*imageMetadata, error) req.Header.Add("X-Docker-Token", "true") resp, err := http.DefaultClient.Do(req) if err != nil { - return nil, fmt.Errorf("error getting X-Docker-Token from index.docker.io: %v", err) + return nil, fmt.Errorf("error making request to %q: %v", host, err) } + if resp.StatusCode != 200 { + return nil, fmt.Errorf("error getting X-Docker-Token from %s: %q", host, resp.Status) + } + endpoints := resp.Header.Get("X-Docker-Endpoints") token := resp.Header.Get("X-Docker-Token") req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v1/repositories/%s/%s/tags/%s", endpoints, namespace, repo, tag), nil)