Skip to content

Commit 262e57d

Browse files
authored
Merge pull request #35 from arangodb/storage-class-default
Implemented isDefault behavior of storage class
2 parents 321ac5a + db03cc3 commit 262e57d

File tree

4 files changed

+185
-2
lines changed

4 files changed

+185
-2
lines changed

examples/arango-local-storage.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ metadata:
55
spec:
66
storageClass:
77
name: my-local-ssd
8+
isDefault: true
89
localPath:
910
- /var/lib/arango-storage

pkg/storage/storage_class.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ var (
3838
// ensureStorageClass creates a storage class for the given local storage.
3939
// If such a class already exists, the create is ignored.
4040
func (l *LocalStorage) ensureStorageClass(apiObject *api.ArangoLocalStorage) error {
41+
log := l.deps.Log
4142
spec := apiObject.Spec.StorageClass
4243
bindingMode := v1.VolumeBindingWaitForFirstConsumer
4344
reclaimPolicy := corev1.PersistentVolumeReclaimRetain
@@ -49,10 +50,60 @@ func (l *LocalStorage) ensureStorageClass(apiObject *api.ArangoLocalStorage) err
4950
VolumeBindingMode: &bindingMode,
5051
Provisioner: storageClassProvisioner,
5152
}
52-
if _, err := l.deps.KubeCli.StorageV1().StorageClasses().Create(sc); !k8sutil.IsAlreadyExists(err) && err != nil {
53+
// Note: We do not attach the StorageClass to the apiObject (OwnerRef) because many
54+
// ArangoLocalStorage resource may use the same StorageClass.
55+
cli := l.deps.KubeCli.StorageV1()
56+
if _, err := cli.StorageClasses().Create(sc); k8sutil.IsAlreadyExists(err) {
57+
log.Debug().
58+
Str("storageclass", sc.GetName()).
59+
Msg("StorageClass already exists")
60+
} else if err != nil {
61+
log.Debug().Err(err).
62+
Str("storageclass", sc.GetName()).
63+
Msg("Failed to create StorageClass")
5364
return maskAny(err)
65+
} else {
66+
log.Debug().
67+
Str("storageclass", sc.GetName()).
68+
Msg("StorageClass created")
69+
}
70+
71+
if apiObject.Spec.StorageClass.IsDefault {
72+
// UnMark current default (if any)
73+
list, err := cli.StorageClasses().List(metav1.ListOptions{})
74+
if err != nil {
75+
log.Debug().Err(err).Msg("Listing StorageClasses failed")
76+
return maskAny(err)
77+
}
78+
for _, scX := range list.Items {
79+
if !k8sutil.StorageClassIsDefault(&scX) || scX.GetName() == sc.GetName() {
80+
continue
81+
}
82+
// Mark storage class as non-default
83+
if err := k8sutil.PatchStorageClassIsDefault(cli, scX.GetName(), false); err != nil {
84+
log.Debug().
85+
Err(err).
86+
Str("storageclass", scX.GetName()).
87+
Msg("Failed to mark StorageClass as not-default")
88+
return maskAny(err)
89+
}
90+
log.Debug().
91+
Str("storageclass", scX.GetName()).
92+
Msg("Marked StorageClass as not-default")
93+
}
94+
95+
// Mark StorageClass default
96+
if err := k8sutil.PatchStorageClassIsDefault(cli, sc.GetName(), true); err != nil {
97+
log.Debug().
98+
Err(err).
99+
Str("storageclass", sc.GetName()).
100+
Msg("Failed to mark StorageClass as default")
101+
return maskAny(err)
102+
}
103+
log.Debug().
104+
Str("storageclass", sc.GetName()).
105+
Msg("Marked StorageClass as default")
54106
}
55-
// TODO make default (if needed)
56107

57108
return nil
58109
}

pkg/util/k8sutil/storageclass.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package k8sutil
24+
25+
import (
26+
"fmt"
27+
"strconv"
28+
29+
"k8s.io/api/storage/v1"
30+
"k8s.io/apimachinery/pkg/types"
31+
storagev1 "k8s.io/client-go/kubernetes/typed/storage/v1"
32+
)
33+
34+
const (
35+
annStorageClassIsDefault = "storageclass.kubernetes.io/is-default-class"
36+
)
37+
38+
// StorageClassIsDefault returns true if the given storage class is marked default,
39+
// false otherwise.
40+
func StorageClassIsDefault(sc *v1.StorageClass) bool {
41+
value, found := sc.GetObjectMeta().GetAnnotations()[annStorageClassIsDefault]
42+
if !found {
43+
return false
44+
}
45+
boolValue, err := strconv.ParseBool(value)
46+
if err != nil {
47+
return false
48+
}
49+
return boolValue
50+
}
51+
52+
// PatchStorageClassIsDefault changes the default flag of the given storage class.
53+
func PatchStorageClassIsDefault(cli storagev1.StorageV1Interface, name string, isDefault bool) error {
54+
jsonPatch := fmt.Sprintf(`{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"%v"}}}`, isDefault)
55+
if _, err := cli.StorageClasses().Patch(name, types.StrategicMergePatchType, []byte(jsonPatch)); err != nil {
56+
return maskAny(err)
57+
}
58+
return nil
59+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package k8sutil
24+
25+
import (
26+
"testing"
27+
28+
"k8s.io/api/storage/v1"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
)
31+
32+
// StorageClassIsDefault returns true if the given storage class is marked default,
33+
// false otherwise.
34+
func TestStorageClassIsDefault(t *testing.T) {
35+
tests := []struct {
36+
StorageClass v1.StorageClass
37+
IsDefault bool
38+
}{
39+
{v1.StorageClass{
40+
ObjectMeta: metav1.ObjectMeta{
41+
Annotations: map[string]string{},
42+
},
43+
}, false},
44+
{v1.StorageClass{
45+
ObjectMeta: metav1.ObjectMeta{
46+
Annotations: map[string]string{
47+
annStorageClassIsDefault: "false",
48+
},
49+
},
50+
}, false},
51+
{v1.StorageClass{
52+
ObjectMeta: metav1.ObjectMeta{
53+
Annotations: map[string]string{
54+
annStorageClassIsDefault: "foo",
55+
},
56+
},
57+
}, false},
58+
{v1.StorageClass{
59+
ObjectMeta: metav1.ObjectMeta{
60+
Annotations: map[string]string{
61+
annStorageClassIsDefault: "true",
62+
},
63+
},
64+
}, true},
65+
}
66+
for _, test := range tests {
67+
result := StorageClassIsDefault(&test.StorageClass)
68+
if result != test.IsDefault {
69+
t.Errorf("StorageClassIsDefault failed. Expected %v, got %v for %#v", test.IsDefault, result, test.StorageClass)
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)