github.com/vchain-us/vcn@v0.9.11-0.20210921212052-a2484d23c0b3/pkg/extractor/docker/docker.go (about)

     1  /*
     2   * Copyright (c) 2018-2020 vChain, Inc. All Rights Reserved.
     3   * This software is released under GPL3.
     4   * The full license information can be found under:
     5   * https://www.gnu.org/licenses/gpl-3.0.en.html
     6   *
     7   */
     8  
     9  package docker
    10  
    11  import (
    12  	"encoding/json"
    13  	"fmt"
    14  	"os/exec"
    15  	"strings"
    16  
    17  	"github.com/vchain-us/vcn/pkg/api"
    18  	"github.com/vchain-us/vcn/pkg/extractor"
    19  	"github.com/vchain-us/vcn/pkg/uri"
    20  )
    21  
    22  // Scheme for docker (default)
    23  const Scheme = "docker"
    24  
    25  // SchemePodman is the scheme for podman (Docker-compatible CLI interface)
    26  const SchemePodman = "podman"
    27  
    28  var schemes = map[string]bool{Scheme: true, SchemePodman: true}
    29  
    30  // Artifact returns a file *api.Artifact from a given u
    31  func Artifact(u *uri.URI, options ...extractor.Option) ([]*api.Artifact, error) {
    32  
    33  	if !schemes[u.Scheme] {
    34  		return nil, nil
    35  	}
    36  
    37  	id := strings.TrimPrefix(u.Opaque, "//")
    38  	images, err := inspect(u.Scheme, id)
    39  	if err != nil {
    40  		return nil, fmt.Errorf("failed to inspect %s image: %s", u.Scheme, err)
    41  	}
    42  	if len(images) < 1 {
    43  		return nil, fmt.Errorf("no %s image found for: %s", u.Scheme, id)
    44  	}
    45  
    46  	i := images[0]
    47  
    48  	m := api.Metadata{
    49  		"architecture": i.Architecture,
    50  		"platform":     i.Os,
    51  	}
    52  
    53  	if version := i.inferVer(); version != "" {
    54  		m["version"] = version
    55  	}
    56  
    57  	m[u.Scheme] = i
    58  	return []*api.Artifact{{
    59  		Kind:     u.Scheme,
    60  		Name:     u.Scheme + "://" + i.name(),
    61  		Hash:     i.hash(),
    62  		Size:     i.Size,
    63  		Metadata: m,
    64  	}}, nil
    65  }
    66  
    67  type image struct {
    68  	ID            string      `json:"Id"`
    69  	RepoTags      []string    `json:"RepoTags"`
    70  	RepoDigests   []string    `json:"RepoDigests"`
    71  	Comment       string      `json:"Comment"`
    72  	Created       string      `json:"Created"`
    73  	DockerVersion string      `json:"DockerVersion"`
    74  	Author        string      `json:"Author"`
    75  	Architecture  string      `json:"Architecture"`
    76  	Os            string      `json:"Os"`
    77  	VirtualSize   uint64      `json:"VirtualSize"`
    78  	Size          uint64      `json:"Size"`
    79  	Metadata      interface{} `json:"Metadata"`
    80  }
    81  
    82  func (i image) hash() string {
    83  	return strings.TrimSpace(strings.Replace(fmt.Sprint(i.ID), "sha256:", "", 1))
    84  }
    85  
    86  func (i image) name() string {
    87  	if len(i.RepoTags) > 0 {
    88  		return i.RepoTags[0]
    89  	}
    90  	return i.hash()
    91  }
    92  
    93  func (i image) inferVer() string {
    94  	if len(i.RepoTags) > 0 {
    95  		parts := strings.SplitN(i.RepoTags[0], ":", 2)
    96  		if len(parts) > 1 && parts[1] != "latest" {
    97  			return parts[1]
    98  		}
    99  	}
   100  
   101  	return ""
   102  }
   103  
   104  func inspect(executable string, arg string) ([]image, error) {
   105  	cmd := exec.Command(executable, "inspect", arg, "--type", "image")
   106  	cmdOutput, err := cmd.Output()
   107  	if err != nil {
   108  		if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
   109  			return nil, fmt.Errorf(string(ee.Stderr))
   110  		}
   111  		return nil, err
   112  	}
   113  	data := []image{}
   114  	if err = json.Unmarshal(cmdOutput, &data); err != nil {
   115  		return nil, err
   116  	}
   117  	return data, nil
   118  }