Adds retrievers for parameters or environment variables

pull/33724/head
Graham Davison 3 years ago
parent 45db531ad4
commit 2f32799d68

@ -524,7 +524,6 @@ func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics {
CallerName: "S3 Backend",
CredsFilename: stringAttr(obj, "shared_credentials_file"),
DebugLogging: logging.IsDebugOrHigher(),
IamEndpoint: stringAttrDefaultEnvVar(obj, "iam_endpoint", "AWS_ENDPOINT_URL_IAM", "AWS_IAM_ENDPOINT"),
MaxRetries: intAttrDefault(obj, "max_retries", 5),
Profile: stringAttr(obj, "profile"),
Region: stringAttr(obj, "region"),
@ -540,6 +539,15 @@ func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics {
},
}
if v, ok := retrieveArgument(&diags,
newAttributeRetriever(obj, cty.GetAttrPath("endpoints").GetAttr("iam")),
newAttributeRetriever(obj, cty.GetAttrPath("iam_endpoint")),
newEnvvarRetriever("AWS_ENDPOINT_URL_IAM"),
newEnvvarRetriever("AWS_IAM_ENDPOINT"),
); ok {
cfg.IamEndpoint = v
}
if assumeRole := obj.GetAttr("assume_role"); !assumeRole.IsNull() {
if val, ok := stringAttrOk(assumeRole, "role_arn"); ok {
cfg.AssumeRoleARN = val
@ -598,55 +606,114 @@ func (b *Backend) Configure(obj cty.Value) tfdiags.Diagnostics {
}
var dynamoConfig aws.Config
var dynamoEndpoint string
if val := obj.GetAttr("endpoints"); !val.IsNull() {
if v := val.GetAttr("dynamodb"); !v.IsNull() {
dynamoEndpoint = v.AsString()
}
if v, ok := retrieveArgument(&diags,
newAttributeRetriever(obj, cty.GetAttrPath("endpoints").GetAttr("dynamodb")),
newAttributeRetriever(obj, cty.GetAttrPath("dynamodb_endpoint")),
newEnvvarRetriever("AWS_ENDPOINT_URL_DYNAMODB"),
newEnvvarRetriever("AWS_DYNAMODB_ENDPOINT"),
); ok {
dynamoConfig.Endpoint = aws.String(v)
}
if dynamoEndpoint == "" {
if val := obj.GetAttr("dynamodb_endpoint"); !val.IsNull() {
dynamoEndpoint = val.AsString()
}
b.dynClient = dynamodb.New(sess.Copy(&dynamoConfig))
var s3Config aws.Config
if v, ok := retrieveArgument(&diags,
newAttributeRetriever(obj, cty.GetAttrPath("endpoints").GetAttr("s3")),
newAttributeRetriever(obj, cty.GetAttrPath("endpoint")),
newEnvvarRetriever("AWS_ENDPOINT_URL_S3"),
newEnvvarRetriever("AWS_S3_ENDPOINT"),
); ok {
s3Config.Endpoint = aws.String(v)
}
if dynamoEndpoint == "" {
dynamoEndpoint = os.Getenv("AWS_ENDPOINT_URL_DYNAMODB")
if v, ok := boolAttrOk(obj, "force_path_style"); ok {
s3Config.S3ForcePathStyle = aws.Bool(v)
}
if dynamoEndpoint == "" {
dynamoEndpoint = os.Getenv("AWS_DYNAMODB_ENDPOINT")
b.s3Client = s3.New(sess.Copy(&s3Config))
return diags
}
type argumentRetriever interface {
Retrieve(diags *tfdiags.Diagnostics) (string, bool)
}
type attributeRetriever struct {
obj cty.Value
objPath cty.Path
attrPath cty.Path
}
var _ argumentRetriever = attributeRetriever{}
func newAttributeRetriever(obj cty.Value, attrPath cty.Path) attributeRetriever {
return attributeRetriever{
obj: obj,
objPath: cty.Path{}, // Assumes that we're working relative to the root object
attrPath: attrPath,
}
if dynamoEndpoint != "" {
dynamoConfig.Endpoint = aws.String(dynamoEndpoint)
}
func (r attributeRetriever) Retrieve(diags *tfdiags.Diagnostics) (string, bool) {
val, err := pathSafeApply(r.attrPath, r.obj)
if err != nil {
*diags = diags.Append(attributeErrDiag(
"Invalid Path for Schema",
"The S3 Backend unexpectedly provided a path that does not match the schema. "+
"Please report this to the developers.\n\n"+
"Path: "+pathString(r.attrPath)+"\n\n"+
"Error: "+err.Error(),
r.objPath,
))
}
b.dynClient = dynamodb.New(sess.Copy(&dynamoConfig))
return stringValueOk(val)
}
var s3Config aws.Config
var s3Endpoint string
if val := obj.GetAttr("endpoints"); !val.IsNull() {
if v := val.GetAttr("s3"); !v.IsNull() {
s3Endpoint = v.AsString()
}
// pathSafeApply applies a `cty.Path` to a `cty.Value`.
// Unlike `path.Apply`, it does not return an error if it encounters a Null value
func pathSafeApply(path cty.Path, obj cty.Value) (cty.Value, error) {
if obj == cty.NilVal || obj.IsNull() {
return obj, nil
}
if s3Endpoint == "" {
if val := obj.GetAttr("endpoint"); !val.IsNull() {
s3Endpoint = val.AsString()
val := obj
var err error
for _, step := range path {
val, err = step.Apply(val)
if err != nil {
return cty.NilVal, err
}
if val == cty.NilVal || val.IsNull() {
return val, nil
}
}
if s3Endpoint == "" {
s3Endpoint = os.Getenv("AWS_ENDPOINT_URL_S3")
}
if s3Endpoint == "" {
s3Endpoint = os.Getenv("AWS_S3_ENDPOINT")
}
if s3Endpoint != "" {
s3Config.Endpoint = aws.String(s3Endpoint)
return val, nil
}
type envvarRetriever struct {
name string
}
var _ argumentRetriever = envvarRetriever{}
func newEnvvarRetriever(name string) envvarRetriever {
return envvarRetriever{
name: name,
}
if v, ok := boolAttrOk(obj, "force_path_style"); ok {
s3Config.S3ForcePathStyle = aws.Bool(v)
}
func (r envvarRetriever) Retrieve(_ *tfdiags.Diagnostics) (string, bool) {
if v := os.Getenv(r.name); v != "" {
return v, true
}
b.s3Client = s3.New(sess.Copy(&s3Config))
return "", false
}
return diags
func retrieveArgument(diags *tfdiags.Diagnostics, retrievers ...argumentRetriever) (string, bool) {
for _, retriever := range retrievers {
if v, ok := retriever.Retrieve(diags); ok {
return v, true
}
}
return "", false
}
func stringValue(val cty.Value) string {

Loading…
Cancel
Save