Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow image resource to configure exact repo #38

Merged
merged 1 commit into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@ TF_ACC=1 go test ./internal/provider/...
This relies on https://www.terraform.io/cli/config/config-file#implied-local-mirror-directories

```
KO_DOCKER_REPO=gcr.io/jason-chainguard
rm .terraform.lock.hcl && \
go build -o ~/.terraform.d/plugins/registry.terraform.io/chainguard-dev/ko/0.0.100/darwin_arm64/terraform-provider-ko && \
terraform init && \
terraform apply -var project=jason-chainguard
terraform apply
```

Also update `version = "0.0.0"` in the .tf file.

This builds the provider code into the correct local mirror location, installs the provider using that location,
This builds the provider code into the correct local mirror location, installs the provider using that location,

Don't forget to delete the provider from the local mirror if you want to use the released provider later.
3 changes: 2 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ provider "ko" {

### Optional

- `docker_repo` (String) Container repositor to publish images to. Defaults to `KO_DOCKER_REPO` env var
- `docker_repo` (String) [DEPRECATED: use `repo`] Container repository to publish images to. Defaults to `KO_DOCKER_REPO` env var
- `repo` (String) Container repository to publish images to. Defaults to `KO_DOCKER_REPO` env var
1 change: 1 addition & 0 deletions docs/resources/image.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ resource "ko_image" "example" {

- `base_image` (String) base image to use
- `platforms` (List of String) Which platform to use when pulling a multi-platform base. Format: all | <os>[/<arch>[/<variant>]][,platform]*
- `repo` (String) Container repository to publish images to. If set, this overrides the provider's docker_repo, and the image name will be exactly the specified `repo`, without the importpath appended.
- `sbom` (String) The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m).
- `working_dir` (String) working directory for the build

Expand Down
16 changes: 9 additions & 7 deletions internal/provider/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,22 @@ const (
BaseImageKey = "base_image"
// TagsKey is used for common "tags" resource attribute
TagsKey = "tags"
// TagOnlyKey used for common "tag_only" resource attribute
// TagOnlyKey is used for common "tag_only" resource attribute
TagOnlyKey = "tag_only"
// PushKey used for common "push" resource attribute
// PushKey is used for common "push" resource attribute
PushKey = "push"
// FilenamesKey used for common "filenames" resource attribute
// FilenamesKey is used for common "filenames" resource attribute
FilenamesKey = "filenames"
// RecursiveKey used for common "recursive" resource attribute
// RecursiveKey is used for common "recursive" resource attribute
RecursiveKey = "recursive"
// SelectorKey used for common "selector" resource attribute
// SelectorKey is used for common "selector" resource attribute
SelectorKey = "selector"
// ImageRefKey used for common "image_ref" resource attribute
// ImageRefKey is used for common "image_ref" resource attribute
ImageRefKey = "image_ref"
// ManifestsKey used for common "manifests" resource attribute
// ManifestsKey is used for common "manifests" resource attribute
ManifestsKey = "manifests"
// RepoKey is used for common "repo" resource attribute
RepoKey = "repo"
)

func StringSlice(in []interface{}) []string {
Expand Down
21 changes: 15 additions & 6 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ func New(version string) func() *schema.Provider {
p := &schema.Provider{
Schema: map[string]*schema.Schema{
"docker_repo": {
Description: "Container repositor to publish images to. Defaults to `KO_DOCKER_REPO` env var",
Description: "[DEPRECATED: use `repo`] Container repository to publish images to. Defaults to `KO_DOCKER_REPO` env var",
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KO_DOCKER_REPO", ""),
Type: schema.TypeString,
},
"repo": {
Description: "Container repository to publish images to. Defaults to `KO_DOCKER_REPO` env var",
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KO_DOCKER_REPO", ""),
Type: schema.TypeString,
Expand All @@ -53,18 +59,21 @@ func New(version string) func() *schema.Provider {
// configure initializes the global provider with sensible defaults (that mimic what ko does with cli/cobra defaults)
func configure(version string, p *schema.Provider) func(context.Context, *schema.ResourceData) (interface{}, diag.Diagnostics) {
return func(ctx context.Context, s *schema.ResourceData) (interface{}, diag.Diagnostics) {
repo, ok := s.Get("docker_repo").(string)
koDockerRepo, ok := s.Get("repo").(string)
if !ok {
return nil, diag.Errorf("expected docker_repo to be string")
return nil, diag.Errorf("expected repo to be string")
}
if repo == "" {
return nil, diag.Errorf("docker_repo attribute or KO_DOCKER_REPO environment variable must be set")
if koDockerRepo == "" {
koDockerRepo, ok = s.Get("docker_repo").(string)
if !ok {
return nil, diag.Errorf("expected docker_repo to be string")
}
}

return &providerOpts{
bo: &options.BuildOptions{},
po: &options.PublishOptions{
DockerRepo: repo,
DockerRepo: koDockerRepo,
},
}, nil
}
Expand Down
56 changes: 41 additions & 15 deletions internal/provider/resource_ko_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package provider

import (
"context"
"errors"
"fmt"
"log"
"sync"
Expand Down Expand Up @@ -85,6 +86,13 @@ func resourceImage() *schema.Resource {
return nil
},
},
RepoKey: {
Description: "Container repository to publish images to. If set, this overrides the provider's docker_repo, and the image name will be exactly the specified `repo`, without the importpath appended.",
Default: "",
Optional: true,
Type: schema.TypeString,
ForceNew: true, // Any time this changes, don't try to update in-place, just create it.
},
ImageRefKey: {
Description: "built image reference by digest",
Type: schema.TypeString,
Expand Down Expand Up @@ -116,12 +124,13 @@ func (o *publishOpts) makePublisher() (publish.Interface, error) {
}

type buildOptions struct {
ip string
workingDir string
dockerRepo string
platforms []string
baseImage string
sbom string
ip string
workingDir string
koDockerRepo string // KO_DOCKER_REPO env var, or the provider's configured repo if set.
imageRepo string // The image's repo, if set.
platforms []string
baseImage string
sbom string
}

func (o *buildOptions) makeBuilder(ctx context.Context) (*build.Caching, error) {
Expand Down Expand Up @@ -178,6 +187,23 @@ func (o *buildOptions) makeBuilder(ctx context.Context) (*build.Caching, error)
var baseImages sync.Map // Cache of base image lookups.

func doBuild(ctx context.Context, opts buildOptions) (string, error) {
if opts.koDockerRepo == "" && opts.imageRepo == "" {
return "", errors.New("one of KO_DOCKER_REPO env var, or provider `docker_repo` or `repo`, or image resource `repo` must be set")
}
po := []publish.Option{publish.WithAuthFromKeychain(authn.DefaultKeychain)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rando thought: should we make this use the helpers automatically?

I think we did it in ko itself, so it might be nice for parity.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good call. I'll send a separate PR.

var repo string
if opts.imageRepo != "" {
// image resource's `repo` takes precedence if set, and selects the
// `--bare` namer so the image is named exactly `repo`.
repo = opts.imageRepo
po = append(po, publish.WithNamer(options.MakeNamer(&options.PublishOptions{
DockerRepo: opts.imageRepo,
Bare: true,
})))
} else {
repo = opts.koDockerRepo
}

b, err := opts.makeBuilder(ctx)
if err != nil {
return "", fmt.Errorf("NewGo: %v", err)
Expand All @@ -187,8 +213,7 @@ func doBuild(ctx context.Context, opts buildOptions) (string, error) {
return "", fmt.Errorf("build: %v", err)
}

p, err := publish.NewDefault(opts.dockerRepo,
publish.WithAuthFromKeychain(authn.DefaultKeychain))
p, err := publish.NewDefault(repo, po...)
if err != nil {
return "", fmt.Errorf("NewDefault: %v", err)
}
Expand All @@ -199,14 +224,15 @@ func doBuild(ctx context.Context, opts buildOptions) (string, error) {
return ref.String(), nil
}

func fromData(d *schema.ResourceData, repo string) buildOptions {
func fromData(d *schema.ResourceData, providerRepo string) buildOptions {
return buildOptions{
ip: d.Get("importpath").(string),
workingDir: d.Get("working_dir").(string),
dockerRepo: repo,
platforms: toStringSlice(d.Get("platforms").([]interface{})),
baseImage: d.Get("base_image").(string),
sbom: d.Get("sbom").(string),
ip: d.Get("importpath").(string),
workingDir: d.Get("working_dir").(string),
koDockerRepo: providerRepo,
imageRepo: d.Get("repo").(string),
platforms: toStringSlice(d.Get("platforms").([]interface{})),
baseImage: d.Get("base_image").(string),
sbom: d.Get("sbom").(string),
}
}

Expand Down