Skip to content

Commit

Permalink
Add support for printing published docker image metadata to a file (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
aradisavljevic committed Apr 29, 2021
1 parent 43db3f2 commit df81f82
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 3 deletions.
76 changes: 76 additions & 0 deletions cmd/artifact/artifact.go
Original file line number Diff line number Diff line change
@@ -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
}
17 changes: 17 additions & 0 deletions cmd/artifact/artifact.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
}
38 changes: 38 additions & 0 deletions cmd/artifact/artifact_test.go
Original file line number Diff line number Diff line change
@@ -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()
}
}
16 changes: 16 additions & 0 deletions cmd/kaniko-docker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/urfave/cli"

kaniko "github.com/drone/drone-kaniko"
"github.com/drone/drone-kaniko/cmd/artifact"
)

const (
Expand All @@ -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 (
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
Expand Down
18 changes: 17 additions & 1 deletion cmd/kaniko-ecr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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 {
Expand All @@ -135,14 +143,22 @@ 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()
}

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
Expand Down
16 changes: 16 additions & 0 deletions cmd/kaniko-gcr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
Expand Down
37 changes: 35 additions & 2 deletions kaniko.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package kaniko

import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"

"github.com/drone/drone-kaniko/cmd/artifact"
)

type (
Expand All @@ -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
}
)

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit df81f82

Please sign in to comment.