From 8cbe8938c96316d946aa4833b9e29da776601be0 Mon Sep 17 00:00:00 2001 From: Yifan Gu Date: Wed, 6 May 2015 14:20:39 -0700 Subject: [PATCH] kubelet/rkt: Remove getImageID(). Replace getImageID() with getImageByName(), this can remove the dependency on rkt.store. --- pkg/kubelet/rkt/image.go | 51 ++++++++++++++++++ pkg/kubelet/rkt/rkt_linux.go | 101 +++++++++++++++++++---------------- 2 files changed, 107 insertions(+), 45 deletions(-) create mode 100644 pkg/kubelet/rkt/image.go diff --git a/pkg/kubelet/rkt/image.go b/pkg/kubelet/rkt/image.go new file mode 100644 index 00000000000..585b4de064d --- /dev/null +++ b/pkg/kubelet/rkt/image.go @@ -0,0 +1,51 @@ +/* +Copyright 2015 The Kubernetes Authors 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. +*/ + +package rkt + +import ( + "fmt" + "strings" +) + +// image stores the appc image information. +// TODO(yifan): Replace with schema.ImageManifest. +type image struct { + // The hash of the image, it must be universal unique. (e.g. sha512-xxx) + id string + // The name of the image manifest. + name string + // The version of the image. (e.g. v2.0.8, latest) + version string +} + +// parseString creates the image struct by parsing the string in the result of 'rkt images', +// the input looks like: +// +// sha512-91e98d7f1679a097c878203c9659f2a26ae394656b3147963324c61fa3832f15 coreos.com/etcd:v2.0.9 +// +func (im *image) parseString(input string) error { + idName := strings.Split(input, "\t") + if len(idName) != 2 { + return fmt.Errorf("invalid image information from 'rkt images': %q", input) + } + nameVersion := strings.Split(idName[1], ":") + if len(nameVersion) != 2 { + return fmt.Errorf("cannot parse the app name: %q", nameVersion) + } + im.id, im.name, im.version = idName[0], nameVersion[0], nameVersion[1] + return nil +} diff --git a/pkg/kubelet/rkt/rkt_linux.go b/pkg/kubelet/rkt/rkt_linux.go index 76ace6c7337..4cfae07f34a 100644 --- a/pkg/kubelet/rkt/rkt_linux.go +++ b/pkg/kubelet/rkt/rkt_linux.go @@ -46,9 +46,8 @@ import ( appctypes "github.com/appc/spec/schema/types" "github.com/coreos/go-systemd/dbus" "github.com/coreos/go-systemd/unit" - "github.com/coreos/rkt/store" "github.com/docker/docker/pkg/parsers" - "github.com/fsouza/go-dockerclient" + docker "github.com/fsouza/go-dockerclient" "github.com/golang/glog" "github.com/kr/pty" ) @@ -342,41 +341,30 @@ func setApp(app *appctypes.App, c *api.Container) error { func (r *runtime) makePodManifest(pod *api.Pod, volumeMap map[string]volume.Volume) (*appcschema.PodManifest, error) { manifest := appcschema.BlankPodManifest() - // Get the image manifests, assume they are already in the cas, - // and extract the app field from the image and to be the 'base app'. - // - // We do this is because we will fully replace the image manifest's app - // with the pod manifest's app in rkt runtime. See below: - // - // https://github.com/coreos/rkt/issues/723. - // - s, err := store.NewStore(rktDataDir) - if err != nil { - return nil, fmt.Errorf("cannot open store: %v", err) - } for _, c := range pod.Spec.Containers { - // Assume we are running docker images for now, see #7203. - imageID, err := r.getImageID(c.Image) + img, err := r.getImageByName(c.Image) if err != nil { - return nil, fmt.Errorf("cannot get image ID for %q: %v", c.Image, err) + return nil, err } - hash, err := appctypes.NewHash(imageID) + hash, err := appctypes.NewHash(img.id) if err != nil { return nil, err } - im, err := s.GetImageManifest(hash.String()) - if err != nil { - return nil, fmt.Errorf("cannot get image manifest: %v", err) - } - - // Override the image manifest's app and store it in the pod manifest. - app := im.App + // TODO(yifan): Override the image manifest's app and store it in the pod manifest. + // We need to get the image manifest. https://github.com/coreos/rkt/issues/850 + app := &appctypes.App{} if err := setApp(app, &c); err != nil { return nil, err } + imageName, err := appctypes.NewACName(img.name) + if err != nil { + return nil, err + } manifest.Apps = append(manifest.Apps, appcschema.RuntimeApp{ - Name: im.Name, + // TODO(yifan): We should allow app name to be different with + // image name. See https://github.com/coreos/rkt/pull/640. + Name: *imageName, Image: appcschema.RuntimeImage{ID: *hash}, App: app, }) @@ -412,22 +400,6 @@ func (r *runtime) makePodManifest(pod *api.Pod, volumeMap map[string]volume.Volu return manifest, nil } -// TODO(yifan): Replace with 'rkt images'. -func (r *runtime) getImageID(imageName string) (string, error) { - output, err := r.runCommand("fetch", dockerPrefix+imageName) - if err != nil { - return "", err - } - if len(output) == 0 { - return "", fmt.Errorf("no result from rkt fetch") - } - last := output[len(output)-1] - if !strings.HasPrefix(last, "sha512-") { - return "", fmt.Errorf("unexpected result: %q", last) - } - return last, nil -} - func newUnitOption(section, name, value string) *unit.UnitOption { return &unit.UnitOption{Section: section, Name: name, Value: value} } @@ -449,12 +421,12 @@ func (r *runtime) apiPodToruntimePod(uuid string, pod *api.Pod) *kubecontainer.P } for i := range pod.Spec.Containers { c := &pod.Spec.Containers[i] - imageID, err := r.getImageID(c.Image) + img, err := r.getImageByName(c.Image) if err != nil { - glog.Warningf("rkt: Cannot get image id: %v", err) + glog.Warningf("rkt: Cannot get image for %q: %v", c.Image, err) } p.Containers = append(p.Containers, &kubecontainer.Container{ - ID: types.UID(buildContainerID(&containerID{uuid, c.Name, imageID})), + ID: types.UID(buildContainerID(&containerID{uuid, c.Name, img.id})), Name: c.Name, Image: c.Image, Hash: hashContainer(c), @@ -1097,3 +1069,42 @@ func (r *runtime) getPodInfos() (map[string]*podInfo, error) { } return result, nil } + +// listImages lists all the available appc images on the machine by invoking 'rkt images'. +func (r *runtime) listImages() ([]image, error) { + output, err := r.runCommand("images", "--no-legend=true", "--fields=key,appname") + if err != nil { + return nil, err + } + if len(output) == 0 { + return nil, nil + } + + var images []image + for _, line := range output { + var img image + if err := img.parseString(line); err != nil { + glog.Warningf("rkt: Cannot parse image info from %q: %v", line, err) + continue + } + images = append(images, img) + } + return images, nil +} + +// getImageByName tries to find the image info with the given image name. +func (r *runtime) getImageByName(name string) (image, error) { + // TODO(yifan): Use rkt image cat-file when that is ready: + // https://github.com/coreos/rkt/pull/649 + images, err := r.listImages() + if err != nil { + return image{}, err + } + + for _, img := range images { + if img.name == name { + return img, nil + } + } + return image{}, fmt.Errorf("cannot find the image %q", name) +}