Repository: pulumi/pulumi-terraform-bridge
Pull request #506 (2022-04-11 11:20:10)

Support different random char sets for autonames
Add a way for providers to opt-into autonames where the name can't contain hex characters (the default random suffix for autonames).

This should allow us to replace such things as the below from the aws provider:
```
Default: &tfbridge.DefaultInfo{
	// This means the name will adhere to ^[a-z]+(_[a-z]+)*$  as per
	// https://docs.aws.amazon.com/athena/latest/ug/tables-databases-columns-names.html
	From: tfbridge.FromName(tfbridge.AutoNameOptions{
		Transform: func(name string) string {
			newName := fmt.Sprintf("%s_%s", name, transformWithRandomString(8))
			return strings.ToLower(newName)
		},
	}),
},
```
With:
```
Default: &tfbridge.DefaultInfo{
	// This means the name will adhere to ^[a-z]+(_[a-z]+)*$  as per
	// https://docs.aws.amazon.com/athena/latest/ug/tables-databases-columns-names.html
	From: tfbridge.FromName(tfbridge.AutoNameOptions{
		Separator: "_",
		Randchars: []rune("abcdefghijklmnopqrstuvwxyz"),
	}),
},
```

This will allow us to fix these resources for deterministic names purely in tfbridge.

github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/cdc9731..4becbd0) with merge commit b7f6e530a9df2d60344be17f045d9d3a63516136
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/0e2a0b1..7c12209) with merge commit b7f6e530a9df2d60344be17f045d9d3a63516136
github-actions[bot]: Diff for [pulumi-gcp](https://github.com/pulumi-bot/pulumi-gcp/compare/9d9767e73..7d65d0e93) with merge commit b7f6e530a9df2d60344be17f045d9d3a63516136
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/efa043378..0680fc7c1) with merge commit b7f6e530a9df2d60344be17f045d9d3a63516136
github-actions[bot]: Diff for [pulumi-aws](https://github.com/pulumi-bot/pulumi-aws/compare/e3ac095cf..74e23b7b1) with merge commit b7f6e530a9df2d60344be17f045d9d3a63516136
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/c0b7d07..504f053) with merge commit e58fd7361d79067fbab1d1ce6d161b6360e71e9e

Patch:
diff --git a/pkg/tfbridge/names.go b/pkg/tfbridge/names.go
index 00a0a7b3..042451e7 100644
--- a/pkg/tfbridge/names.go
+++ b/pkg/tfbridge/names.go
@@ -15,12 +15,12 @@
 package tfbridge
 
 import (
+	"math/rand"
 	"unicode"
 
 	"github.com/pkg/errors"
 
 	"github.com/gedex/inflector"
-	"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
 	"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
 
 	shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
@@ -132,8 +132,11 @@ type AutoNameOptions struct {
 	Separator string
 	// Maximum length of the generated name
 	Maxlen int
-	// Number of characters of random hex digits to add to the name
+	// Number of random characters to add to the name
 	Randlen int
+	// A string of characters that are valid for the generated part of the name, defaults to the set of
+	// hexadecimal characters.
+	Randchars []rune
 	// A transform to apply to the name prior to adding random characters
 	Transform func(string) string
 	// A transform to apply after the auto naming has been computed
@@ -196,11 +199,32 @@ func FromName(options AutoNameOptions) func(res *PulumiResource) (interface{}, e
 			vs = options.Transform(vs)
 		}
 		if options.Randlen > 0 {
-			uniqueHex, err := resource.NewUniqueHex(vs+options.Separator, options.Randlen, options.Maxlen)
-			if err != nil {
-				return uniqueHex, errors.Wrapf(err, "could not make instance of '%v'", res.URN.Type())
+			// Randchars is a new option to allow providers to opt into tfbridges random name generated in
+			// cases where the old default behavior would of hit restrictions imposed by the resource type
+			// (e.g. some resources only allow a-z). Before Randchars this method used to just call
+			// NewUniqueHex which would suffix a random hexadecimal string on the end. To maintain
+			// compatability with the all the current uses of this function that don't set Randchars (i.e.
+			// leave it nil) we default the character set to that of hexadecimal.
+			randchars := options.Randchars
+			if randchars == nil {
+				randchars = []rune("0123456789abcdef")
 			}
-			vs = uniqueHex
+
+			prefix := vs + options.Separator
+			// Generate a unique name using the restricted set
+			if options.Maxlen > 0 && len(prefix)+options.Randlen > options.Maxlen {
+				// This Errorf followed by Wrapf is to match the behavior we had when the random generation
+				// was performed by NewUniqueHex.
+				err := errors.Errorf("name '%s' plus %d random chars is longer than maximum length %d", prefix, options.Randlen, options.Maxlen)
+				return "", errors.Wrapf(err, "could not make instance of '%v'", res.URN.Type())
+			}
+
+			b := make([]rune, options.Randlen)
+			for i := range b {
+				b[i] = randchars[rand.Intn(len(randchars))]
+			}
+
+			vs = prefix + string(b)
 		}
 		if options.PostTransform != nil {
 			return options.PostTransform(res, vs)


Test patch:
diff --git a/pkg/tfbridge/names_test.go b/pkg/tfbridge/names_test.go
index f7fa9384..8df2d8b0 100644
--- a/pkg/tfbridge/names_test.go
+++ b/pkg/tfbridge/names_test.go
@@ -145,3 +145,30 @@ func TestFromName(t *testing.T) {
 	assert.Len(t, out1, len("n1")+1+7+len(".fifo"))
 	assert.True(t, strings.HasSuffix(out1.(string), ".fifo"))
 }
+
+func TestFromNameRandchars(t *testing.T) {
+	res1 := &PulumiResource{
+		URN: "urn:pulumi:test::test::pkgA:index:t1::n1",
+		Properties: resource.PropertyMap{
+			"fifo": resource.NewBoolProperty(true),
+		},
+	}
+	f1 := FromName(AutoNameOptions{
+		Separator: "%",
+		Maxlen:    80,
+		Randlen:   7,
+		Randchars: []rune("a"),
+		PostTransform: func(res *PulumiResource, name string) (string, error) {
+			if fifo, hasfifo := res.Properties["fifo"]; hasfifo {
+				if fifo.IsBool() && fifo.BoolValue() {
+					return name + ".fifo", nil
+				}
+			}
+			return name, nil
+		},
+	})
+	out1, err := f1(res1)
+	outStr := out1.(string)
+	assert.NoError(t, err)
+	assert.Equal(t, "n1%aaaaaaa.fifo", outStr)
+}