Exemple #1
0
// Manifest returns the ImageManifest inside the ACI file
func Manifest(f io.ReadSeeker) (*schema.ImageManifest, error) {
	m, err := specaci.ManifestFromImage(f)
	if err != nil {
		return nil, err
	}
	return m, nil
}
Exemple #2
0
func (ms *conversionStore) WriteACI(path string) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", err
	}
	defer f.Close()

	cr, err := aci.NewCompressedReader(f)
	if err != nil {
		return "", err
	}
	defer cr.Close()

	h := sha512.New()
	r := io.TeeReader(cr, h)

	// read the file so we can get the hash
	if _, err := io.Copy(ioutil.Discard, r); err != nil {
		return "", fmt.Errorf("error reading ACI: %v", err)
	}

	im, err := aci.ManifestFromImage(f)
	if err != nil {
		return "", err
	}

	key := ms.HashToKey(h)
	ms.acis[key] = &aciInfo{path: path, key: key, ImageManifest: im}
	return key, nil
}
Exemple #3
0
// newValidator returns a validator instance if passed image is indeed
// an ACI image.
func newValidator(image io.ReadSeeker) (*validator, error) {
	manifest, err := aci.ManifestFromImage(image)
	if err != nil {
		return nil, err
	}
	v := &validator{
		image:    image,
		manifest: manifest,
	}
	return v, nil
}
Exemple #4
0
func extractManifest(aciPath string) (*schema.ImageManifest, error) {
	aciFile, err := os.Open(aciPath)
	if err != nil {
		return nil, err
	}
	defer aciFile.Close()

	manifest, err := appcaci.ManifestFromImage(aciFile)
	if err != nil {
		return nil, err
	}
	return manifest, nil
}
Exemple #5
0
func getManifest(aciPath string) (*schema.ImageManifest, error) {
	f, err := os.Open(aciPath)
	if err != nil {
		return nil, fmt.Errorf("error opening converted image: %v", err)
	}
	defer f.Close()

	manifest, err := aci.ManifestFromImage(f)
	if err != nil {
		return nil, fmt.Errorf("error reading manifest from converted image: %v", err)
	}

	return manifest, nil
}
Exemple #6
0
// ExtractLayers extracts layers from an ACI and treats its rootfs as the last layer
func ExtractLayers(store *store.Store, in string) (types.Dependencies, error) {
	inFile, err := os.Open(in)
	if err != nil {
		return nil, fmt.Errorf("error opening ACI: %v", err)
	}

	im, err := aci.ManifestFromImage(inFile)
	if err != nil {
		return nil, fmt.Errorf("error extracting manifest from ACI: %v", err)
	}

	// TODO: store rootfs as a layer
	return im.Dependencies, nil
}
Exemple #7
0
// getManifestfromImage extracts the image manifest of an ACI given by a path
func GetManifestFromImage(in string) (*schema.ImageManifest, error) {
	inFile, err := os.Open(in)
	if err != nil {
		return nil, fmt.Errorf("error opening ACI: %v", err)
	}
	defer inFile.Close()

	im, err := aci.ManifestFromImage(inFile)
	if err != nil {
		return nil, fmt.Errorf("error extracting image manifest: %v", err)
	}

	return im, nil
}
Exemple #8
0
func (ts *TestStore) WriteACI(path string) (string, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	imageID := types.NewHashSHA512(data)

	rs, err := os.Open(path)
	if err != nil {
		return "", err
	}
	defer rs.Close()
	im, err := aci.ManifestFromImage(rs)
	if err != nil {
		return "", fmt.Errorf("error retrieving ImageManifest: %v", err)
	}

	key := imageID.String()
	ts.acis[key] = &TestStoreAci{data: data, key: key, ImageManifest: im}
	return key, nil
}
Exemple #9
0
// WriteACI takes an ACI encapsulated in an io.Reader, decompresses it if
// necessary, and then stores it in the store under a key based on the image ID
// (i.e. the hash of the uncompressed ACI)
// latest defines if the aci has to be marked as the latest. For example an ACI
// discovered without asking for a specific version (latest pattern).
func (s Store) WriteACI(r io.Reader, latest bool) (string, error) {
	// Peek at the first 512 bytes of the reader to detect filetype
	br := bufio.NewReaderSize(r, 32768)
	hd, err := br.Peek(512)
	switch err {
	case nil:
	case io.EOF: // We may have still peeked enough to guess some types, so fall through
	default:
		return "", fmt.Errorf("error reading image header: %v", err)
	}
	typ, err := aci.DetectFileType(bytes.NewBuffer(hd))
	if err != nil {
		return "", fmt.Errorf("error detecting image type: %v", err)
	}
	dr, err := decompress(br, typ)
	if err != nil {
		return "", fmt.Errorf("error decompressing image: %v", err)
	}

	// Write the decompressed image (tar) to a temporary file on disk, and
	// tee so we can generate the hash
	h := sha512.New()
	tr := io.TeeReader(dr, h)
	fh, err := s.TmpFile()
	if err != nil {
		return "", fmt.Errorf("error creating image: %v", err)
	}
	if _, err := io.Copy(fh, tr); err != nil {
		return "", fmt.Errorf("error copying image: %v", err)
	}
	im, err := aci.ManifestFromImage(fh)
	if err != nil {
		return "", fmt.Errorf("error extracting image manifest: %v", err)
	}
	if err := fh.Close(); err != nil {
		return "", fmt.Errorf("error closing image: %v", err)
	}

	// Import the uncompressed image into the store at the real key
	key := s.HashToKey(h)
	keyLock, err := lock.ExclusiveKeyLock(s.imageLockDir, key)
	if err != nil {
		return "", fmt.Errorf("error locking image: %v", err)
	}
	defer keyLock.Close()

	if err = s.stores[blobType].Import(fh.Name(), key, true); err != nil {
		return "", fmt.Errorf("error importing image: %v", err)
	}

	// Save the imagemanifest using the same key used for the image
	imj, err := json.Marshal(im)
	if err != nil {
		return "", fmt.Errorf("error marshalling image manifest: %v", err)
	}
	if err = s.stores[imageManifestType].Write(key, imj); err != nil {
		return "", fmt.Errorf("error importing image manifest: %v", err)
	}

	// Save aciinfo
	if err = s.db.Do(func(tx *sql.Tx) error {
		aciinfo := &ACIInfo{
			BlobKey:    key,
			AppName:    im.Name.String(),
			ImportTime: time.Now(),
			Latest:     latest,
		}
		return WriteACIInfo(tx, aciinfo)
	}); err != nil {
		return "", fmt.Errorf("error writing ACI Info: %v", err)
	}

	// The treestore for this ACI is not written here as ACIs downloaded as
	// dependencies of another ACI will be exploded also if never directly used.
	// Users of treestore should call s.RenderTreeStore before using it.

	return key, nil
}
Exemple #10
0
// Upload performs the upload of the ACI and signature specified in the
// Uploader struct.
func (u Uploader) Upload() error {
	acifile, err := os.Open(u.Acipath)
	if err != nil {
		return errs.WithEF(err, data.WithField("file", u.Acipath), "Failed to open aci file")
	}
	defer acifile.Close()

	var ascfile *os.File
	if _, err := os.Stat(u.Ascpath); err == nil {
		ascfile, err = os.Open(u.Ascpath)
		if err != nil {
			return errs.WithEF(err, data.WithField("file", u.Ascpath), "Failed to open asc file")
		}
		defer ascfile.Close()
	}

	manifest, err := aci.ManifestFromImage(acifile)
	if err != nil {
		return errs.WithEF(err, data.WithField("file", u.Ascpath), "Failed to extract manifest from aci")
	}
	app, err := discovery.NewAppFromString(u.Uri)
	if err != nil {
		return errs.WithEF(err, data.WithField("uri", u.Uri), "Failed to prepare app")
	}

	if _, ok := app.Labels[archLabelName]; !ok {
		arch, ok := manifest.Labels.Get(archLabelName)
		if !ok {
			return fmt.Errorf("manifest is missing label: %q", archLabelName)
		}
		app.Labels[archLabelName] = arch
	}

	if _, ok := app.Labels[osLabelName]; !ok {
		os, ok := manifest.Labels.Get(osLabelName)
		if !ok {
			return fmt.Errorf("manifest is missing label: %q", osLabelName)
		}
		app.Labels[osLabelName] = os
	}

	if _, ok := app.Labels[extLabelName]; !ok {
		app.Labels[extLabelName] = strings.Trim(schema.ACIExtension, ".")
	}

	// Just to make sure that we start reading from the front of the file in
	// case aci.ManifestFromImage changed the cursor into the file.
	_, err = acifile.Seek(0, 0)
	if err != nil {
		return errs.WithE(err, "Failed to seek to beginning of file")
	}

	manblob, err := manifest.MarshalJSON()
	if err != nil {
		return errs.WithE(err, "Failed to marshall manifest")
	}

	initurl, err := u.getInitiationURL(app)
	if err != nil {
		return errs.WithEF(err, data.WithField("uri", u.Uri), "Failed to initate url")
	}

	initDeets, err := u.initiateUpload(initurl)
	if err != nil {
		return errs.WithE(err, "Failed to initiate upload")
	}

	type partToUpload struct {
		label string
		url   string
		r     io.Reader
		draw  bool
	}

	parts := []partToUpload{
		{"manifest", initDeets.ManifestURL, bytes.NewReader(manblob), false},
		{"ACI", initDeets.ACIURL, acifile, true}}
	if ascfile != nil {
		parts = append(parts, partToUpload{"signature", initDeets.SignatureURL, ascfile, true})
	}

	for _, part := range parts {
		err = u.uploadPart(part.url, part.r, part.draw, part.label)
		if err != nil {
			reason := fmt.Errorf("error uploading %s: %v", part.label, err)
			reportErr := u.reportFailure(initDeets.CompletedURL, reason.Error())
			if reportErr != nil {
				return fmt.Errorf("error uploading %s and error reporting failure: %v, %v", part.label, err, reportErr)
			}
			return reason
		}
	}

	err = u.reportSuccess(initDeets.CompletedURL)
	if err != nil {
		return errs.WithE(err, "Remote server report upload failure")
	}

	return nil
}
Exemple #11
0
// WriteACI takes an ACI encapsulated in an io.Reader, decompresses it if
// necessary, and then stores it in the store under a key based on the image ID
// (i.e. the hash of the uncompressed ACI)
// latest defines if the aci has to be marked as the latest. For example an ACI
// discovered without asking for a specific version (latest pattern).
func (s *Store) WriteACI(r io.ReadSeeker, fetchInfo ACIFetchInfo) (string, error) {
	// We need to allow the store's setgid bits (if any) to propagate, so
	// disable umask
	um := syscall.Umask(0)
	defer syscall.Umask(um)

	dr, err := aci.NewCompressedReader(r)
	if err != nil {
		return "", errwrap.Wrap(errors.New("error decompressing image"), err)
	}
	defer dr.Close()

	// Write the decompressed image (tar) to a temporary file on disk, and
	// tee so we can generate the hash
	h := sha512.New()
	tr := io.TeeReader(dr, h)
	fh, err := s.TmpFile()
	if err != nil {
		return "", errwrap.Wrap(errors.New("error creating image"), err)
	}
	sz, err := io.Copy(fh, tr)
	if err != nil {
		return "", errwrap.Wrap(errors.New("error copying image"), err)
	}
	im, err := aci.ManifestFromImage(fh)
	if err != nil {
		return "", errwrap.Wrap(errors.New("error extracting image manifest"), err)
	}
	if err := fh.Close(); err != nil {
		return "", errwrap.Wrap(errors.New("error closing image"), err)
	}

	// Import the uncompressed image into the store at the real key
	key := s.HashToKey(h)
	keyLock, err := lock.ExclusiveKeyLock(s.imageLockDir, key)
	if err != nil {
		return "", errwrap.Wrap(errors.New("error locking image"), err)
	}
	defer keyLock.Close()

	if err = s.stores[blobType].Import(fh.Name(), key, true); err != nil {
		return "", errwrap.Wrap(errors.New("error importing image"), err)
	}

	// Save the imagemanifest using the same key used for the image
	imj, err := json.Marshal(im)
	if err != nil {
		return "", errwrap.Wrap(errors.New("error marshalling image manifest"), err)
	}
	if err := s.stores[imageManifestType].Write(key, imj); err != nil {
		return "", errwrap.Wrap(errors.New("error importing image manifest"), err)
	}

	// Save aciinfo
	if err = s.db.Do(func(tx *sql.Tx) error {
		aciinfo := &ACIInfo{
			BlobKey:    key,
			Name:       im.Name.String(),
			ImportTime: time.Now(),
			LastUsed:   time.Now(),
			Latest:     fetchInfo.Latest,
			Size:       sz,
		}
		return WriteACIInfo(tx, aciinfo)
	}); err != nil {
		return "", errwrap.Wrap(errors.New("error writing ACI Info"), err)
	}

	return key, nil
}