1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

Merge pull request #35 from arangodb/storage-class-default

Implemented isDefault behavior of storage class
This commit is contained in:
Ewout Prangsma 2018-03-08 11:38:34 +01:00 committed by GitHub
commit 262e57d6f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 185 additions and 2 deletions

View file

@ -5,5 +5,6 @@ metadata:
spec:
storageClass:
name: my-local-ssd
isDefault: true
localPath:
- /var/lib/arango-storage

View file

@ -38,6 +38,7 @@ var (
// ensureStorageClass creates a storage class for the given local storage.
// If such a class already exists, the create is ignored.
func (l *LocalStorage) ensureStorageClass(apiObject *api.ArangoLocalStorage) error {
log := l.deps.Log
spec := apiObject.Spec.StorageClass
bindingMode := v1.VolumeBindingWaitForFirstConsumer
reclaimPolicy := corev1.PersistentVolumeReclaimRetain
@ -49,10 +50,60 @@ func (l *LocalStorage) ensureStorageClass(apiObject *api.ArangoLocalStorage) err
VolumeBindingMode: &bindingMode,
Provisioner: storageClassProvisioner,
}
if _, err := l.deps.KubeCli.StorageV1().StorageClasses().Create(sc); !k8sutil.IsAlreadyExists(err) && err != nil {
// Note: We do not attach the StorageClass to the apiObject (OwnerRef) because many
// ArangoLocalStorage resource may use the same StorageClass.
cli := l.deps.KubeCli.StorageV1()
if _, err := cli.StorageClasses().Create(sc); k8sutil.IsAlreadyExists(err) {
log.Debug().
Str("storageclass", sc.GetName()).
Msg("StorageClass already exists")
} else if err != nil {
log.Debug().Err(err).
Str("storageclass", sc.GetName()).
Msg("Failed to create StorageClass")
return maskAny(err)
} else {
log.Debug().
Str("storageclass", sc.GetName()).
Msg("StorageClass created")
}
if apiObject.Spec.StorageClass.IsDefault {
// UnMark current default (if any)
list, err := cli.StorageClasses().List(metav1.ListOptions{})
if err != nil {
log.Debug().Err(err).Msg("Listing StorageClasses failed")
return maskAny(err)
}
for _, scX := range list.Items {
if !k8sutil.StorageClassIsDefault(&scX) || scX.GetName() == sc.GetName() {
continue
}
// Mark storage class as non-default
if err := k8sutil.PatchStorageClassIsDefault(cli, scX.GetName(), false); err != nil {
log.Debug().
Err(err).
Str("storageclass", scX.GetName()).
Msg("Failed to mark StorageClass as not-default")
return maskAny(err)
}
log.Debug().
Str("storageclass", scX.GetName()).
Msg("Marked StorageClass as not-default")
}
// Mark StorageClass default
if err := k8sutil.PatchStorageClassIsDefault(cli, sc.GetName(), true); err != nil {
log.Debug().
Err(err).
Str("storageclass", sc.GetName()).
Msg("Failed to mark StorageClass as default")
return maskAny(err)
}
log.Debug().
Str("storageclass", sc.GetName()).
Msg("Marked StorageClass as default")
}
// TODO make default (if needed)
return nil
}

View file

@ -0,0 +1,59 @@
//
// DISCLAIMER
//
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//
package k8sutil
import (
"fmt"
"strconv"
"k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/types"
storagev1 "k8s.io/client-go/kubernetes/typed/storage/v1"
)
const (
annStorageClassIsDefault = "storageclass.kubernetes.io/is-default-class"
)
// StorageClassIsDefault returns true if the given storage class is marked default,
// false otherwise.
func StorageClassIsDefault(sc *v1.StorageClass) bool {
value, found := sc.GetObjectMeta().GetAnnotations()[annStorageClassIsDefault]
if !found {
return false
}
boolValue, err := strconv.ParseBool(value)
if err != nil {
return false
}
return boolValue
}
// PatchStorageClassIsDefault changes the default flag of the given storage class.
func PatchStorageClassIsDefault(cli storagev1.StorageV1Interface, name string, isDefault bool) error {
jsonPatch := fmt.Sprintf(`{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"%v"}}}`, isDefault)
if _, err := cli.StorageClasses().Patch(name, types.StrategicMergePatchType, []byte(jsonPatch)); err != nil {
return maskAny(err)
}
return nil
}

View file

@ -0,0 +1,72 @@
//
// DISCLAIMER
//
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//
package k8sutil
import (
"testing"
"k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// StorageClassIsDefault returns true if the given storage class is marked default,
// false otherwise.
func TestStorageClassIsDefault(t *testing.T) {
tests := []struct {
StorageClass v1.StorageClass
IsDefault bool
}{
{v1.StorageClass{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{},
},
}, false},
{v1.StorageClass{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
annStorageClassIsDefault: "false",
},
},
}, false},
{v1.StorageClass{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
annStorageClassIsDefault: "foo",
},
},
}, false},
{v1.StorageClass{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
annStorageClassIsDefault: "true",
},
},
}, true},
}
for _, test := range tests {
result := StorageClassIsDefault(&test.StorageClass)
if result != test.IsDefault {
t.Errorf("StorageClassIsDefault failed. Expected %v, got %v for %#v", test.IsDefault, result, test.StorageClass)
}
}
}