Пример #1
0
func (v *ImageStore) ListImages(ctx context.Context, store *url.URL, IDs []string) ([]*portlayer.Image, error) {

	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return nil, err
	}

	res, err := v.ds.Ls(ctx, v.imageStorePath(storeName))
	if err != nil {
		return nil, err
	}

	images := []*portlayer.Image{}
	for _, f := range res.File {
		file, ok := f.(*types.FileInfo)
		if !ok {
			continue
		}

		ID := file.Path

		img, err := v.GetImage(ctx, store, ID)
		if err != nil {
			return nil, err
		}

		images = append(images, img)
	}

	return images, nil
}
Пример #2
0
func (c *MockDataStore) WriteImage(op trace.Operation, parent *Image, ID string, meta map[string][]byte, sum string, r io.Reader) (*Image, error) {
	storeName, err := util.ImageStoreName(parent.Store)
	if err != nil {
		return nil, err
	}

	selflink, err := util.ImageURL(storeName, ID)
	if err != nil {
		return nil, err
	}

	var parentLink *url.URL
	if parent.ID != "" {
		parentLink, err = util.ImageURL(storeName, parent.ID)
		if err != nil {
			return nil, err
		}
	}

	i := &Image{
		ID:         ID,
		Store:      parent.Store,
		ParentLink: parentLink,
		SelfLink:   selflink,
		Metadata:   meta,
	}

	c.db[*parent.Store][ID] = i

	return i, nil
}
Пример #3
0
// GetImage gets the specified image from the given store by retreiving it from the cache.
func (c *NameLookupCache) GetImage(ctx context.Context, store *url.URL, ID string) (*Image, error) {
	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return nil, err
	}

	// Check the store exists
	if _, err = c.GetImageStore(ctx, storeName); err != nil {
		return nil, err
	}

	c.storeCacheLock.Lock()
	defer c.storeCacheLock.Unlock()

	var ok bool
	i := &Image{}
	*i, ok = c.storeCache[*store][ID]
	if !ok {
		log.Infof("Image %s not in cache, retreiving from datastore", ID)
		// Not in the cache.  Try to load it.
		i, err = c.DataStore.GetImage(ctx, store, ID)
		if err != nil {
			return nil, err
		}

		c.storeCache[*store][ID] = *i
	}

	return i, nil
}
Пример #4
0
func (v *ImageStore) ListImages(op trace.Operation, store *url.URL, IDs []string) ([]*portlayer.Image, error) {

	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return nil, err
	}

	res, err := v.ds.Ls(op, v.imageStorePath(storeName))
	if err != nil {
		return nil, err
	}

	images := []*portlayer.Image{}
	for _, f := range res.File {
		file, ok := f.(*types.FileInfo)
		if !ok {
			continue
		}

		ID := file.Path

		// GetImage verifies the image is good by calling verifyImage.
		img, err := v.GetImage(op, store, ID)
		if err != nil {
			return nil, err
		}

		images = append(images, img)
	}

	return images, nil
}
Пример #5
0
func (v *ImageStore) GetImage(ctx context.Context, store *url.URL, ID string) (*portlayer.Image, error) {

	defer trace.End(trace.Begin(store.String()))
	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return nil, err
	}

	imageURL, err := util.ImageURL(storeName, ID)
	if err != nil {
		return nil, err
	}

	p := v.imageDirPath(storeName, ID)
	info, err := v.ds.Stat(ctx, p)
	if err != nil {
		return nil, err
	}

	_, ok := info.(*types.FolderFileInfo)
	if !ok {
		return nil, fmt.Errorf("Stat error:  image doesn't exist (%s)", p)
	}

	// get the metadata
	metaDataDir := v.imageMetadataDirPath(storeName, ID)
	meta, err := getMetadata(ctx, v.ds, metaDataDir)
	if err != nil {
		return nil, err
	}

	var s = *store
	var parentURL *url.URL

	parentID := v.parents.Get(ID)
	if parentID != "" {
		parentURL, _ = util.ImageURL(storeName, parentID)
	}

	newImage := &portlayer.Image{
		ID:       ID,
		SelfLink: imageURL,
		// We're relying on the parent map for this since we don't currently have a
		// way to get the disk's spec.  See VIC #482 for details.  Parent:
		// parent.SelfLink,
		Store:    &s,
		Parent:   parentURL,
		Metadata: meta,
	}

	log.Debugf("Returning image from location %s with parent url %s", newImage.SelfLink, newImage.Parent)
	return newImage, nil
}
Пример #6
0
// DeleteImage deletes an image from the image store.  If the image is in
// use either by way of inheritance or because it's attached to a
// container, this will return an error.
func (v *ImageStore) DeleteImage(op trace.Operation, image *portlayer.Image) error {
	//  check if the image is in use.
	if err := imagesInUse(op, image.ID); err != nil {
		op.Errorf("ImageStore: delete image error: %s", err.Error())
		return err
	}

	storeName, err := util.ImageStoreName(image.Store)
	if err != nil {
		return err
	}

	return v.deleteImage(op, storeName, image.ID)
}
Пример #7
0
// WriteImage creates a new image layer from the given parent.
// Eg parentImage + newLayer = new Image built from parent
//
// parent - The parent image to create the new image from.
// ID - textual ID for the image to be written
// meta - metadata associated with the image
// Tag - the tag of the image to be written
func (v *ImageStore) WriteImage(op trace.Operation, parent *portlayer.Image, ID string, meta map[string][]byte, sum string,
	r io.Reader) (*portlayer.Image, error) {

	storeName, err := util.ImageStoreName(parent.Store)
	if err != nil {
		return nil, err
	}

	imageURL, err := util.ImageURL(storeName, ID)
	if err != nil {
		return nil, err
	}

	// If this is scratch, then it's the root of the image store.  All images
	// will be descended from this created and prepared fs.
	if ID == portlayer.Scratch.ID {
		// Create the scratch layer
		if err := v.scratch(op, storeName); err != nil {
			return nil, err
		}
	} else {

		if parent.ID == "" {
			return nil, fmt.Errorf("parent ID is empty")
		}

		// persist the relationship
		v.parents.Add(ID, parent.ID)

		if err := v.parents.Save(op); err != nil {
			return nil, err
		}

		if err := v.writeImage(op, storeName, parent.ID, ID, meta, sum, r); err != nil {
			return nil, err
		}

	}

	newImage := &portlayer.Image{
		ID:         ID,
		SelfLink:   imageURL,
		ParentLink: parent.SelfLink,
		Store:      parent.Store,
		Metadata:   meta,
	}

	return newImage, nil
}
Пример #8
0
func (c *NameLookupCache) WriteImage(ctx context.Context, parent *Image, ID string, meta map[string][]byte, sum string, r io.Reader) (*Image, error) {
	// Check the parent exists (at least in the cache).
	p, err := c.GetImage(ctx, parent.Store, parent.ID)
	if err != nil {
		return nil, fmt.Errorf("parent (%s) doesn't exist in %s: %s", parent.ID, parent.Store.String(), err)
	}

	// Check the image doesn't already exist in the cache.  A miss in this will trigger a datastore lookup.
	i, err := c.GetImage(ctx, p.Store, ID)
	if err == nil && i != nil {
		// TODO(FA) check sums to make sure this is the right image

		// if meta supplied write it
		if meta != nil && len(meta) != 0 {
			// get the storename from the url
			storeName, err := util.ImageStoreName(p.Store)
			if err != nil {
				return nil, err
			}

			c.DataStore.WriteMetadata(ctx, storeName, i.ID, meta)
			i.Metadata = meta
			c.AddImageToStore(*p.Store, i.ID, *i)
		}

		return i, nil
	}

	// Definitely not in cache or image store, create image.
	h := sha256.New()
	t := io.TeeReader(r, h)

	i, err = c.DataStore.WriteImage(ctx, p, ID, meta, t)
	if err != nil {
		return nil, err
	}

	actualSum := fmt.Sprintf("sha256:%x", h.Sum(nil))
	if actualSum != sum {
		// TODO(jzt): cleanup?
		return nil, fmt.Errorf("Failed to validate image checksum. Expected %s, got %s", sum, actualSum)
	}

	// Add the new image to the cache
	c.AddImageToStore(*p.Store, i.ID, *i)

	return i, nil
}
Пример #9
0
// GetImageStore checks to see if a named image store exists and returls the
// URL to it if so or error.
func (c *NameLookupCache) GetImageStore(ctx context.Context, storeName string) (*url.URL, error) {
	store, err := util.ImageStoreNameToURL(storeName)
	if err != nil {
		return nil, err
	}

	c.storeCacheLock.Lock()
	defer c.storeCacheLock.Unlock()

	// check the cache
	_, ok := c.storeCache[*store]
	if !ok {
		log.Info("Refreshing image cache from datastore.")
		// Store isn't in the cache.  Look it up in the datastore.
		storeName, err := util.ImageStoreName(store)
		if err != nil {
			return nil, err
		}

		// If the store doesn't exist, we'll fall out here.
		_, err = c.DataStore.GetImageStore(ctx, storeName)
		if err != nil {
			return nil, err
		}

		c.storeCache[*store] = make(map[string]Image)

		// Fall out here if there are no images.  We should at least have a scratch.
		images, err := c.DataStore.ListImages(ctx, store, nil)
		if err != nil {
			return nil, err
		}

		// add the images we retrieved to the cache.
		for _, v := range images {
			log.Infof("Imagestore: Found image %s on datastore.", v.ID)
			c.storeCache[*store][v.ID] = *v
		}

		// Assert there's a scratch
		if _, ok = c.storeCache[*store][Scratch.ID]; !ok {
			return nil, fmt.Errorf("Scratch does not exist.  Imagestore is corrrupt.")
		}
	}

	return store, nil
}
Пример #10
0
// GetImage gets the specified image from the given store by retreiving it from the cache.
func (c *NameLookupCache) GetImage(op trace.Operation, store *url.URL, ID string) (*Image, error) {

	op.Debugf("Getting image %s from %s", ID, store.String())

	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return nil, err
	}

	// Check the store exists
	if _, err = c.GetImageStore(op, storeName); err != nil {
		return nil, err
	}

	c.storeCacheLock.Lock()
	indx := c.storeCache[*store]
	c.storeCacheLock.Unlock()

	imgURL, err := util.ImageURL(storeName, ID)
	if err != nil {
		return nil, err
	}
	node, err := c.storeCache[*store].Get(imgURL.String())

	var img *Image
	if err != nil {
		if err == index.ErrNodeNotFound {
			debugf("Image %s not in cache, retreiving from datastore", ID)
			// Not in the cache.  Try to load it.
			img, err = c.DataStore.GetImage(op, store, ID)
			if err != nil {
				return nil, err
			}

			if err = indx.Insert(img); err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	} else {
		img, _ = node.(*Image)
	}

	return img, nil
}
Пример #11
0
// ListImages returns a list of Images for a list of IDs, or all if no IDs are passed
func (c *NameLookupCache) ListImages(op trace.Operation, store *url.URL, IDs []string) ([]*Image, error) {
	// Filter the results
	imageList := make([]*Image, 0, len(IDs))

	if len(IDs) > 0 {
		for _, id := range IDs {
			i, err := c.GetImage(op, store, id)
			if err == nil {
				imageList = append(imageList, i)
			}
		}

	} else {

		storeName, err := util.ImageStoreName(store)
		if err != nil {
			return nil, err
		}
		// Check the store exists before we start iterating it.  This will populate the cache if it's empty.
		if _, err := c.GetImageStore(op, storeName); err != nil {
			return nil, err
		}

		// get the relevant cache
		c.storeCacheLock.Lock()
		indx := c.storeCache[*store]
		c.storeCacheLock.Unlock()

		images, err := indx.List()
		if err != nil {
			return nil, err
		}

		for _, v := range images {
			img, _ := v.(*Image)
			// filter out scratch
			if img.ID == Scratch.ID {
				continue
			}

			imageList = append(imageList, img)
		}
	}

	return imageList, nil
}
Пример #12
0
func (v *ImageStore) GetImage(op trace.Operation, store *url.URL, ID string) (*portlayer.Image, error) {

	defer trace.End(trace.Begin(store.String()))
	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return nil, err
	}

	imageURL, err := util.ImageURL(storeName, ID)
	if err != nil {
		return nil, err
	}

	if err = v.verifyImage(op, storeName, ID); err != nil {
		return nil, err
	}

	// get the metadata
	metaDataDir := v.imageMetadataDirPath(storeName, ID)
	meta, err := getMetadata(op, v.ds, metaDataDir)
	if err != nil {
		return nil, err
	}

	var s = *store
	var parentURL *url.URL

	parentID := v.parents.Get(ID)
	if parentID != "" {
		parentURL, _ = util.ImageURL(storeName, parentID)
	}

	newImage := &portlayer.Image{
		ID:       ID,
		SelfLink: imageURL,
		// We're relying on the parent map for this since we don't currently have a
		// way to get the disk's spec.  See VIC #482 for details.  Parent:
		// parent.SelfLink,
		Store:      &s,
		ParentLink: parentURL,
		Metadata:   meta,
	}

	op.Debugf("Returning image from location %s with parent url %s", newImage.SelfLink, newImage.Parent())
	return newImage, nil
}
Пример #13
0
func (c *MockDataStore) WriteImage(op trace.Operation, parent *spl.Image, ID string, meta map[string][]byte, sum string, r io.Reader) (*spl.Image, error) {
	storeName, err := util.ImageStoreName(parent.Store)
	if err != nil {
		return nil, err
	}

	selflink, err := util.ImageURL(storeName, ID)
	if err != nil {
		return nil, err
	}

	i := spl.Image{
		ID:         ID,
		Store:      parent.Store,
		ParentLink: parent.SelfLink,
		SelfLink:   selflink,
		Metadata:   meta,
	}

	return &i, nil
}
Пример #14
0
// Find any image directories without the manifest file and remove them.
func (v *ImageStore) cleanup(ctx context.Context, store *url.URL) error {
	log.Infof("Checking for inconsistent images on %s", store.String())

	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return err
	}

	res, err := v.ds.Ls(ctx, v.imageStorePath(storeName))
	if err != nil {
		return err
	}

	for _, f := range res.File {
		file, ok := f.(*types.FileInfo)
		if !ok {
			continue
		}

		ID := file.Path

		if ID == portlayer.Scratch.ID {
			continue
		}

		imageDir := v.imageDirPath(storeName, ID)

		// check for the manifest file.
		_, err = v.ds.Stat(ctx, path.Join(imageDir, manifest))
		if err != nil {

			log.Infof("Removing inconsistent image (%s) %s", ID, imageDir)

			// Eat the error so we can continue cleaning up.  The tasks package will log the error if there is one.
			_ = v.ds.Rm(ctx, imageDir)
		}
	}

	return nil
}
Пример #15
0
// Find any image directories without the manifest file and remove them.
func (v *ImageStore) cleanup(op trace.Operation, store *url.URL) error {
	op.Infof("Checking for inconsistent images on %s", store.String())

	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return err
	}

	res, err := v.ds.Ls(op, v.imageStorePath(storeName))
	if err != nil {
		return err
	}

	// We could call v.ListImages here but that results in calling GetImage,
	// which pulls and unmarshalls the metadata.  We don't need that.
	for _, f := range res.File {
		file, ok := f.(*types.FileInfo)
		if !ok {
			continue
		}

		ID := file.Path

		if ID == portlayer.Scratch.ID {
			continue
		}

		if err := v.verifyImage(op, storeName, ID); err != nil {

			if err = v.deleteImage(op, storeName, ID); err != nil {
				// deleteImage logs the error in the event there is one.
				return err
			}
		}
	}

	return nil
}
Пример #16
0
// ListImages resturns a list of Images for a list of IDs, or all if no IDs are passed
func (c *NameLookupCache) ListImages(ctx context.Context, store *url.URL, IDs []string) ([]*Image, error) {
	storeName, err := util.ImageStoreName(store)
	if err != nil {
		return nil, err
	}

	// Check the store exists before we start iterating it.  This will populate the cache if it's empty.
	if _, err := c.GetImageStore(ctx, storeName); err != nil {
		return nil, err
	}

	c.storeCacheLock.Lock()
	defer c.storeCacheLock.Unlock()

	// Filter the results
	var imageList []*Image
	if len(IDs) > 0 {
		for _, id := range IDs {
			if i, ok := c.storeCache[*store][id]; ok {
				newImage := i
				imageList = append(imageList, &newImage)
			}
		}
	} else {
		for _, v := range c.storeCache[*store] {
			// filter out scratch
			if v.ID == Scratch.ID {
				continue
			}
			newImage := v
			imageList = append(imageList, &newImage)
		}
	}

	return imageList, nil
}
Пример #17
0
// GetImageStore checks to see if a named image store exists and returls the
// URL to it if so or error.
func (c *NameLookupCache) GetImageStore(op trace.Operation, storeName string) (*url.URL, error) {
	store, err := util.ImageStoreNameToURL(storeName)
	if err != nil {
		return nil, err
	}

	c.storeCacheLock.Lock()
	defer c.storeCacheLock.Unlock()

	// check the cache
	_, ok := c.storeCache[*store]

	if !ok {
		infof("Refreshing image cache from datastore.")
		// Store isn't in the cache.  Look it up in the datastore.
		storeName, err := util.ImageStoreName(store)
		if err != nil {
			return nil, err
		}

		// If the store doesn't exist, we'll fall out here.
		_, err = c.DataStore.GetImageStore(op, storeName)
		if err != nil {
			return nil, err
		}

		idx := index.NewIndex()

		c.storeCache[*store] = idx

		// Add Scratch
		scratch, err := c.DataStore.GetImage(op, store, Scratch.ID)
		if err != nil {
			log.Errorf("ImageCache Error: looking up scratch on %s: %s", store.String(), err)
			return nil, ErrCorruptImageStore
		}

		if err = idx.Insert(scratch); err != nil {
			return nil, err
		}

		// XXX after creating the indx and populating the map, we can put the rest in a go routine

		// Fall out here if there are no images.  We should at least have a scratch.
		images, err := c.DataStore.ListImages(op, store, nil)
		if err != nil {
			return nil, err
		}

		debugf("Found %d images", len(images))

		// Build image map to simplify tree traversal.
		imageMap := make(map[string]*Image, len(images))
		for _, img := range images {
			if img.ID == Scratch.ID {
				continue
			}
			imageMap[img.Self()] = img
		}

		for k := range imageMap {
			parentTree(k, idx, imageMap)
		}
	}

	return store, nil
}