diff --git a/go.mod b/go.mod index efd9f11f..e9f65dad 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.21 require ( github.com/bflad/tfproviderlint v0.29.0 github.com/hashicorp/terraform-plugin-docs v0.19.0 - // juju 3.3.0 - github.com/juju/juju v0.0.0-20240418052717-3d086f386814 + // juju 3.5.0 + github.com/juju/juju v0.0.0-20240406000153-4582af466744 ) @@ -16,7 +16,7 @@ require ( github.com/hashicorp/terraform-plugin-go v0.22.1 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-testing v1.7.0 - github.com/juju/charm/v12 v12.0.1 + github.com/juju/charm/v12 v12.0.0 github.com/juju/clock v1.0.3 github.com/juju/cmd/v3 v3.0.14 github.com/juju/collections v1.0.4 @@ -127,8 +127,9 @@ require ( github.com/juju/lumberjack/v2 v2.0.2 // indirect github.com/juju/mgo/v3 v3.0.4 // indirect github.com/juju/mutex/v2 v2.0.0 // indirect + github.com/juju/names/v4 v4.0.0-20220207005702-9c6532a52823 // indirect github.com/juju/os/v2 v2.2.3 // indirect - github.com/juju/packaging/v3 v3.0.0 // indirect + github.com/juju/packaging/v2 v2.0.1 // indirect github.com/juju/persistent-cookiejar v1.0.0 // indirect github.com/juju/proxy v1.0.0 // indirect github.com/juju/pubsub/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index 2c62b0b3..b06e0877 100644 --- a/go.sum +++ b/go.sum @@ -324,8 +324,8 @@ github.com/juju/ansiterm v1.0.0 h1:gmMvnZRq7JZJx6jkfSq9/+2LMrVEwGwt7UR6G+lmDEg= github.com/juju/ansiterm v1.0.0/go.mod h1:PyXUpnI3olx3bsPcHt98FGPX/KCFZ1Fi+hw1XLI6384= github.com/juju/blobstore/v3 v3.0.2 h1:roZ4YBuZYmWId6y/6ZLQSAMmNlHOclHD8PQAMOQer6E= github.com/juju/blobstore/v3 v3.0.2/go.mod h1:NXEgMhrVH5744/zLfSkzsySlDQUpCgzvcNxjJJhICko= -github.com/juju/charm/v12 v12.0.1 h1:C40Vv7Llfj05y86CnxxbQbSdIXdGzP01rajJR63Ni24= -github.com/juju/charm/v12 v12.0.1/go.mod h1:QRuKxXC5zzfPlAa8ipmxX1tvpbIBliueLVHGbs3T7wU= +github.com/juju/charm/v12 v12.0.0 h1:/h3YRMqbgxT89QkQGgMS/myOxuHy/kzBLCDOvodsoFY= +github.com/juju/charm/v12 v12.0.0/go.mod h1:rX3no84EHT+qN+BGtwqPyvueC1Sxr0bXWxsbUd6i1iY= github.com/juju/clock v1.0.3 h1:yJHIsWXeU8j3QcBdiess09SzfiXRRrsjKPn2whnMeds= github.com/juju/clock v1.0.3/go.mod h1:HIBvJ8kiV/n7UHwKuCkdYL4l/MDECztHR2sAvWDxxf0= github.com/juju/cmd/v3 v3.0.14 h1:KuuamArSH7vQ6SdQKEHYK2scEMkJTEZKLs8abrlW3XE= @@ -354,8 +354,8 @@ github.com/juju/idmclient/v2 v2.0.0 h1:PsGa092JGy6iFNHZCcao+bigVsTyz1C+tHNRdYmKv github.com/juju/idmclient/v2 v2.0.0/go.mod h1:EOiFbPmnkqKvCUS/DHpDRWhL7eKF0AJaTvMjIYlIUak= github.com/juju/jsonschema v1.0.0 h1:2ScR9hhVdHxft+Te3fnclVx61MmlikHNEOirTGi+hV4= github.com/juju/jsonschema v1.0.0/go.mod h1:SlFW+jFtpWX0P4Tb+zTTPR4ufttLrnJIdQPePxVEfkM= -github.com/juju/juju v0.0.0-20240418052717-3d086f386814 h1:GRea7SuGIEBMAzPGif7RDormNiuMm0LKJP22y1LaNoM= -github.com/juju/juju v0.0.0-20240418052717-3d086f386814/go.mod h1:LN4FXgbHGi5VsBjy0gs+xXDWM0eiOHaAyl6QDF7bCjY= +github.com/juju/juju v0.0.0-20240406000153-4582af466744 h1:IM8Nvz6eJ8vHklgsleP11gUhsPsU0t6ePAPw0NQFtwE= +github.com/juju/juju v0.0.0-20240406000153-4582af466744/go.mod h1:8W1iXQ/tGftslRzNF/1U8mVZFjtqc0zZKygwuIcmbPI= github.com/juju/loggo v1.0.0 h1:Y6ZMQOGR9Aj3BGkiWx7HBbIx6zNwNkxhVNOHU2i1bl0= github.com/juju/loggo v1.0.0/go.mod h1:NIXFioti1SmKAlKNuUwbMenNdef59IF52+ZzuOmHYkg= github.com/juju/lru v1.0.0 h1:FP8mBNF3jBnKwGO5PtsR+8iIegx8DREfhRhpcGpYcn4= @@ -366,14 +366,16 @@ github.com/juju/mgo/v3 v3.0.4 h1:ek6YDy71tqikpoFSpvLkpCZ7zvYNYH+xSk/MebMkCEE= github.com/juju/mgo/v3 v3.0.4/go.mod h1:fAvhDCRbUlEbRIae6UQT8RvPUoLwKnJsBgO6OzHKNxw= github.com/juju/mutex/v2 v2.0.0 h1:rVmJdOaXGWF8rjcFHBNd4x57/1tks5CgXHx55O55SB0= github.com/juju/mutex/v2 v2.0.0/go.mod h1:jwCfBs/smYDaeZLqeaCi8CB8M+tOes4yf827HoOEoqk= +github.com/juju/names/v4 v4.0.0-20220207005702-9c6532a52823 h1:Sv0+v4107/GHA0S25ay/rgGVmLyc+5Fjp0NnTksW/IQ= +github.com/juju/names/v4 v4.0.0-20220207005702-9c6532a52823/go.mod h1:xpkrQpHbz1DGY+0Geo32ZnyognGA/2vSB++rpu/Z+Lc= github.com/juju/names/v5 v5.0.0 h1:3IkRTUaniNXsgjy4lNqbJx7dVdsONlzuH6YMYT7uXss= github.com/juju/names/v5 v5.0.0/go.mod h1:PkvHbErUTniKvLu1ejJ5m/AbXOW55MFn1jsGVEbVXk8= github.com/juju/naturalsort v1.0.0 h1:kGmUUy3h8mJ5/SJYaqKOBR3f3owEd5R52Lh+Tjg/dNM= github.com/juju/naturalsort v1.0.0/go.mod h1:Zqa/vGkXr78k47zM6tFmU9phhxKz/PIdqBzpLhJ86zc= github.com/juju/os/v2 v2.2.3 h1:5SnGWfzFTXcFwu/sd9qEEf/No3UZxivOjJuWmsHI4N4= github.com/juju/os/v2 v2.2.3/go.mod h1:xGfP9I+Xb/A03NcGBsoJgwr084hPckkQHecaHuV3wBQ= -github.com/juju/packaging/v3 v3.0.0 h1:ZzuHhR8Ql9z2oeQ0m73x6k58PW65Cgk5wR9Yc1exoOI= -github.com/juju/packaging/v3 v3.0.0/go.mod h1:WXh/SXqh1du8SFzwb1KC+yZuV4Qc4alWP3MEPqFX9Lw= +github.com/juju/packaging/v2 v2.0.1 h1:KeTfqx3Z0c6RcM053GJH7mplroXoRSuh/dK5vqDQLn8= +github.com/juju/packaging/v2 v2.0.1/go.mod h1:JC+FIRTJXGLt9wA+iP3ltkzv+aWVMMojB/R47uIAK0Y= github.com/juju/persistent-cookiejar v1.0.0 h1:Ag7+QLzqC2m+OYXy2QQnRjb3gTkEBSZagZ6QozwT3EQ= github.com/juju/persistent-cookiejar v1.0.0/go.mod h1:zrbmo4nBKaiP/Ez3F67ewkMbzGYfXyMvRtbOfuAwG0w= github.com/juju/proxy v1.0.0 h1:5XMp0opQJx8K/js3RFG/2EAk+cvKba/zwFJwd5f0AW0= diff --git a/internal/juju/applications.go b/internal/juju/applications.go index 98bb8ff1..9fd2e8dd 100644 --- a/internal/juju/applications.go +++ b/internal/juju/applications.go @@ -418,7 +418,7 @@ func (c applicationsClient) legacyDeploy(ctx context.Context, conn api.Connectio urlForOrigin = urlForOrigin.WithSeries(userSuppliedSeries) } - origin, err := utils.MakeOrigin(charm.Schema(charmURL.Schema), charmURL.Revision, channel, platform) + origin, err := utils.MakeOrigin(charm.Schema(urlForOrigin.Schema), transformedInput.charmRevision, channel, platform) if err != nil { return err } diff --git a/internal/juju/secrets.go b/internal/juju/secrets.go index fc007849..286b8aa2 100644 --- a/internal/juju/secrets.go +++ b/internal/juju/secrets.go @@ -310,7 +310,8 @@ func (c *secretsClient) UpdateSecretAccess(input *GrantRevokeSecretAccessInput, func getApplicationsFromAccessInfo(accessInfo []coresecrets.AccessInfo) []string { var applications []string for _, info := range accessInfo { - applications = append(applications, info.Target) + // Trim the prefix "application-" from the application name (info.Target) + applications = append(applications, strings.TrimPrefix(info.Target, "application-")) } return applications } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 0fb3091c..af7f07f7 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -293,6 +293,7 @@ func (p *jujuProvider) Resources(_ context.Context) []func() resource.Resource { func() resource.Resource { return NewSSHKeyResource() }, func() resource.Resource { return NewUserResource() }, func() resource.Resource { return NewSecretResource() }, + func() resource.Resource { return NewSecretAccessResource() }, } } diff --git a/internal/provider/resource_secret.go b/internal/provider/resource_secret.go index 710cb6cf..5b428623 100644 --- a/internal/provider/resource_secret.go +++ b/internal/provider/resource_secret.go @@ -79,6 +79,9 @@ func (s *secretResource) Schema(_ context.Context, req resource.SchemaRequest, r "secret_id": schema.StringAttribute{ Description: "The ID of the secret.", Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "info": schema.StringAttribute{ Description: "The description of the secret.", diff --git a/internal/provider/resource_secret_access.go b/internal/provider/resource_secret_access.go index bda5d73c..c597aadd 100644 --- a/internal/provider/resource_secret_access.go +++ b/internal/provider/resource_secret_access.go @@ -7,13 +7,11 @@ import ( "context" "fmt" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" - "reflect" - "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/juju/terraform-provider-juju/internal/juju" @@ -60,16 +58,18 @@ func (s *secretAccessResource) Schema(_ context.Context, req resource.SchemaRequ Description: "The model in which the secret belongs.", Required: true, PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.RequiresReplaceIfConfigured(), + stringplanmodifier.UseStateForUnknown(), }, }, "secret_id": schema.StringAttribute{ Description: "The ID of the secret.", - Computed: true, + Required: true, }, "applications": schema.ListAttribute{ Description: "The list of applications to which the secret is granted or revoked.", Required: true, + ElementType: types.StringType, }, }, } @@ -113,8 +113,8 @@ func (s *secretAccessResource) Create(ctx context.Context, req resource.CreateRe resp.Diagnostics.Append(plan.Applications.ElementsAs(ctx, &applications, false)...) err := s.client.Secrets.UpdateSecretAccess(&juju.GrantRevokeSecretAccessInput{ - ModelName: plan.Model.String(), - SecretId: plan.SecretId.String(), + ModelName: plan.Model.ValueString(), + SecretId: plan.SecretId.ValueString(), Applications: applications, }, juju.GrantAccess) if err != nil { @@ -190,12 +190,29 @@ func (s *secretAccessResource) Update(ctx context.Context, req resource.UpdateRe updatedSecretAccessInput.ModelName = state.Model.ValueString() updatedSecretAccessInput.SecretId = state.SecretId.ValueString() - var applicationsInPlanNotInState, applicationsInStateNotInPlan interface{} + var applicationsInPlanNotInState, applicationsInStateNotInPlan []string if !plan.Applications.Equal(state.Applications) { noChange = false - applicationsInPlanNotInState = difference(plan.Applications, state.Applications) - applicationsInStateNotInPlan = difference(state.Applications, plan.Applications) + planApplications := make([]string, len(plan.Applications.Elements())) + resp.Diagnostics.Append(plan.Applications.ElementsAs(ctx, &planApplications, false)...) + + //print the applications in the plan + s.trace(fmt.Sprintf("secret_access_debug applications in plan: %v", planApplications)) + + stateApplications := make([]string, len(state.Applications.Elements())) + resp.Diagnostics.Append(state.Applications.ElementsAs(ctx, &stateApplications, false)...) + + //print the applications in the state + s.trace(fmt.Sprintf("secret_access_debug applications in state: %v", stateApplications)) + + applicationsInPlanNotInState = difference(planApplications, stateApplications) + applicationsInStateNotInPlan = difference(stateApplications, planApplications) + + //print the applications that are in the plan but not in the state + s.trace(fmt.Sprintf("secret_access_debug applications in plan but not in state: %v", applicationsInPlanNotInState)) + //print the applications that are in the state but not in the plan + s.trace(fmt.Sprintf("secret_access_debug applications in state but not in plan: %v", applicationsInStateNotInPlan)) resp.Diagnostics.Append(plan.Applications.ElementsAs(ctx, &state.Applications, false)...) if resp.Diagnostics.HasError() { @@ -216,8 +233,8 @@ func (s *secretAccessResource) Update(ctx context.Context, req resource.UpdateRe err = s.client.Secrets.UpdateSecretAccess(&juju.GrantRevokeSecretAccessInput{ ModelName: state.Model.ValueString(), SecretId: state.SecretId.ValueString(), - Applications: applicationsInStateNotInPlan.([]string), - }, juju.RevokeAccess) + Applications: applicationsInStateNotInPlan, + }, juju.GrantAccess) if err != nil { resp.Diagnostics.AddError("Failed to revoke secret access", err.Error()) return @@ -229,8 +246,8 @@ func (s *secretAccessResource) Update(ctx context.Context, req resource.UpdateRe err = s.client.Secrets.UpdateSecretAccess(&juju.GrantRevokeSecretAccessInput{ ModelName: state.Model.ValueString(), SecretId: state.SecretId.ValueString(), - Applications: applicationsInPlanNotInState.([]string), - }, juju.GrantAccess) + Applications: applicationsInPlanNotInState, + }, juju.RevokeAccess) if err != nil { resp.Diagnostics.AddError("Failed to grant secret access", err.Error()) return @@ -289,39 +306,21 @@ func (s *secretAccessResource) Delete(ctx context.Context, req resource.DeleteRe } // difference returns the difference between two slices. -func difference(slice1, slice2 interface{}) interface{} { - slice1Value := reflect.ValueOf(slice1) - slice2Value := reflect.ValueOf(slice2) - - slice1Type := slice1Value.Type() - slice2Type := slice2Value.Type() - - if slice1Type.Kind() != reflect.Slice || slice2Type.Kind() != reflect.Slice { - panic("Invalid data type. Expected slices.") - } +func difference(slice1, slice2 []string) []string { + var diff []string + m := make(map[string]bool) - if slice1Type.Elem() != slice2Type.Elem() { - panic("Inconsistent slice types.") + for _, s1 := range slice1 { + m[s1] = true } - set := make(map[interface{}]bool) - result := reflect.MakeSlice(slice1Type, 0, slice1Value.Len()) - - for i := 0; i < slice1Value.Len(); i++ { - set[slice1Value.Index(i).Interface()] = true - } - - for i := 0; i < slice2Value.Len(); i++ { - if _, found := set[slice2Value.Index(i).Interface()]; found { - delete(set, slice2Value.Index(i).Interface()) + for _, s2 := range slice2 { + if _, ok := m[s2]; !ok { + diff = append(diff, s2) } } - for key := range set { - result = reflect.Append(result, reflect.ValueOf(key)) - } - - return result.Interface() + return diff } func (s *secretAccessResource) trace(msg string, additionalFields ...map[string]interface{}) {