Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

WIP: Allow updating cassandra nodepool resource requests #363

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/apis/navigator/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type CassandraClusterStatus struct {

type CassandraClusterNodePoolStatus struct {
ReadyReplicas int32
Resources v1.ResourceRequirements
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/navigator/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ type CassandraClusterStatus struct {
type CassandraClusterNodePoolStatus struct {
// The number of replicas in the node pool that are currently 'Ready'.
ReadyReplicas int32 `json:"readyReplicas"`

// The applied resource requirements for this nodepool
Resources v1.ResourceRequirements `json:"resources,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/navigator/v1alpha1/zz_generated.conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ func Convert_navigator_CassandraClusterNodePool_To_v1alpha1_CassandraClusterNode

func autoConvert_v1alpha1_CassandraClusterNodePoolStatus_To_navigator_CassandraClusterNodePoolStatus(in *CassandraClusterNodePoolStatus, out *navigator.CassandraClusterNodePoolStatus, s conversion.Scope) error {
out.ReadyReplicas = in.ReadyReplicas
out.Resources = in.Resources
return nil
}

Expand All @@ -207,6 +208,7 @@ func Convert_v1alpha1_CassandraClusterNodePoolStatus_To_navigator_CassandraClust

func autoConvert_navigator_CassandraClusterNodePoolStatus_To_v1alpha1_CassandraClusterNodePoolStatus(in *navigator.CassandraClusterNodePoolStatus, out *CassandraClusterNodePoolStatus, s conversion.Scope) error {
out.ReadyReplicas = in.ReadyReplicas
out.Resources = in.Resources
return nil
}

Expand Down
5 changes: 4 additions & 1 deletion pkg/apis/navigator/v1alpha1/zz_generated.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ func (in *CassandraClusterNodePool) DeepCopy() *CassandraClusterNodePool {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CassandraClusterNodePoolStatus) DeepCopyInto(out *CassandraClusterNodePoolStatus) {
*out = *in
in.Resources.DeepCopyInto(&out.Resources)
return
}

Expand Down Expand Up @@ -206,7 +207,9 @@ func (in *CassandraClusterStatus) DeepCopyInto(out *CassandraClusterStatus) {
in, out := &in.NodePools, &out.NodePools
*out = make(map[string]CassandraClusterNodePoolStatus, len(*in))
for key, val := range *in {
(*out)[key] = val
newVal := new(CassandraClusterNodePoolStatus)
val.DeepCopyInto(newVal)
(*out)[key] = *newVal
}
}
return
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/navigator/validation/cassandra.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,15 @@ func ValidateCassandraClusterUpdate(old, new *navigator.CassandraCluster) field.
restorePersistence := newNp.Persistence
newNp.Persistence = oldNp.Persistence

restoreResources := newNp.Resources
newNp.Resources = oldNp.Resources

if !reflect.DeepEqual(newNp, oldNp) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to nodepool for fields other than 'replicas' and 'persistence' are forbidden."))
}
newNp.Replicas = restoreReplicas
newNp.Persistence = restorePersistence
newNp.Resources = restoreResources

break
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/apis/navigator/zz_generated.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ func (in *CassandraClusterNodePool) DeepCopy() *CassandraClusterNodePool {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CassandraClusterNodePoolStatus) DeepCopyInto(out *CassandraClusterNodePoolStatus) {
*out = *in
in.Resources.DeepCopyInto(&out.Resources)
return
}

Expand Down Expand Up @@ -206,7 +207,9 @@ func (in *CassandraClusterStatus) DeepCopyInto(out *CassandraClusterStatus) {
in, out := &in.NodePools, &out.NodePools
*out = make(map[string]CassandraClusterNodePoolStatus, len(*in))
for key, val := range *in {
(*out)[key] = val
newVal := new(CassandraClusterNodePoolStatus)
val.DeepCopyInto(newVal)
(*out)[key] = *newVal
}
}
return
Expand Down
83 changes: 83 additions & 0 deletions pkg/controllers/cassandra/actions/setresources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package actions

import (
"fmt"

corev1 "k8s.io/api/core/v1"

"github.com/golang/glog"
"github.com/pkg/errors"

"github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1"
"github.com/jetstack/navigator/pkg/controllers"
"github.com/jetstack/navigator/pkg/controllers/cassandra/nodepool"
"github.com/jetstack/navigator/pkg/util/resources"
)

type SetResources struct {
Cluster *v1alpha1.CassandraCluster
NodePool *v1alpha1.CassandraClusterNodePool
}

var _ controllers.Action = &SetResources{}

func (a *SetResources) Name() string {
return "SetResources"
}

func (a *SetResources) Execute(s *controllers.State) error {
baseSet := nodepool.StatefulSetForCluster(a.Cluster, a.NodePool)
existingSet, err := s.StatefulSetLister.
StatefulSets(baseSet.Namespace).Get(baseSet.Name)
if err != nil {
return errors.Wrap(err, "unable to find statefulset")
}

var cassContainerIndex int
var container *corev1.Container
for i, _ := range existingSet.Spec.Template.Spec.Containers {
if existingSet.Spec.Template.Spec.Containers[i].Name == "cassandra" {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"cassandra" should be placed in a constant somewhere

cassContainerIndex = i
container = &existingSet.Spec.Template.Spec.Containers[i]
}
}

if container == nil {
return fmt.Errorf("unable to find cassandra container in StatefulSet %s/%s",
existingSet.Namespace, existingSet.Name,
)
}

if resources.RequirementsEqual(container.Resources, a.NodePool.Resources) {
glog.V(4).Infof(
"SetResources not necessary because StatefulSet '%s/%s' "+
"already has the desired resources value: %v",
existingSet.Namespace, existingSet.Name,
container.Resources,
)
return nil
}

newSet := existingSet.DeepCopy()
newSet.Spec.Template.Spec.Containers[cassContainerIndex].Resources = a.NodePool.Resources
glog.V(4).Infof(
"Setting cassandra resources %s/%s from %v to %v",
newSet.Namespace, newSet.Name,
existingSet.Spec.Template.Spec.Containers[cassContainerIndex].Resources,
a.NodePool.Resources,
)
_, err = s.Clientset.AppsV1beta1().
StatefulSets(newSet.Namespace).Update(newSet)
if err != nil {
return errors.Wrap(err, "unable to update statefulset resources")
}
s.Recorder.Eventf(
a.Cluster,
corev1.EventTypeNormal,
a.Name(),
"SetResources: NodePool=%s/%s/%s, Resources=%v",
a.Cluster.Namespace, a.Cluster.Name, a.NodePool.Name,
a.NodePool.Resources,
)
return nil
}
11 changes: 11 additions & 0 deletions pkg/controllers/cassandra/cluster_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/jetstack/navigator/pkg/controllers/cassandra/seedlabeller"
"github.com/jetstack/navigator/pkg/controllers/cassandra/service"
"github.com/jetstack/navigator/pkg/controllers/cassandra/serviceaccount"
"github.com/jetstack/navigator/pkg/util/resources"
)

const (
Expand Down Expand Up @@ -212,6 +213,16 @@ func NextAction(c *v1alpha1.CassandraCluster) controllers.Action {
NodePool: &np,
}
}

if !resources.RequirementsEqual(np.Resources, nps.Resources) {
return &actions.SetResources{
Cluster: c,
NodePool: &np,
}
} else {
glog.Warningf("requirementsEqual")
}

}
return nil
}
13 changes: 13 additions & 0 deletions pkg/controllers/cassandra/nodepool/nodepool.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nodepool

import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
appslisters "k8s.io/client-go/listers/apps/v1beta1"
"k8s.io/client-go/tools/record"
Expand Down Expand Up @@ -48,6 +49,18 @@ func (e *defaultCassandraClusterNodepoolControl) updateStatus(cluster *v1alpha1.
npName := ss.Labels[v1alpha1.CassandraNodePoolNameLabel]
nps := cluster.Status.NodePools[npName]
nps.ReadyReplicas = ss.Status.ReadyReplicas

var container *apiv1.Container
for i, _ := range ss.Spec.Template.Spec.Containers {
if ss.Spec.Template.Spec.Containers[i].Name == "cassandra" {
container = &ss.Spec.Template.Spec.Containers[i]
}
}

if container != nil {
nps.Resources = container.Resources
}

cluster.Status.NodePools[npName] = nps
}
return nil
Expand Down
25 changes: 25 additions & 0 deletions pkg/util/resources/resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package resources

import (
apiv1 "k8s.io/api/core/v1"
)

func RequirementsEqual(a, b apiv1.ResourceRequirements) bool {
if a.Limits.Cpu().Cmp(*b.Limits.Cpu()) != 0 {
return false
}

if a.Limits.Memory().Cmp(*b.Limits.Memory()) != 0 {
return false
}

if a.Requests.Cpu().Cmp(*b.Requests.Cpu()) != 0 {
return false
}

if a.Requests.Memory().Cmp(*b.Requests.Memory()) != 0 {
return false
}

return true
}