forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
recreate.go
119 lines (99 loc) · 4.31 KB
/
recreate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package recreate
import (
"fmt"
"time"
"github.com/golang/glog"
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
deployapi "github.com/openshift/origin/pkg/deploy/api"
deployutil "github.com/openshift/origin/pkg/deploy/util"
)
// RecreateDeploymentStrategy is a simple strategy appropriate as a default. Its behavior is to increase the
// replica count of the new deployment to 1, and to decrease the replica count of previous deployments
// to zero.
//
// A failure to disable any existing deployments will be considered a deployment failure.
type RecreateDeploymentStrategy struct {
// client is used to interact with ReplicatonControllers.
client replicationControllerClient
// codec is used to decode DeploymentConfigs contained in deployments.
codec runtime.Codec
retryTimeout time.Duration
retryPeriod time.Duration
}
func NewRecreateDeploymentStrategy(client kclient.Interface, codec runtime.Codec) *RecreateDeploymentStrategy {
return &RecreateDeploymentStrategy{
client: &realReplicationController{client},
codec: codec,
retryTimeout: 10 * time.Second,
retryPeriod: 1 * time.Second,
}
}
// Deploy makes deployment active and disables oldDeployments.
func (s *RecreateDeploymentStrategy) Deploy(deployment *kapi.ReplicationController, oldDeployments []kapi.ObjectReference) error {
var err error
var deploymentConfig *deployapi.DeploymentConfig
if deploymentConfig, err = deployutil.DecodeDeploymentConfig(deployment, s.codec); err != nil {
return fmt.Errorf("Couldn't decode DeploymentConfig from deployment %s: %v", deployment.Name, err)
}
if err = s.updateReplicas(deployment.Namespace, deployment.Name, deploymentConfig.Template.ControllerTemplate.Replicas); err != nil {
return err
}
// For this simple deploy, disable previous replication controllers.
glog.Infof("Found %d prior deployments to disable", len(oldDeployments))
allProcessed := true
for _, oldDeployment := range oldDeployments {
if err = s.updateReplicas(oldDeployment.Namespace, oldDeployment.Name, 0); err != nil {
glog.Errorf("%v", err)
allProcessed = false
}
}
if !allProcessed {
return fmt.Errorf("Failed to disable all prior deployments for new deployment %s", deployment.Name)
}
glog.Infof("Deployment %s successfully made active", deployment.Name)
return nil
}
// updateReplicas attempts to set the given deployment's replicaCount using retry logic.
func (s *RecreateDeploymentStrategy) updateReplicas(namespace, name string, replicaCount int) error {
var err error
var deployment *kapi.ReplicationController
timeout := time.After(s.retryTimeout)
for {
select {
case <-timeout:
return fmt.Errorf("Couldn't successfully update deployment %s replica count to %d (timeout exceeded)", deployment.Name, replicaCount)
default:
if deployment, err = s.client.getReplicationController(namespace, name); err != nil {
glog.Errorf("Couldn't get deployment %s/%s: %v", namespace, name, err)
} else {
deployment.Spec.Replicas = replicaCount
glog.Infof("Updating deployment %s/%s replica count to %d", namespace, name, replicaCount)
if _, err = s.client.updateReplicationController(namespace, deployment); err == nil {
return nil
}
// For conflict errors, retry immediately
if kerrors.IsConflict(err) {
continue
}
glog.Errorf("Error updating deployment %s/%s replica count to %d: %v", namespace, name, replicaCount, err)
}
time.Sleep(s.retryPeriod)
}
}
}
type replicationControllerClient interface {
getReplicationController(namespace, name string) (*kapi.ReplicationController, error)
updateReplicationController(namespace string, ctrl *kapi.ReplicationController) (*kapi.ReplicationController, error)
}
type realReplicationController struct {
client kclient.Interface
}
func (r realReplicationController) getReplicationController(namespace string, name string) (*kapi.ReplicationController, error) {
return r.client.ReplicationControllers(namespace).Get(name)
}
func (r realReplicationController) updateReplicationController(namespace string, ctrl *kapi.ReplicationController) (*kapi.ReplicationController, error) {
return r.client.ReplicationControllers(namespace).Update(ctrl)
}