mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Add TF_ORGANIZATION env var support
TF_ORGANIZATION will serve as a fallback for configuring the organization in the `cloud` block. This is the first step to make it easier for users wanting to configure Terraform programmatically.
This commit is contained in:
parent
7e849473a4
commit
45357f5004
@ -113,7 +113,7 @@ func (b *Cloud) ConfigSchema() *configschema.Block {
|
|||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
Type: cty.String,
|
Type: cty.String,
|
||||||
Required: true,
|
Optional: true,
|
||||||
Description: schemaDescriptionOrganization,
|
Description: schemaDescriptionOrganization,
|
||||||
},
|
},
|
||||||
"token": {
|
"token": {
|
||||||
@ -152,8 +152,13 @@ func (b *Cloud) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) {
|
|||||||
return obj, diags
|
return obj, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if organization is specified in the config.
|
||||||
if val := obj.GetAttr("organization"); val.IsNull() || val.AsString() == "" {
|
if val := obj.GetAttr("organization"); val.IsNull() || val.AsString() == "" {
|
||||||
diags = diags.Append(invalidOrganizationConfigMissingValue)
|
// organization is specified in the config but is invalid, so
|
||||||
|
// we'll fallback on TF_ORGANIZATION
|
||||||
|
if val := os.Getenv("TF_ORGANIZATION"); val == "" {
|
||||||
|
diags = diags.Append(invalidOrganizationConfigMissingValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkspaceMapping := WorkspaceMapping{}
|
WorkspaceMapping := WorkspaceMapping{}
|
||||||
@ -342,8 +347,14 @@ func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics {
|
|||||||
b.hostname = defaultHostname
|
b.hostname = defaultHostname
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the organization.
|
// We can have two options, setting the organization via the config
|
||||||
if val := obj.GetAttr("organization"); !val.IsNull() {
|
// or using TF_ORGANIZATION. Since PrepareConfig() validates that one of these
|
||||||
|
// values must exist, we'll initially set it to the env var and override it if
|
||||||
|
// specified in the configuration.
|
||||||
|
b.organization = os.Getenv("TF_ORGANIZATION")
|
||||||
|
|
||||||
|
// Check if the organization is present and valid in the config.
|
||||||
|
if val := obj.GetAttr("organization"); !val.IsNull() && val.AsString() != "" {
|
||||||
b.organization = val.AsString()
|
b.organization = val.AsString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +146,119 @@ func TestCloud_PrepareConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCloud_PrepareConfigWithEnvVars(t *testing.T) {
|
||||||
|
cases := map[string]struct {
|
||||||
|
config cty.Value
|
||||||
|
vars map[string]string
|
||||||
|
expectedErr string
|
||||||
|
}{
|
||||||
|
"with no organization": {
|
||||||
|
config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"organization": cty.NullVal(cty.String),
|
||||||
|
"workspaces": cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"name": cty.StringVal("prod"),
|
||||||
|
"tags": cty.NullVal(cty.Set(cty.String)),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
vars: map[string]string{
|
||||||
|
"TF_ORGANIZATION": "example-org",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"with no organization attribute or env var": {
|
||||||
|
config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"organization": cty.NullVal(cty.String),
|
||||||
|
"workspaces": cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"name": cty.StringVal("prod"),
|
||||||
|
"tags": cty.NullVal(cty.Set(cty.String)),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
vars: map[string]string{},
|
||||||
|
expectedErr: `Invalid organization value: The "organization" attribute value must not be empty.`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range cases {
|
||||||
|
s := testServer(t)
|
||||||
|
b := New(testDisco(s))
|
||||||
|
|
||||||
|
for k, v := range tc.vars {
|
||||||
|
os.Setenv(k, v)
|
||||||
|
defer os.Unsetenv(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, valDiags := b.PrepareConfig(tc.config)
|
||||||
|
if valDiags.Err() != nil && tc.expectedErr != "" {
|
||||||
|
actualErr := valDiags.Err().Error()
|
||||||
|
if !strings.Contains(actualErr, tc.expectedErr) {
|
||||||
|
t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCloud_configWithEnvVars(t *testing.T) {
|
||||||
|
cases := map[string]struct {
|
||||||
|
config cty.Value
|
||||||
|
vars map[string]string
|
||||||
|
expectedOrganization string
|
||||||
|
}{
|
||||||
|
"with no organization specified": {
|
||||||
|
config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"hostname": cty.NullVal(cty.String),
|
||||||
|
"token": cty.NullVal(cty.String),
|
||||||
|
"organization": cty.NullVal(cty.String),
|
||||||
|
"workspaces": cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"name": cty.StringVal("prod"),
|
||||||
|
"tags": cty.NullVal(cty.Set(cty.String)),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
vars: map[string]string{
|
||||||
|
"TF_ORGANIZATION": "hashicorp",
|
||||||
|
},
|
||||||
|
expectedOrganization: "hashicorp",
|
||||||
|
},
|
||||||
|
"with both organization and env var specified": {
|
||||||
|
config: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"hostname": cty.NullVal(cty.String),
|
||||||
|
"token": cty.NullVal(cty.String),
|
||||||
|
"organization": cty.StringVal("hashicorp"),
|
||||||
|
"workspaces": cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"name": cty.StringVal("prod"),
|
||||||
|
"tags": cty.NullVal(cty.Set(cty.String)),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
vars: map[string]string{
|
||||||
|
"TF_ORGANIZATION": "we-should-not-see-this",
|
||||||
|
},
|
||||||
|
expectedOrganization: "hashicorp",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range cases {
|
||||||
|
s := testServer(t)
|
||||||
|
b := New(testDisco(s))
|
||||||
|
|
||||||
|
for k, v := range tc.vars {
|
||||||
|
os.Setenv(k, v)
|
||||||
|
defer os.Unsetenv(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, valDiags := b.PrepareConfig(tc.config)
|
||||||
|
if valDiags.Err() != nil {
|
||||||
|
t.Fatalf("%s: unexpected validation result: %v", name, valDiags.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
diags := b.Configure(tc.config)
|
||||||
|
if diags.Err() != nil {
|
||||||
|
t.Fatalf("%s: unexpected configuration result: %v", name, valDiags.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectedOrganization != "" && tc.expectedOrganization != b.organization {
|
||||||
|
t.Fatalf("%s: organization not valid: %s, expected: %s", name, b.organization, tc.expectedOrganization)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCloud_config(t *testing.T) {
|
func TestCloud_config(t *testing.T) {
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
config cty.Value
|
config cty.Value
|
||||||
|
Loading…
Reference in New Issue
Block a user