package controller
import (
"github.com/golang/glog"
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
deployapi "github.com/openshift/origin/pkg/deploy/api"
)
// BasicDeploymentController implements the DeploymentStrategyTypeBasic deployment strategy. Its behavior
// is to create new replication controllers as defined on a Deployment, and delete any previously existing
// replication controllers for the same DeploymentConfig associated with the deployment.
type BasicDeploymentController struct {
DeploymentUpdater bdcDeploymentUpdater
ReplicationControllerClient bdcReplicationControllerClient
NextDeployment func() *deployapi.Deployment
}
type bdcDeploymentUpdater interface {
UpdateDeployment(ctx kapi.Context, deployment *deployapi.Deployment) (*deployapi.Deployment, error)
}
type bdcReplicationControllerClient interface {
ListReplicationControllers(ctx kapi.Context, selector labels.Selector) (*kapi.ReplicationControllerList, error)
GetReplicationController(ctx kapi.Context, id string) (*kapi.ReplicationController, error)
CreateReplicationController(ctx kapi.Context, ctrl *kapi.ReplicationController) (*kapi.ReplicationController, error)
UpdateReplicationController(ctx kapi.Context, ctrl *kapi.ReplicationController) (*kapi.ReplicationController, error)
DeleteReplicationController(ctx kapi.Context, id string) error
}
func (dc *BasicDeploymentController) Run() {
go util.Forever(func() { dc.HandleDeployment() }, 0)
}
// HandleDeployment executes a single Deployment. It's assumed that the strategy of the deployment is
// DeploymentStrategyTypeBasic.
func (dc *BasicDeploymentController) HandleDeployment() error {
deployment := dc.NextDeployment()
if deployment.Strategy.Type != deployapi.DeploymentStrategyTypeBasic {
glog.V(4).Infof("Ignoring deployment %s due to incompatible strategy type %s", deployment.ID, deployment.Strategy)
return nil
}
ctx := kapi.WithNamespace(kapi.NewContext(), deployment.Namespace)
nextStatus := deployment.Status
switch deployment.Status {
case deployapi.DeploymentStatusNew:
nextStatus = dc.handleNew(ctx, deployment)
}
// persist any status change
if deployment.Status != nextStatus {
deployment.Status = nextStatus
glog.V(4).Infof("Saving deployment %v status: %v", deployment.ID, deployment.Status)
if _, err := dc.DeploymentUpdater.UpdateDeployment(ctx, deployment); err != nil {
glog.V(2).Infof("Received error while saving deployment %v: %v", deployment.ID, err)
return err
}
}
return nil
}
func (dc *BasicDeploymentController) handleNew(ctx kapi.Context, deployment *deployapi.Deployment) deployapi.DeploymentStatus {
controllers := &kapi.ReplicationControllerList{}
var err error
configID, hasConfigID := deployment.Labels[deployapi.DeploymentConfigLabel]
if hasConfigID {
selector, _ := labels.ParseSelector(deployapi.DeploymentConfigLabel + "=" + configID)
controllers, err = dc.ReplicationControllerClient.ListReplicationControllers(ctx, selector)
if err != nil {
glog.V(2).Infof("Unable to get list of replication controllers for previous deploymentConfig %s: %v\n", configID, err)
return deployapi.DeploymentStatusFailed
}
}
controller := &kapi.ReplicationController{
DesiredState: deployment.ControllerTemplate,
Labels: map[string]string{deployapi.DeploymentConfigLabel: configID, "deployment": deployment.ID},
}
if controller.DesiredState.PodTemplate.Labels == nil {
controller.DesiredState.PodTemplate.Labels = make(map[string]string)
}
controller.DesiredState.PodTemplate.Labels[deployapi.DeploymentConfigLabel] = configID
controller.DesiredState.PodTemplate.Labels["deployment"] = deployment.ID
glog.V(2).Infof("Creating replicationController for deployment %s", deployment.ID)
if _, err := dc.ReplicationControllerClient.CreateReplicationController(ctx, controller); err != nil {
glog.V(2).Infof("An error occurred creating the replication controller for deployment %s: %v", deployment.ID, err)
return deployapi.DeploymentStatusFailed
}
allProcessed := true
// For this simple deploy, remove previous replication controllers
for _, rc := range controllers.Items {
configID, _ := deployment.Labels[deployapi.DeploymentConfigLabel]
glog.V(2).Infof("Stopping replication controller for previous deploymentConfig %s: %v", configID, rc.ID)
controller, err := dc.ReplicationControllerClient.GetReplicationController(ctx, rc.ID)
if err != nil {
glog.V(2).Infof("Unable to get replication controller %s for previous deploymentConfig %s: %#v\n", rc.ID, configID, err)
allProcessed = false
continue
}
controller.DesiredState.Replicas = 0
glog.V(2).Infof("Settings Replicas=0 for replicationController %s for previous deploymentConfig %s", rc.ID, configID)
if _, err := dc.ReplicationControllerClient.UpdateReplicationController(ctx, controller); err != nil {
glog.V(2).Infof("Unable to stop replication controller %s for previous deploymentConfig %s: %#v\n", rc.ID, configID, err)
allProcessed = false
continue
}
}
for _, rc := range controllers.Items {
configID, _ := deployment.Labels[deployapi.DeploymentConfigLabel]
glog.V(2).Infof("Deleting replication controller %s for previous deploymentConfig %s", rc.ID, configID)
err := dc.ReplicationControllerClient.DeleteReplicationController(ctx, rc.ID)
if err != nil {
glog.V(2).Infof("Unable to remove replication controller %s for previous deploymentConfig %s:%#v\n", rc.ID, configID, err)
allProcessed = false
continue
}
}
if allProcessed {
return deployapi.DeploymentStatusComplete
}
return deployapi.DeploymentStatusFailed
}