Skip to content

Commit

Permalink
Add support for versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
minamijoyo committed Feb 24, 2022
1 parent 1dc6e78 commit 4628b92
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ For upgrading AWS provider v4, some rules have not been implemented yet. The cur
- [ ] replication_configuration Argument
- [ ] request_payer Argument
- [x] server_side_encryption_configuration Argument
- [ ] versioning Argument
- [x] versioning Argument
- [ ] website, website_domain, and website_endpoint Arguments

Although the initial goal of this project is providing a way for bulk refactoring of the `aws_s3_bucket` resource required by breaking changes in AWS provider v4, but the project scope is not limited to specific use-cases. It's by no means intended to be an upgrade tool for all your providers. Instead of covering all you need, it provides reusable building blocks for Terraform refactoring and shows examples for how to compose them in real world use-cases.
Expand Down
2 changes: 1 addition & 1 deletion filter/awsv4upgrade/aws_s3_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func NewAWSS3BucketFilter() editor.Filter {
// &AWSS3BucketReplicationConfigurationFilter{},
// &AWSS3BucketRequestPayerFilter{},
&AWSS3BucketServerSideEncryptionConfigurationFilter{},
// &AWSS3BucketVersioningFilter{},
&AWSS3BucketVersioningFilter{},
// &AWSS3BucketWebsiteFilter{},

// Remove redundant TokenNewLine tokens in the resource block after removing nested blocks.
Expand Down
12 changes: 12 additions & 0 deletions filter/awsv4upgrade/aws_s3_bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ resource "aws_s3_bucket" "example" {
}
}
}
versioning {
enabled = true
}
}
`,
ok: true,
Expand Down Expand Up @@ -238,6 +242,14 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
}
}
}
resource "aws_s3_bucket_versioning" "example" {
bucket = aws_s3_bucket.example.id
versioning_configuration {
status = "Enabled"
}
}
`,
},
}
Expand Down
67 changes: 67 additions & 0 deletions filter/awsv4upgrade/aws_s3_bucket_versioning.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package awsv4upgrade

import (
"github.com/minamijoyo/tfedit/tfeditor"
"github.com/minamijoyo/tfedit/tfwrite"
"github.com/zclconf/go-cty/cty"
)

// AWSS3BucketVersioningFilter is a filter implementation for upgrading the
// versioning argument of aws_s3_bucket.
// https://registry.terraform.io/providers/hashicorp/aws/latest/docs/guides/version-4-upgrade#versioning-argument
type AWSS3BucketVersioningFilter struct{}

var _ tfeditor.ResourceFilter = (*AWSS3BucketVersioningFilter)(nil)

// NewAWSS3BucketVersioningFilter creates a new instance of AWSS3BucketVersioningFilter.
func NewAWSS3BucketVersioningFilter() tfeditor.ResourceFilter {
return &AWSS3BucketVersioningFilter{}
}

// ResourceFilter upgrades the versioning argument of aws_s3_bucket.
func (f *AWSS3BucketVersioningFilter) ResourceFilter(inFile *tfwrite.File, resource *tfwrite.Resource) (*tfwrite.File, error) {
oldNestedBlock := "versioning"
newResourceType := "aws_s3_bucket_versioning"
newNestedBlock := "versioning_configuration"

nestedBlocks := resource.FindNestedBlocksByType(oldNestedBlock)
if len(nestedBlocks) == 0 {
return inFile, nil
}

resourceName := resource.Name()
newResource := tfwrite.NewEmptyResource(newResourceType, resourceName)
inFile.AppendResource(newResource)
setBucketArgument(newResource, resource)

nestedBlock := nestedBlocks[0]

// Rename a `versioning` block to a `versioning_configuration` block
nestedBlock.SetType(newNestedBlock)

// Map an `enabled` attribute to a `status` attribute
// enabled = true => status = "Enabled"
// enabled = false => status = "Suspended"
enabledAttr := nestedBlock.GetAttribute("enabled")
if enabledAttr != nil {
enabled, err := enabledAttr.ValueAsString()
if err == nil {
switch enabled {
case "true":
nestedBlock.SetAttributeValue("status", cty.StringVal("Enabled"))
case "false":
nestedBlock.SetAttributeValue("status", cty.StringVal("Suspended"))
default:
// If the value is a variable, not literal, we cannot rewrite it automatically.
// Set original raw tokens as it is.
nestedBlock.SetAttributeRaw("status", enabledAttr.ValueAsTokens())
}
}
nestedBlock.RemoveAttribute("enabled")
}

newResource.AppendNestedBlock(nestedBlock)
resource.RemoveNestedBlock(nestedBlock)

return inFile, nil
}
135 changes: 135 additions & 0 deletions filter/awsv4upgrade/aws_s3_bucket_versioning_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package awsv4upgrade

import (
"testing"

"github.com/minamijoyo/hcledit/editor"
"github.com/minamijoyo/tfedit/tfeditor"
)

func TestAWSS3BucketVersioningFilter(t *testing.T) {
cases := []struct {
name string
src string
ok bool
want string
}{
{
name: "enabled = true",
src: `
resource "aws_s3_bucket" "example" {
bucket = "tfedit-test"
versioning {
enabled = true
}
}
`,
ok: true,
want: `
resource "aws_s3_bucket" "example" {
bucket = "tfedit-test"
}
resource "aws_s3_bucket_versioning" "example" {
bucket = aws_s3_bucket.example.id
versioning_configuration {
status = "Enabled"
}
}
`,
},
{
name: "enabled = false",
src: `
resource "aws_s3_bucket" "example" {
bucket = "tfedit-test"
versioning {
enabled = false
}
}
`,
ok: true,
want: `
resource "aws_s3_bucket" "example" {
bucket = "tfedit-test"
}
resource "aws_s3_bucket_versioning" "example" {
bucket = aws_s3_bucket.example.id
versioning_configuration {
status = "Suspended"
}
}
`,
},
{
name: "enabled = var.enabled",
src: `
resource "aws_s3_bucket" "example" {
bucket = "tfedit-test"
versioning {
enabled = var.enabled
}
}
`,
ok: true,
want: `
resource "aws_s3_bucket" "example" {
bucket = "tfedit-test"
}
resource "aws_s3_bucket_versioning" "example" {
bucket = aws_s3_bucket.example.id
versioning_configuration {
status = var.enabled
}
}
`,
},
{
name: "argument not found",
src: `
resource "aws_s3_bucket" "example" {
bucket = "tfedit-test"
foo {}
}
`,
ok: true,
want: `
resource "aws_s3_bucket" "example" {
bucket = "tfedit-test"
foo {}
}
`,
},
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
filter := &AWSS3BucketFilter{filters: []tfeditor.ResourceFilter{&AWSS3BucketVersioningFilter{}}}
o := editor.NewEditOperator(filter)
output, err := o.Apply([]byte(tc.src), "test")
if tc.ok && err != nil {
t.Fatalf("unexpected err = %s", err)
}

got := string(output)
if !tc.ok && err == nil {
t.Fatalf("expected to return an error, but no error, outStream: \n%s", got)
}

if got != tc.want {
t.Fatalf("got:\n%s\nwant:\n%s", got, tc.want)
}
})
}
}

0 comments on commit 4628b92

Please sign in to comment.