2018-03-05 09:00:23 +00:00
|
|
|
//
|
|
|
|
// DISCLAIMER
|
|
|
|
//
|
2023-05-24 13:12:27 +00:00
|
|
|
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
|
2018-03-05 09:00:23 +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.
|
|
|
|
//
|
|
|
|
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
|
|
//
|
|
|
|
|
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
2021-03-23 15:47:28 +00:00
|
|
|
"context"
|
2018-03-05 09:00:23 +00:00
|
|
|
"fmt"
|
2018-03-06 09:54:12 +00:00
|
|
|
"strconv"
|
2018-03-05 09:00:23 +00:00
|
|
|
|
2020-09-08 07:40:44 +00:00
|
|
|
apps "k8s.io/api/apps/v1"
|
|
|
|
core "k8s.io/api/core/v1"
|
|
|
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2018-03-05 09:00:23 +00:00
|
|
|
|
2018-03-13 15:25:33 +00:00
|
|
|
api "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha"
|
|
|
|
"github.com/arangodb/kube-arangodb/pkg/storage/provisioner"
|
2022-07-11 11:49:47 +00:00
|
|
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
2018-03-13 15:25:33 +00:00
|
|
|
"github.com/arangodb/kube-arangodb/pkg/util/constants"
|
2022-07-11 11:49:47 +00:00
|
|
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
2018-03-13 15:25:33 +00:00
|
|
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
2022-11-02 07:29:46 +00:00
|
|
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors"
|
2018-03-05 09:00:23 +00:00
|
|
|
)
|
|
|
|
|
2018-03-06 09:54:12 +00:00
|
|
|
const (
|
|
|
|
roleProvisioner = "provisioner"
|
|
|
|
)
|
|
|
|
|
2018-03-05 09:00:23 +00:00
|
|
|
// ensureDaemonSet ensures that a daemonset is created for the given local storage.
|
2018-03-06 13:39:48 +00:00
|
|
|
// If it already exists, it is updated.
|
|
|
|
func (ls *LocalStorage) ensureDaemonSet(apiObject *api.ArangoLocalStorage) error {
|
2018-03-19 17:51:42 +00:00
|
|
|
ns := ls.config.Namespace
|
2020-09-08 07:40:44 +00:00
|
|
|
c := core.Container{
|
2018-03-06 09:54:12 +00:00
|
|
|
Name: "provisioner",
|
2018-03-06 13:39:48 +00:00
|
|
|
Image: ls.image,
|
|
|
|
ImagePullPolicy: ls.imagePullPolicy,
|
2018-03-05 09:00:23 +00:00
|
|
|
Args: []string{
|
|
|
|
"storage",
|
|
|
|
"provisioner",
|
2018-03-06 09:54:12 +00:00
|
|
|
"--port=" + strconv.Itoa(provisioner.DefaultPort),
|
|
|
|
},
|
2020-09-08 07:40:44 +00:00
|
|
|
Ports: []core.ContainerPort{
|
|
|
|
core.ContainerPort{
|
2018-03-06 09:54:12 +00:00
|
|
|
ContainerPort: int32(provisioner.DefaultPort),
|
|
|
|
},
|
|
|
|
},
|
2020-09-08 07:40:44 +00:00
|
|
|
Env: []core.EnvVar{
|
|
|
|
core.EnvVar{
|
2018-03-06 09:54:12 +00:00
|
|
|
Name: constants.EnvOperatorNodeName,
|
2020-09-08 07:40:44 +00:00
|
|
|
ValueFrom: &core.EnvVarSource{
|
|
|
|
FieldRef: &core.ObjectFieldSelector{
|
2018-03-06 09:54:12 +00:00
|
|
|
FieldPath: "spec.nodeName",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-03-05 09:00:23 +00:00
|
|
|
},
|
|
|
|
}
|
2020-09-08 07:40:44 +00:00
|
|
|
|
|
|
|
if apiObject.Spec.GetPrivileged() {
|
|
|
|
c.SecurityContext = &core.SecurityContext{
|
2023-05-24 13:12:27 +00:00
|
|
|
Privileged: util.NewType[bool](true),
|
2020-09-08 07:40:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-06 09:54:12 +00:00
|
|
|
dsLabels := k8sutil.LabelsForLocalStorage(apiObject.GetName(), roleProvisioner)
|
2020-09-08 07:40:44 +00:00
|
|
|
dsSpec := apps.DaemonSetSpec{
|
|
|
|
Selector: &meta.LabelSelector{
|
2018-03-06 13:39:48 +00:00
|
|
|
MatchLabels: dsLabels,
|
2018-03-05 09:00:23 +00:00
|
|
|
},
|
2020-09-08 07:40:44 +00:00
|
|
|
Template: core.PodTemplateSpec{
|
|
|
|
ObjectMeta: meta.ObjectMeta{
|
2018-03-06 13:39:48 +00:00
|
|
|
Labels: dsLabels,
|
2018-03-06 09:54:12 +00:00
|
|
|
},
|
2020-09-08 07:40:44 +00:00
|
|
|
Spec: core.PodSpec{
|
|
|
|
Containers: []core.Container{
|
2018-03-06 13:39:48 +00:00
|
|
|
c,
|
2018-03-05 09:00:23 +00:00
|
|
|
},
|
2022-03-04 13:27:50 +00:00
|
|
|
NodeSelector: apiObject.Spec.NodeSelector,
|
|
|
|
ImagePullSecrets: ls.imagePullSecrets,
|
2022-04-29 09:43:01 +00:00
|
|
|
Priority: apiObject.Spec.PodCustomization.GetPriority(),
|
2022-12-31 13:04:26 +00:00
|
|
|
Tolerations: apiObject.Spec.Tolerations,
|
2018-03-05 09:00:23 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2020-09-08 07:40:44 +00:00
|
|
|
|
2018-03-05 09:00:23 +00:00
|
|
|
for i, lp := range apiObject.Spec.LocalPath {
|
|
|
|
volName := fmt.Sprintf("local-path-%d", i)
|
2018-03-06 13:39:48 +00:00
|
|
|
c := &dsSpec.Template.Spec.Containers[0]
|
2018-03-05 09:00:23 +00:00
|
|
|
c.VolumeMounts = append(c.VolumeMounts,
|
2020-09-08 07:40:44 +00:00
|
|
|
core.VolumeMount{
|
2018-03-06 09:54:12 +00:00
|
|
|
Name: volName,
|
|
|
|
MountPath: lp,
|
2018-03-05 09:00:23 +00:00
|
|
|
})
|
2020-09-08 07:40:44 +00:00
|
|
|
hostPathType := core.HostPathDirectoryOrCreate
|
|
|
|
dsSpec.Template.Spec.Volumes = append(dsSpec.Template.Spec.Volumes, core.Volume{
|
2018-03-05 09:00:23 +00:00
|
|
|
Name: volName,
|
2020-09-08 07:40:44 +00:00
|
|
|
VolumeSource: core.VolumeSource{
|
|
|
|
HostPath: &core.HostPathVolumeSource{
|
2018-03-05 09:00:23 +00:00
|
|
|
Path: lp,
|
|
|
|
Type: &hostPathType,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
2020-09-08 07:40:44 +00:00
|
|
|
ds := &apps.DaemonSet{
|
|
|
|
ObjectMeta: meta.ObjectMeta{
|
2018-03-06 13:39:48 +00:00
|
|
|
Name: apiObject.GetName(),
|
|
|
|
Labels: dsLabels,
|
|
|
|
},
|
|
|
|
Spec: dsSpec,
|
|
|
|
}
|
2018-03-06 13:53:22 +00:00
|
|
|
// Attach DS to ArangoLocalStorage
|
2018-03-06 09:54:12 +00:00
|
|
|
ds.SetOwnerReferences(append(ds.GetOwnerReferences(), apiObject.AsOwner()))
|
|
|
|
// Create DS
|
2022-02-28 18:53:01 +00:00
|
|
|
if _, err := ls.deps.Client.Kubernetes().AppsV1().DaemonSets(ns).Create(context.Background(), ds, meta.CreateOptions{}); err != nil {
|
2022-11-02 07:29:46 +00:00
|
|
|
if kerrors.IsAlreadyExists(err) {
|
2018-03-06 13:39:48 +00:00
|
|
|
// Already exists, update it
|
|
|
|
} else {
|
2021-01-08 14:35:38 +00:00
|
|
|
return errors.WithStack(err)
|
2018-03-06 13:39:48 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We're done
|
2022-06-14 07:26:07 +00:00
|
|
|
ls.log.Debug("Created DaemonSet")
|
2018-03-06 13:39:48 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update existing DS
|
|
|
|
attempt := 0
|
|
|
|
for {
|
|
|
|
attempt++
|
|
|
|
|
|
|
|
// Load current DS
|
2022-02-28 18:53:01 +00:00
|
|
|
current, err := ls.deps.Client.Kubernetes().AppsV1().DaemonSets(ns).Get(context.Background(), ds.GetName(), meta.GetOptions{})
|
2018-03-06 13:39:48 +00:00
|
|
|
if err != nil {
|
2021-01-08 14:35:38 +00:00
|
|
|
return errors.WithStack(err)
|
2018-03-06 13:39:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update it
|
|
|
|
current.Spec = dsSpec
|
2022-11-02 07:29:46 +00:00
|
|
|
if _, err := ls.deps.Client.Kubernetes().AppsV1().DaemonSets(ns).Update(context.Background(), current, meta.UpdateOptions{}); kerrors.IsConflict(err) && attempt < 10 {
|
2022-12-31 13:04:26 +00:00
|
|
|
ls.log.Err(err).Debug("failed to patch DaemonSet spec")
|
2018-03-06 13:39:48 +00:00
|
|
|
// Failed to update, try again
|
|
|
|
continue
|
|
|
|
} else if err != nil {
|
2022-06-14 07:26:07 +00:00
|
|
|
ls.log.Err(err).Debug("failed to patch DaemonSet spec")
|
2021-01-08 14:35:38 +00:00
|
|
|
return errors.WithStack(errors.Newf("failed to patch DaemonSet spec: %v", err))
|
2018-03-06 13:39:48 +00:00
|
|
|
} else {
|
|
|
|
// Update was a success
|
2022-06-14 07:26:07 +00:00
|
|
|
ls.log.Debug("Updated DaemonSet")
|
2018-03-06 13:39:48 +00:00
|
|
|
return nil
|
|
|
|
}
|
2018-03-05 09:00:23 +00:00
|
|
|
}
|
|
|
|
}
|