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 }