Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Devops 650 allow multiple updates of same resource #16

Merged
merged 3 commits into from
Jan 3, 2018
Merged
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
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 @@ -739,7 +739,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 @@ -766,11 +765,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 @@ -779,7 +778,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 @@ -795,8 +793,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 @@ -805,11 +811,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