2018-12-19 14:26:16 +00:00
|
|
|
/*
|
2019-04-03 08:46:15 +00:00
|
|
|
Copyright 2018 The Ceph-CSI Authors.
|
2018-12-19 14:26:16 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package util
|
|
|
|
|
|
|
|
import (
|
2020-04-14 07:04:33 +00:00
|
|
|
"context"
|
2018-12-19 14:26:16 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"regexp"
|
|
|
|
|
2019-03-13 05:09:58 +00:00
|
|
|
v1 "k8s.io/api/core/v1"
|
2018-12-19 14:33:37 +00:00
|
|
|
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
2018-12-19 14:26:16 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
k8s "k8s.io/client-go/kubernetes"
|
|
|
|
"k8s.io/client-go/rest"
|
|
|
|
"k8s.io/client-go/tools/clientcmd"
|
2020-04-14 07:04:33 +00:00
|
|
|
"k8s.io/klog"
|
2018-12-19 14:26:16 +00:00
|
|
|
)
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// K8sCMCache to store metadata
|
2018-12-19 14:26:16 +00:00
|
|
|
type K8sCMCache struct {
|
|
|
|
Client *k8s.Clientset
|
|
|
|
Namespace string
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
defaultNamespace = "default"
|
|
|
|
|
|
|
|
cmLabel = "csi-metadata"
|
|
|
|
cmDataKey = "content"
|
|
|
|
|
|
|
|
csiMetadataLabelAttr = "com.ceph.ceph-csi/metadata"
|
|
|
|
)
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// GetK8sNamespace returns pod namespace. if pod namespace is empty
|
|
|
|
// it returns default namespace
|
2018-12-19 14:26:16 +00:00
|
|
|
func GetK8sNamespace() string {
|
|
|
|
namespace := os.Getenv("POD_NAMESPACE")
|
|
|
|
if namespace == "" {
|
|
|
|
return defaultNamespace
|
|
|
|
}
|
|
|
|
return namespace
|
|
|
|
}
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// NewK8sClient create kubernetes client
|
2018-12-19 14:26:16 +00:00
|
|
|
func NewK8sClient() *k8s.Clientset {
|
|
|
|
var cfg *rest.Config
|
|
|
|
var err error
|
|
|
|
cPath := os.Getenv("KUBERNETES_CONFIG_PATH")
|
|
|
|
if cPath != "" {
|
|
|
|
cfg, err = clientcmd.BuildConfigFromFlags("", cPath)
|
|
|
|
if err != nil {
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.Errorf("Failed to get cluster config with error: %v\n", err)
|
2018-12-19 14:26:16 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cfg, err = rest.InClusterConfig()
|
|
|
|
if err != nil {
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.Errorf("Failed to get cluster config with error: %v\n", err)
|
2018-12-19 14:26:16 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
client, err := k8s.NewForConfig(cfg)
|
|
|
|
if err != nil {
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.Errorf("Failed to create client with error: %v\n", err)
|
2018-12-19 14:26:16 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
return client
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k8scm *K8sCMCache) getMetadataCM(resourceID string) (*v1.ConfigMap, error) {
|
2020-04-14 07:04:33 +00:00
|
|
|
cm, err := k8scm.Client.CoreV1().ConfigMaps(k8scm.Namespace).Get(context.TODO(), resourceID, metav1.GetOptions{})
|
2018-12-19 14:26:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return cm, nil
|
|
|
|
}
|
|
|
|
|
2019-06-10 06:48:41 +00:00
|
|
|
// ForAll list the metadata in configmaps and filters outs based on the pattern
|
2018-12-19 14:26:16 +00:00
|
|
|
func (k8scm *K8sCMCache) ForAll(pattern string, destObj interface{}, f ForAllFunc) error {
|
|
|
|
listOpts := metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", csiMetadataLabelAttr, cmLabel)}
|
2020-04-14 07:04:33 +00:00
|
|
|
cms, err := k8scm.Client.CoreV1().ConfigMaps(k8scm.Namespace).List(context.TODO(), listOpts)
|
2018-12-19 14:26:16 +00:00
|
|
|
if err != nil {
|
2020-06-25 11:30:04 +00:00
|
|
|
return fmt.Errorf("k8s-cm-cache: failed to list metadata configmaps: %w", err)
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
|
|
|
|
2019-06-10 06:48:41 +00:00
|
|
|
for i := range cms.Items {
|
|
|
|
data := cms.Items[i].Data[cmDataKey]
|
|
|
|
match, err := regexp.MatchString(pattern, cms.Items[i].ObjectMeta.Name)
|
2018-12-19 14:26:16 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !match {
|
|
|
|
continue
|
|
|
|
}
|
2019-01-17 06:49:35 +00:00
|
|
|
if err = json.Unmarshal([]byte(data), destObj); err != nil {
|
2020-06-25 11:30:04 +00:00
|
|
|
return fmt.Errorf("k8s-cm-cache: JSON unmarshaling failed for configmap %s: %w", cms.Items[i].ObjectMeta.Name, err)
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
2019-06-10 06:48:41 +00:00
|
|
|
if err = f(cms.Items[i].ObjectMeta.Name); err != nil {
|
2018-12-19 14:26:16 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// Create stores the metadata in configmaps with identifier name
|
2018-12-19 14:26:16 +00:00
|
|
|
func (k8scm *K8sCMCache) Create(identifier string, data interface{}) error {
|
|
|
|
cm, err := k8scm.getMetadataCM(identifier)
|
|
|
|
if cm != nil && err == nil {
|
2019-02-20 14:04:30 +00:00
|
|
|
klog.V(4).Infof("k8s-cm-cache: configmap %s already exists, skipping configmap creation", identifier)
|
2018-12-19 14:26:16 +00:00
|
|
|
return nil
|
2019-01-17 05:07:59 +00:00
|
|
|
}
|
|
|
|
dataJSON, err := json.Marshal(data)
|
|
|
|
if err != nil {
|
2020-06-25 11:30:04 +00:00
|
|
|
return fmt.Errorf("k8s-cm-cache: JSON marshaling failed for configmap %s: %w", identifier, err)
|
2019-01-17 05:07:59 +00:00
|
|
|
}
|
|
|
|
cm = &v1.ConfigMap{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: identifier,
|
|
|
|
Namespace: k8scm.Namespace,
|
|
|
|
Labels: map[string]string{
|
|
|
|
csiMetadataLabelAttr: cmLabel,
|
2018-12-19 14:26:16 +00:00
|
|
|
},
|
2019-01-17 05:07:59 +00:00
|
|
|
},
|
|
|
|
Data: map[string]string{},
|
|
|
|
}
|
|
|
|
cm.Data[cmDataKey] = string(dataJSON)
|
2018-12-19 14:26:16 +00:00
|
|
|
|
2020-04-14 07:04:33 +00:00
|
|
|
_, err = k8scm.Client.CoreV1().ConfigMaps(k8scm.Namespace).Create(context.TODO(), cm, metav1.CreateOptions{})
|
2019-01-17 05:07:59 +00:00
|
|
|
if err != nil {
|
|
|
|
if apierrs.IsAlreadyExists(err) {
|
2019-02-20 14:04:30 +00:00
|
|
|
klog.V(4).Infof("k8s-cm-cache: configmap %s already exists", identifier)
|
2019-01-17 05:07:59 +00:00
|
|
|
return nil
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
2020-06-25 11:30:04 +00:00
|
|
|
return fmt.Errorf("k8s-cm-cache: couldn't persist %s metadata as configmap: %w", identifier, err)
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
2019-01-17 05:07:59 +00:00
|
|
|
|
2019-02-20 14:04:30 +00:00
|
|
|
klog.V(4).Infof("k8s-cm-cache: configmap %s successfully created", identifier)
|
2018-12-19 14:26:16 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// Get retrieves the metadata in configmaps with identifier name
|
2018-12-19 14:26:16 +00:00
|
|
|
func (k8scm *K8sCMCache) Get(identifier string, data interface{}) error {
|
|
|
|
cm, err := k8scm.getMetadataCM(identifier)
|
|
|
|
if err != nil {
|
2019-02-25 17:05:20 +00:00
|
|
|
if apierrs.IsNotFound(err) {
|
|
|
|
return &CacheEntryNotFound{err}
|
|
|
|
}
|
|
|
|
|
2018-12-19 14:26:16 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = json.Unmarshal([]byte(cm.Data[cmDataKey]), data)
|
|
|
|
if err != nil {
|
2020-06-25 11:30:04 +00:00
|
|
|
return fmt.Errorf("k8s-cm-cache: JSON unmarshaling failed for configmap %s: %w", identifier, err)
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-28 11:47:06 +00:00
|
|
|
// Delete deletes the metadata in configmaps with identifier name
|
2018-12-19 14:26:16 +00:00
|
|
|
func (k8scm *K8sCMCache) Delete(identifier string) error {
|
2020-04-14 07:04:33 +00:00
|
|
|
err := k8scm.Client.CoreV1().ConfigMaps(k8scm.Namespace).Delete(context.TODO(), identifier, metav1.DeleteOptions{})
|
2018-12-19 14:26:16 +00:00
|
|
|
if err != nil {
|
2019-02-20 14:04:30 +00:00
|
|
|
if apierrs.IsNotFound(err) {
|
|
|
|
klog.V(4).Infof("k8s-cm-cache: cannot delete missing metadata configmap %s, assuming it's already deleted", identifier)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-25 11:30:04 +00:00
|
|
|
return fmt.Errorf("k8s-cm-cache: couldn't delete metadata configmap %s: %w", identifier, err)
|
2018-12-19 14:26:16 +00:00
|
|
|
}
|
2019-02-04 13:05:43 +00:00
|
|
|
klog.V(4).Infof("k8s-cm-cache: successfully deleted metadata configmap %s", identifier)
|
2018-12-19 14:26:16 +00:00
|
|
|
return nil
|
|
|
|
}
|