Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/FEATURE-BRANCH-ephemeral-resou…
Browse files Browse the repository at this point in the history
…rce' into sync-main-FEATURE-BRANCH-ephemeral-resources
  • Loading branch information
BBBmau committed Nov 21, 2024
2 parents ccba3e7 + b1c6428 commit d5208be
Show file tree
Hide file tree
Showing 15 changed files with 1,438 additions and 13 deletions.
2 changes: 1 addition & 1 deletion mmv1/provider/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ func (t Terraform) getCommonCopyFiles(versionName string, generateCode, generate
// save the folder name to foldersCopiedToGoogleDir
var foldersCopiedToGoogleDir []string
if generateCode {
foldersCopiedToGoogleDir = []string{"third_party/terraform/services", "third_party/terraform/acctest", "third_party/terraform/sweeper", "third_party/terraform/provider", "third_party/terraform/tpgdclresource", "third_party/terraform/tpgiamresource", "third_party/terraform/tpgresource", "third_party/terraform/transport", "third_party/terraform/fwmodels", "third_party/terraform/fwprovider", "third_party/terraform/fwtransport", "third_party/terraform/fwresource", "third_party/terraform/verify", "third_party/terraform/envvar", "third_party/terraform/functions", "third_party/terraform/test-fixtures"}
foldersCopiedToGoogleDir = []string{"third_party/terraform/services", "third_party/terraform/acctest", "third_party/terraform/sweeper", "third_party/terraform/provider", "third_party/terraform/tpgdclresource", "third_party/terraform/tpgiamresource", "third_party/terraform/tpgresource", "third_party/terraform/transport", "third_party/terraform/fwmodels", "third_party/terraform/fwprovider", "third_party/terraform/fwtransport", "third_party/terraform/fwresource", "third_party/terraform/fwutils", "third_party/terraform/fwvalidators", "third_party/terraform/verify", "third_party/terraform/envvar", "third_party/terraform/functions", "third_party/terraform/test-fixtures"}
}
googleDir := "google"
if versionName != "ga" {
Expand Down
14 changes: 14 additions & 0 deletions mmv1/provider/terraform/common~copy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@
'<%= dir -%>/fwprovider/<%= fname -%>': 'third_party/terraform/fwprovider/<%= fname -%>'
<% end -%>

<%
Dir["third_party/terraform/fwutils/*.go"].each do |file_path|
fname = file_path.split('/')[-1]
-%>
'<%= dir -%>/fwutils/<%= fname -%>': 'third_party/terraform/fwutils/<%= fname -%>'
<% end -%>

<%
Dir["third_party/terraform/fwvalidators/*.go"].each do |file_path|
fname = file_path.split('/')[-1]
-%>
'<%= dir -%>/fwvalidators/<%= fname -%>': 'third_party/terraform/fwvalidators/<%= fname -%>'
<% end -%>

<%
Dir["third_party/terraform/fwtransport/*.go"].each do |file_path|
fname = file_path.split('/')[-1]
Expand Down
25 changes: 14 additions & 11 deletions mmv1/third_party/terraform/fwprovider/framework_provider.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"

"github.com/hashicorp/terraform-provider-google/google/fwvalidators"
"github.com/hashicorp/terraform-provider-google/google/functions"
"github.com/hashicorp/terraform-provider-google/google/fwmodels"
"github.com/hashicorp/terraform-provider-google/google/services/resourcemanager"
Expand Down Expand Up @@ -82,8 +83,8 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest,
stringvalidator.ConflictsWith(path.Expressions{
path.MatchRoot("access_token"),
}...),
CredentialsValidator(),
NonEmptyStringValidator(),
fwvalidators.CredentialsValidator(),
fwvalidators.NonEmptyStringValidator(),
},
},
"access_token": schema.StringAttribute{
Expand All @@ -92,13 +93,13 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest,
stringvalidator.ConflictsWith(path.Expressions{
path.MatchRoot("credentials"),
}...),
NonEmptyStringValidator(),
fwvalidators.NonEmptyStringValidator(),
},
},
"impersonate_service_account": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
NonEmptyStringValidator(),
fwvalidators.NonEmptyStringValidator(),
},
},
"impersonate_service_account_delegates": schema.ListAttribute{
Expand All @@ -108,25 +109,25 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest,
"project": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
NonEmptyStringValidator(),
fwvalidators.NonEmptyStringValidator(),
},
},
"billing_project": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
NonEmptyStringValidator(),
fwvalidators.NonEmptyStringValidator(),
},
},
"region": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
NonEmptyStringValidator(),
fwvalidators.NonEmptyStringValidator(),
},
},
"zone": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
NonEmptyStringValidator(),
fwvalidators.NonEmptyStringValidator(),
},
},
"scopes": schema.ListAttribute{
Expand Down Expand Up @@ -242,7 +243,7 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest,
"send_after": schema.StringAttribute{
Optional: true,
Validators: []validator.String{
NonNegativeDurationValidator(),
fwvalidators.NonNegativeDurationValidator(),
},
},
"enable_batching": schema.BoolAttribute{
Expand Down Expand Up @@ -320,6 +321,8 @@ func (p *FrameworkProvider) Functions(_ context.Context) []func() function.Funct
// EphemeralResources defines the resources that are of ephemeral type implemented in the provider.
func (p *FrameworkProvider) EphemeralResources(_ context.Context) []func() ephemeral.EphemeralResource {
return []func() ephemeral.EphemeralResource{
// TODO!
resourcemanager.GoogleEphemeralServiceAccountAccessToken,
resourcemanager.GoogleEphemeralServiceAccountIdToken,
resourcemanager.GoogleEphemeralServiceAccountJwt,
}
}
}
12 changes: 12 additions & 0 deletions mmv1/third_party/terraform/fwutils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fwutils

import "github.com/hashicorp/terraform-plugin-framework/types/basetypes"

func StringSet(d basetypes.SetValue) []string {

StringSlice := make([]string, 0)
for _, v := range d.Elements() {
StringSlice = append(StringSlice, v.(basetypes.StringValue).ValueString())
}
return StringSlice
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package fwprovider
package fwvalidators

import (
"context"
"fmt"
"os"
"regexp"
"time"

"github.com/hashicorp/terraform-plugin-framework/schema/validator"
Expand Down Expand Up @@ -115,3 +116,93 @@ func (v nonEmptyStringValidator) ValidateString(ctx context.Context, request val
func NonEmptyStringValidator() validator.String {
return nonEmptyStringValidator{}
}

// Define the possible service account name patterns
var ServiceAccountEmailPatterns = []string{
`^.+@.+\.iam\.gserviceaccount\.com$`, // Standard IAM service account
`^.+@developer\.gserviceaccount\.com$`, // Legacy developer service account
`^.+@appspot\.gserviceaccount\.com$`, // App Engine service account
`^.+@cloudservices\.gserviceaccount\.com$`, // Google Cloud services service account
`^.+@cloudbuild\.gserviceaccount\.com$`, // Cloud Build service account
`^service-[0-9]+@.+-compute\.iam\.gserviceaccount\.com$`, // Compute Engine service account
}

// Create a custom validator for service account names
type ServiceAccountEmailValidator struct{}

func (v ServiceAccountEmailValidator) Description(ctx context.Context) string {
return "value must be a valid service account email address"
}

func (v ServiceAccountEmailValidator) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}

func (v ServiceAccountEmailValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) {
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
return
}

value := req.ConfigValue.ValueString()

// Check for empty string
if value == "" {
resp.Diagnostics.AddError("Invalid Service Account Name", "Service account name must not be empty")
return
}

valid := false
for _, pattern := range ServiceAccountEmailPatterns {
if matched, _ := regexp.MatchString(pattern, value); matched {
valid = true
break
}
}

if !valid {
resp.Diagnostics.AddAttributeError(
req.Path,
"Invalid Service Account Name",
"Service account name must match one of the expected patterns for Google service accounts",
)
}
}

// Create a custom validator for duration
type BoundedDuration struct {
MinDuration time.Duration
MaxDuration time.Duration
}

func (v BoundedDuration) Description(ctx context.Context) string {
return fmt.Sprintf("value must be a valid duration string between %v and %v", v.MinDuration, v.MaxDuration)
}

func (v BoundedDuration) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}

func (v BoundedDuration) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) {
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
return
}

value := req.ConfigValue.ValueString()
duration, err := time.ParseDuration(value)
if err != nil {
resp.Diagnostics.AddAttributeError(
req.Path,
"Invalid Duration Format",
"Duration must be a valid duration string (e.g., '3600s', '1h')",
)
return
}

if duration < v.MinDuration || duration > v.MaxDuration {
resp.Diagnostics.AddAttributeError(
req.Path,
"Invalid Duration",
fmt.Sprintf("Duration must be between %v and %v", v.MinDuration, v.MaxDuration),
)
}
}
Loading

0 comments on commit d5208be

Please sign in to comment.