Skip to content

Commit 552030f

Browse files
Update deployment logs and surge on recreate
1 parent b38927b commit 552030f

File tree

7 files changed

+233
-163
lines changed

7 files changed

+233
-163
lines changed

pkg/cmd/infra/deployer/deployer.go

+57-45
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@ package deployer
22

33
import (
44
"fmt"
5+
"io"
6+
"os"
57
"sort"
68
"time"
79

8-
"github.com/golang/glog"
910
"github.com/spf13/cobra"
1011

1112
kapi "k8s.io/kubernetes/pkg/api"
1213
"k8s.io/kubernetes/pkg/client/restclient"
1314
kclient "k8s.io/kubernetes/pkg/client/unversioned"
1415
"k8s.io/kubernetes/pkg/kubectl"
16+
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
1517

1618
"github.com/openshift/origin/pkg/client"
1719
"github.com/openshift/origin/pkg/cmd/util"
@@ -32,8 +34,10 @@ This command launches a deployment as described by a deployment configuration.`
3234
)
3335

3436
type config struct {
35-
DeploymentName string
36-
Namespace string
37+
Out, ErrOut io.Writer
38+
39+
rcName string
40+
Namespace string
3741
}
3842

3943
// NewCommandDeployer provides a CLI handler for deploy.
@@ -45,46 +49,53 @@ func NewCommandDeployer(name string) *cobra.Command {
4549
Short: "Run the deployer",
4650
Long: deployerLong,
4751
Run: func(c *cobra.Command, args []string) {
48-
if len(cfg.DeploymentName) == 0 {
49-
glog.Fatal("deployment is required")
50-
}
51-
if len(cfg.Namespace) == 0 {
52-
glog.Fatal("namespace is required")
53-
}
54-
55-
kcfg, err := restclient.InClusterConfig()
56-
if err != nil {
57-
glog.Fatal(err)
58-
}
59-
kc, err := kclient.New(kcfg)
60-
if err != nil {
61-
glog.Fatal(err)
62-
}
63-
oc, err := client.New(kcfg)
64-
if err != nil {
65-
glog.Fatal(err)
66-
}
67-
68-
deployer := NewDeployer(kc, oc)
69-
if err = deployer.Deploy(cfg.Namespace, cfg.DeploymentName); err != nil {
70-
glog.Fatal(err)
71-
}
52+
cfg.Out = os.Stdout
53+
cfg.ErrOut = c.Out()
54+
err := cfg.RunDeployer()
55+
kcmdutil.CheckErr(err)
7256
},
7357
}
7458

7559
cmd.AddCommand(version.NewVersionCommand(name, false))
7660

7761
flag := cmd.Flags()
78-
flag.StringVar(&cfg.DeploymentName, "deployment", util.Env("OPENSHIFT_DEPLOYMENT_NAME", ""), "The deployment name to start")
62+
flag.StringVar(&cfg.rcName, "deployment", util.Env("OPENSHIFT_DEPLOYMENT_NAME", ""), "The deployment name to start")
7963
flag.StringVar(&cfg.Namespace, "namespace", util.Env("OPENSHIFT_DEPLOYMENT_NAMESPACE", ""), "The deployment namespace")
8064

8165
return cmd
8266
}
8367

68+
func (cfg *config) RunDeployer() error {
69+
if len(cfg.rcName) == 0 {
70+
return fmt.Errorf("--deployment or OPENSHIFT_DEPLOYMENT_NAME is required")
71+
}
72+
if len(cfg.Namespace) == 0 {
73+
return fmt.Errorf("--namespace or OPENSHIFT_DEPLOYMENT_NAMESPACE is required")
74+
}
75+
76+
kcfg, err := restclient.InClusterConfig()
77+
if err != nil {
78+
return err
79+
}
80+
kc, err := kclient.New(kcfg)
81+
if err != nil {
82+
return err
83+
}
84+
oc, err := client.New(kcfg)
85+
if err != nil {
86+
return err
87+
}
88+
89+
deployer := NewDeployer(kc, oc, cfg.Out, cfg.ErrOut)
90+
return deployer.Deploy(cfg.Namespace, cfg.rcName)
91+
}
92+
8493
// NewDeployer makes a new Deployer from a kube client.
85-
func NewDeployer(client kclient.Interface, oclient client.Interface) *Deployer {
94+
func NewDeployer(client kclient.Interface, oclient client.Interface, out, errOut io.Writer) *Deployer {
8695
scaler, _ := kubectl.ScalerFor(kapi.Kind("ReplicationController"), client)
8796
return &Deployer{
97+
out: out,
98+
errOut: errOut,
8899
getDeployment: func(namespace, name string) (*kapi.ReplicationController, error) {
89100
return client.ReplicationControllers(namespace).Get(name)
90101
},
@@ -95,10 +106,10 @@ func NewDeployer(client kclient.Interface, oclient client.Interface) *Deployer {
95106
strategyFor: func(config *deployapi.DeploymentConfig) (strategy.DeploymentStrategy, error) {
96107
switch config.Spec.Strategy.Type {
97108
case deployapi.DeploymentStrategyTypeRecreate:
98-
return recreate.NewRecreateDeploymentStrategy(client, oclient, kapi.Codecs.UniversalDecoder()), nil
109+
return recreate.NewRecreateDeploymentStrategy(client, oclient, kapi.Codecs.UniversalDecoder(), out, errOut), nil
99110
case deployapi.DeploymentStrategyTypeRolling:
100-
recreate := recreate.NewRecreateDeploymentStrategy(client, oclient, kapi.Codecs.UniversalDecoder())
101-
return rolling.NewRollingDeploymentStrategy(config.Namespace, client, oclient, kapi.Codecs.UniversalDecoder(), recreate), nil
111+
recreate := recreate.NewRecreateDeploymentStrategy(client, oclient, kapi.Codecs.UniversalDecoder(), out, errOut)
112+
return rolling.NewRollingDeploymentStrategy(config.Namespace, client, oclient, kapi.Codecs.UniversalDecoder(), recreate, out, errOut), nil
102113
default:
103114
return nil, fmt.Errorf("unsupported strategy type: %s", config.Spec.Strategy.Type)
104115
}
@@ -115,6 +126,8 @@ func NewDeployer(client kclient.Interface, oclient client.Interface) *Deployer {
115126
// 4. Pass the last completed deployment and the new deployment to a strategy
116127
// to perform the deployment.
117128
type Deployer struct {
129+
// out and errOut control display when deploy is invoked
130+
out, errOut io.Writer
118131
// strategyFor returns a DeploymentStrategy for config.
119132
strategyFor func(config *deployapi.DeploymentConfig) (strategy.DeploymentStrategy, error)
120133
// getDeployment finds the named deployment.
@@ -125,18 +138,18 @@ type Deployer struct {
125138
scaler kubectl.Scaler
126139
}
127140

128-
// Deploy starts the deployment process for deploymentName.
129-
func (d *Deployer) Deploy(namespace, deploymentName string) error {
141+
// Deploy starts the deployment process for rcName.
142+
func (d *Deployer) Deploy(namespace, rcName string) error {
130143
// Look up the new deployment.
131-
to, err := d.getDeployment(namespace, deploymentName)
144+
to, err := d.getDeployment(namespace, rcName)
132145
if err != nil {
133-
return fmt.Errorf("couldn't get deployment %s/%s: %v", namespace, deploymentName, err)
146+
return fmt.Errorf("couldn't get deployment %s: %v", rcName, err)
134147
}
135148

136149
// Decode the config from the deployment.
137150
config, err := deployutil.DecodeDeploymentConfig(to, kapi.Codecs.UniversalDecoder())
138151
if err != nil {
139-
return fmt.Errorf("couldn't decode deployment config from deployment %s/%s: %v", to.Namespace, to.Name, err)
152+
return fmt.Errorf("couldn't decode deployment config from deployment %s: %v", to.Name, err)
140153
}
141154

142155
// Get a strategy for the deployment.
@@ -148,7 +161,7 @@ func (d *Deployer) Deploy(namespace, deploymentName string) error {
148161
// New deployments must have a desired replica count.
149162
desiredReplicas, hasDesired := deployutil.DeploymentDesiredReplicas(to)
150163
if !hasDesired {
151-
return fmt.Errorf("deployment %s has no desired replica count", deployutil.LabelForDeployment(to))
164+
return fmt.Errorf("deployment %s has already run to completion", to.Name)
152165
}
153166

154167
// Find all deployments for the config.
@@ -189,17 +202,16 @@ func (d *Deployer) Deploy(namespace, deploymentName string) error {
189202
// Scale the deployment down to zero.
190203
retryWaitParams := kubectl.NewRetryParams(1*time.Second, 120*time.Second)
191204
if err := d.scaler.Scale(candidate.Namespace, candidate.Name, uint(0), &kubectl.ScalePrecondition{Size: -1, ResourceVersion: ""}, retryWaitParams, retryWaitParams); err != nil {
192-
glog.Errorf("Couldn't scale down prior deployment %s: %v", deployutil.LabelForDeployment(&candidate), err)
205+
fmt.Fprintf(d.errOut, "error: Couldn't scale down prior deployment %s: %v\n", deployutil.LabelForDeployment(&candidate), err)
193206
} else {
194-
glog.Infof("Scaled down prior deployment %s", deployutil.LabelForDeployment(&candidate))
207+
fmt.Fprintf(d.out, "--> Scaled older deployment %s down\n", candidate.Name)
195208
}
196209
}
197210

198211
// Perform the deployment.
199-
if from == nil {
200-
glog.Infof("Deploying %s for the first time (replicas: %d)", deployutil.LabelForDeployment(to), desiredReplicas)
201-
} else {
202-
glog.Infof("Deploying from %s to %s (replicas: %d)", deployutil.LabelForDeployment(from), deployutil.LabelForDeployment(to), desiredReplicas)
212+
if err := strategy.Deploy(from, to, desiredReplicas); err != nil {
213+
return err
203214
}
204-
return strategy.Deploy(from, to, desiredReplicas)
215+
fmt.Fprintf(d.out, "--> Success\n")
216+
return nil
205217
}

pkg/deploy/strategy/recreate/recreate.go

+39-31
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package recreate
22

33
import (
44
"fmt"
5+
"io"
6+
"io/ioutil"
57
"os"
68
"time"
79

8-
"github.com/golang/glog"
9-
1010
kapi "k8s.io/kubernetes/pkg/api"
1111
kclient "k8s.io/kubernetes/pkg/client/unversioned"
1212
"k8s.io/kubernetes/pkg/kubectl"
@@ -26,6 +26,8 @@ import (
2626
// A failure to disable any existing deployments will be considered a
2727
// deployment failure.
2828
type RecreateDeploymentStrategy struct {
29+
// out and errOut control where output is sent during the strategy
30+
out, errOut io.Writer
2931
// getReplicationController knows how to get a replication controller.
3032
getReplicationController func(namespace, name string) (*kapi.ReplicationController, error)
3133
// getUpdateAcceptor returns an UpdateAcceptor to verify the first replica
@@ -52,14 +54,22 @@ const AcceptorInterval = 1 * time.Second
5254

5355
// NewRecreateDeploymentStrategy makes a RecreateDeploymentStrategy backed by
5456
// a real HookExecutor and client.
55-
func NewRecreateDeploymentStrategy(client kclient.Interface, tagClient client.ImageStreamTagsNamespacer, decoder runtime.Decoder) *RecreateDeploymentStrategy {
57+
func NewRecreateDeploymentStrategy(client kclient.Interface, tagClient client.ImageStreamTagsNamespacer, decoder runtime.Decoder, out, errOut io.Writer) *RecreateDeploymentStrategy {
58+
if out == nil {
59+
out = ioutil.Discard
60+
}
61+
if errOut == nil {
62+
errOut = ioutil.Discard
63+
}
5664
scaler, _ := kubectl.ScalerFor(kapi.Kind("ReplicationController"), client)
5765
return &RecreateDeploymentStrategy{
66+
out: out,
67+
errOut: errOut,
5868
getReplicationController: func(namespace, name string) (*kapi.ReplicationController, error) {
5969
return client.ReplicationControllers(namespace).Get(name)
6070
},
6171
getUpdateAcceptor: func(timeout time.Duration) strat.UpdateAcceptor {
62-
return stratsupport.NewAcceptNewlyObservedReadyPods(client, timeout, AcceptorInterval)
72+
return stratsupport.NewAcceptNewlyObservedReadyPods(out, client, timeout, AcceptorInterval)
6373
},
6474
scaler: scaler,
6575
decoder: decoder,
@@ -97,63 +107,61 @@ func (s *RecreateDeploymentStrategy) DeployWithAcceptor(from *kapi.ReplicationCo
97107

98108
// Execute any pre-hook.
99109
if params != nil && params.Pre != nil {
100-
if err := s.hookExecutor.Execute(params.Pre, to, deployapi.PreHookPodSuffix); err != nil {
101-
return fmt.Errorf("Pre hook failed: %s", err)
110+
if err := s.hookExecutor.Execute(params.Pre, to, deployapi.PreHookPodSuffix, "pre"); err != nil {
111+
return fmt.Errorf("pre hook failed: %s", err)
102112
}
103-
glog.Infof("Pre hook finished")
104113
}
105114

106115
// Scale down the from deployment.
107116
if from != nil {
108-
glog.Infof("Scaling %s down to zero", deployutil.LabelForDeployment(from))
117+
fmt.Fprintf(s.out, "--> Scaling %s down to zero\n", from.Name)
109118
_, err := s.scaleAndWait(from, 0, retryParams, waitParams)
110119
if err != nil {
111-
return fmt.Errorf("couldn't scale %s to 0: %v", deployutil.LabelForDeployment(from), err)
120+
return fmt.Errorf("couldn't scale %s to 0: %v", from.Name, err)
112121
}
113122
}
114123

115124
if params != nil && params.Mid != nil {
116-
if err := s.hookExecutor.Execute(params.Mid, to, deployapi.MidHookPodSuffix); err != nil {
125+
if err := s.hookExecutor.Execute(params.Mid, to, deployapi.MidHookPodSuffix, "mid"); err != nil {
117126
return fmt.Errorf("mid hook failed: %s", err)
118127
}
119-
glog.Infof("Mid hook finished")
120128
}
121129

122130
// Scale up the to deployment.
123131
if desiredReplicas > 0 {
124-
// Scale up to 1 and validate the replica,
125-
// aborting if the replica isn't acceptable.
126-
glog.Infof("Scaling %s to 1 before performing acceptance check", deployutil.LabelForDeployment(to))
127-
updatedTo, err := s.scaleAndWait(to, 1, retryParams, waitParams)
128-
if err != nil {
129-
return fmt.Errorf("couldn't scale %s to 1: %v", deployutil.LabelForDeployment(to), err)
130-
}
131-
glog.Infof("Performing acceptance check of %s", deployutil.LabelForDeployment(to))
132-
if err := updateAcceptor.Accept(updatedTo); err != nil {
133-
return fmt.Errorf("update acceptor rejected %s: %v", deployutil.LabelForDeployment(to), err)
132+
if from != nil {
133+
// Scale up to 1 and validate the replica,
134+
// aborting if the replica isn't acceptable.
135+
fmt.Fprintf(s.out, "--> Scaling %s to 1 before performing acceptance check\n", to.Name)
136+
updatedTo, err := s.scaleAndWait(to, 1, retryParams, waitParams)
137+
if err != nil {
138+
return fmt.Errorf("couldn't scale %s to 1: %v", to.Name, err)
139+
}
140+
fmt.Fprintf(s.out, "--> Performing acceptance check of %s\n", to.Name)
141+
if err := updateAcceptor.Accept(updatedTo); err != nil {
142+
return fmt.Errorf("update acceptor rejected %s: %v", to.Name, err)
143+
}
144+
to = updatedTo
134145
}
135-
to = updatedTo
136146

137147
// Complete the scale up.
138148
if to.Spec.Replicas != desiredReplicas {
139-
glog.Infof("Scaling %s to %d", deployutil.LabelForDeployment(to), desiredReplicas)
149+
fmt.Fprintf(s.out, "--> Scaling %s to %d\n", to.Name, desiredReplicas)
140150
updatedTo, err := s.scaleAndWait(to, desiredReplicas, retryParams, waitParams)
141151
if err != nil {
142-
return fmt.Errorf("couldn't scale %s to %d: %v", deployutil.LabelForDeployment(to), desiredReplicas, err)
152+
return fmt.Errorf("couldn't scale %s to %d: %v", to.Name, desiredReplicas, err)
143153
}
144154
to = updatedTo
145155
}
146156
}
147157

148158
// Execute any post-hook.
149159
if params != nil && params.Post != nil {
150-
if err := s.hookExecutor.Execute(params.Post, to, deployapi.PostHookPodSuffix); err != nil {
160+
if err := s.hookExecutor.Execute(params.Post, to, deployapi.PostHookPodSuffix, "post"); err != nil {
151161
return fmt.Errorf("post hook failed: %s", err)
152162
}
153-
glog.Infof("Post hook finished")
154163
}
155164

156-
glog.Infof("Deployment %s successfully made active", to.Name)
157165
return nil
158166
}
159167

@@ -170,15 +178,15 @@ func (s *RecreateDeploymentStrategy) scaleAndWait(deployment *kapi.ReplicationCo
170178

171179
// hookExecutor knows how to execute a deployment lifecycle hook.
172180
type hookExecutor interface {
173-
Execute(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, label string) error
181+
Execute(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, suffix, label string) error
174182
}
175183

176184
// hookExecutorImpl is a pluggable hookExecutor.
177185
type hookExecutorImpl struct {
178-
executeFunc func(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, label string) error
186+
executeFunc func(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, suffix, label string) error
179187
}
180188

181189
// Execute executes the provided lifecycle hook
182-
func (i *hookExecutorImpl) Execute(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, label string) error {
183-
return i.executeFunc(hook, deployment, label)
190+
func (i *hookExecutorImpl) Execute(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, suffix, label string) error {
191+
return i.executeFunc(hook, deployment, suffix, label)
184192
}

0 commit comments

Comments
 (0)