Skip to content

Commit

Permalink
Merge pull request appc#237 from dgonyeo/annotate-manifest-hash
Browse files Browse the repository at this point in the history
Annotate manifest hash
  • Loading branch information
Derek Gonyeo authored Jan 26, 2017
2 parents 32eea66 + 065228f commit 1f3b030
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 69 deletions.
1 change: 1 addition & 0 deletions lib/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (
AppcDockerParentImageID = "appc.io/docker/parentimageid"
AppcDockerEntrypoint = "appc.io/docker/entrypoint"
AppcDockerCmd = "appc.io/docker/cmd"
AppcDockerManifestHash = "appc.io/docker/manifesthash"
)

const defaultTag = "latest"
Expand Down
18 changes: 12 additions & 6 deletions lib/docker2aci.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ import (
// CommonConfig represents the shared configuration options for converting
// Docker images.
type CommonConfig struct {
Squash bool // squash the layers in one file
OutputDir string // where to put the resulting ACI
TmpDir string // directory to use for temporary files
Compression common.Compression // which compression to use for the resulting file(s)
Squash bool // squash the layers in one file
OutputDir string // where to put the resulting ACI
TmpDir string // directory to use for temporary files
Compression common.Compression // which compression to use for the resulting file(s)
CurrentManifestHashes []string // any manifest hashes the caller already has

Info log.Logger
Debug log.Logger
Expand Down Expand Up @@ -141,10 +142,15 @@ type converter struct {

func (c *converter) convert() ([]string, error) {
c.config.Debug.Println("Getting image info...")
ancestry, parsedDockerURL, err := c.backend.GetImageInfo(c.dockerURL)
ancestry, manhash, parsedDockerURL, err := c.backend.GetImageInfo(c.dockerURL)
if err != nil {
return nil, err
}
for _, h := range c.config.CurrentManifestHashes {
if manhash == h {
return nil, nil
}
}

layersOutputDir := c.config.OutputDir
if c.config.Squash {
Expand All @@ -163,7 +169,7 @@ func (c *converter) convert() ([]string, error) {
layerCompression = common.NoCompression
}

aciLayerPaths, aciManifests, err := c.backend.BuildACI(ancestry, parsedDockerURL, layersOutputDir, c.config.TmpDir, layerCompression)
aciLayerPaths, aciManifests, err := c.backend.BuildACI(ancestry, manhash, parsedDockerURL, layersOutputDir, c.config.TmpDir, layerCompression)
if err != nil {
return nil, err
}
Expand Down
26 changes: 16 additions & 10 deletions lib/internal/backend/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,21 @@ func NewFileBackend(file *os.File, debug, info log.Logger) *FileBackend {
}
}

func (lb *FileBackend) GetImageInfo(dockerURL string) ([]string, *common.ParsedDockerURL, error) {
// GetImageInfo, given the url for a docker image, will return the
// following:
// - []string: an ordered list of all layer hashes
// - string: a unique identifier for this image, like a hash of the manifest
// - *common.ParsedDockerURL: a parsed docker URL
// - error: an error if one occurred
func (lb *FileBackend) GetImageInfo(dockerURL string) ([]string, string, *common.ParsedDockerURL, error) {
// a missing Docker URL could mean that the file only contains one
// image so it's okay for dockerURL to be blank
var parsedDockerURL *common.ParsedDockerURL
if dockerURL != "" {
var err error
parsedDockerURL, err = common.ParseDockerURL(dockerURL)
if err != nil {
return nil, nil, fmt.Errorf("image provided couldnot be parsed: %v", err)
return nil, "", nil, fmt.Errorf("image provided couldnot be parsed: %v", err)
}
}

Expand All @@ -70,25 +76,25 @@ func (lb *FileBackend) GetImageInfo(dockerURL string) ([]string, *common.ParsedD
name := strings.Split(filepath.Base(lb.file.Name()), ".")[0]
appImageID, ancestry, parsedDockerURL, err := getImageID(lb.file, parsedDockerURL, name, lb.debug)
if err != nil {
return nil, nil, err
return nil, "", nil, err
}

if len(ancestry) == 0 {
ancestry, err = getAncestry(lb.file, appImageID, lb.debug)
if err != nil {
return nil, nil, fmt.Errorf("error getting ancestry: %v", err)
return nil, "", nil, fmt.Errorf("error getting ancestry: %v", err)
}
} else {
// for oci the first image is the config
ancestry = append([]string{appImageID}, ancestry...)
}

return ancestry, parsedDockerURL, nil
return ancestry, appImageID, parsedDockerURL, nil
}

func (lb *FileBackend) BuildACI(layerIDs []string, dockerURL *common.ParsedDockerURL, outputDir string, tmpBaseDir string, compression common.Compression) ([]string, []*schema.ImageManifest, error) {
func (lb *FileBackend) BuildACI(layerIDs []string, manhash string, dockerURL *common.ParsedDockerURL, outputDir string, tmpBaseDir string, compression common.Compression) ([]string, []*schema.ImageManifest, error) {
if strings.Contains(layerIDs[0], ":") {
return lb.BuildACIV22(layerIDs, dockerURL, outputDir, tmpBaseDir, compression)
return lb.BuildACIV22(layerIDs, manhash, dockerURL, outputDir, tmpBaseDir, compression)
}
var aciLayerPaths []string
var aciManifests []*schema.ImageManifest
Expand Down Expand Up @@ -125,7 +131,7 @@ func (lb *FileBackend) BuildACI(layerIDs []string, dockerURL *common.ParsedDocke
defer layerFile.Close()

lb.debug.Println("Generating layer ACI...")
aciPath, manifest, err := internal.GenerateACI(i, layerData, dockerURL, outputDir, layerFile, curPwl, compression, lb.debug)
aciPath, manifest, err := internal.GenerateACI(i, manhash, layerData, dockerURL, outputDir, layerFile, curPwl, compression, lb.debug)
if err != nil {
return nil, nil, fmt.Errorf("error generating ACI: %v", err)
}
Expand All @@ -138,7 +144,7 @@ func (lb *FileBackend) BuildACI(layerIDs []string, dockerURL *common.ParsedDocke
return aciLayerPaths, aciManifests, nil
}

func (lb *FileBackend) BuildACIV22(layerIDs []string, dockerURL *common.ParsedDockerURL, outputDir string, tmpBaseDir string, compression common.Compression) ([]string, []*schema.ImageManifest, error) {
func (lb *FileBackend) BuildACIV22(layerIDs []string, manhash string, dockerURL *common.ParsedDockerURL, outputDir string, tmpBaseDir string, compression common.Compression) ([]string, []*schema.ImageManifest, error) {
if len(layerIDs) < 2 {
return nil, nil, fmt.Errorf("insufficient layers for oci image")
}
Expand Down Expand Up @@ -179,7 +185,7 @@ func (lb *FileBackend) BuildACIV22(layerIDs []string, dockerURL *common.ParsedDo
if i != 0 {
aciPath, manifest, err = internal.GenerateACI22LowerLayer(dockerURL, parts[1], outputDir, layerFile, curPwl, compression)
} else {
aciPath, manifest, err = internal.GenerateACI22TopLayer(dockerURL, &imageConfig, parts[1], outputDir, layerFile, curPwl, compression, aciManifests, lb.debug)
aciPath, manifest, err = internal.GenerateACI22TopLayer(dockerURL, manhash, &imageConfig, parts[1], outputDir, layerFile, curPwl, compression, aciManifests, lb.debug)
}
if err != nil {
return nil, nil, fmt.Errorf("error generating ACI: %v", err)
Expand Down
28 changes: 17 additions & 11 deletions lib/internal/backend/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,16 @@ func NewRepositoryBackend(username string, password string, insecure common.Inse
}
}

func (rb *RepositoryBackend) GetImageInfo(url string) ([]string, *common.ParsedDockerURL, error) {
// GetImageInfo, given the url for a docker image, will return the
// following:
// - []string: an ordered list of all layer hashes
// - string: a unique identifier for this image, like a hash of the manifest
// - *common.ParsedDockerURL: a parsed docker URL
// - error: an error if one occurred
func (rb *RepositoryBackend) GetImageInfo(url string) ([]string, string, *common.ParsedDockerURL, error) {
dockerURL, err := common.ParseDockerURL(url)
if err != nil {
return nil, nil, err
return nil, "", nil, err
}

var supportsV2, supportsV1, ok bool
Expand All @@ -100,42 +106,42 @@ func (rb *RepositoryBackend) GetImageInfo(url string) ([]string, *common.ParsedD
var err error
URLSchema, supportsV2, err = rb.supportsRegistry(dockerURL.IndexURL, registryV2)
if err != nil {
return nil, nil, err
return nil, "", nil, err
}
rb.schema = URLSchema + "://"
rb.hostsV2Support[dockerURL.IndexURL] = supportsV2
}

// try v2
if supportsV2 {
layers, dockerURL, err := rb.getImageInfoV2(dockerURL)
layers, manhash, dockerURL, err := rb.getImageInfoV2(dockerURL)
if !isErrHTTP404(err) {
return layers, dockerURL, err
return layers, manhash, dockerURL, err
}
// fallback on 404 failure
rb.hostsV1fallback = true
}

URLSchema, supportsV1, err = rb.supportsRegistry(dockerURL.IndexURL, registryV1)
if err != nil {
return nil, nil, err
return nil, "", nil, err
}
if !supportsV1 && rb.hostsV1fallback {
return nil, nil, fmt.Errorf("attempted fallback to API v1 but not supported")
return nil, "", nil, fmt.Errorf("attempted fallback to API v1 but not supported")
}
if !supportsV1 && !supportsV2 {
return nil, nil, fmt.Errorf("registry doesn't support API v2 nor v1")
return nil, "", nil, fmt.Errorf("registry doesn't support API v2 nor v1")
}
rb.schema = URLSchema + "://"
// try v1, hard fail on failure
return rb.getImageInfoV1(dockerURL)
}

func (rb *RepositoryBackend) BuildACI(layerIDs []string, dockerURL *common.ParsedDockerURL, outputDir string, tmpBaseDir string, compression common.Compression) ([]string, []*schema.ImageManifest, error) {
func (rb *RepositoryBackend) BuildACI(layerIDs []string, manhash string, dockerURL *common.ParsedDockerURL, outputDir string, tmpBaseDir string, compression common.Compression) ([]string, []*schema.ImageManifest, error) {
if rb.hostsV1fallback || !rb.hostsV2Support[dockerURL.IndexURL] {
return rb.buildACIV1(layerIDs, dockerURL, outputDir, tmpBaseDir, compression)
return rb.buildACIV1(layerIDs, manhash, dockerURL, outputDir, tmpBaseDir, compression)
} else {
return rb.buildACIV2(layerIDs, dockerURL, outputDir, tmpBaseDir, compression)
return rb.buildACIV2(layerIDs, manhash, dockerURL, outputDir, tmpBaseDir, compression)
}
}

Expand Down
14 changes: 7 additions & 7 deletions lib/internal/backend/repository/repository1.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,29 @@ type RepoData struct {
Cookie []string
}

func (rb *RepositoryBackend) getImageInfoV1(dockerURL *common.ParsedDockerURL) ([]string, *common.ParsedDockerURL, error) {
func (rb *RepositoryBackend) getImageInfoV1(dockerURL *common.ParsedDockerURL) ([]string, string, *common.ParsedDockerURL, error) {
repoData, err := rb.getRepoDataV1(dockerURL.IndexURL, dockerURL.ImageName)
if err != nil {
return nil, nil, fmt.Errorf("error getting repository data: %v", err)
return nil, "", nil, fmt.Errorf("error getting repository data: %v", err)
}

// TODO(iaguis) check more endpoints
appImageID, err := rb.getImageIDFromTagV1(repoData.Endpoints[0], dockerURL.ImageName, dockerURL.Tag, repoData)
if err != nil {
return nil, nil, fmt.Errorf("error getting ImageID from tag %s: %v", dockerURL.Tag, err)
return nil, "", nil, fmt.Errorf("error getting ImageID from tag %s: %v", dockerURL.Tag, err)
}

ancestry, err := rb.getAncestryV1(appImageID, repoData.Endpoints[0], repoData)
if err != nil {
return nil, nil, err
return nil, "", nil, err
}

rb.repoData = repoData

return ancestry, dockerURL, nil
return ancestry, appImageID, dockerURL, nil
}

func (rb *RepositoryBackend) buildACIV1(layerIDs []string, dockerURL *common.ParsedDockerURL, outputDir string, tmpBaseDir string, compression common.Compression) ([]string, []*schema.ImageManifest, error) {
func (rb *RepositoryBackend) buildACIV1(layerIDs []string, manhash string, dockerURL *common.ParsedDockerURL, outputDir string, tmpBaseDir string, compression common.Compression) ([]string, []*schema.ImageManifest, error) {
layerFiles := make([]*os.File, len(layerIDs))
layerDatas := make([]types.DockerImageData, len(layerIDs))

Expand Down Expand Up @@ -121,7 +121,7 @@ func (rb *RepositoryBackend) buildACIV1(layerIDs []string, dockerURL *common.Par

for i := len(layerIDs) - 1; i >= 0; i-- {
rb.debug.Println("Generating layer ACI...")
aciPath, manifest, err := internal.GenerateACI(i, layerDatas[i], dockerURL, outputDir, layerFiles[i], curPwl, compression, rb.debug)
aciPath, manifest, err := internal.GenerateACI(i, manhash, layerDatas[i], dockerURL, outputDir, layerFiles[i], curPwl, compression, rb.debug)
if err != nil {
return nil, nil, fmt.Errorf("error generating ACI: %v", err)
}
Expand Down
Loading

0 comments on commit 1f3b030

Please sign in to comment.