Cloud provider Azure: add Secrets / Volumes / VolumeMounts / Env to cluster-autoscaler deployment

This commit is contained in:
Malte Poll 2022-03-29 13:26:35 +02:00 committed by Malte Poll
parent 97685648a4
commit cf738bb973
2 changed files with 192 additions and 1 deletions

View File

@ -1,5 +1,12 @@
package azure
import (
"github.com/edgelesssys/constellation/coordinator/core"
"github.com/edgelesssys/constellation/coordinator/kubernetes/k8sapi/resources"
k8s "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Autoscaler holds the Azure cluster-autoscaler configuration.
type Autoscaler struct{}
@ -8,7 +15,109 @@ func (a *Autoscaler) Name() string {
return "azure"
}
// Secrets returns a list of secrets to deploy together with the k8s cluster-autoscaler.
func (a *Autoscaler) Secrets(instance core.Instance, cloudServiceAccountURI string) (resources.Secrets, error) {
subscriptionID, resourceGroup, err := extractBasicsFromProviderID(instance.ProviderID)
if err != nil {
return resources.Secrets{}, err
}
creds, err := getApplicationCredentials(cloudServiceAccountURI)
if err != nil {
return resources.Secrets{}, err
}
return resources.Secrets{
&k8s.Secret{
TypeMeta: meta.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: meta.ObjectMeta{
Name: "cluster-autoscaler-azure",
Namespace: "kube-system",
},
Data: map[string][]byte{
"ClientID": []byte(creds.ClientID),
"ClientSecret": []byte(creds.ClientSecret),
"ResourceGroup": []byte(resourceGroup),
"SubscriptionID": []byte(subscriptionID),
"TenantID": []byte(creds.TenantID),
"VMType": []byte("vmss"),
},
},
}, nil
}
// Volumes returns a list of volumes to deploy together with the k8s cluster-autoscaler.
func (a *Autoscaler) Volumes() []k8s.Volume {
return []k8s.Volume{}
}
// VolumeMounts returns a list of volume mounts to deploy together with the k8s cluster-autoscaler.
func (a *Autoscaler) VolumeMounts() []k8s.VolumeMount {
return []k8s.VolumeMount{}
}
// Env returns a list of k8s environment key-value pairs to deploy together with the k8s cluster-autoscaler.
func (a *Autoscaler) Env() []k8s.EnvVar {
return []k8s.EnvVar{
{
Name: "ARM_SUBSCRIPTION_ID",
ValueFrom: &k8s.EnvVarSource{
SecretKeyRef: &k8s.SecretKeySelector{
Key: "SubscriptionID",
LocalObjectReference: k8s.LocalObjectReference{Name: "cluster-autoscaler-azure"},
},
},
},
{
Name: "ARM_RESOURCE_GROUP",
ValueFrom: &k8s.EnvVarSource{
SecretKeyRef: &k8s.SecretKeySelector{
Key: "ResourceGroup",
LocalObjectReference: k8s.LocalObjectReference{Name: "cluster-autoscaler-azure"},
},
},
},
{
Name: "ARM_TENANT_ID",
ValueFrom: &k8s.EnvVarSource{
SecretKeyRef: &k8s.SecretKeySelector{
Key: "TenantID",
LocalObjectReference: k8s.LocalObjectReference{Name: "cluster-autoscaler-azure"},
},
},
},
{
Name: "ARM_CLIENT_ID",
ValueFrom: &k8s.EnvVarSource{
SecretKeyRef: &k8s.SecretKeySelector{
Key: "ClientID",
LocalObjectReference: k8s.LocalObjectReference{Name: "cluster-autoscaler-azure"},
},
},
},
{
Name: "ARM_CLIENT_SECRET",
ValueFrom: &k8s.EnvVarSource{
SecretKeyRef: &k8s.SecretKeySelector{
Key: "ClientSecret",
LocalObjectReference: k8s.LocalObjectReference{Name: "cluster-autoscaler-azure"},
},
},
},
{
Name: "ARM_VM_TYPE",
ValueFrom: &k8s.EnvVarSource{
SecretKeyRef: &k8s.SecretKeySelector{
Key: "VMType",
LocalObjectReference: k8s.LocalObjectReference{Name: "cluster-autoscaler-azure"},
},
},
},
}
}
// Supported is used to determine if we support autoscaling for the cloud provider.
func (a *Autoscaler) Supported() bool {
return false
return true
}

View File

@ -0,0 +1,82 @@
package azure
import (
"testing"
"github.com/edgelesssys/constellation/coordinator/core"
"github.com/edgelesssys/constellation/coordinator/kubernetes/k8sapi/resources"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
k8s "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestAutoscalerSecrets(t *testing.T) {
testCases := map[string]struct {
instance core.Instance
cloudServiceAccountURI string
expectedSecrets resources.Secrets
expectErr bool
}{
"Secrets works": {
instance: core.Instance{ProviderID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-name"},
cloudServiceAccountURI: "serviceaccount://azure?tenant_id=tenant-id&client_id=client-id&client_secret=client-secret",
expectedSecrets: resources.Secrets{
&k8s.Secret{
TypeMeta: meta.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: meta.ObjectMeta{
Name: "cluster-autoscaler-azure",
Namespace: "kube-system",
},
Data: map[string][]byte{
"ClientID": []byte("client-id"),
"ClientSecret": []byte("client-secret"),
"ResourceGroup": []byte("resource-group"),
"SubscriptionID": []byte("subscription-id"),
"TenantID": []byte("tenant-id"),
"VMType": []byte("vmss"),
},
},
},
},
"invalid providerID fails": {
instance: core.Instance{ProviderID: "invalid"},
expectErr: true,
},
"invalid cloudServiceAccountURI fails": {
instance: core.Instance{ProviderID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-name"},
cloudServiceAccountURI: "invalid",
expectErr: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
autoscaler := Autoscaler{}
secrets, err := autoscaler.Secrets(tc.instance, tc.cloudServiceAccountURI)
if tc.expectErr {
assert.Error(err)
return
}
require.NoError(err)
assert.Equal(tc.expectedSecrets, secrets)
})
}
}
func TestTrivialAutoscalerFunctions(t *testing.T) {
assert := assert.New(t)
autoscaler := Autoscaler{}
assert.NotEmpty(autoscaler.Name())
assert.Empty(autoscaler.Volumes())
assert.Empty(autoscaler.VolumeMounts())
assert.NotEmpty(autoscaler.Env())
assert.True(autoscaler.Supported())
}