pkg/deploy/controller/deployment/factory.go
224b3b44
 package deployment
 
 import (
 	"fmt"
0e2896f4
 	"time"
224b3b44
 
83c702b4
 	kapi "k8s.io/kubernetes/pkg/api"
 	kclient "k8s.io/kubernetes/pkg/client"
 	"k8s.io/kubernetes/pkg/client/cache"
 	"k8s.io/kubernetes/pkg/client/record"
 	"k8s.io/kubernetes/pkg/fields"
 	"k8s.io/kubernetes/pkg/labels"
 	"k8s.io/kubernetes/pkg/runtime"
 	kutil "k8s.io/kubernetes/pkg/util"
 	"k8s.io/kubernetes/pkg/watch"
224b3b44
 
 	controller "github.com/openshift/origin/pkg/controller"
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
 )
 
 // DeploymentControllerFactory can create a DeploymentController that creates
 // deployer pods in a configurable way.
 type DeploymentControllerFactory struct {
 	// KubeClient is a Kubernetes client.
 	KubeClient kclient.Interface
 	// Codec is used for encoding/decoding.
 	Codec runtime.Codec
89364aa9
 	// ServiceAccount is the service account name to run deployer pods as
 	ServiceAccount string
224b3b44
 	// Environment is a set of environment which should be injected into all deployer pod containers.
 	Environment []kapi.EnvVar
4ad08f13
 	// DeployerImage specifies which Docker image can support the default strategies.
 	DeployerImage string
224b3b44
 }
 
 // Create creates a DeploymentController.
 func (factory *DeploymentControllerFactory) Create() controller.RunnableController {
 	deploymentLW := &deployutil.ListWatcherImpl{
120c5b7d
 		// TODO: Investigate specifying annotation field selectors to fetch only 'deployments'
 		// Currently field selectors are not supported for replication controllers
224b3b44
 		ListFunc: func() (runtime.Object, error) {
 			return factory.KubeClient.ReplicationControllers(kapi.NamespaceAll).List(labels.Everything())
 		},
 		WatchFunc: func(resourceVersion string) (watch.Interface, error) {
0321b4d6
 			return factory.KubeClient.ReplicationControllers(kapi.NamespaceAll).Watch(labels.Everything(), fields.Everything(), resourceVersion)
224b3b44
 		},
 	}
 	deploymentQueue := cache.NewFIFO(cache.MetaNamespaceKeyFunc)
0e2896f4
 	cache.NewReflector(deploymentLW, &kapi.ReplicationController{}, deploymentQueue, 2*time.Minute).Run()
224b3b44
 
eadc390b
 	eventBroadcaster := record.NewBroadcaster()
 	eventBroadcaster.StartRecordingToSink(factory.KubeClient.Events(""))
 
224b3b44
 	deployController := &DeploymentController{
89364aa9
 		serviceAccount: factory.ServiceAccount,
224b3b44
 		deploymentClient: &deploymentClientImpl{
 			getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
 				return factory.KubeClient.ReplicationControllers(namespace).Get(name)
 			},
 			updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
 				return factory.KubeClient.ReplicationControllers(namespace).Update(deployment)
 			},
 		},
 		podClient: &podClientImpl{
df0cf4ac
 			getPodFunc: func(namespace, name string) (*kapi.Pod, error) {
 				return factory.KubeClient.Pods(namespace).Get(name)
 			},
224b3b44
 			createPodFunc: func(namespace string, pod *kapi.Pod) (*kapi.Pod, error) {
 				return factory.KubeClient.Pods(namespace).Create(pod)
 			},
 			deletePodFunc: func(namespace, name string) error {
cb58b0ff
 				return factory.KubeClient.Pods(namespace).Delete(name, nil)
224b3b44
 			},
0081d32b
 			updatePodFunc: func(namespace string, pod *kapi.Pod) (*kapi.Pod, error) {
 				return factory.KubeClient.Pods(namespace).Update(pod)
 			},
42b6f658
 			// Find deployer pods using the label they should all have which
 			// correlates them to the named deployment.
 			getDeployerPodsForFunc: func(namespace, name string) ([]kapi.Pod, error) {
 				labelSel, err := labels.Parse(fmt.Sprintf("%s=%s", deployapi.DeployerPodForDeploymentLabel, name))
 				if err != nil {
 					return []kapi.Pod{}, err
 				}
 				pods, err := factory.KubeClient.Pods(namespace).List(labelSel, fields.Everything())
 				if err != nil {
 					return []kapi.Pod{}, err
 				}
 				return pods.Items, nil
 			},
224b3b44
 		},
 		makeContainer: func(strategy *deployapi.DeploymentStrategy) (*kapi.Container, error) {
 			return factory.makeContainer(strategy)
 		},
 		decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) {
 			return deployutil.DecodeDeploymentConfig(deployment, factory.Codec)
 		},
eadc390b
 		recorder: eventBroadcaster.NewRecorder(kapi.EventSource{Component: "deployer"}),
224b3b44
 	}
 
 	return &controller.RetryController{
8ec1918b
 		Queue: deploymentQueue,
 		RetryManager: controller.NewQueueRetryManager(
 			deploymentQueue,
 			cache.MetaNamespaceKeyFunc,
1319afbe
 			func(obj interface{}, err error, retries controller.Retry) bool {
8ec1918b
 				if _, isFatal := err.(fatalError); isFatal {
 					kutil.HandleError(err)
 					return false
 				}
1319afbe
 				if retries.Count > 1 {
8ec1918b
 					return false
 				}
 				return true
 			},
e03b50d7
 			kutil.NewTokenBucketRateLimiter(1, 10),
8ec1918b
 		),
224b3b44
 		Handle: func(obj interface{}) error {
 			deployment := obj.(*kapi.ReplicationController)
 			return deployController.Handle(deployment)
 		},
 	}
 }
 
 // makeContainer creates containers in the following way:
 //
4ad08f13
 //   1. For the Recreate and Rolling strategies, strategy, use the factory's
 //      DeployerImage as the container image, and the factory's Environment
 //      as the container environment.
224b3b44
 //   2. For all Custom strategy, use the strategy's image for the container
 //      image, and use the combination of the factory's Environment and the
 //      strategy's environment as the container environment.
 //
 // An error is returned if the deployment strategy type is not supported.
 func (factory *DeploymentControllerFactory) makeContainer(strategy *deployapi.DeploymentStrategy) (*kapi.Container, error) {
 	// Set default environment values
 	environment := []kapi.EnvVar{}
 	for _, env := range factory.Environment {
 		environment = append(environment, env)
 	}
 
 	// Every strategy type should be handled here.
 	switch strategy.Type {
4ad08f13
 	case deployapi.DeploymentStrategyTypeRecreate, deployapi.DeploymentStrategyTypeRolling:
224b3b44
 		// Use the factory-configured image.
 		return &kapi.Container{
4ad08f13
 			Image: factory.DeployerImage,
224b3b44
 			Env:   environment,
 		}, nil
 	case deployapi.DeploymentStrategyTypeCustom:
 		// Use user-defined values from the strategy input.
 		for _, env := range strategy.CustomParams.Environment {
 			environment = append(environment, env)
 		}
 		return &kapi.Container{
 			Image: strategy.CustomParams.Image,
 			Env:   environment,
 		}, nil
 	default:
 		return nil, fmt.Errorf("unsupported deployment strategy type: %s", strategy.Type)
 	}
 }