forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config_change_controller.go
116 lines (95 loc) · 4.29 KB
/
config_change_controller.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package controller
import (
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
cache "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
runtime "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
util "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
deployapi "github.com/openshift/origin/pkg/deploy/api"
deployutil "github.com/openshift/origin/pkg/deploy/util"
"github.com/golang/glog"
)
// DeploymentConfigChangeController watches for changes to DeploymentConfigs and regenerates them only
// when detecting a change to the PodTemplate of a DeploymentConfig containing a ConfigChange trigger.
type DeploymentConfigChangeController struct {
ChangeStrategy ChangeStrategy
NextDeploymentConfig func() *deployapi.DeploymentConfig
DeploymentStore cache.Store
Codec runtime.Codec
// Stop is an optional channel that controls when the controller exits
Stop <-chan struct{}
}
// ChangeStrategy knows how to generate and update DeploymentConfigs.
type ChangeStrategy interface {
GenerateDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error)
UpdateDeploymentConfig(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error)
}
// Run watches for config change events.
func (dc *DeploymentConfigChangeController) Run() {
go util.Until(func() { dc.HandleDeploymentConfig() }, 0, dc.Stop)
}
// HandleDeploymentConfig handles the next DeploymentConfig change that happens.
func (dc *DeploymentConfigChangeController) HandleDeploymentConfig() {
config := dc.NextDeploymentConfig()
hasChangeTrigger := false
for _, trigger := range config.Triggers {
if trigger.Type == deployapi.DeploymentTriggerOnConfigChange {
hasChangeTrigger = true
break
}
}
if !hasChangeTrigger {
glog.V(4).Infof("Config has no change trigger; skipping")
return
}
if config.LatestVersion == 0 {
glog.V(4).Infof("Creating new deployment for config %v", config.Name)
dc.generateDeployment(config, nil)
return
}
latestDeploymentID := deployutil.LatestDeploymentNameForConfig(config)
obj, exists := dc.DeploymentStore.Get(latestDeploymentID)
if !exists {
glog.V(4).Info("Ignoring config change due to lack of existing deployment")
return
}
deployment := obj.(*kapi.ReplicationController)
deployedConfig, err := deployutil.DecodeDeploymentConfig(deployment, dc.Codec)
if err != nil {
glog.V(0).Infof("Error decoding deploymentConfig from deployment %s: %v", deployment.Name, err)
return
}
if deployutil.PodSpecsEqual(config.Template.ControllerTemplate.Template.Spec, deployedConfig.Template.ControllerTemplate.Template.Spec) {
glog.V(4).Infof("Ignoring updated config %s with LatestVersion=%d because it matches deployed config %s", config.Name, config.LatestVersion, deployment.Name)
return
}
glog.V(4).Infof("Diff:\n%s", util.ObjectDiff(config.Template.ControllerTemplate.Template.Spec, deployedConfig.Template.ControllerTemplate.Template.Spec))
dc.generateDeployment(config, deployment)
}
func (dc *DeploymentConfigChangeController) generateDeployment(config *deployapi.DeploymentConfig, deployment *kapi.ReplicationController) {
newConfig, err := dc.ChangeStrategy.GenerateDeploymentConfig(config.Namespace, config.Name)
if err != nil {
glog.V(2).Infof("Error generating new version of deploymentConfig %v: %#v", config.Name, err)
return
}
if newConfig.LatestVersion == config.LatestVersion {
newConfig.LatestVersion++
}
if deployment != nil {
glog.V(4).Infof("Updating config %s (LatestVersion: %d -> %d) to advance existing deployment %s", config.Name, config.LatestVersion, newConfig.LatestVersion, deployment.Name)
}
// set the trigger details for the new deployment config
causes := []*deployapi.DeploymentCause{}
causes = append(causes,
&deployapi.DeploymentCause{
Type: deployapi.DeploymentTriggerOnConfigChange,
})
newConfig.Details = &deployapi.DeploymentDetails{
Causes: causes,
}
// This update is atomic. If it fails because a newer resource was already persisted, that's
// okay - we can just ignore the update for the old resource and any changes to the more
// current config will be captured in future events.
if _, err = dc.ChangeStrategy.UpdateDeploymentConfig(config.Namespace, newConfig); err != nil {
glog.V(2).Infof("Error updating deploymentConfig %v: %#v", config.Name, err)
}
}