From d98d613dd68bb5ac83c440c19e10d066f5303eaf Mon Sep 17 00:00:00 2001 From: Bryce Lampe Date: Mon, 28 Apr 2025 14:10:51 -0700 Subject: [PATCH] Changes for upcoming go-provider v1.0 --- go.mod | 2 +- go.sum | 4 +- provider/internal/image.go | 125 ++++++++++++++++------------- provider/internal/index.go | 116 +++++++++++++++----------- provider/internal/provider_test.go | 1 + 5 files changed, 144 insertions(+), 104 deletions(-) diff --git a/go.mod b/go.mod index dab0195..5c98dfe 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/otiai10/copy v1.14.0 github.com/pulumi/providertest v0.3.1 github.com/pulumi/pulumi-dotnet/pulumi-language-dotnet v0.0.0-20241219213128-b19d8c8da35b - github.com/pulumi/pulumi-go-provider v0.26.0 + github.com/pulumi/pulumi-go-provider v0.25.1-0.20250421175102-c887ad454804 github.com/pulumi/pulumi-java/pkg v1.10.0 github.com/pulumi/pulumi-yaml v1.17.0 github.com/pulumi/pulumi/pkg/v3 v3.163.0 diff --git a/go.sum b/go.sum index b8f19df..0277ef8 100644 --- a/go.sum +++ b/go.sum @@ -950,8 +950,8 @@ github.com/pulumi/providertest v0.3.1 h1:vlftr7TZlObh81mL88IhhF0/9ZbLrZZos4NAvR4 github.com/pulumi/providertest v0.3.1/go.mod h1:fFHUP4/9DRyYnHWiRnwcynMtM/a7hHR/QcJfcuZKO3A= github.com/pulumi/pulumi-dotnet/pulumi-language-dotnet v0.0.0-20241219213128-b19d8c8da35b h1:pyYHkDsogl5q4dorkTKVk4/87l+fFUEIIVuwBqKJMHM= github.com/pulumi/pulumi-dotnet/pulumi-language-dotnet v0.0.0-20241219213128-b19d8c8da35b/go.mod h1:5LjEUmPDpUyXzFbQCy3s1oFgeU9K3gVA6tX+xn1Xvbo= -github.com/pulumi/pulumi-go-provider v0.26.0 h1:3ia10+irvv7qPph2NZ2YwUGI/KCf6li8Frlc1luv7D4= -github.com/pulumi/pulumi-go-provider v0.26.0/go.mod h1:zJiGxY5xnodPzLulpRS+fsS960MzeCdlsdiVCZ5TMRA= +github.com/pulumi/pulumi-go-provider v0.25.1-0.20250421175102-c887ad454804 h1:IPmEPPcRnYqwznnCPcjk8xpWZGna2situWWQdM3Ljws= +github.com/pulumi/pulumi-go-provider v0.25.1-0.20250421175102-c887ad454804/go.mod h1:WaxPrK2ohj29oHINF8aZlqbnj/iOLnQWk7WrV0EMMe0= github.com/pulumi/pulumi-java/pkg v1.10.0 h1:gPW5dtKOdagDak7KUedkwRKKKUlhkdT7/vV21+ouWCw= github.com/pulumi/pulumi-java/pkg v1.10.0/go.mod h1:MgV+XcV5jcs0R5Naqyxp3UBJn+lXLE3aG5JVb/O8JeE= github.com/pulumi/pulumi-yaml v1.17.0 h1:ebzggygqBcQrtmdBUqi28B1L/fAyHCFVIt0dS5re8Oc= diff --git a/provider/internal/image.go b/provider/internal/image.go index 04e532e..c7cc307 100644 --- a/provider/internal/image.go +++ b/provider/internal/image.go @@ -38,7 +38,6 @@ import ( provider "github.com/pulumi/pulumi-go-provider" "github.com/pulumi/pulumi-go-provider/infer" - "github.com/pulumi/pulumi/sdk/v3/go/common/resource" "github.com/pulumi/pulumi/sdk/v3/go/pulumi" ) @@ -350,17 +349,14 @@ func (i *Image) client(ctx context.Context, state ImageState, args ImageArgs) (C // authenticated. func (i *Image) Check( ctx context.Context, - _ string, - _ resource.PropertyMap, - news resource.PropertyMap, -) (ImageArgs, []provider.CheckFailure, error) { - args, failures, err := infer.DefaultCheck[ImageArgs](ctx, news) + req infer.CheckRequest, +) (infer.CheckResponse[ImageArgs], error) { + args, failures, err := infer.DefaultCheck[ImageArgs](ctx, req.NewInputs) if err != nil || len(failures) != 0 { - return args, failures, err + return infer.CheckResponse[ImageArgs]{Failures: failures, Inputs: args}, err } - // :( - preview := news.ContainsUnknowns() + preview := req.NewInputs.ContainsUnknowns() cfg := infer.GetConfig[Config](ctx) supportsMultipleExports := true @@ -376,7 +372,7 @@ func (i *Image) Check( } } - return args, failures, err + return infer.CheckResponse[ImageArgs]{Failures: failures, Inputs: args}, err } type checkFailure struct { @@ -523,7 +519,9 @@ func (ia ImageArgs) toBuild( // validate confirms the ImageArgs are valid and returns BuildOptions // appropriate for passing to builders. -func (ia *ImageArgs) validate(supportsMultipleExports, preview bool) (controllerapi.BuildOptions, error) { +func (ia *ImageArgs) validate( + supportsMultipleExports, preview bool, +) (controllerapi.BuildOptions, error) { var multierr error if !supportsMultipleExports { @@ -531,7 +529,6 @@ func (ia *ImageArgs) validate(supportsMultipleExports, preview bool) (controller multierr = errors.Join(multierr, newCheckFailure(errors.New("multiple exports require a v0.13 buildkit daemon or newer"), "exports"), ) - } if ia.Push && ia.Load { multierr = errors.Join( multierr, @@ -683,12 +680,11 @@ func (ia *ImageArgs) validate(supportsMultipleExports, preview bool) (controller // Create builds an image using buildkit. func (i *Image) Create( ctx context.Context, - name string, - input ImageArgs, - preview bool, -) (string, ImageState, error) { + req infer.CreateRequest[ImageArgs], +) (infer.CreateResponse[ImageState], error) { + input := req.Inputs state := ImageState{ImageArgs: input} - id := name + id := req.Name // Default our ref to one of our tags. for _, tag := range state.Tags { @@ -701,20 +697,29 @@ func (i *Image) Create( cli, err := i.client(ctx, state, input) if err != nil { - return id, state, err + return infer.CreateResponse[ImageState]{ID: id, Output: state}, err } ok, err := cli.BuildKitEnabled() if err != nil { - return id, state, fmt.Errorf("checking buildkit compatibility: %w", err) + return infer.CreateResponse[ImageState]{ + ID: id, + Output: state, + }, fmt.Errorf("checking buildkit compatibility: %w", err) } if !ok { - return id, state, errors.New("buildkit is not supported on this host") + return infer.CreateResponse[ImageState]{ + ID: id, + Output: state, + }, fmt.Errorf("buildkit is not supported on this host") } - build, err := input.toBuild(ctx, cli.SupportsMultipleExports(), preview) + build, err := input.toBuild(ctx, cli.SupportsMultipleExports(), req.Preview) if err != nil { - return id, state, fmt.Errorf("preparing: %w", err) + return infer.CreateResponse[ImageState]{ + ID: id, + Output: state, + }, fmt.Errorf("preparing: %w", err) } hash, err := hashBuildContext( @@ -723,21 +728,24 @@ func (i *Image) Create( input.Context.Named.Map(), ) if err != nil { - return id, state, fmt.Errorf("hashing build context: %w", err) + return infer.CreateResponse[ImageState]{ + ID: id, + Output: state, + }, fmt.Errorf("hashing build context: %w", err) } state.ContextHash = hash - if preview && !input.shouldBuildOnPreview() { - return id, state, nil + if req.Preview && !input.shouldBuildOnPreview() { + return infer.CreateResponse[ImageState]{ID: id, Output: state}, nil } - if preview && !input.buildable() { + if req.Preview && !input.buildable() { provider.GetLogger(ctx).Warning("Skipping preview build because some inputs are unknown.") - return id, state, nil + return infer.CreateResponse[ImageState]{ID: id, Output: state}, nil } result, err := cli.Build(ctx, build) if err != nil { - return id, state, err + return infer.CreateResponse[ImageState]{ID: id, Output: state}, err } if d, ok := result.ExporterResponse[exptypes.ExporterImageDigestKey]; ok { @@ -747,7 +755,7 @@ func (i *Image) Create( if state.Digest == "" { // Can't construct a ref, nothing else to do. - return id, state, nil + return infer.CreateResponse[ImageState]{ID: id, Output: state}, nil } // Take the first registry tag we find and add a digest to it. That becomes @@ -762,7 +770,7 @@ func (i *Image) Create( break } - return id, state, nil + return infer.CreateResponse[ImageState]{ID: id, Output: state}, nil } // Update builds a new image. Normally we create-replace resources, but for @@ -770,36 +778,41 @@ func (i *Image) Create( // updates and simply re-build the image without deleting anything. func (i *Image) Update( ctx context.Context, - name string, - _ ImageState, - input ImageArgs, - preview bool, -) (ImageState, error) { - _, state, err := i.Create(ctx, name, input, preview) - return state, err + req infer.UpdateRequest[ImageArgs, ImageState], +) (infer.UpdateResponse[ImageState], error) { + resp, err := i.Create(ctx, + infer.CreateRequest[ImageArgs]{Name: req.ID, Inputs: req.News, Preview: req.Preview}, + ) + return infer.UpdateResponse[ImageState]{Output: resp.Output}, err } // Read attempts to read manifests from an image's exports. An image without // exports will have no manifests. func (i *Image) Read( ctx context.Context, - name string, - input ImageArgs, - state ImageState, + req infer.ReadRequest[ImageArgs, ImageState], ) ( - string, // id - ImageArgs, // normalized inputs - ImageState, // normalized state + infer.ReadResponse[ImageArgs, ImageState], error, ) { + state, input := req.State, req.Inputs + cli, err := i.client(ctx, state, input) if err != nil { - return name, input, state, err + return infer.ReadResponse[ImageArgs, ImageState]{ + ID: req.ID, + Inputs: input, + State: state, + }, err } if !state.isExported() { // Nothing was pushed -- all done. - return name, input, state, nil + return infer.ReadResponse[ImageArgs, ImageState]{ + ID: req.ID, + Inputs: input, + State: state, + }, nil } tagsToKeep := []string{} @@ -835,29 +848,29 @@ func (i *Image) Read( // If we couldn't find the tags we expected then return an empty ID to // delete the resource. if len(input.Tags) > 0 && len(tagsToKeep) == 0 { - return "", input, state, nil + return infer.ReadResponse[ImageArgs, ImageState]{ID: "", Inputs: input, State: state}, nil } state.Tags = tagsToKeep - return name, input, state, nil + return infer.ReadResponse[ImageArgs, ImageState]{ID: req.ID, Inputs: input, State: state}, nil } // Delete deletes an Image. If the Image was already deleted out-of-band it is // treated as a success. func (i *Image) Delete( ctx context.Context, - _ string, - state ImageState, -) error { + req infer.DeleteRequest[ImageState], +) (infer.DeleteResponse, error) { + state := req.State cli, err := i.client(ctx, state, state.ImageArgs) if err != nil { - return err + return infer.DeleteResponse{}, err } if state.Digest == "" { // Nothing was exported. Just try to delete the local image. - return cli.Delete(ctx, state.Ref) + return infer.DeleteResponse{}, cli.Delete(ctx, state.Ref) } digests := []string{} @@ -885,17 +898,17 @@ func (i *Image) Delete( multierr = errors.Join(multierr, err) } - return multierr + return infer.DeleteResponse{}, multierr } // Diff re-implements most of the default diff behavior, with the exception of // ignoring "password" changes on registry inputs. func (*Image) Diff( _ context.Context, - _ string, - olds ImageState, - news ImageArgs, + req infer.DiffRequest[ImageArgs, ImageState], ) (provider.DiffResponse, error) { + olds, news := req.Olds, req.News + diff := map[string]provider.PropertyDiff{} update := provider.PropertyDiff{Kind: provider.Update} diff --git a/provider/internal/index.go b/provider/internal/index.go index 516f7d6..514e300 100644 --- a/provider/internal/index.go +++ b/provider/internal/index.go @@ -28,7 +28,6 @@ import ( provider "github.com/pulumi/pulumi-go-provider" "github.com/pulumi/pulumi-go-provider/infer" - "github.com/pulumi/pulumi/sdk/v3/go/common/resource" ) var ( @@ -132,66 +131,83 @@ func (i *IndexState) Annotate(a infer.Annotator) { // Create is a passthrough to Update. func (i *Index) Create( ctx context.Context, - name string, - input IndexArgs, - preview bool, -) (string, IndexState, error) { - state, err := i.Update(ctx, name, IndexState{}, input, preview) - return name, state, err + req infer.CreateRequest[IndexArgs], +) (infer.CreateResponse[IndexState], error) { + resp, err := i.Update( + ctx, + infer.UpdateRequest[IndexArgs, IndexState]{ + ID: req.Name, + News: req.Inputs, + Preview: req.Preview, + }, + ) + return infer.CreateResponse[IndexState]{ID: req.Name, Output: resp.Output}, err } // Update performs `buildx imagetools create` to create a new OCI index / // manifest list. func (i *Index) Update( ctx context.Context, - name string, - state IndexState, - input IndexArgs, - preview bool, -) (IndexState, error) { + req infer.UpdateRequest[IndexArgs, IndexState], +) (infer.UpdateResponse[IndexState], error) { + state, input := req.Olds, req.News + state.IndexArgs = input state.Ref = input.Tag cli, err := i.client(ctx, state, input) if err != nil { - return state, err + return infer.UpdateResponse[IndexState]{Output: state}, err } - if preview { - return state, nil + if req.Preview { + return infer.UpdateResponse[IndexState]{Output: state}, nil } - provider.GetLogger(ctx).Debugf("creating index with tag %s and sources %s", input.Tag, input.Sources) + provider.GetLogger(ctx). + Debugf("creating index with tag %s and sources %s", input.Tag, input.Sources) err = cli.ManifestCreate(ctx, input.isPushed(), input.Tag, input.Sources...) if err != nil { - return state, fmt.Errorf("creating: %w", err) + return infer.UpdateResponse[IndexState]{Output: state}, fmt.Errorf("creating: %w", err) } - _, _, state, err = i.Read(ctx, name, input, state) + // Read remote manifest information, if it exists. + _, err = i.Read( + ctx, + infer.ReadRequest[IndexArgs, IndexState]{ID: req.ID, Inputs: input, State: state}, + ) if err != nil { - return state, fmt.Errorf("reading: %w", err) + return infer.UpdateResponse[IndexState]{Output: state}, fmt.Errorf("reading: %w", err) } - return state, nil + return infer.UpdateResponse[IndexState]{Output: state}, nil } func (i *Index) Read( ctx context.Context, - name string, - input IndexArgs, - state IndexState, -) (string, IndexArgs, IndexState, error) { + req infer.ReadRequest[IndexArgs, IndexState], +) (infer.ReadResponse[IndexArgs, IndexState], error) { + state, input := req.State, req.Inputs + state.IndexArgs = input state.Ref = input.Tag if !input.isPushed() { provider.GetLogger(ctx).Debug("skipping read because index was not pushed") - return name, input, state, nil // Nothing to read. + return infer.ReadResponse[IndexArgs, IndexState]{ + ID: req.ID, + Inputs: input, + State: state, + }, nil // Nothing to read. } cli, err := i.client(ctx, state, input) if err != nil { - return name, input, state, err + return infer.ReadResponse[IndexArgs, IndexState]{ + ID: req.ID, + Inputs: input, + State: state, + }, err } provider.GetLogger(ctx).Debug("reading index with tag " + input.Tag) @@ -199,21 +215,29 @@ func (i *Index) Read( digest, err := cli.ManifestInspect(ctx, input.Tag) if errors.Is(err, errs.ErrNotFound) { // A remote tag was expected but isn't there -- delete the resource. - return "", input, state, nil + return infer.ReadResponse[IndexArgs, IndexState]{ID: "", Inputs: input, State: state}, nil } if errors.Is(err, errs.ErrHTTPUnauthorized) { provider.GetLogger(ctx).Warning("invalid credentials, skipping") - return name, input, state, nil + return infer.ReadResponse[IndexArgs, IndexState]{ + ID: req.ID, + Inputs: input, + State: state, + }, nil } if err != nil { - return name, input, state, err + return infer.ReadResponse[IndexArgs, IndexState]{ + ID: req.ID, + Inputs: input, + State: state, + }, err } if ref, ok := addDigest(input.Tag, digest); ok { state.Ref = ref } - return name, input, state, nil + return infer.ReadResponse[IndexArgs, IndexState]{ID: req.ID, Inputs: input, State: state}, nil } // Check confirms the Index's tag and source refs are all valid. This doesn't @@ -222,13 +246,11 @@ func (i *Index) Read( // cases for now. func (i *Index) Check( ctx context.Context, - _ string, - _ resource.PropertyMap, - news resource.PropertyMap, -) (IndexArgs, []provider.CheckFailure, error) { - args, failures, err := infer.DefaultCheck[IndexArgs](ctx, news) + req infer.CheckRequest, +) (infer.CheckResponse[IndexArgs], error) { + args, failures, err := infer.DefaultCheck[IndexArgs](ctx, req.NewInputs) if err != nil { - return args, failures, err + return infer.CheckResponse[IndexArgs]{Failures: failures, Inputs: args}, err } if _, err := normalizeReference(args.Tag); args.Tag != "" && err != nil { @@ -253,27 +275,31 @@ func (i *Index) Check( } } - return args, failures, nil + return infer.CheckResponse[IndexArgs]{Failures: failures, Inputs: args}, nil } // Delete attempts to delete the remote manifest. -func (i *Index) Delete(ctx context.Context, _ string, state IndexState) error { +func (i *Index) Delete( + ctx context.Context, + req infer.DeleteRequest[IndexState], +) (infer.DeleteResponse, error) { + state := req.State if !state.isPushed() { - return nil // Nothing to delete. + return infer.DeleteResponse{}, nil // Nothing to delete. } cli, err := i.client(ctx, state, state.IndexArgs) if err != nil { - return err + return infer.DeleteResponse{}, err } err = cli.ManifestDelete(ctx, state.Ref) // TODO: Upstream buildx swallows the error types we'd like to test for // here. if err != nil && strings.Contains(err.Error(), "No such manifest:") { - return nil + return infer.DeleteResponse{}, nil } - return err + return infer.DeleteResponse{}, err } // Diff returns a diff of proposed changes against current state. Ideally we @@ -282,10 +308,10 @@ func (i *Index) Delete(ctx context.Context, _ string, state IndexState) error { // change all the time due to short-lived AWS credentials). func (i *Index) Diff( _ context.Context, - _ string, - olds IndexState, - news IndexArgs, + req infer.DiffRequest[IndexArgs, IndexState], ) (provider.DiffResponse, error) { + olds, news := req.Olds, req.News + diff := map[string]provider.PropertyDiff{} update := provider.PropertyDiff{Kind: provider.Update} replace := provider.PropertyDiff{Kind: provider.UpdateReplace} diff --git a/provider/internal/provider_test.go b/provider/internal/provider_test.go index 2436fae..b8da6a8 100644 --- a/provider/internal/provider_test.go +++ b/provider/internal/provider_test.go @@ -68,6 +68,7 @@ func TestSchema(t *testing.T) { type annotator struct{} +func (annotator) Deprecate(_ any, _ string) {} func (annotator) Describe(_ any, _ string) {} func (annotator) SetDefault(_, _ any, _ ...string) {} func (annotator) SetToken(tokens.ModuleName, tokens.TypeName) {}