mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 21:47:07 +00:00
Merge pull request #4868 from proppy/podex-httpd
contrib/podex: add daemon mode
This commit is contained in:
commit
ac0ecda1d6
@ -45,9 +45,10 @@ import (
|
|||||||
|
|
||||||
const usage = "podex [-format=yaml|json] [-type=pod|container] [-id NAME] IMAGES..."
|
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 flManifestFormat = 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 flManifestType = flag.String("type", "pod", "manifest type to output, `pod` or `container`")
|
||||||
var manifestName = flag.String("name", "", "manifest name, default to image base name")
|
var flManifestName = flag.String("name", "", "manifest name, default to image base name")
|
||||||
|
var flDaemon = flag.Bool("daemon", false, "daemon mode")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
@ -66,21 +67,54 @@ type image struct {
|
|||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
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 {
|
if flag.NArg() < 1 {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
log.Fatal("pod: missing image argument")
|
log.Fatal("pod: missing image argument")
|
||||||
}
|
}
|
||||||
if *manifestName == "" {
|
if *flManifestName == "" {
|
||||||
if flag.NArg() > 1 {
|
if flag.NArg() > 1 {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
log.Fatal("podex: -id arg is required when passing more than one image")
|
log.Fatal("podex: -id arg is required when passing more than one image")
|
||||||
}
|
}
|
||||||
_, _, *manifestName, _ = splitDockerImageName(flag.Arg(0))
|
_, _, *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{}
|
podContainers := []goyaml.MapSlice{}
|
||||||
|
|
||||||
for _, imageName := range flag.Args() {
|
for _, imageName := range images {
|
||||||
host, namespace, repo, tag := splitDockerImageName(imageName)
|
host, namespace, repo, tag := splitDockerImageName(imageName)
|
||||||
|
|
||||||
container := goyaml.MapSlice{
|
container := goyaml.MapSlice{
|
||||||
@ -91,13 +125,13 @@ func main() {
|
|||||||
img, err := getImageMetadata(host, namespace, repo, tag)
|
img, err := getImageMetadata(host, namespace, repo, tag)
|
||||||
|
|
||||||
if err != nil {
|
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{}
|
portSlice := []goyaml.MapSlice{}
|
||||||
for p := range img.ContainerConfig.ExposedPorts {
|
for p := range img.ContainerConfig.ExposedPorts {
|
||||||
port, err := strconv.Atoi(p.Port())
|
port, err := strconv.Atoi(p.Port())
|
||||||
if err != nil {
|
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{{
|
portEntry := goyaml.MapSlice{{
|
||||||
Key: "name",
|
Key: "name",
|
||||||
@ -125,15 +159,15 @@ func main() {
|
|||||||
|
|
||||||
var data interface{}
|
var data interface{}
|
||||||
|
|
||||||
switch *manifestType {
|
switch manifestType {
|
||||||
case "container":
|
case "container":
|
||||||
containerManifest = append(goyaml.MapSlice{
|
containerManifest = append(goyaml.MapSlice{
|
||||||
{Key: "id", Value: *manifestName},
|
{Key: "id", Value: manifestName},
|
||||||
}, containerManifest...)
|
}, containerManifest...)
|
||||||
data = containerManifest
|
data = containerManifest
|
||||||
case "pod":
|
case "pod":
|
||||||
data = goyaml.MapSlice{
|
data = goyaml.MapSlice{
|
||||||
{Key: "id", Value: *manifestName},
|
{Key: "id", Value: manifestName},
|
||||||
{Key: "kind", Value: "Pod"},
|
{Key: "kind", Value: "Pod"},
|
||||||
{Key: "apiVersion", Value: "v1beta1"},
|
{Key: "apiVersion", Value: "v1beta1"},
|
||||||
{Key: "desiredState", Value: goyaml.MapSlice{
|
{Key: "desiredState", Value: goyaml.MapSlice{
|
||||||
@ -141,32 +175,31 @@ func main() {
|
|||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
flag.Usage()
|
return nil, fmt.Errorf("unsupported manifest type %q", manifestFormat)
|
||||||
log.Fatalf("unsupported manifest type %q", *manifestType)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yamlBytes, err := goyaml.Marshal(data)
|
yamlBytes, err := goyaml.Marshal(data)
|
||||||
if err != nil {
|
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":
|
case "yaml":
|
||||||
os.Stdout.Write(yamlBytes)
|
return bytes.NewBuffer(yamlBytes), nil
|
||||||
case "json":
|
case "json":
|
||||||
jsonBytes, err := yaml.YAMLToJSON(yamlBytes)
|
jsonBytes, err := yaml.YAMLToJSON(yamlBytes)
|
||||||
if err != nil {
|
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
|
var jsonPretty bytes.Buffer
|
||||||
if err := json.Indent(&jsonPretty, jsonBytes, "", " "); err != nil {
|
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:
|
default:
|
||||||
flag.Usage()
|
return nil, fmt.Errorf("unsupported manifest format %q", manifestFormat)
|
||||||
log.Fatalf("unsupported manifest format %q", *manifestFormat)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitDockerImageName split a docker image name of the form [HOST/][NAMESPACE/]REPOSITORY[:TAG]
|
// splitDockerImageName split a docker image name of the form [HOST/][NAMESPACE/]REPOSITORY[:TAG]
|
||||||
@ -229,8 +262,12 @@ func getImageMetadata(host, namespace, repo, tag string) (*imageMetadata, error)
|
|||||||
req.Header.Add("X-Docker-Token", "true")
|
req.Header.Add("X-Docker-Token", "true")
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
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")
|
endpoints := resp.Header.Get("X-Docker-Endpoints")
|
||||||
token := resp.Header.Get("X-Docker-Token")
|
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)
|
req, err = http.NewRequest("GET", fmt.Sprintf("https://%s/v1/repositories/%s/%s/tags/%s", endpoints, namespace, repo, tag), nil)
|
||||||
|
Loading…
Reference in New Issue
Block a user