Beispiel #1
0
// 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
}
Beispiel #2
0
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
}
Beispiel #3
0
// 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
}
Beispiel #4
0
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
}
Beispiel #5
0
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
}
Beispiel #6
0
// 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)
		}
	}
}