diff --git a/README.md b/README.md index ba5fd0b..0c4d987 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ jobs: steps: - checkout - lambroll/install: - version: v1.0.1 + version: v1.1.0 - run: command: | lambroll deploy @@ -398,6 +398,11 @@ function.json is a definition for Lambda function. JSON structure is based from } } ``` + +The template functions is available in `{{ }}`. +- `env` function expands environment variables. +- `must_env` function expands environment variables. If the environment variable is not defined, lambroll will panic and abort. + #### Tags When "Tags" key exists in function.json, lambroll set / remove tags to the lambda function at deploy. @@ -415,6 +420,44 @@ When "Tags" key exists in function.json, lambroll set / remove tags to the lambd When "Tags" key does not exist, lambroll doesn't manage tags. If you hope to remove all tags, set `"Tags": {}` expressly. +#### Environment variables from envfile + +`lambroll --envfile .env1 .env2` reads files named .env1 and .env2 as environment files and export variables in these files. + +These files are parsed by [hashicorp/go-envparse](https://github.com/hashicorp/go-envparse). + +```env +FOO=foo +export BAR="bar" +``` + +#### Jsonnet support for function configuration + +lambroll also can read function.jsonnet as [Jsonnet](https://jsonnet.org/) format instead of plain JSON. + +```jsonnet +{ + FunctionName: 'hello', + Handler: 'index.handler', + MemorySize: std.extVar('memorySize'), + Role: 'arn:aws:iam::%s:role/lambda_role' % [ std.extVar('accountID') ], + Runtime: 'nodejs20.x', +} +``` + +```console +$ lambroll \ + --function function.jsonnet \ + --ext-str accountID=0123456789012 \ + --ext-code memorySize="128 * 4" \ + deploy +``` + +- `--ext-str` sets external string values for Jsonnet. +- `--ext-code` sets external code values for Jsonnet. + +v1.1.0 and later, lambroll supports Jsonnet native functions. See below for details. + #### Expand SSM parameter values At reading the file, lambroll evaluates `{{ ssm }}` syntax in JSON. @@ -427,6 +470,19 @@ For example, SSM parameter value of `/path/to/param` is expanded here. +For Jsonnet, the `ssm` function is available. + +```jsonnet +local ssm = std.native('ssm'); +{ + Environment: { + Variables: { + FOO: ssm('/path/to/param'), + }, + }, +} +``` + #### Expand environment variables At reading the file, lambroll evaluates `{{ env }}` and `{{ must_env }}` syntax in JSON. @@ -457,17 +513,48 @@ Environment variable `FOO` is expanded. When `FOO` is not defined, lambroll will } ``` -#### Environment variables from envfile +For Jsonnet, the `env` and `must_env` native functions are available. -`lambroll --envfile .env1 .env2` reads files named .env1 and .env2 as environment files and export variables in these files. +```jsonnet +local env = std.native('env'); +local must_env = std.native('must_env'); +{ + Environment: { + Variables: { + FOO: env('FOO', 'default for FOO'), + BAR: must_env('BAR'), + }, + }, +} +``` -These files are parsed by [hashicorp/go-envparse](https://github.com/hashicorp/go-envparse). +#### Resolve AWS caller identity -```env -FOO=foo -export BAR="bar" +The `caller_identity` template function resolves the AWS caller identity. + +```json +{ + "Account": "{{ caller_identity.Account }}", + "Arn": "{{ caller_identity.Arn }}", + "UserId": "{{ caller_identity.UserId }}" +} +``` + +The `caller_identity` native function also available in Jsonnet. + +```jsonnet +local caller = std.native('caller_identity')(); +{ + Account: caller.Account, + Arn: caller.Arn, + UserId: caller.UserId, +} ``` +The `caller_identity` function returns an object containing the following fields: `Account`, `Arn`, and `UserId`. + +This object is the same as the result of [GetCallerIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html) API. + #### Lookup resource attributes in tfstate ([Terraform state](https://www.terraform.io/docs/state/index.html)) When `--tfstate` option set to an URL to `terraform.tfstate`, tfstate template function enabled. @@ -491,7 +578,7 @@ data "aws_iam_role" "lambda" { "Handler": "index.js", "MemorySize": 128, "Role": "{{ tfstate `data.aws_iam_role.lambda.arn` }}", - "Runtime": "nodejs12.x", + "Runtime": "nodejs20.x", "Timeout": 5, "TracingConfig": { "Mode": "PassThrough" @@ -508,6 +595,33 @@ data "aws_iam_role" "lambda" { } ``` +For Jsonnet, the `tfstate` native function is available. + +```jsonnet +local tfstate = std.native('tfstate'); +{ + Description: 'hello function', + FunctionName: 'hello', + Handler: 'index.js', + MemorySize: 128, + Role: tfstate('data.aws_iam_role.lambda.arn'), + Runtime: 'nodejs20.x', + Timeout: 5, + TracingConfig: { + Mode: 'PassThrough', + }, + VpcConfig: { + SubnetIds: [ + tfstate('aws_subnet.lambda["az-a"].id'), + tfstate('aws_subnet.lambda["az-b"].id'), + ], + SecurityGroupIds: [ + tfstate('aws_security_group.internal["%s"].id' % must_env('WORLD')), + ], + }, +} +``` + Likewise, if you have AWS resource definitions spread across multiple tfstate files, you can utilize `--prefixed-tfstate` option: e.g. @@ -530,28 +644,23 @@ which then exposes additional template functions available like: } ``` -### Jsonnet support for function configuration - -lambroll also can read function.jsonnet as [Jsonnet](https://jsonnet.org/) format instead of plain JSON. +For Jsonnet, a `{prefix}_tfstate` native function is generated by the `--prefixed-tfstate` option. ```jsonnet +local first_tfstate = std.native('my_first_tfstate'); +local second_tfstate = std.native('my_second_tfstate'); { - FunctionName: 'hello', - Handler: 'index.handler', - MemorySize: std.extVar('memorySize'), - Role: 'arn:aws:iam::%s:role/lambda_role' % [ std.extVar('accountID') ], - Runtime: 'nodejs20.x', + Description: 'hello function', + Environment: { + Variables: { + FIRST_VALUE: first_tfstate('data.aws_iam_role.lambda.arn'), + SECOND_VALUE: second_tfstate('data.aws_iam_role.lambda.arn'), + }, + }, + "rest of the parameters": "...", } ``` -```console -$ lambroll \ - --function function.jsonnet \ - --ext-str accountID=0123456789012 \ - --ext-code memorySize="128 * 4" \ - deploy -``` - ### .lambdaignore lambroll will ignore files defined in `.lambdaignore` file at creating a zip archive. diff --git a/caller.go b/caller.go new file mode 100644 index 0000000..eceaeb0 --- /dev/null +++ b/caller.go @@ -0,0 +1,73 @@ +package lambroll + +import ( + "context" + "text/template" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/google/go-jsonnet" + "github.com/google/go-jsonnet/ast" +) + +type CallerIdentity struct { + data map[string]any + Resolver func(ctx context.Context) (*sts.GetCallerIdentityOutput, error) +} + +func newCallerIdentity(cfg aws.Config) *CallerIdentity { + return &CallerIdentity{ + Resolver: func(ctx context.Context) (*sts.GetCallerIdentityOutput, error) { + return sts.NewFromConfig(cfg).GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{}) + }, + } +} + +func (c *CallerIdentity) resolve(ctx context.Context) error { + if c.data != nil { + return nil + } + res, err := c.Resolver(ctx) + if err != nil { + return err + } + c.data = map[string]any{ + "Account": *res.Account, + "Arn": *res.Arn, + "UserId": *res.UserId, + } + return nil +} + +func (c *CallerIdentity) Account(ctx context.Context) string { + if err := c.resolve(ctx); err != nil { + return "" + } + return c.data["Account"].(string) +} + +func (c *CallerIdentity) JsonnetNativeFuncs(ctx context.Context) []*jsonnet.NativeFunction { + return []*jsonnet.NativeFunction{ + { + Name: "caller_identity", + Params: []ast.Identifier{}, + Func: func(params []any) (any, error) { + if err := c.resolve(ctx); err != nil { + return nil, err + } + return c.data, nil + }, + }, + } +} + +func (c *CallerIdentity) FuncMap(ctx context.Context) template.FuncMap { + return template.FuncMap{ + "caller_identity": func() map[string]any { + if err := c.resolve(ctx); err != nil { + return nil + } + return c.data + }, + } +} diff --git a/caller_test.go b/caller_test.go new file mode 100644 index 0000000..8f92e51 --- /dev/null +++ b/caller_test.go @@ -0,0 +1,25 @@ +package lambroll_test + +import ( + "context" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/fujiwara/lambroll" +) + +func TestCallerIdentity(t *testing.T) { + c := lambroll.NewCallerIdentity(aws.Config{}) + c.Resolver = func(_ context.Context) (*sts.GetCallerIdentityOutput, error) { + return &sts.GetCallerIdentityOutput{ + Account: aws.String("123456789012"), + Arn: aws.String("arn:aws:iam::123456789012:user/test-user"), + UserId: aws.String("AIXXXXXXXXX"), + }, nil + } + ctx := context.Background() + if c.Account(ctx) != "123456789012" { + t.Errorf("unexpected account id: %s", c.Account(ctx)) + } +} diff --git a/export_test.go b/export_test.go index ac929ef..26f7892 100644 --- a/export_test.go +++ b/export_test.go @@ -6,7 +6,19 @@ var ( LoadZipArchive = loadZipArchive MergeTags = mergeTags FillDefaultValues = fillDefaultValues + JSONStr = jsonStr + MarshalJSON = marshalJSON + NewFunctionFrom = newFunctionFrom + NewCallerIdentity = newCallerIdentity ) type VersionsOutput = versionsOutput type VersionsOutputs = versionsOutputs + +func (app *App) CallerIdentity() *CallerIdentity { + return app.callerIdentity +} + +func (app *App) LoadFunction(f string) (*Function, error) { + return app.loadFunction(f) +} diff --git a/function_test.go b/function_test.go index 9ea6ca1..7206e07 100644 --- a/function_test.go +++ b/function_test.go @@ -1,25 +1,37 @@ -package lambroll +package lambroll_test import ( "context" - "os" "testing" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/lambda" "github.com/aws/aws-sdk-go-v2/service/lambda/types" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/fujiwara/lambroll" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +var ignore = cmpopts.IgnoreUnexported( + types.EphemeralStorage{}, + types.Environment{}, + types.FileSystemConfig{}, + types.LoggingConfig{}, + types.TracingConfig{}, + types.VpcConfig{}, + lambda.CreateFunctionOutput{}, ) func TestLoadFunction(t *testing.T) { - os.Setenv("FUNCTION_NAME", "test") - envfiles := []string{"test/env"} - path := "test/terraform.tfstate" - app, err := New(context.Background(), &Option{ - TFState: &path, + t.Setenv("FUNCTION_NAME", "test") + app, err := lambroll.New(context.Background(), &lambroll.Option{ + TFState: aws.String("test/terraform.tfstate"), PrefixedTFState: map[string]string{ "prefix1_": "test/terraform_1.tfstate", "prefix2_": "test/terraform_2.tfstate", }, - Envfile: envfiles, + Envfile: []string{"test/env"}, ExtStr: map[string]string{ "Description": "hello function", }, @@ -30,43 +42,69 @@ func TestLoadFunction(t *testing.T) { if err != nil { t.Error(err) } + app.CallerIdentity().Resolver = func(_ context.Context) (*sts.GetCallerIdentityOutput, error) { + return &sts.GetCallerIdentityOutput{ + Account: aws.String("123456789012"), + Arn: aws.String("arn:aws:iam::123456789012:user/test-user"), + UserId: aws.String("AIXXXXXXXXXXXXXXXXXX"), + }, nil + } + expected := lambroll.Function{ + Architectures: []types.Architecture{types.ArchitectureX8664}, + Description: aws.String("hello function"), + Environment: &types.Environment{ + Variables: map[string]string{ + "PREFIXED_TFSTATE_1": "arn:aws:iam::123456789012:role/test_lambda_role_1", + "PREFIXED_TFSTATE_2": "arn:aws:iam::123456789012:role/test_lambda_role_2", + "JSON": `{"foo":"bar"}`, + }, + }, + EphemeralStorage: &types.EphemeralStorage{ + Size: aws.Int32(1024), + }, + FileSystemConfigs: []types.FileSystemConfig{ + { + Arn: aws.String("arn:aws:elasticfilesystem:ap-northeast-1:123456789012:access-point/fsap-04fc0858274e7dd9a"), + LocalMountPath: aws.String("/mnt/lambda"), + }, + }, + FunctionName: aws.String("test"), + Handler: aws.String("index.js"), + LoggingConfig: &types.LoggingConfig{ + ApplicationLogLevel: "DEBUG", + LogGroup: aws.String("/aws/lambda/test/json"), + SystemLogLevel: "INFO", + LogFormat: types.LogFormatJson, + }, + MemorySize: aws.Int32(128), + Runtime: types.RuntimeNodejs16x, + Role: aws.String("arn:aws:iam::123456789012:role/test_lambda_role"), + Timeout: aws.Int32(5), + TracingConfig: &types.TracingConfig{ + Mode: types.TracingModePassThrough, + }, + VpcConfig: &types.VpcConfig{ + SubnetIds: []string{ + "subnet-08dc9a51660120991", + "subnet-023e96b860485e2ad", + "subnet-045cd24ab8e92a20d", + }, + SecurityGroupIds: []string{ + "sg-01a9b01eab0a3c154", + }, + }, + } + for _, f := range []string{"test/function.json", "test/function.jsonnet"} { - fn, err := app.loadFunction(f) + fn, err := app.LoadFunction(f) if err != nil { t.Error(err) } - if *fn.Role != "arn:aws:iam::123456789012:role/test_lambda_role" { - t.Errorf("unexpected role got %s", *fn.Role) - } - if *fn.FunctionName != "test" { - t.Errorf("unexpected function name got %s", *fn.FunctionName) - } - if *fn.FileSystemConfigs[0].Arn != "arn:aws:elasticfilesystem:ap-northeast-1:123456789012:access-point/fsap-04fc0858274e7dd9a" { - t.Errorf("unexpected fileSystemConfigs %v", *&fn.FileSystemConfigs) - } - if fn.Environment.Variables["JSON"] != `{"foo":"bar"}` { - t.Errorf("unexpected environment %v", fn.Environment.Variables) - } - if fn.Environment.Variables["PREFIXED_TFSTATE_1"] != "arn:aws:iam::123456789012:role/test_lambda_role_1" { - t.Errorf("unexpected environment %v", fn.Environment.Variables) - } - if fn.Environment.Variables["PREFIXED_TFSTATE_2"] != "arn:aws:iam::123456789012:role/test_lambda_role_2" { - t.Errorf("unexpected environment %v", fn.Environment.Variables) - } - if fn.VpcConfig.SecurityGroupIds[0] != "sg-01a9b01eab0a3c154" { - t.Errorf("unexpected SecurityGroupIds %v", fn.VpcConfig.SecurityGroupIds) + expectedJSON, _ := lambroll.MarshalJSON(expected) + fnJSON, _ := lambroll.MarshalJSON(fn) + if diff := cmp.Diff(string(expectedJSON), string(fnJSON), ignore); diff != "" { + t.Errorf("unexpected function got %s", diff) } - arch := fn.Architectures - if len(arch) != 1 || arch[0] != "x86_64" { - t.Errorf("unexpected Architectures %v", fn.Architectures) - } - if *fn.LoggingConfig.LogGroup != "/aws/lambda/test/json" { - t.Errorf("unexpected LoggingConfig %v", fn.LoggingConfig) - } - if *fn.EphemeralStorage.Size != 1024 { - t.Errorf("unexpected EphemeralStorage %v", fn.EphemeralStorage) - } - t.Log(fn) } } @@ -82,29 +120,21 @@ func TestNewFunction(t *testing.T) { tags := map[string]string{ "foo": "bar", } - fn := newFunctionFrom(conf, nil, tags) - if *fn.FunctionName != "hello" { - t.Errorf("unexpected function name got %s", *fn.FunctionName) - } - if *fn.MemorySize != 128 { - t.Errorf("unexpected memory size got %d", *fn.MemorySize) - } - if fn.Runtime != types.RuntimeNodejs18x { - t.Errorf("unexpected runtime got %s", fn.Runtime) - } - if *fn.Timeout != 3 { - t.Errorf("unexpected timeout got %d", *fn.Timeout) - } - if *fn.Handler != "index.handler" { - t.Errorf("unexpected handler got %s", *fn.Handler) - } - if *fn.Role != "arn:aws:iam::0123456789012:role/YOUR_LAMBDA_ROLE_NAME" { - t.Errorf("unexpected role got %s", *fn.Role) - } - if fn.Tags["foo"] != "bar" { - t.Errorf("unexpected tags got %v", fn.Tags) + fn := lambroll.NewFunctionFrom(conf, nil, tags) + + expected := lambroll.Function{ + FunctionName: aws.String("hello"), + MemorySize: aws.Int32(128), + Runtime: types.RuntimeNodejs18x, + Timeout: aws.Int32(3), + Handler: aws.String("index.handler"), + Role: aws.String("arn:aws:iam::0123456789012:role/YOUR_LAMBDA_ROLE_NAME"), + Tags: tags, } - if fn.SnapStart != nil { - t.Errorf("unexpected snap start got %v", fn.SnapStart) + + fnJSON, _ := lambroll.MarshalJSON(fn) + expectedJSON, _ := lambroll.MarshalJSON(expected) + if diff := cmp.Diff(string(expectedJSON), string(fnJSON), ignore); diff != "" { + t.Errorf("unexpected function got %s", diff) } } diff --git a/go.mod b/go.mod index fc76f24..82c8fb0 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/fatih/color v1.16.0 github.com/fujiwara/logutils v1.1.2 github.com/fujiwara/ssm-lookup v0.1.0 - github.com/fujiwara/tfstate-lookup v1.1.6 + github.com/fujiwara/tfstate-lookup v1.3.2 github.com/go-test/deep v1.1.0 github.com/google/go-cmp v0.6.0 github.com/google/go-jsonnet v0.20.0 @@ -31,11 +31,11 @@ require ( ) require ( - cloud.google.com/go v0.110.0 // indirect - cloud.google.com/go/compute v1.19.1 // indirect + cloud.google.com/go v0.112.0 // indirect + cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.13.0 // indirect - cloud.google.com/go/storage v1.28.1 // indirect + cloud.google.com/go/iam v1.1.5 // indirect + cloud.google.com/go/storage v1.36.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect @@ -52,7 +52,7 @@ require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.24 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect @@ -66,39 +66,50 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect github.com/aws/smithy-go v1.20.3 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.7.1 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect - github.com/hashicorp/go-slug v0.8.1 // indirect - github.com/hashicorp/go-tfe v1.2.0 // indirect - github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d // indirect + github.com/hashicorp/go-slug v0.15.0 // indirect + github.com/hashicorp/go-tfe v1.56.0 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/jsonapi v1.3.1 // indirect github.com/itchyny/timefmt-go v0.1.6 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/net v0.26.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/sync v0.7.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.114.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.3 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/api v0.155.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/grpc v1.62.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect sigs.k8s.io/yaml v1.1.0 // indirect diff --git a/go.sum b/go.sum index c902b1f..03424f0 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,14 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= -cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg= @@ -59,8 +58,8 @@ github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVO github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7 h1:FnLf60PtjXp8ZOzQfhJVsqF0OtYKQZWQfqOLshh8YXg= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7/go.mod h1:tDVvl8hyU6E9B8TrnNrZQEVkQlB8hjJwcgpPhgtlnNg= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.24 h1:FzNwpVTZDCvm597Ty6mGYvxTolyC1oup0waaKntZI4E= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.24/go.mod h1:wM9NElT/Wn6n3CT1eyVcXtfCy8lSVjjQXfdawQbSShc= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= @@ -94,6 +93,7 @@ github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -103,14 +103,22 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fujiwara/logutils v1.1.2 h1:nYVRyTj+5SyCvpZUrYIZU4kubqNycGTxFXMKJBKe0Sg= github.com/fujiwara/logutils v1.1.2/go.mod h1:pdb/Uk70rjQWEmFm/OvYH7OG8meZt1fEIqC0qZbvro4= github.com/fujiwara/ssm-lookup v0.1.0 h1:30dFvRurr1cvBq6KZL0QJrN1e5y80p6EUAari6LoL3Y= github.com/fujiwara/ssm-lookup v0.1.0/go.mod h1:ssVwS1FrHAKouOMEmYC6j07XRKqBGdABRmv6gBKewVg= -github.com/fujiwara/tfstate-lookup v1.1.6 h1:IFWGCpJ/mhK0OkWiBGd/0kIgjwE/H6eh9BobLptkebo= -github.com/fujiwara/tfstate-lookup v1.1.6/go.mod h1:G+sFc6osVH71L32pX3+2ibfdhqePPrDZa0ren/QaMYs= +github.com/fujiwara/tfstate-lookup v1.3.2 h1:jfPPRecZ9yzPI0epCnK5UCxY3CQAAF0Iq4L3osJ3d58= +github.com/fujiwara/tfstate-lookup v1.3.2/go.mod h1:qYLO+8Ane5hF54BdvLQTbXiHWviq3uGCuW6Lz3fcWCM= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= @@ -120,11 +128,11 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -134,6 +142,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -151,13 +160,15 @@ github.com/google/go-jsonnet v0.20.0/go.mod h1:VbgWF9JX7ztlv770x/TolZNGGFfiHEVx9 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-envparse v0.0.0-20200406174449-d9cfd743a15e h1:v1d9+AJMP6i4p8BSKNU0InuvmIAdZjQLNN19V86AG4Q= @@ -165,13 +176,15 @@ github.com/hashicorp/go-envparse v0.0.0-20200406174449-d9cfd743a15e/go.mod h1:/N github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= -github.com/hashicorp/go-slug v0.8.1 h1:srN7ivgAjHfZddYY1DjBaihRCFy20+vCcOrlx1O2AfE= -github.com/hashicorp/go-slug v0.8.1/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4= -github.com/hashicorp/go-tfe v1.2.0 h1:L29LCo/qIjOqBUjfiUsZSAzBdxmsOLzwnwZpA+68WW8= -github.com/hashicorp/go-tfe v1.2.0/go.mod h1:tJF/OlAXzVbmjiimAPLplSLgwg6kZDUOy0MzHuMwvF4= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d h1:9ARUJJ1VVynB176G1HCwleORqCaXm/Vx0uUi0dL26I0= -github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d/go.mod h1:Yog5+CPEM3c99L1CL2CFCYoSzgWm5vTU58idbRUaLik= +github.com/hashicorp/go-slug v0.15.0 h1:AhMnE6JIyW0KoDJlmRDwv4xd52a5ZK3VdioQ7SMmZhI= +github.com/hashicorp/go-slug v0.15.0/go.mod h1:THWVTAXwJEinbsp4/bBRcmbaO5EYNLTqxbG4tZ3gCYQ= +github.com/hashicorp/go-tfe v1.56.0 h1:AjBTo7TmWoz42l4KhH65Q3NvjRD5yD3XZrG1tzFySeI= +github.com/hashicorp/go-tfe v1.56.0/go.mod h1:XnTtBj3tVQ4uFkcFsv8Grn+O1CVcIcceL1uc2AgUcaU= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/jsonapi v1.3.1 h1:GtPvnmcWgYwCuDGvYT5VZBHcUyFdq9lSyCzDjn1DdPo= +github.com/hashicorp/jsonapi v1.3.1/go.mod h1:kWfdn49yCjQvbpnvY1dxxAuAFzISwrrMDQOcu6NsFoM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/itchyny/gojq v0.12.16 h1:yLfgLxhIr/6sJNVmYfQjTIv0jGctu6/DgDoivmxTr7g= @@ -202,8 +215,6 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -223,8 +234,20 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -235,23 +258,28 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -259,48 +287,58 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= -golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.155.0 h1:vBmGhCYs0djJttDNynWo44zosHlPvHmA0XiN2zP2DtA= +google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/jsonnet.go b/jsonnet.go new file mode 100644 index 0000000..143dd78 --- /dev/null +++ b/jsonnet.go @@ -0,0 +1,42 @@ +package lambroll + +import ( + "fmt" + "os" + + "github.com/google/go-jsonnet" + "github.com/google/go-jsonnet/ast" +) + +func DefaultJsonnetNativeFuncs() []*jsonnet.NativeFunction { + return []*jsonnet.NativeFunction{ + { + Name: "env", + Params: []ast.Identifier{"name", "default"}, + Func: func(args []any) (any, error) { + key, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf("env: name must be a string") + } + if v := os.Getenv(key); v != "" { + return v, nil + } + return args[1], nil + }, + }, + { + Name: "must_env", + Params: []ast.Identifier{"name"}, + Func: func(args []any) (any, error) { + key, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf("must_env: name must be a string") + } + if v, ok := os.LookupEnv(key); ok { + return v, nil + } + return nil, fmt.Errorf("must_env: %s is not set", key) + }, + }, + } +} diff --git a/jsonnet_test.go b/jsonnet_test.go new file mode 100644 index 0000000..d7adb22 --- /dev/null +++ b/jsonnet_test.go @@ -0,0 +1,86 @@ +package lambroll_test + +import ( + "encoding/json" + "testing" + + "github.com/fujiwara/lambroll" + "github.com/google/go-cmp/cmp" + "github.com/google/go-jsonnet" +) + +var testSrcJsonnet = ` +local env = std.native("env"); +local must_env = std.native("must_env"); +{ + foo: env("FOO", "default"), + bar: must_env("BAR"), +} +` + +var testCaseJsonnetNativeFuncs = []struct { + name string + env map[string]string + expected map[string]string + errExpected bool +}{ + { + name: "env FOO not set", + env: map[string]string{ + "BAR": "bar", + }, + expected: map[string]string{ + "foo": "default", + "bar": "bar", + }, + }, + { + name: "env FOO set", + env: map[string]string{ + "FOO": "foo", + "BAR": "bar", + }, + expected: map[string]string{ + "foo": "foo", + "bar": "bar", + }, + }, + { + name: "must_env BAR not set", + env: map[string]string{ + "FOO": "foo", + }, + errExpected: true, + }, +} + +func TestJsonnetNativeFuncs(t *testing.T) { + vm := jsonnet.MakeVM() + for _, f := range lambroll.DefaultJsonnetNativeFuncs() { + vm.NativeFunction(f) + } + + for _, c := range testCaseJsonnetNativeFuncs { + t.Run(c.name, func(t *testing.T) { + for k, v := range c.env { + t.Setenv(k, v) + } + out, err := vm.EvaluateAnonymousSnippet("test.jsonnet", testSrcJsonnet) + if c.errExpected { + if err == nil { + t.Fatal("expected error") + } + return + } else if err != nil { + t.Fatal(err) + } + var got map[string]string + if err := json.Unmarshal([]byte(out), &got); err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(c.expected, got); diff != "" { + t.Errorf("(-expected, +got)\n%s", diff) + } + }) + } +} diff --git a/lambroll.go b/lambroll.go index b2aa5f7..acab35d 100644 --- a/lambroll.go +++ b/lambroll.go @@ -88,15 +88,16 @@ var ( // App represents lambroll application type App struct { - accountID string - profile string - loader *config.Loader + callerIdentity *CallerIdentity + profile string + loader *config.Loader awsConfig aws.Config lambda *lambda.Client - extStr map[string]string - extCode map[string]string + extStr map[string]string + extCode map[string]string + nativeFuncs []*jsonnet.NativeFunction functionFilePath string } @@ -148,6 +149,7 @@ func New(ctx context.Context, opt *Option) (*App, error) { } loader := config.New() + nativeFuncs := DefaultJsonnetNativeFuncs() // load ssm functions if ssmFuncs, err := ssm.FuncMap(ctx, v2cfg); err != nil { @@ -155,14 +157,20 @@ func New(ctx context.Context, opt *Option) (*App, error) { } else { loader.Funcs(ssmFuncs) } + if ssmNativeFuncs, err := ssm.JsonnetNativeFuncs(ctx, v2cfg); err != nil { + return nil, err + } else { + nativeFuncs = append(nativeFuncs, ssmNativeFuncs...) + } // load tfstate functions if opt.TFState != nil && *opt.TFState != "" { - funcs, err := tfstate.FuncMap(ctx, *opt.TFState) + lookup, err := tfstate.ReadURL(ctx, *opt.TFState) if err != nil { return nil, err } - loader.Funcs(funcs) + loader.Funcs(lookup.FuncMap(ctx)) + nativeFuncs = append(nativeFuncs, lookup.JsonnetNativeFuncs(ctx)...) } if len(opt.PrefixedTFState) > 0 { prefixedFuncs := make(template.FuncMap) @@ -170,43 +178,39 @@ func New(ctx context.Context, opt *Option) (*App, error) { if prefix == "" { return nil, fmt.Errorf("--prefixed-tfstate option cannot have empty key") } - funcs, err := tfstate.FuncMap(ctx, path) + loader, err := tfstate.ReadURL(ctx, path) if err != nil { return nil, err } - for name, f := range funcs { + for name, f := range loader.FuncMap(ctx) { prefixedFuncs[prefix+name] = f } + nativeFuncs = append(nativeFuncs, loader.JsonnetNativeFuncsWithPrefix(ctx, prefix)...) } loader.Funcs(prefixedFuncs) } + callerIdentity := newCallerIdentity(v2cfg) + nativeFuncs = append(nativeFuncs, callerIdentity.JsonnetNativeFuncs(ctx)...) + loader.Funcs(callerIdentity.FuncMap(ctx)) + app := &App{ + callerIdentity: callerIdentity, profile: profile, loader: loader, awsConfig: v2cfg, lambda: lambda.NewFromConfig(v2cfg), functionFilePath: opt.Function, + nativeFuncs: nativeFuncs, + extStr: opt.ExtStr, + extCode: opt.ExtCode, } - app.extStr = opt.ExtStr - app.extCode = opt.ExtCode - return app, nil } // AWSAccountID returns AWS account ID in current session func (app *App) AWSAccountID(ctx context.Context) string { - if app.accountID != "" { - return app.accountID - } - svc := sts.NewFromConfig(app.awsConfig) - r, err := svc.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{}) - if err != nil { - log.Println("[warn] failed to get caller identity.", err) - return "" - } - app.accountID = *r.Account - return app.accountID + return app.callerIdentity.Account(ctx) } func loadDefinitionFile[T any](app *App, path string, defaults []string) (*T, error) { @@ -225,6 +229,9 @@ func loadDefinitionFile[T any](app *App, path string, defaults []string) (*T, er switch filepath.Ext(path) { case ".jsonnet": vm := jsonnet.MakeVM() + for _, f := range app.nativeFuncs { + vm.NativeFunction(f) + } for k, v := range app.extStr { vm.ExtVar(k, v) } diff --git a/test/function.json b/test/function.json index ad81f7b..0513aaf 100644 --- a/test/function.json +++ b/test/function.json @@ -16,7 +16,7 @@ "FunctionName": "{{ must_env `FUNCTION_NAME` }}", "FileSystemConfigs": [ { - "Arn": "arn:aws:elasticfilesystem:ap-northeast-1:123456789012:access-point/fsap-04fc0858274e7dd9a", + "Arn": "arn:aws:elasticfilesystem:ap-northeast-1:{{ caller_identity.Account }}:access-point/fsap-04fc0858274e7dd9a", "LocalMountPath": "/mnt/lambda" } ], diff --git a/test/function.jsonnet b/test/function.jsonnet index 5abf6f9..dc87cdb 100644 --- a/test/function.jsonnet +++ b/test/function.jsonnet @@ -1,3 +1,7 @@ +local prefix1_tfstate = std.native('prefix1_tfstate'); +local tfstate = std.native('tfstate'); +local must_env = std.native('must_env'); +local caller = std.native('caller_identity')(); { Architectures: [ 'x86_64', @@ -9,14 +13,14 @@ Environment: { Variables: { JSON: '{{ env `JSON` | json_escape }}', - PREFIXED_TFSTATE_1: '{{ prefix1_tfstate `data.aws_iam_role.lambda.arn` }}', + PREFIXED_TFSTATE_1: prefix1_tfstate('data.aws_iam_role.lambda.arn'), PREFIXED_TFSTATE_2: '{{ prefix2_tfstate `data.aws_iam_role.lambda.arn` }}', }, }, - FunctionName: '{{ must_env `FUNCTION_NAME` }}', + FunctionName: must_env('FUNCTION_NAME'), FileSystemConfigs: [ { - Arn: 'arn:aws:elasticfilesystem:ap-northeast-1:123456789012:access-point/fsap-04fc0858274e7dd9a', + Arn: 'arn:aws:elasticfilesystem:ap-northeast-1:%s:access-point/fsap-04fc0858274e7dd9a' % caller.Account, LocalMountPath: '/mnt/lambda', }, ], @@ -28,8 +32,8 @@ SystemLogLevel: 'INFO', }, MemorySize: std.extVar('MemorySize'), - Role: '{{ tfstate `data.aws_iam_role.lambda.arn` }}', - Runtime: 'nodejs12.x', + Role: tfstate('data.aws_iam_role.lambda.arn'), + Runtime: 'nodejs16.x', Timeout: 5, TracingConfig: { Mode: 'PassThrough',