Beispiel #1
0
func extractFromFile(filename string) (api.BoundPod, error) {
	var pod api.BoundPod

	glog.V(3).Infof("Reading config file %q", filename)
	file, err := os.Open(filename)
	if err != nil {
		return pod, err
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return pod, err
	}

	manifest := &api.ContainerManifest{}
	// TODO: use api.Scheme.DecodeInto
	if err := yaml.Unmarshal(data, manifest); err != nil {
		return pod, fmt.Errorf("can't unmarshal file %q: %v", filename, err)
	}

	if err := api.Scheme.Convert(manifest, &pod); err != nil {
		return pod, fmt.Errorf("can't convert pod from file %q: %v", filename, err)
	}

	hostname, err := os.Hostname() //TODO: kubelet name would be better
	if err != nil {
		return pod, err
	}

	if len(pod.UID) == 0 {
		hasher := md5.New()
		fmt.Fprintf(hasher, "host:%s", hostname)
		fmt.Fprintf(hasher, "file:%s", filename)
		util.DeepHashObject(hasher, pod)
		pod.UID = hex.EncodeToString(hasher.Sum(nil)[0:])
		glog.V(5).Infof("Generated UID %q for pod %q from file %s", pod.UID, pod.Name, filename)
	}
	if len(pod.Namespace) == 0 {
		hasher := adler32.New()
		fmt.Fprint(hasher, filename)
		// TODO: file-<sum>.hostname would be better, if DNS subdomains
		// are allowed for namespace (some places only allow DNS
		// labels).
		pod.Namespace = fmt.Sprintf("file-%08x-%s", hasher.Sum32(), hostname)
		glog.V(5).Infof("Generated namespace %q for pod %q from file %s", pod.Namespace, pod.Name, filename)
	}
	// TODO(dchen1107): BoundPod is not type of runtime.Object. Once we allow kubelet talks
	// about Pod directly, we can use SelfLinker defined in package: latest
	// Currently just simply follow the same format in resthandler.go
	pod.ObjectMeta.SelfLink = fmt.Sprintf("/api/v1beta2/pods/%s?namespace=%s",
		pod.Name, pod.Namespace)

	if glog.V(4) {
		glog.Infof("Got pod from file %q: %#v", filename, pod)
	} else {
		glog.V(1).Infof("Got pod from file %q: %s.%s (%s)", filename, pod.Namespace, pod.Name, pod.UID)
	}
	return pod, nil
}
Beispiel #2
0
// handleContainer handles container requests against the Kubelet.
func (s *Server) handleContainer(w http.ResponseWriter, req *http.Request) {
	defer req.Body.Close()
	data, err := ioutil.ReadAll(req.Body)
	if err != nil {
		s.error(w, err)
		return
	}
	// This is to provide backward compatibility. It only supports a single manifest
	var pod api.BoundPod
	var containerManifest api.ContainerManifest
	err = yaml.Unmarshal(data, &containerManifest)
	if err != nil {
		s.error(w, err)
		return
	}
	pod.Name = containerManifest.ID
	pod.UID = containerManifest.UUID
	pod.Spec.Containers = containerManifest.Containers
	pod.Spec.Volumes = containerManifest.Volumes
	pod.Spec.RestartPolicy = containerManifest.RestartPolicy
	//TODO: sha1 of manifest?
	if pod.Name == "" {
		pod.Name = "1"
	}
	if pod.UID == "" {
		pod.UID = "1"
	}
	s.updates <- PodUpdate{[]api.BoundPod{pod}, SET}

}
Beispiel #3
0
func applyDefaults(pod *api.BoundPod, url string) {
	if len(pod.UID) == 0 {
		hasher := md5.New()
		fmt.Fprintf(hasher, "url:%s", url)
		util.DeepHashObject(hasher, pod)
		pod.UID = types.UID(hex.EncodeToString(hasher.Sum(nil)[0:]))
		glog.V(5).Infof("Generated UID %q for pod %q from URL %s", pod.UID, pod.Name, url)
	}
	if len(pod.Namespace) == 0 {
		hasher := adler32.New()
		fmt.Fprint(hasher, url)
		pod.Namespace = fmt.Sprintf("url-%08x", hasher.Sum32())
		glog.V(5).Infof("Generated namespace %q for pod %q from URL %s", pod.Namespace, pod.Name, url)
	}
}
// newSourceApiserverFromLW holds creates a config source that watches an pulls from the apiserver.
func newSourceApiserverFromLW(lw cache.ListerWatcher, updates chan<- interface{}) {
	send := func(objs []interface{}) {
		var bpods []api.BoundPod
		for _, o := range objs {
			pod := o.(*api.Pod)
			bpod := api.BoundPod{}
			if err := api.Scheme.Convert(pod, &bpod); err != nil {
				glog.Errorf("Unable to interpret Pod from apiserver as a BoundPod: %v: %+v", err, pod)
				continue
			}
			// Make a dummy self link so that references to this bound pod will work.
			bpod.SelfLink = "/api/v1beta1/boundPods/" + bpod.Name
			bpods = append(bpods, bpod)
		}
		updates <- kubelet.PodUpdate{bpods, kubelet.SET, kubelet.ApiserverSource}
	}
	cache.NewReflector(lw, &api.Pod{}, cache.NewUndeltaStore(send)).Run()
}
Beispiel #5
0
func applyDefaults(pod *api.BoundPod, url string) {
	if len(pod.UID) == 0 {
		hasher := md5.New()
		fmt.Fprintf(hasher, "url:%s", url)
		util.DeepHashObject(hasher, pod)
		pod.UID = types.UID(hex.EncodeToString(hasher.Sum(nil)[0:]))
		glog.V(5).Infof("Generated UID %q for pod %q from URL %s", pod.UID, pod.Name, url)
	}
	// This is required for backward compatibility, and should be removed once we
	// completely deprecate ContainerManifest.
	if len(pod.Name) == 0 {
		pod.Name = string(pod.UID)
		glog.V(5).Infof("Generate Name %q from UID %q from URL %s", pod.Name, pod.UID, url)
	}
	if len(pod.Namespace) == 0 {
		hasher := adler32.New()
		fmt.Fprint(hasher, url)
		pod.Namespace = fmt.Sprintf("url-%08x", hasher.Sum32())
		glog.V(5).Infof("Generated namespace %q for pod %q from URL %s", pod.Namespace, pod.Name, url)
	}
}
Beispiel #6
0
func extractFromFile(filename string) (api.BoundPod, error) {
	var pod api.BoundPod

	glog.V(3).Infof("Reading config file %q", filename)
	file, err := os.Open(filename)
	if err != nil {
		return pod, err
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return pod, err
	}

	manifest := &api.ContainerManifest{}
	// TODO: use api.Scheme.DecodeInto
	if err := yaml.Unmarshal(data, manifest); err != nil {
		return pod, fmt.Errorf("can't unmarshal file %q: %v", filename, err)
	}

	if err := api.Scheme.Convert(manifest, &pod); err != nil {
		return pod, fmt.Errorf("can't convert pod from file %q: %v", filename, err)
	}

	pod.Name = simpleSubdomainSafeHash(filename)
	if len(pod.UID) == 0 {
		pod.UID = simpleSubdomainSafeHash(filename)
	}
	if len(pod.Namespace) == 0 {
		pod.Namespace = api.NamespaceDefault
	}

	if glog.V(4) {
		glog.Infof("Got pod from file %q: %#v", filename, pod)
	} else {
		glog.V(1).Infof("Got pod from file %q: %s.%s (%s)", filename, pod.Namespace, pod.Name, pod.UID)
	}
	return pod, nil
}
Beispiel #7
0
func extractFromFile(filename string) (api.BoundPod, error) {
	var pod api.BoundPod

	glog.V(3).Infof("Reading config file %q", filename)
	file, err := os.Open(filename)
	if err != nil {
		return pod, err
	}
	defer file.Close()

	data, err := ioutil.ReadAll(file)
	if err != nil {
		return pod, err
	}

	// TODO: use api.Scheme.DecodeInto
	// This is awful.  DecodeInto() expects to find an APIObject, which
	// Manifest is not.  We keep reading manifest for now for compat, but
	// we will eventually change it to read Pod (at which point this all
	// becomes nicer).  Until then, we assert that the ContainerManifest
	// structure on disk is always v1beta1.  Read that, convert it to a
	// "current" ContainerManifest (should be ~identical), then convert
	// that to a BoundPod (which is a well-understood conversion).  This
	// avoids writing a v1beta1.ContainerManifest -> api.BoundPod
	// conversion which would be identical to the api.ContainerManifest ->
	// api.BoundPod conversion.
	oldManifest := &v1beta1.ContainerManifest{}
	if err := yaml.Unmarshal(data, oldManifest); err != nil {
		return pod, fmt.Errorf("can't unmarshal file %q: %v", filename, err)
	}
	newManifest := &api.ContainerManifest{}
	if err := api.Scheme.Convert(oldManifest, newManifest); err != nil {
		return pod, fmt.Errorf("can't convert pod from file %q: %v", filename, err)
	}
	if err := api.Scheme.Convert(newManifest, &pod); err != nil {
		return pod, fmt.Errorf("can't convert pod from file %q: %v", filename, err)
	}

	hostname, err := os.Hostname() //TODO: kubelet name would be better
	if err != nil {
		return pod, err
	}

	if len(pod.UID) == 0 {
		hasher := md5.New()
		fmt.Fprintf(hasher, "host:%s", hostname)
		fmt.Fprintf(hasher, "file:%s", filename)
		util.DeepHashObject(hasher, pod)
		pod.UID = types.UID(hex.EncodeToString(hasher.Sum(nil)[0:]))
		glog.V(5).Infof("Generated UID %q for pod %q from file %s", pod.UID, pod.Name, filename)
	}
	// This is required for backward compatibility, and should be removed once we
	// completely deprecate ContainerManifest.
	if len(pod.Name) == 0 {
		pod.Name = string(pod.UID)
		glog.V(5).Infof("Generated Name %q for UID %q from file %s", pod.Name, pod.UID, filename)
	}
	if len(pod.Namespace) == 0 {
		hasher := adler32.New()
		fmt.Fprint(hasher, filename)
		// TODO: file-<sum>.hostname would be better, if DNS subdomains
		// are allowed for namespace (some places only allow DNS
		// labels).
		pod.Namespace = fmt.Sprintf("file-%08x-%s", hasher.Sum32(), hostname)
		glog.V(5).Infof("Generated namespace %q for pod %q from file %s", pod.Namespace, pod.Name, filename)
	}
	// TODO(dchen1107): BoundPod is not type of runtime.Object. Once we allow kubelet talks
	// about Pod directly, we can use SelfLinker defined in package: latest
	// Currently just simply follow the same format in resthandler.go
	pod.ObjectMeta.SelfLink = fmt.Sprintf("/api/v1beta2/pods/%s?namespace=%s",
		pod.Name, pod.Namespace)

	if glog.V(4) {
		glog.Infof("Got pod from file %q: %#v", filename, pod)
	} else {
		glog.V(1).Infof("Got pod from file %q: %s.%s (%s)", filename, pod.Namespace, pod.Name, pod.UID)
	}
	return pod, nil
}
Beispiel #8
0
func (s *sourceURL) extractFromURL() error {
	resp, err := http.Get(s.url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("%v: %v", s.url, resp.Status)
	}
	if len(data) == 0 {
		return fmt.Errorf("zero-length data received from %v", s.url)
	}
	// Short circuit if the manifest has not changed since the last time it was read.
	if bytes.Compare(data, s.data) == 0 {
		return nil
	}
	s.data = data

	// First try as if it's a single manifest
	var manifest api.ContainerManifest
	// TODO: should be api.Scheme.Decode
	singleErr := yaml.Unmarshal(data, &manifest)
	if singleErr == nil {
		if errs := validation.ValidateManifest(&manifest); len(errs) > 0 {
			singleErr = fmt.Errorf("invalid manifest: %v", errs)
		}
	}
	if singleErr == nil {
		pod := api.BoundPod{}
		if err := api.Scheme.Convert(&manifest, &pod); err != nil {
			return err
		}
		if len(pod.Name) == 0 {
			pod.Name = "1"
		}
		if len(pod.Namespace) == 0 {
			pod.Namespace = api.NamespaceDefault
		}
		s.updates <- kubelet.PodUpdate{[]api.BoundPod{pod}, kubelet.SET}
		return nil
	}

	// That didn't work, so try an array of manifests.
	var manifests []api.ContainerManifest
	// TODO: should be api.Scheme.Decode
	multiErr := yaml.Unmarshal(data, &manifests)
	// We're not sure if the person reading the logs is going to care about the single or
	// multiple manifest unmarshalling attempt, so we need to put both in the logs, as is
	// done at the end. Hence not returning early here.
	if multiErr == nil {
		for _, manifest := range manifests {
			if errs := validation.ValidateManifest(&manifest); len(errs) > 0 {
				multiErr = fmt.Errorf("invalid manifest: %v", errs)
				break
			}
		}
	}
	if multiErr == nil {
		// A single manifest that did not pass semantic validation will yield an empty
		// array of manifests (and no error) when unmarshaled as such.  In that case,
		// if the single manifest at least had a Version, we return the single-manifest
		// error (if any).
		if len(manifests) == 0 && len(manifest.Version) != 0 {
			return singleErr
		}
		list := api.ContainerManifestList{Items: manifests}
		boundPods := &api.BoundPods{}
		if err := api.Scheme.Convert(&list, boundPods); err != nil {
			return err
		}
		for i := range boundPods.Items {
			pod := &boundPods.Items[i]
			if len(pod.Name) == 0 {
				pod.Name = fmt.Sprintf("%d", i+1)
			}
			if len(pod.Namespace) == 0 {
				pod.Namespace = api.NamespaceDefault
			}
		}
		s.updates <- kubelet.PodUpdate{boundPods.Items, kubelet.SET}
		return nil
	}

	return fmt.Errorf("%v: received '%v', but couldn't parse as a "+
		"single manifest (%v: %+v) or as multiple manifests (%v: %+v).\n",
		s.url, string(data), singleErr, manifest, multiErr, manifests)
}