forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
deployer.go
173 lines (140 loc) · 6.37 KB
/
deployer.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package deployer
import (
"fmt"
"strconv"
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/openshift/origin/pkg/api/latest"
"github.com/openshift/origin/pkg/cmd/util"
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
deployapi "github.com/openshift/origin/pkg/deploy/api"
"github.com/openshift/origin/pkg/deploy/strategy"
"github.com/openshift/origin/pkg/deploy/strategy/recreate"
"github.com/openshift/origin/pkg/deploy/strategy/rolling"
deployutil "github.com/openshift/origin/pkg/deploy/util"
"github.com/openshift/origin/pkg/version"
)
const (
deployer_long = `Perform a Deployment.
This command makes calls to OpenShift to perform a deployment as described by a deployment config.`
)
type config struct {
Config *clientcmd.Config
DeploymentName string
Namespace string
}
type replicationControllerGetter interface {
Get(namespace, name string) (*kapi.ReplicationController, error)
List(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error)
}
// NewCommandDeployer provides a CLI handler for deploy.
func NewCommandDeployer(name string) *cobra.Command {
cfg := &config{
Config: clientcmd.NewConfig(),
}
cmd := &cobra.Command{
Use: fmt.Sprintf("%s%s", name, clientcmd.ConfigSyntax),
Short: "Run the OpenShift deployer",
Long: deployer_long,
Run: func(c *cobra.Command, args []string) {
_, kClient, err := cfg.Config.Clients()
if err != nil {
glog.Fatal(err)
}
if len(cfg.DeploymentName) == 0 {
glog.Fatal("deployment is required")
}
if len(cfg.Namespace) == 0 {
glog.Fatal("namespace is required")
}
if err = deploy(kClient, cfg.Namespace, cfg.DeploymentName); err != nil {
glog.Fatal(err)
}
},
}
cmd.AddCommand(version.NewVersionCommand(name))
flag := cmd.Flags()
cfg.Config.Bind(flag)
flag.StringVar(&cfg.DeploymentName, "deployment", util.Env("OPENSHIFT_DEPLOYMENT_NAME", ""), "The deployment name to start")
flag.StringVar(&cfg.Namespace, "namespace", util.Env("OPENSHIFT_DEPLOYMENT_NAMESPACE", ""), "The deployment namespace")
return cmd
}
// deploy executes a deployment strategy.
func deploy(kClient kclient.Interface, namespace, deploymentName string) error {
deployment, oldDeployments, err := getDeployerContext(&realReplicationControllerGetter{kClient}, namespace, deploymentName)
if err != nil {
return err
}
config, err := deployutil.DecodeDeploymentConfig(deployment, latest.Codec)
if err != nil {
return fmt.Errorf("couldn't decode DeploymentConfig from deployment %s/%s: %v", deployment.Namespace, deployment.Name, err)
}
var strategy strategy.DeploymentStrategy
switch config.Template.Strategy.Type {
case deployapi.DeploymentStrategyTypeRecreate:
strategy = recreate.NewRecreateDeploymentStrategy(kClient, latest.Codec)
case deployapi.DeploymentStrategyTypeRolling:
recreate := recreate.NewRecreateDeploymentStrategy(kClient, latest.Codec)
strategy = rolling.NewRollingDeploymentStrategy(deployment.Namespace, kClient, latest.Codec, recreate)
default:
return fmt.Errorf("unsupported strategy type: %s", config.Template.Strategy.Type)
}
return strategy.Deploy(deployment, oldDeployments)
}
// getDeployerContext finds the target deployment and any deployments it considers to be prior to the
// target deployment. Only deployments whose LatestVersion is less than the target deployment are
// considered to be prior.
func getDeployerContext(controllerGetter replicationControllerGetter, namespace, deploymentName string) (*kapi.ReplicationController, []*kapi.ReplicationController, error) {
var err error
var newDeployment *kapi.ReplicationController
var newConfig *deployapi.DeploymentConfig
// Look up the new deployment and its associated config.
if newDeployment, err = controllerGetter.Get(namespace, deploymentName); err != nil {
return nil, nil, err
}
if newConfig, err = deployutil.DecodeDeploymentConfig(newDeployment, latest.Codec); err != nil {
return nil, nil, err
}
glog.Infof("Found new deployment %s for config %s with latestVersion %d", newDeployment.Name, newConfig.Name, newConfig.LatestVersion)
// Collect all deployments that predate the new one by comparing all old ReplicationControllers with
// encoded DeploymentConfigs to the new one by LatestVersion. Treat a failure to interpret a given
// old deployment as a fatal error to prevent overlapping deployments.
var allControllers *kapi.ReplicationControllerList
oldDeployments := []*kapi.ReplicationController{}
if allControllers, err = controllerGetter.List(newDeployment.Namespace, labels.Everything()); err != nil {
return nil, nil, fmt.Errorf("Unable to get list replication controllers in deployment namespace %s: %v", newDeployment.Namespace, err)
}
glog.Infof("Inspecting %d potential prior deployments", len(allControllers.Items))
for i, controller := range allControllers.Items {
if configName, hasConfigName := controller.Annotations[deployapi.DeploymentConfigAnnotation]; !hasConfigName {
glog.Infof("Disregarding replicationController %s (not a deployment)", controller.Name)
continue
} else if configName != newConfig.Name {
glog.Infof("Disregarding deployment %s (doesn't match target deploymentConfig %s)", controller.Name, configName)
continue
}
var oldVersion int
if oldVersion, err = strconv.Atoi(controller.Annotations[deployapi.DeploymentVersionAnnotation]); err != nil {
return nil, nil, fmt.Errorf("Couldn't determine version of deployment %s: %v", controller.Name, err)
}
if oldVersion < newConfig.LatestVersion {
glog.Infof("Marking deployment %s as a prior deployment", controller.Name)
oldDeployments = append(oldDeployments, &allControllers.Items[i])
} else {
glog.Infof("Disregarding deployment %s (same as or newer than target)", controller.Name)
}
}
return newDeployment, oldDeployments, nil
}
type realReplicationControllerGetter struct {
kClient kclient.Interface
}
func (r *realReplicationControllerGetter) Get(namespace, name string) (*kapi.ReplicationController, error) {
return r.kClient.ReplicationControllers(namespace).Get(name)
}
func (r *realReplicationControllerGetter) List(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) {
return r.kClient.ReplicationControllers(namespace).List(selector)
}