Add support for printing published docker image metadata to a file (#17)
This commit is contained in:
parent
43db3f2ccc
commit
df81f82f84
|
@ -0,0 +1,76 @@
|
|||
package artifact
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
dockerArtifactV1 string = "docker/v1"
|
||||
)
|
||||
|
||||
type RegistryTypeEnum string
|
||||
|
||||
const (
|
||||
Docker RegistryTypeEnum = "Docker"
|
||||
ECR RegistryTypeEnum = "ECR"
|
||||
GCR RegistryTypeEnum = "GCR"
|
||||
)
|
||||
|
||||
type (
|
||||
Image struct {
|
||||
Image string `json:"image"`
|
||||
Digest string `json:"digest"`
|
||||
}
|
||||
Data struct {
|
||||
RegistryType RegistryTypeEnum `json:"registryType"`
|
||||
RegistryUrl string `json:"registryUrl"`
|
||||
Images []Image `json:"images"`
|
||||
}
|
||||
DockerArtifact struct {
|
||||
Kind string `json:"kind"`
|
||||
Data Data `json:"data"`
|
||||
}
|
||||
)
|
||||
|
||||
func WritePluginArtifactFile(registryType RegistryTypeEnum, artifactFilePath, registryUrl, imageName, digest string, tags []string) error {
|
||||
var images []Image
|
||||
for _, tag := range tags {
|
||||
images = append(images, Image{
|
||||
Image: fmt.Sprintf("%s:%s", imageName, tag),
|
||||
Digest: digest,
|
||||
})
|
||||
}
|
||||
data := Data{
|
||||
RegistryType: registryType,
|
||||
RegistryUrl: registryUrl,
|
||||
Images: images,
|
||||
}
|
||||
|
||||
dockerArtifact := DockerArtifact{
|
||||
Kind: dockerArtifactV1,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(dockerArtifact, "", "\t")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("failed to marshal output %+v", dockerArtifact))
|
||||
}
|
||||
|
||||
dir := filepath.Dir(artifactFilePath)
|
||||
err = os.MkdirAll(dir, 0644)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("failed to create %s directory for artifact file", dir))
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(artifactFilePath, b, 0644)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("failed to write artifact to artifact file %s", artifactFilePath))
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"kind": "docker/v1",
|
||||
"data": {
|
||||
"registryType": "Docker",
|
||||
"registryUrl": "https://index.docker.io/",
|
||||
"images": [
|
||||
{
|
||||
"image": "image:a1",
|
||||
"digest": "sha256:22332233"
|
||||
},
|
||||
{
|
||||
"image": "image:latest",
|
||||
"digest": "sha256:22332233"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package artifact
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWritePluginArtifactFile(t *testing.T) {
|
||||
|
||||
testFile := t.TempDir() + "got.json"
|
||||
|
||||
err := WritePluginArtifactFile(Docker, testFile, "https://index.docker.io/", "image", "sha256:22332233", []string{"a1", "latest"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
gotBytes, err := ioutil.ReadFile(testFile)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
wantBytes, err := ioutil.ReadFile("./artifact.json")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
got := string(gotBytes)
|
||||
want := string(wantBytes)
|
||||
|
||||
if got != want {
|
||||
t.Logf("got:%s", got)
|
||||
t.Logf("want:%s", want)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
|
||||
kaniko "github.com/drone/drone-kaniko"
|
||||
"github.com/drone/drone-kaniko/cmd/artifact"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -21,6 +22,8 @@ const (
|
|||
|
||||
v1Registry string = "https://index.docker.io/v1/" // Default registry
|
||||
v2Registry string = "https://index.docker.io/v2/" // v2 registry is not supported
|
||||
|
||||
defaultDigestFile string = "/kaniko/digest-file"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -119,6 +122,11 @@ func main() {
|
|||
Usage: "Cache timeout in hours. Defaults to two weeks.",
|
||||
EnvVar: "PLUGIN_CACHE_TTL",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "artifact-file",
|
||||
Usage: "Artifact file location that will be generated by the plugin. This file will include information of docker images that are uploaded by the plugin.",
|
||||
EnvVar: "PLUGIN_ARTIFACT_FILE",
|
||||
},
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
|
@ -146,6 +154,14 @@ func run(c *cli.Context) error {
|
|||
EnableCache: c.Bool("enable-cache"),
|
||||
CacheRepo: c.String("cache-repo"),
|
||||
CacheTTL: c.Int("cache-ttl"),
|
||||
DigestFile: defaultDigestFile,
|
||||
},
|
||||
Artifact: kaniko.Artifact{
|
||||
Tags: c.StringSlice("tags"),
|
||||
Repo: c.String("repo"),
|
||||
Registry: c.String("registry"),
|
||||
ArtifactFile: c.String("artifact-file"),
|
||||
RegistryType: artifact.Docker,
|
||||
},
|
||||
}
|
||||
return plugin.Exec()
|
||||
|
|
|
@ -11,12 +11,15 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
|
||||
kaniko "github.com/drone/drone-kaniko"
|
||||
"github.com/drone/drone-kaniko/cmd/artifact"
|
||||
)
|
||||
|
||||
const (
|
||||
accessKeyEnv string = "AWS_ACCESS_KEY_ID"
|
||||
secretKeyEnv string = "AWS_SECRET_ACCESS_KEY"
|
||||
dockerConfigPath string = "/kaniko/.docker/config.json"
|
||||
|
||||
defaultDigestFile string = "/kaniko/digest-file"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -109,6 +112,11 @@ func main() {
|
|||
Usage: "Cache timeout in hours. Defaults to two weeks.",
|
||||
EnvVar: "PLUGIN_CACHE_TTL",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "artifact-file",
|
||||
Usage: "Artifact file location that will be generated by the plugin. This file will include information of docker images that are uploaded by the plugin.",
|
||||
EnvVar: "PLUGIN_ARTIFACT_FILE",
|
||||
},
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
|
@ -135,6 +143,14 @@ func run(c *cli.Context) error {
|
|||
EnableCache: c.Bool("enable-cache"),
|
||||
CacheRepo: fmt.Sprintf("%s/%s", c.String("registry"), c.String("cache-repo")),
|
||||
CacheTTL: c.Int("cache-ttl"),
|
||||
DigestFile: defaultDigestFile,
|
||||
},
|
||||
Artifact: kaniko.Artifact{
|
||||
Tags: c.StringSlice("tags"),
|
||||
Repo: c.String("repo"),
|
||||
Registry: c.String("registry"),
|
||||
ArtifactFile: c.String("artifact-file"),
|
||||
RegistryType: artifact.ECR,
|
||||
},
|
||||
}
|
||||
return plugin.Exec()
|
||||
|
@ -142,7 +158,7 @@ func run(c *cli.Context) error {
|
|||
|
||||
func setupECRAuth(accessKey, secretKey, registry string) error {
|
||||
if registry == "" {
|
||||
return fmt.Errorf("Registry must be specified")
|
||||
return fmt.Errorf("registry must be specified")
|
||||
}
|
||||
|
||||
// If IAM role is used, access key & secret key are not required
|
||||
|
|
|
@ -11,12 +11,15 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
|
||||
kaniko "github.com/drone/drone-kaniko"
|
||||
"github.com/drone/drone-kaniko/cmd/artifact"
|
||||
)
|
||||
|
||||
const (
|
||||
// GCR JSON key file path
|
||||
gcrKeyPath string = "/kaniko/config.json"
|
||||
gcrEnvVariable string = "GOOGLE_APPLICATION_CREDENTIALS"
|
||||
|
||||
defaultDigestFile string = "/kaniko/digest-file"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -105,6 +108,11 @@ func main() {
|
|||
Usage: "Cache timeout in hours. Defaults to two weeks.",
|
||||
EnvVar: "PLUGIN_CACHE_TTL",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "artifact-file",
|
||||
Usage: "Artifact file location that will be generated by the plugin. This file will include information of docker images that are uploaded by the plugin.",
|
||||
EnvVar: "PLUGIN_ARTIFACT_FILE",
|
||||
},
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
|
@ -135,6 +143,14 @@ func run(c *cli.Context) error {
|
|||
EnableCache: c.Bool("enable-cache"),
|
||||
CacheRepo: fmt.Sprintf("%s/%s", c.String("registry"), c.String("cache-repo")),
|
||||
CacheTTL: c.Int("cache-ttl"),
|
||||
DigestFile: defaultDigestFile,
|
||||
},
|
||||
Artifact: kaniko.Artifact{
|
||||
Tags: c.StringSlice("tags"),
|
||||
Repo: c.String("repo"),
|
||||
Registry: c.String("registry"),
|
||||
ArtifactFile: c.String("artifact-file"),
|
||||
RegistryType: artifact.GCR,
|
||||
},
|
||||
}
|
||||
return plugin.Exec()
|
||||
|
|
37
kaniko.go
37
kaniko.go
|
@ -2,9 +2,12 @@ package kaniko
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone-kaniko/cmd/artifact"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -22,11 +25,22 @@ type (
|
|||
EnableCache bool // Whether to enable kaniko cache
|
||||
CacheRepo string // Remote repository that will be used to store cached layers
|
||||
CacheTTL int // Cache timeout in hours
|
||||
DigestFile string // Digest file location
|
||||
}
|
||||
// Artifact defines content of artifact file
|
||||
Artifact struct {
|
||||
Tags []string // Docker artifact tags
|
||||
Repo string // Docker artifact repository
|
||||
Registry string // Docker artifact registry
|
||||
RegistryType artifact.RegistryTypeEnum // Rocker artifact registry type
|
||||
ArtifactFile string // Artifact file location
|
||||
|
||||
}
|
||||
|
||||
// Plugin defines the Docker plugin parameters.
|
||||
Plugin struct {
|
||||
Build Build // Docker build configuration
|
||||
Build Build // Docker build configuration
|
||||
Artifact Artifact // Artifact file content
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -82,13 +96,32 @@ func (p Plugin) Exec() error {
|
|||
cmdArgs = append(cmdArgs, fmt.Sprintf("--cache-ttl=%d", p.Build.CacheTTL))
|
||||
}
|
||||
|
||||
if p.Build.DigestFile != "" {
|
||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--digest-file=%s", p.Build.DigestFile))
|
||||
}
|
||||
|
||||
cmd := exec.Command("/kaniko/executor", cmdArgs...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
trace(cmd)
|
||||
|
||||
err := cmd.Run()
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Build.DigestFile != "" && p.Artifact.ArtifactFile != "" {
|
||||
content, err := ioutil.ReadFile(p.Build.DigestFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to read digest file contents at path: %s with error: %s\n", p.Build.DigestFile, err)
|
||||
}
|
||||
err = artifact.WritePluginArtifactFile(p.Artifact.RegistryType, p.Artifact.ArtifactFile, p.Artifact.Registry, p.Artifact.Repo, string(content), p.Artifact.Tags)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to write plugin artifact file at path: %s with error: %s\n", p.Artifact.ArtifactFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// trace writes each command to stdout with the command wrapped in an xml
|
||||
|
|
Loading…
Reference in New Issue