Skip to content

Commit

Permalink
Merge pull request #16 from spotahome/devops-650-allow-multiple-updat…
Browse files Browse the repository at this point in the history
…es-of-same-resource

Devops 650 allow multiple updates of same resource
  • Loading branch information
jchanam authored Jan 3, 2018
2 parents 8c9a2d0 + 56622f7 commit bcf9b3a
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The following are targers that do not exist in the filesystem as real files and should be always executed by make
.PHONY: default build deps-development docker-build shell run image unit-test test generate go-generate get-deps update-deps
VERSION := 0.1.4
VERSION := 0.1.5

# Name of this service/application
SERVICE_NAME := redis-operator
Expand Down
22 changes: 14 additions & 8 deletions pkg/failover/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,6 @@ func (r *RedisFailoverKubeClient) createPodDisruptionBudget(rf *RedisFailover, n

// UpdateSentinelDeployment updates the spec of the existing sentinel deployment
func (r *RedisFailoverKubeClient) UpdateSentinelDeployment(rf *RedisFailover) error {
name := r.GetSentinelName(rf)
namespace := rf.Metadata.Namespace
logger := r.logger.WithField(logNameField, rf.Metadata.Name).WithField(logNamespaceField, rf.Metadata.Namespace)

Expand All @@ -786,11 +785,11 @@ func (r *RedisFailoverKubeClient) UpdateSentinelDeployment(rf *RedisFailover) er
oldSD.Spec.Template.Spec.Containers[0].Image = getRedisImage(rf)
oldSD.Spec.Template.Spec.Containers[0].Resources = getSentinelResources(rf.Spec)

if _, err := r.Client.AppsV1beta1().Deployments(namespace).Update(oldSD); err != nil {
if err := r.waitForStatefulset(r.GetRedisName(rf), namespace, rf.Spec.Redis.Replicas, logger); err != nil {
return err
}

if err := r.waitForDeployment(name, namespace, replicas, logger); err != nil {
if _, err := r.Client.AppsV1beta1().Deployments(namespace).Update(oldSD); err != nil {
return err
}

Expand All @@ -799,7 +798,6 @@ func (r *RedisFailoverKubeClient) UpdateSentinelDeployment(rf *RedisFailover) er

// UpdateRedisStatefulset updates the spec of the existing redis statefulset
func (r *RedisFailoverKubeClient) UpdateRedisStatefulset(rf *RedisFailover) error {
name := r.GetRedisName(rf)
namespace := rf.Metadata.Namespace
logger := r.logger.WithField(logNameField, rf.Metadata.Name).WithField(logNamespaceField, rf.Metadata.Namespace)

Expand All @@ -815,8 +813,16 @@ func (r *RedisFailoverKubeClient) UpdateRedisStatefulset(rf *RedisFailover) erro
oldSS.Spec.Template.Spec.Containers[0].Image = getRedisImage(rf)

if rf.Spec.Redis.Exporter {
exporter := createRedisExporterContainer()
oldSS.Spec.Template.Spec.Containers = append(oldSS.Spec.Template.Spec.Containers, exporter)
found := false
for _, container := range oldSS.Spec.Template.Spec.Containers {
if container.Name == exporterContainerName {
found = true
}
}
if !found {
exporter := createRedisExporterContainer()
oldSS.Spec.Template.Spec.Containers = append(oldSS.Spec.Template.Spec.Containers, exporter)
}
} else {
for pos, container := range oldSS.Spec.Template.Spec.Containers {
if container.Name == exporterContainerName {
Expand All @@ -825,11 +831,11 @@ func (r *RedisFailoverKubeClient) UpdateRedisStatefulset(rf *RedisFailover) erro
}
}

if _, err := r.Client.AppsV1beta1().StatefulSets(namespace).Update(oldSS); err != nil {
if err := r.waitForDeployment(r.GetSentinelName(rf), namespace, rf.Spec.Sentinel.Replicas, logger); err != nil {
return err
}

if err := r.waitForStatefulset(name, namespace, replicas, logger); err != nil {
if _, err := r.Client.AppsV1beta1().StatefulSets(namespace).Update(oldSS); err != nil {
return err
}

Expand Down
128 changes: 128 additions & 0 deletions pkg/failover/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1690,9 +1690,29 @@ func TestUpdateSentinelDeploymentError(t *testing.T) {
return true, deployment, nil
})

statefulsetSize := int32(3)
// Add a reactor when calling pods
client.Fake.AddReactor("get", "statefulsets", func(action k8stesting.Action) (bool, runtime.Object, error) {
// Create the statefulset to be returned with Replicas = 3
statefulset := &v1beta1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: redisName,
Namespace: namespace,
},
Status: v1beta1.StatefulSetStatus{
ReadyReplicas: statefulsetSize,
},
}

// Return the statefulset as if we where the API responding to GET statefulsets
return true, statefulset, nil
})

mc := &mocks.Clock{}
mc.On("NewTicker", mock.Anything).
Once().Return(time.NewTicker(1))
mc.On("After", mock.Anything).
Once().Return(time.After(time.Hour))
r := failover.NewRedisFailoverKubeClient(client, mc, log.Nil)

redisFailover := &failover.RedisFailover{
Expand Down Expand Up @@ -1757,6 +1777,22 @@ func TestUpdateSentinelDeploymentTimeoutError(t *testing.T) {
return true, deployment, nil
})

client.Fake.AddReactor("get", "statefulsets", func(action k8stesting.Action) (bool, runtime.Object, error) {
// Create the statefulset to be returned with Replicas = 3
statefulset := &v1beta1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: redisName,
Namespace: namespace,
},
Status: v1beta1.StatefulSetStatus{
ReadyReplicas: int32(3),
},
}

// Return the statefulset as if we where the API responding to GET statefulsets
return true, statefulset, nil
})

mc := &mocks.Clock{}
mc.On("NewTicker", mock.Anything).
Once().Return(time.NewTicker(time.Hour))
Expand Down Expand Up @@ -1849,6 +1885,24 @@ func TestUpdateSentinelDeployment(t *testing.T) {
return true, deployment, nil
})

statefulsetSize := int32(3)
// Add a reactor when calling pods
client.Fake.AddReactor("get", "statefulsets", func(action k8stesting.Action) (bool, runtime.Object, error) {
// Create the statefulset to be returned with Replicas = 3
statefulset := &v1beta1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Name: redisName,
Namespace: namespace,
},
Status: v1beta1.StatefulSetStatus{
ReadyReplicas: statefulsetSize,
},
}

// Return the statefulset as if we where the API responding to GET statefulsets
return true, statefulset, nil
})

mc := &mocks.Clock{}
mc.On("NewTicker", mock.Anything).
Once().Return(time.NewTicker(1))
Expand Down Expand Up @@ -1949,9 +2003,27 @@ func TestUpdateRedisStatefulsetError(t *testing.T) {
return true, nil, errors.New("")
})

replicas := int32(3)

client.Fake.AddReactor("get", "deployments", func(action k8stesting.Action) (bool, runtime.Object, error) {
deployment := &v1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: sentinelName,
Namespace: namespace,
},
Status: v1beta1.DeploymentStatus{
ReadyReplicas: replicas,
UpdatedReplicas: replicas,
},
}
return true, deployment, nil
})

mc := &mocks.Clock{}
mc.On("NewTicker", mock.Anything).
Once().Return(time.NewTicker(1))
mc.On("After", mock.Anything).
Once().Return(time.After(time.Hour))
r := failover.NewRedisFailoverKubeClient(client, mc, log.Nil)

redisFailover := &failover.RedisFailover{
Expand Down Expand Up @@ -2055,6 +2127,20 @@ func TestUpdateRedisStatefulsetWithUpdate(t *testing.T) {
return true, nil, nil
})

client.Fake.AddReactor("get", "deployments", func(action k8stesting.Action) (bool, runtime.Object, error) {
deployment := &v1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: sentinelName,
Namespace: namespace,
},
Status: v1beta1.DeploymentStatus{
ReadyReplicas: replicas,
UpdatedReplicas: replicas,
},
}
return true, deployment, nil
})

mc := &mocks.Clock{}
mc.On("NewTicker", mock.Anything).
Once().Return(time.NewTicker(1))
Expand Down Expand Up @@ -2179,6 +2265,20 @@ func TestUpdateRedisStatefulsetWithoutUpdate(t *testing.T) {
return true, nil, nil
})

client.Fake.AddReactor("get", "deployments", func(action k8stesting.Action) (bool, runtime.Object, error) {
deployment := &v1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: sentinelName,
Namespace: namespace,
},
Status: v1beta1.DeploymentStatus{
ReadyReplicas: replicas,
UpdatedReplicas: replicas,
},
}
return true, deployment, nil
})

mc := &mocks.Clock{}
mc.On("NewTicker", mock.Anything).
Once().Return(time.NewTicker(1))
Expand Down Expand Up @@ -2277,6 +2377,20 @@ func TestUpdateRedisStatefulsetTimeoutError(t *testing.T) {
return true, nil, nil
})

client.Fake.AddReactor("get", "deployments", func(action k8stesting.Action) (bool, runtime.Object, error) {
deployment := &v1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: sentinelName,
Namespace: namespace,
},
Status: v1beta1.DeploymentStatus{
ReadyReplicas: replicas,
UpdatedReplicas: replicas,
},
}
return true, deployment, nil
})

mc := &mocks.Clock{}
mc.On("NewTicker", mock.Anything).
Once().Return(time.NewTicker(time.Hour))
Expand Down Expand Up @@ -2385,6 +2499,20 @@ func TestUpdateRedisStatefulset(t *testing.T) {
return true, nil, nil
})

client.Fake.AddReactor("get", "deployments", func(action k8stesting.Action) (bool, runtime.Object, error) {
deployment := &v1beta1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: sentinelName,
Namespace: namespace,
},
Status: v1beta1.DeploymentStatus{
ReadyReplicas: replicas,
UpdatedReplicas: replicas,
},
}
return true, deployment, nil
})

mc := &mocks.Clock{}
mc.On("NewTicker", mock.Anything).
Once().Return(time.NewTicker(1))
Expand Down

0 comments on commit bcf9b3a

Please sign in to comment.