Change:
Currently it assumes it can read ContainerManifest - it should try both
Why not hold on this until we have Kubelet-read-Pod in?
Also the HTTP source has the same problem.
It should read Pod. Changed the title.
Ideally, I'd like all Pods created directly via Kubelet to be to etcd and surfaced via the API. If updates are made via the API, I'd like those to propagate back to the node. We can discuss whether the config file should be updated or ignored. At some point, I'd like Kubelet to persistently cache pods received from the apiserver, perhaps by just writing them all out as config files.
is the issue to sync local pods back to apiserver.
this is somewhat related to other issues we talked about.
Detail: We want locally specified pods to be able to use YAML config files, but we also want to rip YAML out of the API server . The config-file behavior should be as similar to the kubectl experience. Kubelet could use parts of the kubectl library to translate YAML to JSON. Vision: Eventually, I'd like Kubelet to use the apiserver library and support exactly the same Pod API as the master, at which time I'd like kubectl be able to create pods directly on Kubelets, as well as reading from config files. I also expect to have a per-node controller . I'd like to be able to use the per-node controller to update pods started via config files (or direct kubectl-kubelet pods), overriding those original files. For availability and self-hosting, we'll eventually need local checkpointing , ideally just using serialized JSON for each object. If Kubelet used apiserver, this could be done using a custom registry implementation.
I think that is a prerequisite for it.
If noone picks it up, I'm going to start working on it tomorrow.
thanks, wojtek-t
fixed it for http channel

Discussion:
w.WriteHeader(http.StatusNotFound) } <del> func startComponents(manifestURL, apiVersion string) (string, string) { </del> <ins> func startComponents(firstManifestURL, secondManifestURL, apiVersion string) (string, string) { </ins> // Setup servers := []string{} glog.Infof("Creating etcd client pointing to %v", servers)

testRootDir := makeTempDirOrDie("kubelet_integ_1.", "") configFilePath := makeTempDirOrDie("config", testRootDir) glog.Infof("Using %s as root dir for kubelet #1", testRootDir) <del> kcfg := kubeletapp.SimpleKubelet(cl, &fakeDocker1, machineList[0], testRootDir, manifestURL, "127.0.0.1", 10250, api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, configFilePath) </del> <ins> kcfg := kubeletapp.SimpleKubelet(cl, &fakeDocker1, machineList[0], testRootDir, firstManifestURL, "127.0.0.1", 10250, api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, configFilePath) </ins> kcfg.PodStatusUpdateFrequency = 1 * time.Second kubeletapp.RunKubelet(kcfg) // Kubelet (machine)

// have a place they can schedule. testRootDir = makeTempDirOrDie("kubelet_integ_2.", "") glog.Infof("Using %s as root dir for kubelet #2", testRootDir) <del> kcfg = kubeletapp.SimpleKubelet(cl, &fakeDocker2, machineList[1], testRootDir, "", "127.0.0.1", 10251, api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, "") </del> <ins> kcfg = kubeletapp.SimpleKubelet(cl, &fakeDocker2, machineList[1], testRootDir, secondManifestURL, "127.0.0.1", 10251, api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, "") </ins> kcfg.PodStatusUpdateFrequency = 1 * time.Second kubeletapp.RunKubelet(kcfg) return apiServer.URL, configFilePath

} func runStaticPodTest(c *client.Client, configFilePath string) { <del> manifest := `version: v1beta2 id: static-pod </del> <ins> var testCases = []struct { desc         string fileContents string }{ { desc: "static-pod-from-manifest", fileContents: `version: v1beta2 id: static-pod-from-manifest </ins> containers: <del> - name: static-container image: kubernetes/pause` manifestFile, err := ioutil.TempFile(configFilePath, "") defer os.Remove(manifestFile.Name()) ioutil.WriteFile(manifestFile.Name(), []byte(manifest), 0600) // Wait for the mirror pod to be created. podName := "static-pod-localhost" namespace := kubelet.NamespaceDefault if err := wait.Poll(time.Second, time.Minute*2, podRunning(c, namespace, podName)); err != nil { if pods, err := c.Pods(namespace).List(labels.Everything()); err == nil { for _, pod := range pods.Items { glog.Infof("pod found: %s/%s", namespace, pod.Name) } } glog.Fatalf("FAILED: mirror pod has not been created or is not running: %v", err) } // Delete the mirror pod, and wait for it to be recreated. c.Pods(namespace).Delete(podName) if err = wait.Poll(time.Second, time.Second*30, podRunning(c, namespace, podName)); err != nil { glog.Fatalf("FAILED: mirror pod has not been re-created or is not running: %v", err) } // Remove the manifest file, and wait for the mirror pod to be deleted. os.Remove(manifestFile.Name()) if err = wait.Poll(time.Second, time.Second*30, podNotFound(c, namespace, podName)); err != nil { glog.Fatalf("FAILED: mirror pod has not been deleted: %v", err) </del> <ins> - name: static-container image: kubernetes/pause`, }, { desc: "static-pod-from-spec", fileContents: `{ "kind": "Pod", "apiVersion": "v1beta3", "metadata": { "name": "static-pod-from-spec" }, "spec": { "containers": [{ "name": "static-container", "image": "kubernetes/pause" }] } }`, }, </ins> } <ins> for _, testCase := range testCases { func() { desc := testCase.desc manifestFile, err := ioutil.TempFile(configFilePath, "") defer os.Remove(manifestFile.Name()) ioutil.WriteFile(manifestFile.Name(), []byte(testCase.fileContents), 0600) // Wait for the mirror pod to be created. podName := fmt.Sprintf("%s-localhost", desc) namespace := kubelet.NamespaceDefault if err := wait.Poll(time.Second, time.Minute*2, podRunning(c, namespace, podName)); err != nil { if pods, err := c.Pods(namespace).List(labels.Everything()); err == nil { for _, pod := range pods.Items { glog.Infof("pod found: %s/%s", namespace, pod.Name) } } glog.Fatalf("%s FAILED: mirror pod has not been created or is not running: %v", desc, err) } // Delete the mirror pod, and wait for it to be recreated. c.Pods(namespace).Delete(podName) if err = wait.Poll(time.Second, time.Second*30, podRunning(c, namespace, podName)); err != nil { glog.Fatalf("%s FAILED: mirror pod has not been re-created or is not running: %v", desc, err) } // Remove the manifest file, and wait for the mirror pod to be deleted. os.Remove(manifestFile.Name()) if err = wait.Poll(time.Second, time.Second*30, podNotFound(c, namespace, podName)); err != nil { glog.Fatalf("%s FAILED: mirror pod has not been deleted: %v", desc, err) } }() } </ins> } func runReplicationControllerTest(c *client.Client) {

glog.Infof("Running tests for APIVersion: %s", apiVersion) <del> manifestURL := ServeCachedManifestFile() apiServerURL, configFilePath := startComponents(manifestURL, apiVersion) </del> <ins> firstManifestURL := ServeCachedManifestFile(testPodSpecFile) secondManifestURL := ServeCachedManifestFile(testManifestFile) apiServerURL, configFilePath := startComponents(firstManifestURL, secondManifestURL, apiVersion) </ins> // Ok. we're good to go. glog.Infof("API Server started on %s", apiServerURL)

createdConts.Insert(p[:n-8]) } } <del> // We expect 9: 2 pod infra containers + 2 pods from the replication controller + //              1 pod infra container + 2 pods from the URL + //              1 pod infra container + 1 pod from the service test. // In addition, runStaticPodTest creates 1 pod infra containers + //                                       1 pod container from the mainfest file // The total number of container created is 11 </del> <ins> // We expect 9: 2 pod infra containers + 2 containers from the replication controller + //              1 pod infra container + 2 containers from the URL on first Kubelet + //              1 pod infra container + 2 containers from the URL on second Kubelet + //              1 pod infra container + 1 container from the service test. // In addition, runStaticPodTest creates 2 pod infra containers + //                                       2 pod containers from the file (1 for manifest and 1 for spec) // The total number of container created is 13 </ins> <del> if len(createdConts) != 11 { glog.Fatalf("Expected 11 containers; got %vnnlist of created containers:nn%#vnnDocker 1 Created:nn%#vnnDocker 2 Created:nn%#vnn", len(createdConts), createdConts.List(), fakeDocker1.Created, fakeDocker2.Created) </del> <ins> if len(createdConts) != 16 { glog.Fatalf("Expected 16 containers; got %vnnlist of created containers:nn%#vnnDocker 1 Created:nn%#vnnDocker 2 Created:nn%#vnn", len(createdConts), createdConts.List(), fakeDocker1.Created, fakeDocker2.Created) </ins> } glog.Infof("OK - found created containers: %#v", createdConts.List()) } // ServeCachedManifestFile serves a file for kubelet to read. <del> func ServeCachedManifestFile() (servingAddress string) { </del> <ins> func ServeCachedManifestFile(contents string) (servingAddress string) { </ins> server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/manifest" { <del> w.Write([]byte(testManifestFile)) </del> <ins> w.Write([]byte(contents)) </ins> return } glog.Fatalf("Got request: %#vn", r)

} const ( <ins> testPodSpecFile = `{ "kind": "Pod", "apiVersion": "v1beta3", "metadata": { "name": "container-vm-guestbook-pod-spec" }, "spec": { "containers": [ { "name": "redis", "image": "dockerfile/redis", "volumeMounts": [{ "name": "redis-data", "mountPath": "/data" }] }, { "name": "guestbook", "image": "google/guestbook-python-redis", "ports": [{ "name": "www", "hostPort": 80, "containerPort": 80 }] }], "volumes": [{	"name": "redis-data" }] } }` ) const ( </ins> // This is copied from, and should be kept in sync with: // https://raw.githubusercontent.com/GoogleCloudPlatform/container-vm-guestbook-redis-python/master/manifest.yaml // Note that kubelet complains about these containers not having a self link. testManifestFile = `version: v1beta2 <del> id: container-vm-guestbook </del> <ins> id: container-vm-guestbook-manifest </ins> containers: - name: redis image: dockerfile/redis