@@ -2,7 +2,6 @@ package provider
22
33import (
44 "context"
5- "errors"
65 "fmt"
76
87 "github.com/chainguard-dev/terraform-provider-oci/pkg/validators"
@@ -11,13 +10,10 @@ import (
1110 "github.com/hashicorp/terraform-plugin-framework/path"
1211 "github.com/hashicorp/terraform-plugin-framework/resource"
1312 "github.com/hashicorp/terraform-plugin-framework/resource/schema"
14- "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
1513 "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
1614 "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
1715 "github.com/hashicorp/terraform-plugin-framework/schema/validator"
1816 "github.com/hashicorp/terraform-plugin-framework/types"
19- "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
20- "golang.org/x/sync/errgroup"
2117)
2218
2319var _ resource.Resource = & TagResource {}
@@ -39,7 +35,6 @@ type TagResourceModel struct {
3935
4036 DigestRef types.String `tfsdk:"digest_ref"`
4137 Tag types.String `tfsdk:"tag"`
42- Tags []string `tfsdk:"tags"`
4338}
4439
4540func (r * TagResource ) Metadata (ctx context.Context , req resource.MetadataRequest , resp * resource.MetadataResponse ) {
@@ -58,19 +53,11 @@ func (r *TagResource) Schema(ctx context.Context, req resource.SchemaRequest, re
5853 },
5954 "tag" : schema.StringAttribute {
6055 MarkdownDescription : "Tag to apply to the image." ,
61- Optional : true ,
56+ Required : true ,
6257 Validators : []validator.String {validators.TagValidator {}},
6358 PlanModifiers : []planmodifier.String {stringplanmodifier .RequiresReplace ()},
64- DeprecationMessage : "The `tag` attribute is deprecated. Use `tags` instead." ,
65- },
66- "tags" : schema.ListAttribute {
67- MarkdownDescription : "Tags to apply to the image." ,
68- // TODO: make this required after tag deprecation period.
69- Optional : true ,
70- ElementType : basetypes.StringType {},
71- Validators : []validator.List {uniqueTagsValidator {}},
72- PlanModifiers : []planmodifier.List {listplanmodifier .RequiresReplace ()},
7359 },
60+
7461 "tagged_ref" : schema.StringAttribute {
7562 Computed : true ,
7663 MarkdownDescription : "The resulting fully-qualified image ref by digest (e.g. {repo}:tag@sha256:deadbeef)." ,
@@ -126,8 +113,8 @@ func (r *TagResource) Read(ctx context.Context, req resource.ReadRequest, resp *
126113 return
127114 }
128115
129- // Don't actually tag, but check whether the digest is already tagged with all requested tags, so we get a useful diff.
130- // If the digest is already tagged with all requested tags , we'll set the ID and tagged_ref to the correct output value.
116+ // Don't actually tag, but check whether the digest is already tagged so we get a useful diff.
117+ // If the digest is already tagged, we'll set the ID and tagged_ref to the correct output value.
131118 // Otherwise, we'll set them to empty strings so that the create will run when applied.
132119
133120 d , err := name .NewDigest (data .DigestRef .ValueString ())
@@ -136,38 +123,22 @@ func (r *TagResource) Read(ctx context.Context, req resource.ReadRequest, resp *
136123 return
137124 }
138125
139- tags := []string {}
140- if data .Tag .ValueString () != "" {
141- tags = append (tags , data .Tag .ValueString ())
142- } else if len (data .Tags ) > 0 {
143- tags = data .Tags
144- } else {
145- resp .Diagnostics .AddError ("Tag Error" , "either tag or tags must be set" )
146- }
147- if data .Tag .ValueString () != "" && len (data .Tags ) > 0 {
148- resp .Diagnostics .AddError ("Tag Error" , "only one of tag or tags may be set" )
126+ t := d .Context ().Tag (data .Tag .ValueString ())
127+ desc , err := remote .Get (t , r .popts .withContext (ctx )... )
128+ if err != nil {
129+ resp .Diagnostics .AddError ("Tag Error" , fmt .Sprintf ("Error getting image: %s" , err .Error ()))
130+ return
149131 }
150- for _ , tag := range tags {
151- t := d .Context ().Tag (tag )
152- desc , err := remote .Get (t , r .popts .withContext (ctx )... )
153- if err != nil {
154- // Failed to get the image by tag, so we need to create.
155- return
156- }
157132
158- // Some tag is wrong, so we need to create.
159- if desc .Digest .String () != d .DigestStr () {
160- data .Id = types .StringValue ("" )
161- data .TaggedRef = types .StringValue ("" )
162- break
163- }
133+ if desc .Digest .String () != d .DigestStr () {
134+ data .Id = types .StringValue ("" )
135+ data .TaggedRef = types .StringValue ("" )
136+ } else {
137+ id := fmt .Sprintf ("%s@%s" , t .Name (), desc .Digest .String ())
138+ data .Id = types .StringValue (id )
139+ data .TaggedRef = types .StringValue (id )
164140 }
165141
166- // All tags are correct so we can set the ID and tagged_ref to the correct output value.
167- id := fmt .Sprintf ("%s@%s" , d .Context ().Tag (tags [0 ]), d .DigestStr ())
168- data .Id = types .StringValue (id )
169- data .TaggedRef = types .StringValue (id )
170-
171142 // Save updated data into Terraform state
172143 resp .Diagnostics .Append (resp .State .Set (ctx , & data )... )
173144}
@@ -200,83 +171,21 @@ func (r *TagResource) ImportState(ctx context.Context, req resource.ImportStateR
200171}
201172
202173func (r * TagResource ) doTag (ctx context.Context , data * TagResourceModel ) (string , error ) {
203- var tags []string
204- if data .Tag .ValueString () != "" {
205- tags = append (tags , data .Tag .ValueString ())
206- } else if len (data .Tags ) > 0 {
207- tags = data .Tags
208- } else {
209- return "" , errors .New ("either tag or tags must be set" )
210- }
211- if data .Tag .ValueString () != "" && len (data .Tags ) > 0 {
212- return "" , errors .New ("only one of tag or tags may be set" )
213- }
214-
215174 d , err := name .NewDigest (data .DigestRef .ValueString ())
216175 if err != nil {
217176 return "" , fmt .Errorf ("digest_ref must be a digest reference: %v" , err )
218177 }
219-
178+ t := d .Context ().Tag (data .Tag .ValueString ())
179+ if err != nil {
180+ return "" , fmt .Errorf ("error parsing tag: %v" , err )
181+ }
220182 desc , err := remote .Get (d , r .popts .withContext (ctx )... )
221183 if err != nil {
222184 return "" , fmt .Errorf ("error fetching digest: %v" , err )
223185 }
224-
225- errg , ctx := errgroup .WithContext (ctx )
226- for _ , tag := range tags {
227- tag := tag
228- errg .Go (func () error {
229- t := d .Context ().Tag (tag )
230- if err != nil {
231- return fmt .Errorf ("error parsing tag %q: %v" , tag , err )
232- }
233- if err := remote .Tag (t , desc , r .popts .withContext (ctx )... ); err != nil {
234- return fmt .Errorf ("error tagging digest with %q: %v" , tag , err )
235- }
236- return nil
237- })
238- }
239- if err := errg .Wait (); err != nil {
240- return "" , err
241- }
242-
243- t := d .Context ().Tag (tags [0 ])
244- if err != nil {
245- return "" , fmt .Errorf ("error parsing tag: %v" , err )
186+ if err := remote .Tag (t , desc , r .popts .withContext (ctx )... ); err != nil {
187+ return "" , fmt .Errorf ("error tagging digest: %v" , err )
246188 }
247- digest := fmt .Sprintf ("%s@%s" , t .Name (), d . DigestStr ())
189+ digest := fmt .Sprintf ("%s@%s" , t .Name (), desc . Digest . String ())
248190 return digest , nil
249191}
250-
251- type uniqueTagsValidator struct {}
252-
253- var _ validator.List = uniqueTagsValidator {}
254-
255- func (v uniqueTagsValidator ) Description (context.Context ) string {
256- return `value must be valid OCI tag elements (e.g., "latest", "v1.2.3")`
257- }
258- func (v uniqueTagsValidator ) MarkdownDescription (ctx context.Context ) string {
259- return v .Description (ctx )
260- }
261-
262- func (v uniqueTagsValidator ) ValidateList (ctx context.Context , req validator.ListRequest , resp * validator.ListResponse ) {
263- if req .ConfigValue .IsNull () || req .ConfigValue .IsUnknown () {
264- return
265- }
266- var tags []string
267- if diag := req .ConfigValue .ElementsAs (ctx , & tags , false ); diag .HasError () {
268- resp .Diagnostics .Append (diag ... )
269- return
270- }
271-
272- seen := map [string ]bool {}
273- for _ , t := range tags {
274- if seen [t ] {
275- resp .Diagnostics .AddWarning ("Duplicate tag" , fmt .Sprintf ("duplicate tag %q" , t ))
276- }
277- seen [t ] = true
278- if _ , err := name .NewTag ("example.com:" + t ); err != nil {
279- resp .Diagnostics .AddError ("Invalid OCI tag name" , fmt .Sprintf ("parsing tag %q: %v" , t , err ))
280- }
281- }
282- }
0 commit comments