Skip to content

Commit

Permalink
Merge pull request #141 from JonCole/clouds-custom-config
Browse files Browse the repository at this point in the history
Read custom cloud list from json string
  • Loading branch information
aangelisc authored May 17, 2024
2 parents 2a25011 + 73d2d55 commit c271284
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 22 deletions.
51 changes: 32 additions & 19 deletions azsettings/cloud_settings.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package azsettings

import (
"encoding/json"
"fmt"
)

Expand All @@ -10,10 +11,10 @@ type AzureCloudInfo struct {
}

type AzureCloudSettings struct {
Name string
DisplayName string
AadAuthority string
Properties map[string]string
Name string `json:"name"`
DisplayName string `json:"displayName"`
AadAuthority string `json:"aadAuthority"`
Properties map[string]string `json:"properties"`
}

var predefinedClouds = []*AzureCloudSettings{
Expand Down Expand Up @@ -55,8 +56,8 @@ var predefinedClouds = []*AzureCloudSettings{
},
}

func (*AzureSettings) GetCloud(cloudName string) (*AzureCloudSettings, error) {
clouds := getClouds()
func (settings *AzureSettings) GetCloud(cloudName string) (*AzureCloudSettings, error) {
clouds := settings.getClouds()

for _, cloud := range clouds {
if cloud.Name == cloudName {
Expand All @@ -68,15 +69,31 @@ func (*AzureSettings) GetCloud(cloudName string) (*AzureCloudSettings, error) {
}

// Returns all clouds configured on the instance, including custom clouds if any
func (*AzureSettings) Clouds() []AzureCloudInfo {
clouds := getClouds()
func (settings *AzureSettings) Clouds() []AzureCloudInfo {
clouds := settings.getClouds()
return mapCloudInfo(clouds)
}

// Returns only the custom clouds configured on the instance
func (*AzureSettings) CustomClouds() []AzureCloudInfo {
clouds := getCustomClouds()
return mapCloudInfo(clouds)
func (settings *AzureSettings) CustomClouds() []AzureCloudInfo {
return mapCloudInfo(settings.CustomCloudList)
}

// Parses the JSON list of custom clouds passed in, then stores the list on the instance
func (settings *AzureSettings) SetCustomClouds(customCloudsJSON string) error {
//only Unmarshal if the JSON has changed
if settings.CustomCloudListJSON != customCloudsJSON {
var customClouds []*AzureCloudSettings
if err := json.Unmarshal([]byte(customCloudsJSON), &customClouds); err != nil {
return err
}

settings.CustomCloudList = customClouds

// store it so we don't have to re-serialize back to JSON when adding to the plugin context
settings.CustomCloudListJSON = customCloudsJSON
}
return nil
}

func mapCloudInfo(clouds []*AzureCloudSettings) []AzureCloudInfo {
Expand All @@ -91,16 +108,12 @@ func mapCloudInfo(clouds []*AzureCloudSettings) []AzureCloudInfo {
return results
}

func getClouds() []*AzureCloudSettings {
if clouds := getCustomClouds(); len(clouds) > 0 {
allClouds := append(clouds, predefinedClouds...)
func (settings *AzureSettings) getClouds() []*AzureCloudSettings {
clouds := settings.CustomCloudList
if len(settings.CustomCloudList) > 0 {
allClouds := append(predefinedClouds, clouds...)
return allClouds
}

return predefinedClouds
}

func getCustomClouds() []*AzureCloudSettings {
// Configuration of Azure clouds not yet supported
return nil
}
93 changes: 91 additions & 2 deletions azsettings/cloud_settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,34 @@ import (
"github.com/stretchr/testify/require"
)

func TestGetClouds(t *testing.T) {
var testCustomClouds = []*AzureCloudSettings{
{
Name: "CustomCloud1",
DisplayName: "Custom Cloud 1",
AadAuthority: "https://login.contoso.com/",
Properties: map[string]string{
"azureDataExplorerSuffix": ".kusto.cloud1.contoso.com",
"logAnalytics": "https://api.loganalytics.cloud1.contoso.com",
"portal": "https://portal.azure.cloud1.contoso.com",
"prometheusResourceId": "https://prometheus.monitor.azure.cloud1.contoso.com",
"resourceManager": "https://management.azure.cloud1.contoso.com",
},
},
{
Name: "CustomCloud2",
DisplayName: "Custom Cloud 2",
AadAuthority: "https://login.cloud2.contoso.com/",
Properties: map[string]string{
"azureDataExplorerSuffix": ".kusto.cloud2.contoso.com",
"logAnalytics": "https://api.loganalytics.cloud2.contoso.com",
"portal": "https://portal.azure.cloud2.contoso.com",
"prometheusResourceId": "https://prometheus.monitor.cloud2.azure.contoso.com",
"resourceManager": "https://management.azure.cloud2.contoso.com",
},
},
}

func TestGetCloudsNoCustomClouds(t *testing.T) {
settings := &AzureSettings{}

clouds := settings.Clouds()
Expand All @@ -18,12 +45,39 @@ func TestGetClouds(t *testing.T) {
assert.Equal(t, clouds[2].Name, "AzureUSGovernment")
}

func TestGetCloudsWithCustomClouds(t *testing.T) {
settings := &AzureSettings{}
settings.CustomCloudList = testCustomClouds

// should merge predefined and custom clouds into one list
clouds := settings.Clouds()

assert.Len(t, clouds, 5)
assert.Equal(t, clouds[0].Name, "AzureCloud")
assert.Equal(t, clouds[1].Name, "AzureChinaCloud")
assert.Equal(t, clouds[2].Name, "AzureUSGovernment")
assert.Equal(t, clouds[3].Name, "CustomCloud1")
assert.Equal(t, clouds[4].Name, "CustomCloud2")
}

func TestGetCustomClouds(t *testing.T) {
settings := &AzureSettings{}
settings.CustomCloudList = testCustomClouds

// should return ONLY the custom clouds
clouds := settings.CustomClouds()

// Configuration of Azure clouds not yet supported
assert.Len(t, clouds, len(testCustomClouds))
}

func TestGetCustomCloudsWithNilList(t *testing.T) {
settings := &AzureSettings{}
settings.CustomCloudList = nil

// should return ONLY the custom clouds
clouds := settings.CustomClouds()

assert.NotNil(t, clouds)
assert.Len(t, clouds, 0)
}

Expand All @@ -43,3 +97,38 @@ func TestGetCloud(t *testing.T) {
assert.Error(t, err)
})
}

func TestSetCustomClouds(t *testing.T) {
settings := &AzureSettings{}

json := `[
{
"name":"CustomCloud1",
"displayName":"Custom Cloud 1",
"aadAuthority":"https://login.contoso.com/",
"properties":{
"azureDataExplorerSuffix":".kusto.cloud1.contoso.com",
"logAnalytics":"https://api.loganalytics.cloud1.contoso.com",
"portal":"https://portal.azure.cloud1.contoso.com",
"prometheusResourceId":"https://prometheus.monitor.azure.cloud1.contoso.com",
"resourceManager":"https://management.azure.cloud1.contoso.com"
}
}
]`

err := settings.SetCustomClouds(json)
assert.Nil(t, err)

clouds := settings.CustomCloudList

assert.Len(t, clouds, 1)
cloud := clouds[0]
assert.Equal(t, cloud.Name, "CustomCloud1")
assert.Equal(t, cloud.DisplayName, "Custom Cloud 1")
assert.Equal(t, cloud.AadAuthority, "https://login.contoso.com/")
assert.Len(t, cloud.Properties, 5)

cloud2, err := settings.GetCloud("CustomCloud1")
assert.Nil(t, err)
assert.Equal(t, cloud2.Name, "CustomCloud1")
}
10 changes: 9 additions & 1 deletion azsettings/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (
)

const (
AzureCloud = "GFAZPL_AZURE_CLOUD"
AzureCloud = "GFAZPL_AZURE_CLOUD"
AzureCustomCloudsConfig = "GFAZPL_AZURE_CLOUDS_CONFIG"

AzureAuthEnabled = "GFAZPL_AZURE_AUTH_ENABLED"

Expand Down Expand Up @@ -45,6 +46,13 @@ func ReadFromEnv() (*AzureSettings, error) {
azureSettings.AzureAuthEnabled = true
}

if customCloudsJSON := envutil.GetOrDefault(AzureCustomCloudsConfig, ""); customCloudsJSON != "" {
// this method will parse the JSON and set the custom cloud list in one go
if err := azureSettings.SetCustomClouds(customCloudsJSON); err != nil {
return nil, err
}
}

// Managed Identity authentication
if msiEnabled, err := envutil.GetBoolOrFallback(ManagedIdentityEnabled, fallbackManagedIdentityEnabled, false); err != nil {
err = fmt.Errorf("invalid Azure configuration: %w", err)
Expand Down
10 changes: 10 additions & 0 deletions azsettings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ type AzureSettings struct {

// This field determines which plugins will receive the settings via plugin context
ForwardSettingsPlugins []string

CustomCloudList []*AzureCloudSettings
CustomCloudListJSON string
}

type WorkloadIdentitySettings struct {
Expand Down Expand Up @@ -60,6 +63,13 @@ func ReadFromContext(ctx context.Context) (*AzureSettings, bool) {
settings.AzureAuthEnabled = true
}

if customCloudsJSON := cfg.Get(AzureCustomCloudsConfig); customCloudsJSON != "" {
// this method will parse the JSON and set the custom cloud list in one go
if err := settings.SetCustomClouds(customCloudsJSON); err != nil {
backend.Logger.Error("Error setting custom clouds: %w", err)
}
}

hasSettings := false
if v := cfg.Get(AzureCloud); v != "" {
settings.Cloud = v
Expand Down

0 comments on commit c271284

Please sign in to comment.