@@ -3,16 +3,30 @@ package main
3
3
import (
4
4
"fmt"
5
5
"io/ioutil"
6
+ "log"
6
7
"os"
7
8
"os/exec"
9
+ "strings"
8
10
"time"
9
11
10
12
"github.com/urfave/cli"
11
13
"gopkg.in/yaml.v2"
12
14
)
13
15
14
- // Version is set at compile time, passing -ldflags "-X main.Version=<build version>"
15
- var Version string
16
+ var (
17
+ // Version is set at compile time, passing -ldflags "-X main.Version=<build version>"
18
+ Version string
19
+
20
+ logInfo * log.Logger
21
+ logError * log.Logger
22
+ logDebug * log.Logger
23
+ )
24
+
25
+ func init () {
26
+ logInfo = log .New (os .Stdout , "[INFO] " , log .Ldate | log .Ltime | log .Lshortfile )
27
+ logError = log .New (os .Stderr , "[ERROR] " , log .Ldate | log .Ltime | log .Lshortfile )
28
+ logDebug = log .New (os .Stderr , "[DEBUG] " , log .Ldate | log .Ltime | log .Lshortfile )
29
+ }
16
30
17
31
func main () {
18
32
app := cli .NewApp ()
@@ -23,10 +37,9 @@ func main() {
23
37
24
38
app .Flags = []cli.Flag {
25
39
cli.BoolFlag {
26
- Name : "verbose" ,
27
- Usage : "verbose output" ,
28
- EnvVar : "VERBOSE,PLUGIN_VERBOSE" ,
29
- Hidden : true ,
40
+ Name : "debug" ,
41
+ Usage : "debug output" ,
42
+ EnvVar : "DEBUG,PLUGIN_DEBUG" ,
30
43
},
31
44
cli.BoolFlag {
32
45
Name : "insecure-skip-tls-verify" ,
@@ -60,20 +73,20 @@ func main() {
60
73
},
61
74
cli.StringSliceFlag {
62
75
Name : "file, f" ,
63
- Usage : "a list of kubernetes resources FILE" ,
76
+ Usage : "list of kubernetes resources FILE" ,
64
77
EnvVar : "FILES,PLUGIN_FILES" ,
65
78
},
66
79
cli.IntFlag {
67
80
Name : "retries" ,
68
- Usage : "deployment status check retries. Sleep 30s between each check " ,
81
+ Usage : "number of deployment status check retries" ,
69
82
EnvVar : "RETRIES,PLUGIN_RETRIES" ,
70
83
Value : 10 ,
71
84
},
72
85
cli.DurationFlag {
73
86
Name : "check-interval" ,
74
87
Usage : "deployment status check interval" ,
75
88
EnvVar : "CHECK_INTERVAL,PLUGIN_CHECK_INTERVAL" ,
76
- Value : 10 * time .Second ,
89
+ Value : 15 * time .Second ,
77
90
},
78
91
}
79
92
@@ -82,36 +95,39 @@ func main() {
82
95
}
83
96
84
97
func run (c * cli.Context ) error {
85
- if len (os .Args ) < 2 {
86
- cli .ShowAppHelp (c )
87
- }
88
98
if len (c .StringSlice ("file" )) == 0 {
89
- return cli .NewExitError ("At least one resource file must be specified." , 1 )
99
+ logError .Print ("no kubernetes resource files specified" )
100
+ return cli .NewExitError ("" , 1 )
90
101
}
91
102
// Check if all files exist first - fail early
92
103
for _ , fn := range c .StringSlice ("file" ) {
93
104
if _ , err := os .Stat (fn ); err != nil {
94
- return cli .NewExitError (err .Error (), 1 )
105
+ logError .Println (err )
106
+ return cli .NewExitError ("" , 1 )
95
107
}
96
108
}
97
109
98
110
for _ , fn := range c .StringSlice ("file" ) {
99
111
// TODO: check if `-f` is a directory and expand all files in it
100
112
f , err := os .Open (fn )
101
113
if err != nil {
102
- return cli .NewExitError (err .Error (), 1 )
114
+ logError .Println (err )
115
+ return cli .NewExitError ("" , 1 )
103
116
}
104
117
defer f .Close ()
105
118
106
119
resource := ObjectResource {FileName : fn }
107
- if err := render (& resource , envToMap ()); err != nil {
108
- return cli .NewExitError (err .Error (), 1 )
120
+ if err := render (& resource , envToMap (), c .Bool ("debug" )); err != nil {
121
+ logError .Println (err )
122
+ return cli .NewExitError ("" , 1 )
109
123
}
110
124
if err := yaml .Unmarshal (resource .Template , & resource ); err != nil {
111
- return cli .NewExitError (err .Error (), 1 )
125
+ logError .Println (err )
126
+ return cli .NewExitError ("" , 1 )
112
127
}
113
128
if err := deploy (c , & resource ); err != nil {
114
- return cli .NewExitError (err .Error (), 1 )
129
+ logError .Println (err )
130
+ return cli .NewExitError ("" , 1 )
115
131
}
116
132
}
117
133
@@ -121,6 +137,9 @@ func run(c *cli.Context) error {
121
137
func deploy (c * cli.Context , r * ObjectResource ) error {
122
138
args := []string {"apply" , "-f" , "-" }
123
139
cmd := newKubeCmd (c , args )
140
+ if c .Bool ("debug" ) {
141
+ logDebug .Printf ("kubectl arguments: %q" , strings .Join (cmd .Args , " " ))
142
+ }
124
143
stdin , err := cmd .StdinPipe ()
125
144
if err != nil {
126
145
return err
@@ -131,12 +150,11 @@ func deploy(c *cli.Context, r *ObjectResource) error {
131
150
if err != nil {
132
151
return err
133
152
}
134
- cmd .Stdout = os .Stdout
135
- cmd .Stderr = os .Stderr
153
+ logInfo .Printf ("deploying %s/%s" , strings .ToLower (r .Kind ), r .Name )
136
154
if err = cmd .Run (); err != nil {
137
155
return err
138
156
}
139
-
157
+ logInfo . Printf ( "%s %q submitted" , strings . ToLower ( r . Kind ), r . Name )
140
158
if r .Kind != "Deployment" {
141
159
return nil
142
160
}
@@ -147,38 +165,46 @@ func deploy(c *cli.Context, r *ObjectResource) error {
147
165
if err := updateDeploymentStatus (c , r ); err != nil {
148
166
return err
149
167
}
168
+ // If this is a new deployment, Replicas and UpdatedReplicas count will
169
+ // be 0, so we want to wait and retry
170
+ if r .DeploymentStatus .Replicas == 0 && r .DeploymentStatus .UpdatedReplicas == 0 {
171
+ if c .Bool ("debug" ) {
172
+ logDebug .Printf ("new deployment, sleeping 3 seconds" )
173
+ }
174
+ time .Sleep (3 * time .Second )
175
+ }
176
+
150
177
og := r .DeploymentStatus .ObservedGeneration
151
178
for {
152
179
r .DeploymentStatus = DeploymentStatus {}
153
180
if err := updateDeploymentStatus (c , r ); err != nil {
154
181
return err
155
182
}
156
-
157
- // If this is a new deployment, r.DeploymentStatus.Replicas count will
158
- // be 0, so we want to wait and retry
159
- if r .DeploymentStatus .Replicas == 0 {
160
- time .Sleep (5 * time .Second )
161
- continue
183
+ if c .Bool ("debug" ) {
184
+ logDebug .Printf ("fetching deployment status: %+v" , r .DeploymentStatus )
162
185
}
163
186
164
- if (r .DeploymentStatus .UnavailableReplicas == 0 || r .DeploymentStatus .AvailableReplicas == r .DeploymentStatus .Replicas ) &&
187
+ if (r .DeploymentStatus .UnavailableReplicas == 0 && r .DeploymentStatus .AvailableReplicas == r .DeploymentStatus .Replicas ) &&
165
188
r .DeploymentStatus .Replicas == r .DeploymentStatus .UpdatedReplicas {
166
- fmt .Printf ("%q deployment is complete. Available replicas: %d. \n " ,
189
+ logInfo .Printf ("deployment %q is complete. Available replicas: %d\n " ,
167
190
r .Name , r .DeploymentStatus .AvailableReplicas )
168
191
return nil
169
192
}
170
- fmt .Printf ("%q deployment in progress. Unavailable replicas: %d.\n " ,
193
+ logInfo .Printf ("deployment %q in progress. Unavailable replicas: %d.\n " ,
171
194
r .Name , r .DeploymentStatus .UnavailableReplicas )
172
- time .Sleep (time .Second * 30 )
195
+ if c .Bool ("debug" ) {
196
+ logDebug .Printf ("sleeping for %q" , c .Duration ("check-interval" ))
197
+ }
198
+ time .Sleep (c .Duration ("check-interval" ))
173
199
attempt ++
174
200
if attempt > retries {
175
- return fmt .Errorf ("Deployment failed. Max retries reached." )
201
+ return fmt .Errorf ("deployment %q failed. Max retries reached" , r . Name )
176
202
}
177
203
178
204
// Fail the deployment in case another deployment has started
179
205
if c .Bool ("fail-superseded" ) {
180
206
if og != r .DeploymentStatus .ObservedGeneration {
181
- return fmt .Errorf ("Deployment failed. It has been superseded by another deployment. " )
207
+ return fmt .Errorf ("deployment failed. It has been superseded by another deployment" )
182
208
}
183
209
}
184
210
}
@@ -205,20 +231,21 @@ func updateDeploymentStatus(c *cli.Context, r *ObjectResource) error {
205
231
206
232
func newKubeCmd (c * cli.Context , args []string ) * exec.Cmd {
207
233
kube := "kubectl"
208
- if c .IsSet ("kube-server " ) {
209
- args = append (args , "--server=" + c .String ("kube-server" ) )
234
+ if c .IsSet ("namespace " ) {
235
+ args = append ([] string { "--namespace=" + c .String ("namespace" )}, args ... )
210
236
}
211
- if c .IsSet ("insecure-skip-tls-verify " ) {
212
- args = append (args , "--insecure-skip-tls-verify" )
237
+ if c .IsSet ("context " ) {
238
+ args = append ([] string { "--context=" + c . String ( "context" )}, args ... )
213
239
}
214
240
if c .IsSet ("kube-token" ) {
215
- args = append (args , "--token=" + c .String ("kube-token" ))
241
+ args = append ([] string { "--token=" + c .String ("kube-token" )}, args ... )
216
242
}
217
- if c .IsSet ("context " ) {
218
- args = append (args , "--context=" + c . String ( "context" ) )
243
+ if c .IsSet ("insecure-skip-tls-verify " ) {
244
+ args = append ([] string { "--insecure-skip-tls-verify" }, args ... )
219
245
}
220
- if c .IsSet ("namespace " ) {
221
- args = append (args , "--namespace=" + c .String ("namespace" ) )
246
+ if c .IsSet ("kube-server " ) {
247
+ args = append ([] string { "--server=" + c .String ("kube-server" )}, args ... )
222
248
}
249
+
223
250
return exec .Command (kube , args ... )
224
251
}
0 commit comments