Skip to content

Commit

Permalink
initial draft pr
Browse files Browse the repository at this point in the history
  • Loading branch information
lakshmimsft committed Feb 23, 2024
1 parent 6885574 commit 725f211
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 60 deletions.
1 change: 1 addition & 0 deletions pkg/corerp/api/v20231001preview/environment_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func (src *EnvironmentResource) ConvertTo() (v1.DataModelInterface, error) {
return nil, err
}
converted.Properties.Compute = *envCompute
converted.Properties.RecipeConfig = datamodel.RecipeConfigProperties{}

if src.Properties.Recipes != nil {
envRecipes := make(map[string]map[string]datamodel.EnvironmentRecipeProperties)
Expand Down
47 changes: 42 additions & 5 deletions pkg/corerp/datamodel/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,48 @@ func (e *Environment) ResourceTypeName() string {

// EnvironmentProperties represents the properties of Environment.
type EnvironmentProperties struct {
Compute rpv1.EnvironmentCompute `json:"compute,omitempty"`
Recipes map[string]map[string]EnvironmentRecipeProperties `json:"recipes,omitempty"`
Providers Providers `json:"providers,omitempty"`
Extensions []Extension `json:"extensions,omitempty"`
Simulated bool `json:"simulated,omitempty"`
Compute rpv1.EnvironmentCompute `json:"compute,omitempty"`
Recipes map[string]map[string]EnvironmentRecipeProperties `json:"recipes,omitempty"`
Providers Providers `json:"providers,omitempty"`
Extensions []Extension `json:"extensions,omitempty"`
Simulated bool `json:"simulated,omitempty"`
RecipeConfig RecipeConfigProperties `json:"recipeConfig,omitempty"`
}

// RecipeConfigProperties - Specifies recipe configurations needed for the recipes.
type RecipeConfigProperties struct {
// Terraform specifies the terraform config properties
Terraform TerraformConfigProperties `json:"terraform,omitempty"`
}

// TerraformConfigProperties - Specifies the terraform config properties
type TerraformConfigProperties struct {
// Authentication specifies authentication information needed to use private terraform module repositories.
Authentication AuthConfig `json:"authentication,omitempty"`
Providers TerraformProviders `json:"providers,omitempty"`
}

// AuthConfig - Specifies authentication information needed to use private terraform module repositories.
type AuthConfig struct {
// Git specifies authentication information needed to use private terraform module repositories from git module source
Git GitAuthConfig `json:"git,omitempty"`
}

// GitAuthConfig - Specifies authentication information needed to use private terraform module repositories from git module source
type GitAuthConfig struct {
// GitAuthConfig specifies the secret details of type personal access token for each different git platforms
PAT map[string]SecretConfig `json:"pat,omitempty"`
}

// SecretConfig - Specifies the secret details of type personal access token for each different git platforms
type SecretConfig struct {
// Secret represent the resource id for the secret store containing credentials
Secret string `json:"secret,omitempty"`
}

// TerraformProviders - Providers to be referenced by terraform recipes
type TerraformProviders struct {
ProviderConfigs map[string][]any `json:"fields,omitempty"`
}

// EnvironmentRecipeProperties represents the properties of environment's recipe.
Expand Down
24 changes: 13 additions & 11 deletions pkg/recipes/configloader/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
recipes_util "github.com/radius-project/radius/pkg/recipes/util"
"github.com/radius-project/radius/pkg/rp/kube"
"github.com/radius-project/radius/pkg/rp/util"
"github.com/radius-project/radius/pkg/to"
"github.com/radius-project/radius/pkg/ucp/resources"
)

Expand Down Expand Up @@ -72,8 +71,9 @@ func (e *environmentLoader) LoadConfiguration(ctx context.Context, recipe recipe

func getConfiguration(environment *v20231001preview.EnvironmentResource, application *v20231001preview.ApplicationResource) (*recipes.Configuration, error) {
config := recipes.Configuration{
Runtime: recipes.RuntimeConfiguration{},
Providers: datamodel.Providers{},
Runtime: recipes.RuntimeConfiguration{},
Providers: datamodel.Providers{},
RecipeConfig: datamodel.RecipeConfigProperties{},
}

switch environment.Properties.Compute.(type) {
Expand Down Expand Up @@ -101,15 +101,17 @@ func getConfiguration(environment *v20231001preview.EnvironmentResource, applica
return nil, ErrUnsupportedComputeKind
}

providers := environment.Properties.Providers
if providers != nil {
if providers.Aws != nil {
config.Providers.AWS.Scope = to.String(providers.Aws.Scope)
}
if providers.Azure != nil {
config.Providers.Azure.Scope = to.String(providers.Azure.Scope)
}
env, err := environment.ConvertTo()
if err != nil {
return nil, err
}
envDatamodel := env.(*datamodel.Environment)
if environment.Properties.Providers != nil {
config.Providers = envDatamodel.Properties.Providers
}
//if environment.Properties.RecipeConfig != nil {
// config.RecipeConfig = envDatamodel.Properties.RecipeConfig
//}

if environment.Properties.Simulated != nil && *environment.Properties.Simulated {
config.Simulated = true
Expand Down
43 changes: 36 additions & 7 deletions pkg/recipes/terraform/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ func (cfg *TerraformConfig) Save(ctx context.Context, workingDir string) error {
// by Radius to generate custom provider configurations. Save() must be called to save
// the generated providers config. requiredProviders contains a list of provider names
// that are required for the module.
func (cfg *TerraformConfig) AddProviders(ctx context.Context, requiredProviders []string, supportedProviders map[string]providers.Provider, envConfig *recipes.Configuration) error {
providerConfigs, err := getProviderConfigs(ctx, requiredProviders, supportedProviders, envConfig)
func (cfg *TerraformConfig) AddProviders(ctx context.Context, requiredProviders []string, ucpSupportedProviders map[string]providers.Provider, envConfig *recipes.Configuration) error {
providerConfigs, err := getProviderConfigs(ctx, requiredProviders, ucpSupportedProviders, envConfig)
if err != nil {
return err
}
Expand Down Expand Up @@ -136,12 +136,29 @@ func newModuleConfig(moduleSource string, moduleVersion string, params ...Recipe
}

// getProviderConfigs generates the Terraform provider configurations for the required providers.
func getProviderConfigs(ctx context.Context, requiredProviders []string, supportedProviders map[string]providers.Provider, envConfig *recipes.Configuration) (map[string]any, error) {
providerConfigs := make(map[string]any)
func getProviderConfigs(ctx context.Context, requiredProviders []string, ucpSupportedProviders map[string]providers.Provider, envConfig *recipes.Configuration) (map[string][]any, error) {
providerConfigs := make(map[string][]any)

// Get recipe provider configurations from the environment configuration
recipeProviderConfigs := getRecipeProviderConfigs(ctx, envConfig)

// Add provider config from recipeProviderConfigs to providerConfigs
for provider, config := range recipeProviderConfigs {
if len(config) > 0 {
providerConfigs[provider] = config
}
}

// Build provider configurations for required providers excluding the ones already present in providerConfigs
for _, provider := range requiredProviders {
builder, ok := supportedProviders[provider]
if _, ok := providerConfigs[provider]; ok {
// If provider is in providerConfigs, skip this iteration
continue
}

builder, ok := ucpSupportedProviders[provider]
if !ok {
// No-op: For any other provider, Radius doesn't generate any custom configuration.
// No-op: For any other provider under required_providers, Radius doesn't generate any custom configuration.
continue
}

Expand All @@ -150,13 +167,25 @@ func getProviderConfigs(ctx context.Context, requiredProviders []string, support
return nil, err
}
if len(config) > 0 {
providerConfigs[provider] = config
providerConfigs[provider] = []any{config}
}
}

return providerConfigs, nil
}

// getRecipeProviderConfigs returns the Terraform provider configurations for Terraform providers.
func getRecipeProviderConfigs(ctx context.Context, envConfig *recipes.Configuration) map[string][]any {

// If the provider is not configured, return an empty config
if envConfig.RecipeConfig.Terraform.Providers.ProviderConfigs == nil {
// Handle the case where one or more objects in the chain are nil...
return nil
}

return envConfig.RecipeConfig.Terraform.Providers.ProviderConfigs
}

// AddTerraformBackend adds backend configurations to store Terraform state file for the deployment.
// Save() must be called to save the generated backend config.
// Currently, the supported backend for Terraform Recipes is Kubernetes secret. https://developer.hashicorp.com/terraform/language/settings/backends/kubernetes
Expand Down
131 changes: 112 additions & 19 deletions pkg/recipes/terraform/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func Test_AddRecipeContext(t *testing.T) {
}

func Test_AddProviders(t *testing.T) {
mProvider, supportedProviders, mBackend := setup(t)
mProvider, supportedUCPProviders, mBackend := setup(t)
envRecipe, resourceRecipe := getTestInputs()
expectedBackend := map[string]any{
"kubernetes": map[string]any{
Expand All @@ -305,17 +305,19 @@ func Test_AddProviders(t *testing.T) {
"namespace": "radius-system",
},
}

configTests := []struct {
desc string
envConfig recipes.Configuration
requiredProviders []string
expectedProviders []map[string]any
expectedConfigFile string
Err error
desc string
envConfig recipes.Configuration
requiredProviders []string
expectedUCPSupportedProviders []map[string]any
expectedConfigFile string
Err error
times int
}{
{
desc: "valid all supported providers",
expectedProviders: []map[string]any{
expectedUCPSupportedProviders: []map[string]any{
{
"region": "test-region",
},
Expand Down Expand Up @@ -344,13 +346,13 @@ func Test_AddProviders(t *testing.T) {
providers.KubernetesProviderName,
"sql",
},

times: 1,
expectedConfigFile: "testdata/providers-valid.tf.json",
},
{
desc: "invalid aws scope",
expectedProviders: nil,
Err: errors.New("Invalid AWS provider scope"),
desc: "invalid aws scope",
expectedUCPSupportedProviders: nil,
Err: errors.New("Invalid AWS provider scope"),
envConfig: recipes.Configuration{
Providers: datamodel.Providers{
AWS: datamodel.ProvidersAWS{
Expand All @@ -361,22 +363,24 @@ func Test_AddProviders(t *testing.T) {
requiredProviders: []string{
providers.AWSProviderName,
},
times: 1,
},
{
desc: "empty aws provider config",
expectedProviders: []map[string]any{
expectedUCPSupportedProviders: []map[string]any{
{},
},
Err: nil,
envConfig: recipes.Configuration{},
requiredProviders: []string{
providers.AWSProviderName,
},
times: 1,
expectedConfigFile: "testdata/providers-empty.tf.json",
},
{
desc: "empty aws scope",
expectedProviders: []map[string]any{
expectedUCPSupportedProviders: []map[string]any{
nil,
},
Err: nil,
Expand All @@ -393,11 +397,12 @@ func Test_AddProviders(t *testing.T) {
requiredProviders: []string{
providers.AWSProviderName,
},
times: 1,
expectedConfigFile: "testdata/providers-empty.tf.json",
},
{
desc: "empty azure provider config",
expectedProviders: []map[string]any{
expectedUCPSupportedProviders: []map[string]any{
{
"features": map[string]any{},
},
Expand All @@ -407,8 +412,88 @@ func Test_AddProviders(t *testing.T) {
requiredProviders: []string{
providers.AzureProviderName,
},
times: 1,
expectedConfigFile: "testdata/providers-emptyazureconfig.tf.json",
},
// Tests for providers block under RecipeConfig/Terraform added here:
{
desc: "valid recipe providers",
expectedUCPSupportedProviders: nil,
Err: nil,
envConfig: recipes.Configuration{
RecipeConfig: datamodel.RecipeConfigProperties{
Terraform: datamodel.TerraformConfigProperties{
Providers: datamodel.TerraformProviders{
ProviderConfigs: map[string][]any{
"azurerm": {
map[string]any{
"subscriptionid": 1234,
"tenant_id": "745fg88bf-86f1-41af-43ut",
},
map[string]any{
"alias": "az-paymentservice",
"subscriptionid": 45678,
"tenant_id": "gfhf45345-5d73-gh34-wh84",
},
},
},
},
},
},
},
requiredProviders: nil,
times: 1,
expectedConfigFile: "testdata/providers-envrecipeproviders.tf.json",
},
{
desc: "overridding required provider configs",
expectedUCPSupportedProviders: []map[string]any{
{
"region": "test-region",
},
{
"config_path": "/home/radius/.kube/config",
},
},
Err: nil,
envConfig: recipes.Configuration{
RecipeConfig: datamodel.RecipeConfigProperties{
Terraform: datamodel.TerraformConfigProperties{
Providers: datamodel.TerraformProviders{
ProviderConfigs: map[string][]any{
"kubernetes": {
map[string]any{
"config_path": "/home/radius/.kube/configPath1",
},
map[string]any{
"config_path": "/home/radius/.kube/configPath2",
},
},
},
},
},
},
},
requiredProviders: []string{
providers.AWSProviderName,
providers.KubernetesProviderName,
},
times: -1,
expectedConfigFile: "testdata/providers-overridereqproviders.tf.json",
},
{
desc: "recipe providers not populated",
expectedUCPSupportedProviders: nil,
Err: nil,
envConfig: recipes.Configuration{
RecipeConfig: datamodel.RecipeConfigProperties{
Terraform: datamodel.TerraformConfigProperties{},
},
},
requiredProviders: nil,
times: 1,
expectedConfigFile: "testdata/providers-empty.tf.json",
},
}

for _, tc := range configTests {
Expand All @@ -417,13 +502,21 @@ func Test_AddProviders(t *testing.T) {
workingDir := t.TempDir()

tfconfig := New(testRecipeName, &envRecipe, &resourceRecipe)
for _, p := range tc.expectedProviders {
mProvider.EXPECT().BuildConfig(ctx, &tc.envConfig).Times(1).Return(p, nil)
for _, p := range tc.expectedUCPSupportedProviders {
if tc.times > 0 {
mProvider.EXPECT().BuildConfig(ctx, &tc.envConfig).Times(tc.times).Return(p, nil)
} else {
mProvider.EXPECT().BuildConfig(ctx, &tc.envConfig).Return(p, tc.Err).AnyTimes()
}
}
if tc.Err != nil {
mProvider.EXPECT().BuildConfig(ctx, &tc.envConfig).Times(1).Return(nil, tc.Err)
if tc.times > 0 {
mProvider.EXPECT().BuildConfig(ctx, &tc.envConfig).Times(1).Return(nil, tc.Err)
} else {
mProvider.EXPECT().BuildConfig(ctx, &tc.envConfig).Return(nil, tc.Err).AnyTimes()
}
}
err := tfconfig.AddProviders(ctx, tc.requiredProviders, supportedProviders, &tc.envConfig)
err := tfconfig.AddProviders(ctx, tc.requiredProviders, supportedUCPProviders, &tc.envConfig)
if tc.Err != nil {
require.ErrorContains(t, err, tc.Err.Error())
return
Expand Down
Loading

0 comments on commit 725f211

Please sign in to comment.