// 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 }
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 }
// 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 }
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 }
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 }
// 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 }
// 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 }
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 }
// 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 }
// 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 }
// 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 }