Co-authored-by: Nicholas Loomans <nicholas.loomans@portainer.io> Co-authored-by: Robbie Cowan <robert.cowan@portainer.io> Co-authored-by: RHCowan <50324595+RHCowan@users.noreply.github.com>
247 lines
6.5 KiB
Go
247 lines
6.5 KiB
Go
package cli
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
storagev1 "k8s.io/api/storage/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
kfake "k8s.io/client-go/kubernetes/fake"
|
|
)
|
|
|
|
func TestParseStorageClassDetail_IsDefault(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("annotation true sets isDefault", func(t *testing.T) {
|
|
t.Parallel()
|
|
sc := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "fast",
|
|
Annotations: map[string]string{
|
|
storageClassDefaultAnnotation: "true",
|
|
},
|
|
},
|
|
}
|
|
result := parseStorageClassDetail(sc)
|
|
assert.True(t, result.IsDefault)
|
|
})
|
|
|
|
t.Run("annotation false gives isDefault=false", func(t *testing.T) {
|
|
t.Parallel()
|
|
sc := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "slow",
|
|
Annotations: map[string]string{
|
|
storageClassDefaultAnnotation: "false",
|
|
},
|
|
},
|
|
}
|
|
result := parseStorageClassDetail(sc)
|
|
assert.False(t, result.IsDefault)
|
|
})
|
|
|
|
t.Run("missing annotation gives isDefault=false", func(t *testing.T) {
|
|
t.Parallel()
|
|
sc := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "no-annotation"},
|
|
}
|
|
result := parseStorageClassDetail(sc)
|
|
assert.False(t, result.IsDefault)
|
|
})
|
|
}
|
|
|
|
func TestSetDefaultStorageClass(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("sets default annotation on target SC", func(t *testing.T) {
|
|
t.Parallel()
|
|
k := NewTestKubeClient(kfake.NewClientset())
|
|
|
|
sc := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "standard"},
|
|
}
|
|
_, err := k.cli.StorageV1().StorageClasses().Create(t.Context(), sc, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
err = k.SetDefaultStorageClass("standard")
|
|
require.NoError(t, err)
|
|
|
|
result, err := k.GetStorageClass("standard")
|
|
require.NoError(t, err)
|
|
assert.True(t, result.IsDefault)
|
|
})
|
|
|
|
t.Run("removes default annotation from previously-default SC", func(t *testing.T) {
|
|
t.Parallel()
|
|
k := NewTestKubeClient(kfake.NewClientset())
|
|
|
|
oldDefault := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "old-default",
|
|
Annotations: map[string]string{
|
|
storageClassDefaultAnnotation: "true",
|
|
},
|
|
},
|
|
}
|
|
newDefault := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "new-default"},
|
|
}
|
|
|
|
_, err := k.cli.StorageV1().StorageClasses().Create(t.Context(), oldDefault, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
_, err = k.cli.StorageV1().StorageClasses().Create(t.Context(), newDefault, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
err = k.SetDefaultStorageClass("new-default")
|
|
require.NoError(t, err)
|
|
|
|
old, err := k.GetStorageClass("old-default")
|
|
require.NoError(t, err)
|
|
assert.False(t, old.IsDefault)
|
|
|
|
newSC, err := k.GetStorageClass("new-default")
|
|
require.NoError(t, err)
|
|
assert.True(t, newSC.IsDefault)
|
|
})
|
|
|
|
t.Run("no-op if target is already default", func(t *testing.T) {
|
|
t.Parallel()
|
|
k := NewTestKubeClient(kfake.NewClientset())
|
|
|
|
sc := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "already-default",
|
|
Annotations: map[string]string{
|
|
storageClassDefaultAnnotation: "true",
|
|
},
|
|
},
|
|
}
|
|
_, err := k.cli.StorageV1().StorageClasses().Create(t.Context(), sc, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
err = k.SetDefaultStorageClass("already-default")
|
|
require.NoError(t, err)
|
|
|
|
result, err := k.GetStorageClass("already-default")
|
|
require.NoError(t, err)
|
|
assert.True(t, result.IsDefault)
|
|
})
|
|
|
|
t.Run("handles multiple SCs where only one was previously default", func(t *testing.T) {
|
|
t.Parallel()
|
|
k := NewTestKubeClient(kfake.NewClientset())
|
|
|
|
scs := []*storagev1.StorageClass{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "sc-default",
|
|
Annotations: map[string]string{
|
|
storageClassDefaultAnnotation: "true",
|
|
},
|
|
},
|
|
},
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "sc-other-1"}},
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "sc-other-2"}},
|
|
{ObjectMeta: metav1.ObjectMeta{Name: "sc-target"}},
|
|
}
|
|
|
|
for _, sc := range scs {
|
|
_, err := k.cli.StorageV1().StorageClasses().Create(t.Context(), sc, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
err := k.SetDefaultStorageClass("sc-target")
|
|
require.NoError(t, err)
|
|
|
|
target, err := k.GetStorageClass("sc-target")
|
|
require.NoError(t, err)
|
|
assert.True(t, target.IsDefault)
|
|
|
|
oldDefault, err := k.GetStorageClass("sc-default")
|
|
require.NoError(t, err)
|
|
assert.False(t, oldDefault.IsDefault)
|
|
|
|
for _, name := range []string{"sc-other-1", "sc-other-2"} {
|
|
sc, err := k.GetStorageClass(name)
|
|
require.NoError(t, err)
|
|
assert.False(t, sc.IsDefault)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetStorageClasses(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("empty cluster returns empty slice", func(t *testing.T) {
|
|
t.Parallel()
|
|
k := NewTestKubeClient(kfake.NewClientset())
|
|
scs, err := k.GetStorageClasses()
|
|
require.NoError(t, err)
|
|
assert.Empty(t, scs)
|
|
})
|
|
|
|
t.Run("returns all SCs with correct fields", func(t *testing.T) {
|
|
t.Parallel()
|
|
k := NewTestKubeClient(kfake.NewClientset())
|
|
|
|
allowExpansion := true
|
|
sc := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "fast",
|
|
Annotations: map[string]string{
|
|
storageClassDefaultAnnotation: "true",
|
|
},
|
|
},
|
|
Provisioner: "kubernetes.io/aws-ebs",
|
|
AllowVolumeExpansion: &allowExpansion,
|
|
}
|
|
_, err := k.cli.StorageV1().StorageClasses().Create(t.Context(), sc, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
scs, err := k.GetStorageClasses()
|
|
require.NoError(t, err)
|
|
require.Len(t, scs, 1)
|
|
|
|
got := scs[0]
|
|
assert.Equal(t, "fast", got.Name)
|
|
assert.Equal(t, "kubernetes.io/aws-ebs", got.Provisioner)
|
|
assert.True(t, got.IsDefault)
|
|
require.NotNil(t, got.AllowVolumeExpansion)
|
|
assert.True(t, *got.AllowVolumeExpansion)
|
|
})
|
|
}
|
|
|
|
func TestDeleteStorageClasses(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("deletes specified SCs", func(t *testing.T) {
|
|
t.Parallel()
|
|
k := NewTestKubeClient(kfake.NewClientset())
|
|
|
|
for _, name := range []string{"sc-a", "sc-b", "sc-c"} {
|
|
sc := &storagev1.StorageClass{
|
|
ObjectMeta: metav1.ObjectMeta{Name: name},
|
|
}
|
|
_, err := k.cli.StorageV1().StorageClasses().Create(t.Context(), sc, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
err := k.DeleteStorageClasses([]string{"sc-a", "sc-c"})
|
|
require.NoError(t, err)
|
|
|
|
scs, err := k.GetStorageClasses()
|
|
require.NoError(t, err)
|
|
require.Len(t, scs, 1)
|
|
assert.Equal(t, "sc-b", scs[0].Name)
|
|
})
|
|
|
|
t.Run("returns error for non-existent SC", func(t *testing.T) {
|
|
t.Parallel()
|
|
k := NewTestKubeClient(kfake.NewClientset())
|
|
|
|
err := k.DeleteStorageClasses([]string{"does-not-exist"})
|
|
assert.Error(t, err)
|
|
})
|
|
}
|