Browse code

deploy: add pausing for deploymentconfigs

Michail Kargakis authored on 2016/05/02 23:56:54
Showing 8 changed files
... ...
@@ -211,6 +211,9 @@ func (o DeployOptions) RunDeploy() error {
211 211
 // deploy launches a new deployment unless there's already a deployment
212 212
 // process in progress for config.
213 213
 func (o DeployOptions) deploy(config *deployapi.DeploymentConfig, out io.Writer) error {
214
+	if config.Spec.Paused {
215
+		return fmt.Errorf("cannot deploy a paused deployment config")
216
+	}
214 217
 	// TODO: This implies that deploymentconfig.status.latestVersion is always synced. Currently,
215 218
 	// that's the case because clients (oc, trigger controllers) are updating the status directly.
216 219
 	// Clients should be acting either on spec or on annotations and status updates should be a
... ...
@@ -244,6 +247,9 @@ func (o DeployOptions) deploy(config *deployapi.DeploymentConfig, out io.Writer)
244 244
 // the deployment to be retried. An error is returned if the deployment is not
245 245
 // currently in a failed state.
246 246
 func (o DeployOptions) retry(config *deployapi.DeploymentConfig, out io.Writer) error {
247
+	if config.Spec.Paused {
248
+		return fmt.Errorf("cannot retry a paused deployment config")
249
+	}
247 250
 	if config.Status.LatestVersion == 0 {
248 251
 		return fmt.Errorf("no deployments found for %s/%s", config.Namespace, config.Name)
249 252
 	}
... ...
@@ -297,6 +303,9 @@ func (o DeployOptions) retry(config *deployapi.DeploymentConfig, out io.Writer)
297 297
 
298 298
 // cancel cancels any deployment process in progress for config.
299 299
 func (o DeployOptions) cancel(config *deployapi.DeploymentConfig, out io.Writer) error {
300
+	if config.Spec.Paused {
301
+		return fmt.Errorf("cannot cancel a paused deployment config")
302
+	}
300 303
 	deployments, err := o.kubeClient.ReplicationControllers(config.Namespace).List(kapi.ListOptions{LabelSelector: deployutil.ConfigSelector(config.Name)})
301 304
 	if err != nil {
302 305
 		return err
... ...
@@ -150,7 +150,7 @@ func (o *RollbackOptions) Complete(f *clientcmd.Factory, args []string, out io.W
150 150
 // a rollback.
151 151
 func (o *RollbackOptions) Validate() error {
152 152
 	if len(o.TargetName) == 0 {
153
-		return fmt.Errorf("a deployment or deploymentconfig name is required")
153
+		return fmt.Errorf("a deployment or deployment config name is required")
154 154
 	}
155 155
 	if o.DesiredVersion < 0 {
156 156
 		return fmt.Errorf("the to version must be >= 0")
... ...
@@ -187,9 +187,21 @@ func (o *RollbackOptions) Run() error {
187 187
 	var target *kapi.ReplicationController
188 188
 	switch r := obj.(type) {
189 189
 	case *kapi.ReplicationController:
190
+		dcName := deployutil.DeploymentConfigNameFor(r)
191
+		dc, err := o.oc.DeploymentConfigs(r.Namespace).Get(dcName)
192
+		if err != nil {
193
+			return err
194
+		}
195
+		if dc.Spec.Paused {
196
+			return fmt.Errorf("cannot rollback a paused deployment config")
197
+		}
198
+
190 199
 		// A specific deployment was used.
191 200
 		target = r
192 201
 	case *deployapi.DeploymentConfig:
202
+		if r.Spec.Paused {
203
+			return fmt.Errorf("cannot rollback a paused deployment config")
204
+		}
193 205
 		// A deploymentconfig was used. Find the target deployment by the
194 206
 		// specified version, or by a lookup of the last completed deployment if
195 207
 		// no version was supplied.
... ...
@@ -200,7 +212,7 @@ func (o *RollbackOptions) Run() error {
200 200
 		target = deployment
201 201
 	}
202 202
 	if target == nil {
203
-		return fmt.Errorf("%s is not a valid deployment or deploymentconfig", o.TargetName)
203
+		return fmt.Errorf("%s is not a valid deployment or deployment config", o.TargetName)
204 204
 	}
205 205
 
206 206
 	// Set up the rollback and generate a new rolled back config.
... ...
@@ -297,7 +309,7 @@ func (o *RollbackOptions) findResource(targetName string) (runtime.Object, error
297 297
 		break
298 298
 	}
299 299
 	if obj == nil {
300
-		return nil, fmt.Errorf("%s is not a valid deployment or deploymentconfig", targetName)
300
+		return nil, fmt.Errorf("%s is not a valid deployment or deployment config", targetName)
301 301
 	}
302 302
 	return obj, nil
303 303
 }
... ...
@@ -311,6 +311,10 @@ type DeploymentConfigSpec struct {
311 311
 	// or failing. Post strategy hooks and After actions can be used to integrate successful deployment with an action.
312 312
 	Test bool
313 313
 
314
+	// Paused indicates that the deployment config is paused resulting in no new deployments on template
315
+	// changes or changes in the template caused by other triggers.
316
+	Paused bool
317
+
314 318
 	// Selector is a label query over pods that should match the Replicas count.
315 319
 	Selector map[string]string
316 320
 
... ...
@@ -268,6 +268,10 @@ type DeploymentConfigSpec struct {
268 268
 	// or failing. Post strategy hooks and After actions can be used to integrate successful deployment with an action.
269 269
 	Test bool `json:"test"`
270 270
 
271
+	// Paused indicates that the deployment config is paused resulting in no new deployments on template
272
+	// changes or changes in the template caused by other triggers.
273
+	Paused bool `json:"paused,omitempty"`
274
+
271 275
 	// Selector is a label query over pods that should match the Replicas count.
272 276
 	Selector map[string]string `json:"selector,omitempty"`
273 277
 
... ...
@@ -284,6 +284,10 @@ type DeploymentConfigSpec struct {
284 284
 	// or failing. Post strategy hooks and After actions can be used to integrate successful deployment with an action.
285 285
 	Test bool `json:"test"`
286 286
 
287
+	// Paused indicates that the deployment config is paused resulting in no new deployments on template
288
+	// changes or changes in the template caused by other triggers.
289
+	Paused bool `json:"paused,omitempty"`
290
+
287 291
 	// Selector is a label query over pods that should match the Replicas count.
288 292
 	Selector map[string]string `json:"selector,omitempty"`
289 293
 
... ...
@@ -35,8 +35,7 @@ func (e fatalError) Error() string {
35 35
 
36 36
 // Handle processes change triggers for config.
37 37
 func (c *DeploymentConfigChangeController) Handle(config *deployapi.DeploymentConfig) error {
38
-	if !deployutil.HasChangeTrigger(config) {
39
-		glog.V(5).Infof("Ignoring deployment config %q; no change triggers detected", deployutil.LabelForDeploymentConfig(config))
38
+	if !deployutil.HasChangeTrigger(config) || config.Spec.Paused {
40 39
 		return nil
41 40
 	}
42 41
 
... ...
@@ -119,6 +119,11 @@ func (c *DeploymentConfigController) Handle(config *deployapi.DeploymentConfig)
119 119
 		}
120 120
 		return c.reconcileDeployments(existingDeployments, config)
121 121
 	}
122
+	// If the config is paused we shouldn't create new deployments for it.
123
+	// TODO: Make sure cleanup policy will work for paused configs.
124
+	if config.Spec.Paused {
125
+		return c.updateStatus(config)
126
+	}
122 127
 	// No deployments are running and the latest deployment doesn't exist, so
123 128
 	// create the new deployment.
124 129
 	deployment, err := deployutil.MakeDeployment(config, c.codec)
... ...
@@ -54,7 +54,7 @@ func (c *ImageChangeController) Handle(stream *imageapi.ImageStream) error {
54 54
 			// be able to work and not try to pull non-existent images from DockerHub.
55 55
 			// Deployments with automatic set to false that have been deployed at least
56 56
 			// once shouldn't have their images updated.
57
-			if !params.Automatic && len(params.LastTriggeredImage) > 0 {
57
+			if (!params.Automatic || config.Spec.Paused) && len(params.LastTriggeredImage) > 0 {
58 58
 				continue
59 59
 			}
60 60