| 
          // Copyright 2015 Google Inc. All Rights Reserved. | 
        
        
           | 
          // | 
        
        
           | 
          // Licensed under the Apache License, Version 2.0 (the "License"); | 
        
        
           | 
          // you may not use this file except in compliance with the License. | 
        
        
           | 
          // You may obtain a copy of the License at | 
        
        
           | 
          // | 
        
        
           | 
          //      http://www.apache.org/licenses/LICENSE-2.0 | 
        
        
           | 
          // | 
        
        
           | 
          // Unless required by applicable law or agreed to in writing, software | 
        
        
           | 
          // distributed under the License is distributed on an "AS IS" BASIS, | 
        
        
           | 
          // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
        
        
           | 
          // See the License for the specific language governing permissions and | 
        
        
           | 
          // limitations under the License. | 
        
        
           | 
          
 | 
        
        
           | 
          // podlet is a tiny CLI tool & daemon to launch kubernetes pods on a bare docker host. | 
        
        
           | 
          // Usage: | 
        
        
           | 
          // podlet [PODS...] [-daemon] | 
        
        
           | 
          // Examples: | 
        
        
           | 
          // launch a pod from stdin | 
        
        
           | 
          // $ cat pod.yaml | podlet | 
        
        
           | 
          // 962009ab45ee0baa5f5dfbd4a900241151f47fc7d4f2efa9e1c6ee3a84bfeae8 | 
        
        
           | 
          // 5e70817c999ed5e7ff6ebb4c8e5d238f1aa48b958b4fdf27aa40fd3194dcbc7a | 
        
        
           | 
          // launch multiple pods from files | 
        
        
           | 
          // $ podlet podi.yaml poda.yaml | 
        
        
           | 
          // podi.yaml: 6d01dfd8edc91d02c6497224e31bd2988a05526234f08afe1cb0d0ad29187578 | 
        
        
           | 
          // podi.yaml: 3507edb1ae9cf69f607ce398752fedcdd06866d4553f1a63abc7e9424c3928b4 | 
        
        
           | 
          // poda.yaml: 8c118d1a4d8daec3cdf5047c04adf1c9cf4f68d00b97ed658d475140bc89349b | 
        
        
           | 
          // poda.yaml: 0b9a6f7a57c89c6689f08384044ae2b35d7f033dd2dd983d24773f4d093c82ad | 
        
        
           | 
          // launch pods from HTTP | 
        
        
           | 
          // $ podlet -daemon | 
        
        
           | 
          // $ curl -X POST --data-binary @pod.yaml localhost:8000/pods | 
        
        
           | 
          // [{"Id":"6a173b0d475d8fce2880ce95ede6b8461c6a11d708b53859699d524fe607c1e6","Created":"0001-01-01T00:00:00Z","State":{"StartedAt":"0001-01-01T00:00:00Z","FinishedAt":"0001-01-01T00:00:00Z"}},{"Id":"d1355c04c5533dd1e1648d541191ad17440da2324d76fedb5d7803897a291e05","Created":"0001-01-01T00:00:00Z","State":{"StartedAt":"0001-01-01T00:00:00Z","FinishedAt":"0001-01-01T00:00:00Z"}}] | 
        
        
           | 
          package main | 
        
        
           | 
          
 | 
        
        
           | 
          import ( | 
        
        
           | 
          	"encoding/json" | 
        
        
           | 
          	"flag" | 
        
        
           | 
          	"fmt" | 
        
        
           | 
          	"io" | 
        
        
           | 
          	"io/ioutil" | 
        
        
           | 
          	"log" | 
        
        
           | 
          	"net/http" | 
        
        
           | 
          	"os" | 
        
        
           | 
          
 | 
        
        
           | 
          	docker "github.com/fsouza/go-dockerclient" | 
        
        
           | 
          	"github.com/ghodss/yaml" | 
        
        
           | 
          ) | 
        
        
           | 
          
 | 
        
        
           | 
          var addr = flag.String("addr", ":8000", "address to listen on") | 
        
        
           | 
          var dockerEndpoint = flag.String("dockerhost", "unix://var/run/docker.sock", "docker host endpoint") | 
        
        
           | 
          var daemon = flag.Bool("daemon", false, "daemon mode listen over HTTP for pod definitions") | 
        
        
           | 
          
 | 
        
        
           | 
          type Pod struct { | 
        
        
           | 
          	Kind       string | 
        
        
           | 
          	ApiVersion string `json:"apiVersion"` | 
        
        
           | 
          	Metadata   struct { | 
        
        
           | 
          		Name string | 
        
        
           | 
          	} | 
        
        
           | 
          	Spec struct { | 
        
        
           | 
          		Containers []struct { | 
        
        
           | 
          			Name  string | 
        
        
           | 
          			Image string | 
        
        
           | 
          			Env   []struct { | 
        
        
           | 
          				Name  string | 
        
        
           | 
          				Value string | 
        
        
           | 
          			} | 
        
        
           | 
          			Ports []struct { | 
        
        
           | 
          				HostIP        string `json:"hostIP"` | 
        
        
           | 
          				HostPort      string `json:"hostPort"` | 
        
        
           | 
          				ContainerPort string `json:"containerPort"` | 
        
        
           | 
          			} | 
        
        
           | 
          			VolumeMounts []struct { | 
        
        
           | 
          				Name      string | 
        
        
           | 
          				MountPath string `json:"mountPath"` | 
        
        
           | 
          			} `json:"volumeMounts"` | 
        
        
           | 
          		} | 
        
        
           | 
          		Volumes []struct { | 
        
        
           | 
          			Name     string | 
        
        
           | 
          			HostPath struct { | 
        
        
           | 
          				Path string | 
        
        
           | 
          			} `json:"hostPath"` | 
        
        
           | 
          		} | 
        
        
           | 
          	} | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          func runPod(reader io.Reader) ([]*docker.Container, error) { | 
        
        
           | 
          	// decode pod | 
        
        
           | 
          	content, err := ioutil.ReadAll(reader) | 
        
        
           | 
          	if err != nil { | 
        
        
           | 
          		return nil, fmt.Errorf("failed to read pod: %v", err) | 
        
        
           | 
          	} | 
        
        
           | 
          	var pod Pod | 
        
        
           | 
          	if err := yaml.Unmarshal(content, &pod); err != nil { | 
        
        
           | 
          		return nil, fmt.Errorf("failed to decode pod: %v", err) | 
        
        
           | 
          	} | 
        
        
           | 
          
 | 
        
        
           | 
          	// compute port bindings | 
        
        
           | 
          	exposedPorts := make(map[docker.Port]struct{}) | 
        
        
           | 
          	portBindings := make(map[docker.Port][]docker.PortBinding) | 
        
        
           | 
          	for _, c := range pod.Spec.Containers { | 
        
        
           | 
          		for _, p := range c.Ports { | 
        
        
           | 
          			exposedPorts[docker.Port(p.ContainerPort)] = struct{}{} | 
        
        
           | 
          			portBindings[docker.Port(p.ContainerPort)] = []docker.PortBinding{ | 
        
        
           | 
          				{ | 
        
        
           | 
          					HostIP:   p.HostIP, | 
        
        
           | 
          					HostPort: p.HostPort, | 
        
        
           | 
          				}, | 
        
        
           | 
          			} | 
        
        
           | 
          		} | 
        
        
           | 
          	} | 
        
        
           | 
          
 | 
        
        
           | 
          	// create net container | 
        
        
           | 
          	netContainer, err := dockerClient.CreateContainer(docker.CreateContainerOptions{ | 
        
        
           | 
          		Config: &docker.Config{ | 
        
        
           | 
          			Image:        "kubernetes/pause", | 
        
        
           | 
          			ExposedPorts: exposedPorts, | 
        
        
           | 
          		}, | 
        
        
           | 
          		HostConfig: &docker.HostConfig{ | 
        
        
           | 
          			PortBindings: portBindings, | 
        
        
           | 
          		}, | 
        
        
           | 
          	}) | 
        
        
           | 
          	if err != nil { | 
        
        
           | 
          		return nil, fmt.Errorf("failed to create net container: %v", err) | 
        
        
           | 
          	} | 
        
        
           | 
          
 | 
        
        
           | 
          	// create host volume mapp | 
        
        
           | 
          	volumeMap := make(map[string]string) | 
        
        
           | 
          	for _, v := range pod.Spec.Volumes { | 
        
        
           | 
          		volumeMap[v.Name] = v.HostPath.Path | 
        
        
           | 
          	} | 
        
        
           | 
          
 | 
        
        
           | 
          	containers := []*docker.Container{ | 
        
        
           | 
          		netContainer, | 
        
        
           | 
          	} | 
        
        
           | 
          	// create pods container | 
        
        
           | 
          	for _, c := range pod.Spec.Containers { | 
        
        
           | 
          		var env []string | 
        
        
           | 
          		for _, e := range c.Env { | 
        
        
           | 
          			env = append(env, fmt.Sprintf("%s=%s", e.Name, e.Value)) | 
        
        
           | 
          		} | 
        
        
           | 
          		var binds []string | 
        
        
           | 
          		for _, v := range c.VolumeMounts { | 
        
        
           | 
          			hostPath, ok := volumeMap[v.Name] | 
        
        
           | 
          			if !ok { | 
        
        
           | 
          				return nil, fmt.Errorf("hostPath not found for %q:", v.Name) | 
        
        
           | 
          			} | 
        
        
           | 
          			binds = append(binds, fmt.Sprintf("%s:%s", hostPath, v.MountPath)) | 
        
        
           | 
          		} | 
        
        
           | 
          		container, err := dockerClient.CreateContainer(docker.CreateContainerOptions{ | 
        
        
           | 
          			Config: &docker.Config{ | 
        
        
           | 
          				Image: c.Image, | 
        
        
           | 
          				Env:   env, | 
        
        
           | 
          			}, | 
        
        
           | 
          			HostConfig: &docker.HostConfig{ | 
        
        
           | 
          				Binds:       binds, | 
        
        
           | 
          				NetworkMode: fmt.Sprintf("container:%s", netContainer.ID), | 
        
        
           | 
          			}, | 
        
        
           | 
          		}) | 
        
        
           | 
          		if err != nil { | 
        
        
           | 
          			return nil, fmt.Errorf("failed to create container %q: %v", c.Name, err) | 
        
        
           | 
          		} | 
        
        
           | 
          		containers = append(containers, container) | 
        
        
           | 
          	} | 
        
        
           | 
          
 | 
        
        
           | 
          	// start containers | 
        
        
           | 
          	for _, c := range containers { | 
        
        
           | 
          		if err := dockerClient.StartContainer(c.ID, nil); err != nil { | 
        
        
           | 
          			return nil, fmt.Errorf("failed to start container %q: %v", c.ID, err) | 
        
        
           | 
          		} | 
        
        
           | 
          	} | 
        
        
           | 
          	return containers, nil | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          func handlePods(w http.ResponseWriter, r *http.Request) error { | 
        
        
           | 
          	containers, err := runPod(r.Body) | 
        
        
           | 
          	if err != nil { | 
        
        
           | 
          		return fmt.Errorf("api error: %v", err) | 
        
        
           | 
          	} | 
        
        
           | 
          	if err := json.NewEncoder(w).Encode(containers); err != nil { | 
        
        
           | 
          		return fmt.Errorf("failed to marshall containers list in json: %v", err) | 
        
        
           | 
          	} | 
        
        
           | 
          	return nil | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          var dockerClient *docker.Client | 
        
        
           | 
          
 | 
        
        
           | 
          func init() { | 
        
        
           | 
          	flag.Parse() | 
        
        
           | 
          	var err error | 
        
        
           | 
          	dockerClient, err = docker.NewClient(*dockerEndpoint) | 
        
        
           | 
          	if err != nil { | 
        
        
           | 
          		log.Fatal("failed to connect to docker endpoint %q: %v", *dockerEndpoint, err) | 
        
        
           | 
          	} | 
        
        
           | 
          	http.Handle("/pods", Handler(handlePods)) | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          type Handler func(w http.ResponseWriter, r *http.Request) error | 
        
        
           | 
          
 | 
        
        
           | 
          func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
        
        
           | 
          	err := h(w, r) | 
        
        
           | 
          	if err != nil { | 
        
        
           | 
          		log.Println(err) | 
        
        
           | 
          		http.Error(w, err.Error(), http.StatusInternalServerError) | 
        
        
           | 
          		return | 
        
        
           | 
          	} | 
        
        
           | 
          } | 
        
        
           | 
          
 | 
        
        
           | 
          func main() { | 
        
        
           | 
          	if *daemon { | 
        
        
           | 
          		log.Fatal(http.ListenAndServe(*addr, nil)) | 
        
        
           | 
          		return | 
        
        
           | 
          	} | 
        
        
           | 
          	if flag.NArg() == 0 { | 
        
        
           | 
          		containers, err := runPod(os.Stdin) | 
        
        
           | 
          		if err != nil { | 
        
        
           | 
          			log.Printf("failed to run pod from stdin: %v", err) | 
        
        
           | 
          		} | 
        
        
           | 
          		for _, c := range containers { | 
        
        
           | 
          			fmt.Println(c.ID) | 
        
        
           | 
          		} | 
        
        
           | 
          	} | 
        
        
           | 
          	for _, arg := range flag.Args() { | 
        
        
           | 
          		f, err := os.Open(arg) | 
        
        
           | 
          		if err != nil { | 
        
        
           | 
          			log.Fatalf("failed to open file %q: %v", arg, err) | 
        
        
           | 
          		} | 
        
        
           | 
          		defer f.Close() | 
        
        
           | 
          		containers, err := runPod(f) | 
        
        
           | 
          		if err != nil { | 
        
        
           | 
          			log.Printf("failed to run pod %q: %v", arg, err) | 
        
        
           | 
          			continue | 
        
        
           | 
          		} | 
        
        
           | 
          		for _, c := range containers { | 
        
        
           | 
          			fmt.Printf("%s: %s\n", arg, c.ID) | 
        
        
           | 
          		} | 
        
        
           | 
          	} | 
        
        
           | 
          } |