lang/funcs: New "uuidv5" function
This generates name-based uuids, rather than pseudorandom uuids as with the "uuid" function.
This commit is contained in:
parent
d33c5163a7
commit
aa07806bfc
1
go.mod
1
go.mod
|
@ -94,6 +94,7 @@ require (
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect
|
||||||
github.com/pkg/errors v0.0.0-20170505043639-c605e284fe17 // indirect
|
github.com/pkg/errors v0.0.0-20170505043639-c605e284fe17 // indirect
|
||||||
github.com/posener/complete v1.2.1
|
github.com/posener/complete v1.2.1
|
||||||
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
||||||
github.com/sirupsen/logrus v1.1.1 // indirect
|
github.com/sirupsen/logrus v1.1.1 // indirect
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"hash"
|
"hash"
|
||||||
|
|
||||||
uuid "github.com/hashicorp/go-uuid"
|
uuid "github.com/hashicorp/go-uuid"
|
||||||
|
uuidv5 "github.com/satori/go.uuid"
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
"github.com/zclconf/go-cty/cty/function"
|
"github.com/zclconf/go-cty/cty/function"
|
||||||
"github.com/zclconf/go-cty/cty/gocty"
|
"github.com/zclconf/go-cty/cty/gocty"
|
||||||
|
@ -32,6 +33,39 @@ var UUIDFunc = function.New(&function.Spec{
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var UUIDV5Func = function.New(&function.Spec{
|
||||||
|
Params: []function.Parameter{
|
||||||
|
{
|
||||||
|
Name: "namespace",
|
||||||
|
Type: cty.String,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "name",
|
||||||
|
Type: cty.String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: function.StaticReturnType(cty.String),
|
||||||
|
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||||
|
var namespace uuidv5.UUID
|
||||||
|
switch {
|
||||||
|
case args[0].AsString() == "dns":
|
||||||
|
namespace = uuidv5.NamespaceDNS
|
||||||
|
case args[0].AsString() == "url":
|
||||||
|
namespace = uuidv5.NamespaceURL
|
||||||
|
case args[0].AsString() == "oid":
|
||||||
|
namespace = uuidv5.NamespaceOID
|
||||||
|
case args[0].AsString() == "x500":
|
||||||
|
namespace = uuidv5.NamespaceX500
|
||||||
|
default:
|
||||||
|
if namespace, err = uuidv5.FromString(args[0].AsString()); err != nil {
|
||||||
|
return cty.UnknownVal(cty.String), fmt.Errorf("uuidv5() doesn't support namespace %s (%v)", args[0].AsString(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val := args[1].AsString()
|
||||||
|
return cty.StringVal(uuidv5.NewV5(namespace, val).String()), nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
// Base64Sha256Func constructs a function that computes the SHA256 hash of a given string
|
// Base64Sha256Func constructs a function that computes the SHA256 hash of a given string
|
||||||
// and encodes it with Base64.
|
// and encodes it with Base64.
|
||||||
var Base64Sha256Func = makeStringHashFunction(sha256.New, base64.StdEncoding.EncodeToString)
|
var Base64Sha256Func = makeStringHashFunction(sha256.New, base64.StdEncoding.EncodeToString)
|
||||||
|
@ -228,6 +262,12 @@ func UUID() (cty.Value, error) {
|
||||||
return UUIDFunc.Call(nil)
|
return UUIDFunc.Call(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UUIDV5 generates and returns a Type-5 UUID in the standard hexadecimal string
|
||||||
|
// format.
|
||||||
|
func UUIDV5(namespace cty.Value, name cty.Value) (cty.Value, error) {
|
||||||
|
return UUIDV5Func.Call([]cty.Value{namespace, name})
|
||||||
|
}
|
||||||
|
|
||||||
// Base64Sha256 computes the SHA256 hash of a given string and encodes it with
|
// Base64Sha256 computes the SHA256 hash of a given string and encodes it with
|
||||||
// Base64.
|
// Base64.
|
||||||
//
|
//
|
||||||
|
|
|
@ -20,6 +20,71 @@ func TestUUID(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUUIDV5(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Namespace cty.Value
|
||||||
|
Name cty.Value
|
||||||
|
Want cty.Value
|
||||||
|
Err bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
cty.StringVal("dns"),
|
||||||
|
cty.StringVal("tada"),
|
||||||
|
cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.StringVal("url"),
|
||||||
|
cty.StringVal("tada"),
|
||||||
|
cty.StringVal("2c1ff6b4-211f-577e-94de-d978b0caa16e"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.StringVal("oid"),
|
||||||
|
cty.StringVal("tada"),
|
||||||
|
cty.StringVal("61eeea26-5176-5288-87fc-232d6ed30d2f"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.StringVal("x500"),
|
||||||
|
cty.StringVal("tada"),
|
||||||
|
cty.StringVal("7e12415e-f7c9-57c3-9e43-52dc9950d264"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.StringVal("6ba7b810-9dad-11d1-80b4-00c04fd430c8"),
|
||||||
|
cty.StringVal("tada"),
|
||||||
|
cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cty.StringVal("tada"),
|
||||||
|
cty.StringVal("tada"),
|
||||||
|
cty.UnknownVal(cty.String),
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(fmt.Sprintf("uuidv5(%#v, %#v)", test.Namespace, test.Name), func(t *testing.T) {
|
||||||
|
got, err := UUIDV5(test.Namespace, test.Name)
|
||||||
|
|
||||||
|
if test.Err {
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("succeeded; want error")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !got.RawEquals(test.Want) {
|
||||||
|
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBase64Sha256(t *testing.T) {
|
func TestBase64Sha256(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
String cty.Value
|
String cty.Value
|
||||||
|
|
|
@ -116,6 +116,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
||||||
"upper": stdlib.UpperFunc,
|
"upper": stdlib.UpperFunc,
|
||||||
"urlencode": funcs.URLEncodeFunc,
|
"urlencode": funcs.URLEncodeFunc,
|
||||||
"uuid": funcs.UUIDFunc,
|
"uuid": funcs.UUIDFunc,
|
||||||
|
"uuidv5": funcs.UUIDV5Func,
|
||||||
"values": funcs.ValuesFunc,
|
"values": funcs.ValuesFunc,
|
||||||
"yamldecode": ctyyaml.YAMLDecodeFunc,
|
"yamldecode": ctyyaml.YAMLDecodeFunc,
|
||||||
"yamlencode": ctyyaml.YAMLEncodeFunc,
|
"yamlencode": ctyyaml.YAMLEncodeFunc,
|
||||||
|
|
|
@ -777,6 +777,29 @@ func TestFunctions(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"uuidv5": {
|
||||||
|
{
|
||||||
|
`uuidv5("dns", "tada")`,
|
||||||
|
cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`uuidv5("url", "tada")`,
|
||||||
|
cty.StringVal("2c1ff6b4-211f-577e-94de-d978b0caa16e"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`uuidv5("oid", "tada")`,
|
||||||
|
cty.StringVal("61eeea26-5176-5288-87fc-232d6ed30d2f"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`uuidv5("x500", "tada")`,
|
||||||
|
cty.StringVal("7e12415e-f7c9-57c3-9e43-52dc9950d264"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`uuidv5("6ba7b810-9dad-11d1-80b4-00c04fd430c8", "tada")`,
|
||||||
|
cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
"values": {
|
"values": {
|
||||||
{
|
{
|
||||||
`values({"hello"="world", "what's"="up"})`,
|
`values({"hello"="world", "what's"="up"})`,
|
||||||
|
|
|
@ -38,3 +38,7 @@ equivalent randomness to the `uuid` function.
|
||||||
> uuid()
|
> uuid()
|
||||||
b5ee72a3-54dd-c4b8-551c-4bdc0204cedb
|
b5ee72a3-54dd-c4b8-551c-4bdc0204cedb
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Related Functions
|
||||||
|
|
||||||
|
* [`uuidv5`](./uuidv5.html), which generates name-based UUIDs.
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
---
|
||||||
|
layout: "functions"
|
||||||
|
page_title: "uuidv5 - Functions - Configuration Language"
|
||||||
|
sidebar_current: "docs-funcs-crypto-uuidv5"
|
||||||
|
description: |-
|
||||||
|
The uuidv5 function generates a uuid v5 string representation of the value in the specified namespace.
|
||||||
|
---
|
||||||
|
|
||||||
|
# `uuidv5` Function
|
||||||
|
|
||||||
|
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
|
||||||
|
earlier, see
|
||||||
|
[0.11 Configuration Language: Interpolation Syntax](../../configuration-0-11/interpolation.html).
|
||||||
|
|
||||||
|
`uuidv5` generates a _name-based_ UUID, as described in
|
||||||
|
[RFC 4122 section 4.3](https://tools.ietf.org/html/rfc4122#section-4.3),
|
||||||
|
also known as a "version 5" UUID.
|
||||||
|
|
||||||
|
```
|
||||||
|
uuidv5(namespace, name)
|
||||||
|
```
|
||||||
|
|
||||||
|
Unlike the pseudo-random UUIDs generated by
|
||||||
|
[`uuid`](./uuid.html), name-based UUIDs derive from namespace and an name,
|
||||||
|
producing the same UUID value every time if the namespace and name are
|
||||||
|
unchanged.
|
||||||
|
|
||||||
|
Name-based UUID namespaces are themselves UUIDs, but for readability this
|
||||||
|
function accepts some keywords as aliases for the namespaces that were
|
||||||
|
assigned by RFC 4122:
|
||||||
|
|
||||||
|
| Keyword | Namespace ID | Name format |
|
||||||
|
| ------- | ------------ | ----------- |
|
||||||
|
| `"dns"` | `6ba7b810-9dad-11d1-80b4-00c04fd430c8` | A fully-qualified DNS domain name. |
|
||||||
|
| `"url"` | `6ba7b811-9dad-11d1-80b4-00c04fd430c8` | Any valid URL as defined in [RFC 3986](https://tools.ietf.org/html/rfc3986). |
|
||||||
|
| `"oid"` | `6ba7b812-9dad-11d1-80b4-00c04fd430c8` | An [ISO/IEC object identifier](https://oidref.com/) |
|
||||||
|
| `"x500"` | `6ba7b814-9dad-11d1-80b4-00c04fd430c8` | [X.500 Distinguished Name](https://tools.ietf.org/html/rfc1779) |
|
||||||
|
|
||||||
|
To use any other namespace not included in the above table, pass its assigned
|
||||||
|
namespace ID directly in the first argument in the usual UUID string format.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Use the namespace keywords where possible, to make the intent more obvious to
|
||||||
|
a future reader:
|
||||||
|
|
||||||
|
```
|
||||||
|
> uuidv5("dns", "www.terraform.io")
|
||||||
|
a5008fae-b28c-5ba5-96cd-82b4c53552d6
|
||||||
|
|
||||||
|
> uuidv5("url", "https://www.terraform.io/")
|
||||||
|
9db6f67c-dd95-5ea0-aa5b-e70e5c5f7cf5
|
||||||
|
|
||||||
|
> uuidv5("oid", "1.3.6.1.4")
|
||||||
|
af9d40a5-7a36-5c07-b23a-851cd99fbfa5
|
||||||
|
|
||||||
|
> uuidv5("x500", "CN=Example,C=GB")
|
||||||
|
84e09961-4aa4-57f8-95b7-03edb1073253
|
||||||
|
```
|
||||||
|
|
||||||
|
The namespace keywords treated as equivalent to their corresponding namespace
|
||||||
|
UUIDs, and in some special cases it may be more appropriate to use the
|
||||||
|
UUID form:
|
||||||
|
|
||||||
|
```
|
||||||
|
> uuidv5("6ba7b810-9dad-11d1-80b4-00c04fd430c8", "www.terraform.io")
|
||||||
|
a5008fae-b28c-5ba5-96cd-82b4c53552d6
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish to use a namespace defined outside of RFC 4122, using the namespace
|
||||||
|
UUID is required because no corresponding keyword is available:
|
||||||
|
|
||||||
|
```
|
||||||
|
> uuidv5("743ac3c0-3bf7-4a5b-9e6c-59360447c757", "LIBS:diskfont.library")
|
||||||
|
ede1a974-df7e-5f17-84b9-76208818b2c8
|
||||||
|
```
|
||||||
|
|
||||||
|
When using raw UUID namespaces, consider including a comment alongside the
|
||||||
|
expression that indicates which namespace this repressents in a
|
||||||
|
human-significant manner, such as by reference to the standard that
|
||||||
|
defined it.
|
||||||
|
|
||||||
|
## Related Functions
|
||||||
|
|
||||||
|
* [`uuid`](./uuid.html), which generates pseudorandom UUIDs.
|
|
@ -386,6 +386,10 @@
|
||||||
<a href="/docs/configuration/functions/uuid.html">uuid</a>
|
<a href="/docs/configuration/functions/uuid.html">uuid</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="/docs/configuration/functions/uuidv5.html">uuidv5</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue