// deploy launches a new deployment unless there's already a deployment // process in progress for config. func (o DeployOptions) deploy(config *deployapi.DeploymentConfig, out io.Writer) error { // TODO: This implies that deploymentconfig.status.latestVersion is always synced. Currently, // that's the case because clients (oc, trigger controllers) are updating the status directly. // Clients should be acting either on spec or on annotations and status updates should be a // responsibility of the main controller. We need to start by unplugging this assumption from // our client tools. deploymentName := deployutil.LatestDeploymentNameForConfig(config) deployment, err := o.kubeClient.ReplicationControllers(config.Namespace).Get(deploymentName) if err == nil { // Reject attempts to start a concurrent deployment. status := deployutil.DeploymentStatusFor(deployment) if status != deployapi.DeploymentStatusComplete && status != deployapi.DeploymentStatusFailed { return fmt.Errorf("#%d is already in progress (%s).\nOptionally, you can cancel this deployment using the --cancel option.", config.Status.LatestVersion, status) } } else { if !kerrors.IsNotFound(err) { return err } } if config.Annotations == nil { config.Annotations = make(map[string]string) } config.Annotations[deployapi.DeploymentInstantiatedAnnotation] = deployapi.DeploymentInstantiatedAnnotationValue dc, err := o.osClient.DeploymentConfigs(config.Namespace).Update(config) if err != nil { return err } fmt.Fprintf(out, "Started deployment #%d\n", dc.Status.LatestVersion) fmt.Fprintf(out, "Use '%s logs -f dc/%s' to track its progress.\n", o.baseCommandName, dc.Name) return nil }
func Instantiate(dc deployapi.DeploymentConfig) *deployapi.DeploymentConfig { if dc.Annotations == nil { dc.Annotations = make(map[string]string) } dc.Annotations[deployapi.DeploymentInstantiatedAnnotation] = deployapi.DeploymentInstantiatedAnnotationValue return &dc }
// updateDetails updates a deployment configuration with the provided details func (c *DeploymentConfigController) updateDetails(config *deployapi.DeploymentConfig, details string) (*deployapi.DeploymentConfig, error) { if config.Details == nil { config.Details = new(deployapi.DeploymentDetails) } if details != config.Details.Message { config.Details.Message = details return c.osClient.DeploymentConfigs(config.Namespace).Update(config) } return config, nil }
func convert_v1_DeploymentConfig_To_api_DeploymentConfig(in *DeploymentConfig, out *newer.DeploymentConfig, s conversion.Scope) error { if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields); err != nil { return err } if err := s.Convert(&in.Spec, &out.Template, 0); err != nil { return err } if err := s.Convert(&in.Spec.Triggers, &out.Triggers, 0); err != nil { return err } out.LatestVersion = in.Status.LatestVersion if err := s.Convert(&in.Status.Details, &out.Details, 0); err != nil { return err } return nil }
func (c *DeploymentConfigController) updateStatus(config *deployapi.DeploymentConfig, deployments []kapi.ReplicationController) error { newStatus, err := c.calculateStatus(*config, deployments) if err != nil { glog.V(2).Infof("Cannot calculate the status for %q: %v", deployutil.LabelForDeploymentConfig(config), err) return err } // NOTE: We should update the status of the deployment config only if we need to, otherwise // we hotloop between updates. if reflect.DeepEqual(newStatus, config.Status) { return nil } config.Status = newStatus if _, err := c.dn.DeploymentConfigs(config.Namespace).UpdateStatus(config); err != nil { glog.V(2).Infof("Cannot update the status for %q: %v", deployutil.LabelForDeploymentConfig(config), err) return err } glog.V(4).Infof("Updated the status for %q (observed generation: %d)", deployutil.LabelForDeploymentConfig(config), config.Status.ObservedGeneration) return nil }
// TestHandle_updateOk ensures that an updated config (version >0) results in // a new deployment with the appropriate replica count based on a variety of // existing prior deployments. func TestHandle_updateOk(t *testing.T) { var ( config *deployapi.DeploymentConfig deployed *kapi.ReplicationController existingDeployments *kapi.ReplicationControllerList ) controller := &DeploymentConfigController{ makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) { return deployutil.MakeDeployment(config, api.Codec) }, deploymentClient: &deploymentClientImpl{ createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { deployed = deployment return deployment, nil }, listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) { return existingDeployments, nil }, updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected update call with deployment %v", deployment) return nil, nil }, }, osClient: testclient.NewSimpleFake(), } type existing struct { version int replicas int status deployapi.DeploymentStatus } type scenario struct { version int expectedReplicas int existing []existing } scenarios := []scenario{ {1, 1, []existing{}}, {2, 1, []existing{ {1, 1, deployapi.DeploymentStatusComplete}, }}, {3, 4, []existing{ {1, 0, deployapi.DeploymentStatusComplete}, {2, 4, deployapi.DeploymentStatusComplete}, }}, {3, 4, []existing{ {1, 4, deployapi.DeploymentStatusComplete}, {2, 1, deployapi.DeploymentStatusFailed}, }}, {4, 2, []existing{ {1, 0, deployapi.DeploymentStatusComplete}, {2, 0, deployapi.DeploymentStatusFailed}, {3, 2, deployapi.DeploymentStatusComplete}, }}, // Scramble the order of the previous to ensure we still get it right. {4, 2, []existing{ {2, 0, deployapi.DeploymentStatusFailed}, {3, 2, deployapi.DeploymentStatusComplete}, {1, 0, deployapi.DeploymentStatusComplete}, }}, } for _, scenario := range scenarios { deployed = nil config = deploytest.OkDeploymentConfig(scenario.version) config.Triggers = []deployapi.DeploymentTriggerPolicy{} existingDeployments = &kapi.ReplicationControllerList{} for _, e := range scenario.existing { d, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(e.version), api.Codec) d.Spec.Replicas = e.replicas d.Annotations[deployapi.DeploymentStatusAnnotation] = string(e.status) existingDeployments.Items = append(existingDeployments.Items, *d) } err := controller.Handle(config) if deployed == nil { t.Fatalf("expected a deployment") } if err != nil { t.Fatalf("unexpected error: %v", err) } desired, hasDesired := deployutil.DeploymentDesiredReplicas(deployed) if !hasDesired { t.Fatalf("expected desired replicas") } if e, a := scenario.expectedReplicas, desired; e != a { t.Errorf("expected desired replicas %d, got %d", e, a) } } }