Skip to content

Commit f8b5988

Browse files
authored
Merge pull request #14 from UKHomeOffice/improv
Improvements
2 parents 9e54787 + e755172 commit f8b5988

File tree

2 files changed

+78
-45
lines changed

2 files changed

+78
-45
lines changed

main.go

+70-43
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,30 @@ package main
33
import (
44
"fmt"
55
"io/ioutil"
6+
"log"
67
"os"
78
"os/exec"
9+
"strings"
810
"time"
911

1012
"github.com/urfave/cli"
1113
"gopkg.in/yaml.v2"
1214
)
1315

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+
}
1630

1731
func main() {
1832
app := cli.NewApp()
@@ -23,10 +37,9 @@ func main() {
2337

2438
app.Flags = []cli.Flag{
2539
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",
3043
},
3144
cli.BoolFlag{
3245
Name: "insecure-skip-tls-verify",
@@ -60,20 +73,20 @@ func main() {
6073
},
6174
cli.StringSliceFlag{
6275
Name: "file, f",
63-
Usage: "a list of kubernetes resources FILE",
76+
Usage: "list of kubernetes resources FILE",
6477
EnvVar: "FILES,PLUGIN_FILES",
6578
},
6679
cli.IntFlag{
6780
Name: "retries",
68-
Usage: "deployment status check retries. Sleep 30s between each check",
81+
Usage: "number of deployment status check retries",
6982
EnvVar: "RETRIES,PLUGIN_RETRIES",
7083
Value: 10,
7184
},
7285
cli.DurationFlag{
7386
Name: "check-interval",
7487
Usage: "deployment status check interval",
7588
EnvVar: "CHECK_INTERVAL,PLUGIN_CHECK_INTERVAL",
76-
Value: 10 * time.Second,
89+
Value: 15 * time.Second,
7790
},
7891
}
7992

@@ -82,36 +95,39 @@ func main() {
8295
}
8396

8497
func run(c *cli.Context) error {
85-
if len(os.Args) < 2 {
86-
cli.ShowAppHelp(c)
87-
}
8898
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)
90101
}
91102
// Check if all files exist first - fail early
92103
for _, fn := range c.StringSlice("file") {
93104
if _, err := os.Stat(fn); err != nil {
94-
return cli.NewExitError(err.Error(), 1)
105+
logError.Println(err)
106+
return cli.NewExitError("", 1)
95107
}
96108
}
97109

98110
for _, fn := range c.StringSlice("file") {
99111
// TODO: check if `-f` is a directory and expand all files in it
100112
f, err := os.Open(fn)
101113
if err != nil {
102-
return cli.NewExitError(err.Error(), 1)
114+
logError.Println(err)
115+
return cli.NewExitError("", 1)
103116
}
104117
defer f.Close()
105118

106119
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)
109123
}
110124
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)
112127
}
113128
if err := deploy(c, &resource); err != nil {
114-
return cli.NewExitError(err.Error(), 1)
129+
logError.Println(err)
130+
return cli.NewExitError("", 1)
115131
}
116132
}
117133

@@ -121,6 +137,9 @@ func run(c *cli.Context) error {
121137
func deploy(c *cli.Context, r *ObjectResource) error {
122138
args := []string{"apply", "-f", "-"}
123139
cmd := newKubeCmd(c, args)
140+
if c.Bool("debug") {
141+
logDebug.Printf("kubectl arguments: %q", strings.Join(cmd.Args, " "))
142+
}
124143
stdin, err := cmd.StdinPipe()
125144
if err != nil {
126145
return err
@@ -131,12 +150,11 @@ func deploy(c *cli.Context, r *ObjectResource) error {
131150
if err != nil {
132151
return err
133152
}
134-
cmd.Stdout = os.Stdout
135-
cmd.Stderr = os.Stderr
153+
logInfo.Printf("deploying %s/%s", strings.ToLower(r.Kind), r.Name)
136154
if err = cmd.Run(); err != nil {
137155
return err
138156
}
139-
157+
logInfo.Printf("%s %q submitted", strings.ToLower(r.Kind), r.Name)
140158
if r.Kind != "Deployment" {
141159
return nil
142160
}
@@ -147,38 +165,46 @@ func deploy(c *cli.Context, r *ObjectResource) error {
147165
if err := updateDeploymentStatus(c, r); err != nil {
148166
return err
149167
}
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+
150177
og := r.DeploymentStatus.ObservedGeneration
151178
for {
152179
r.DeploymentStatus = DeploymentStatus{}
153180
if err := updateDeploymentStatus(c, r); err != nil {
154181
return err
155182
}
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)
162185
}
163186

164-
if (r.DeploymentStatus.UnavailableReplicas == 0 || r.DeploymentStatus.AvailableReplicas == r.DeploymentStatus.Replicas) &&
187+
if (r.DeploymentStatus.UnavailableReplicas == 0 && r.DeploymentStatus.AvailableReplicas == r.DeploymentStatus.Replicas) &&
165188
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",
167190
r.Name, r.DeploymentStatus.AvailableReplicas)
168191
return nil
169192
}
170-
fmt.Printf("%q deployment in progress. Unavailable replicas: %d.\n",
193+
logInfo.Printf("deployment %q in progress. Unavailable replicas: %d.\n",
171194
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"))
173199
attempt++
174200
if attempt > retries {
175-
return fmt.Errorf("Deployment failed. Max retries reached.")
201+
return fmt.Errorf("deployment %q failed. Max retries reached", r.Name)
176202
}
177203

178204
// Fail the deployment in case another deployment has started
179205
if c.Bool("fail-superseded") {
180206
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")
182208
}
183209
}
184210
}
@@ -205,20 +231,21 @@ func updateDeploymentStatus(c *cli.Context, r *ObjectResource) error {
205231

206232
func newKubeCmd(c *cli.Context, args []string) *exec.Cmd {
207233
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...)
210236
}
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...)
213239
}
214240
if c.IsSet("kube-token") {
215-
args = append(args, "--token="+c.String("kube-token"))
241+
args = append([]string{"--token=" + c.String("kube-token")}, args...)
216242
}
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...)
219245
}
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...)
222248
}
249+
223250
return exec.Command(kube, args...)
224251
}

tmpl.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,24 @@ import (
88
"text/template"
99
)
1010

11-
func render(r *ObjectResource, vars map[string]string) error {
11+
func render(r *ObjectResource, vars map[string]string, debug bool) error {
12+
if debug {
13+
logDebug.Printf("rendering %q template.", r.FileName)
14+
}
1215
tmpl, err := ioutil.ReadFile(r.FileName)
1316
if err != nil {
1417
return err
1518
}
16-
var b bytes.Buffer
1719
t := template.Must(template.New(r.FileName).Parse(string(tmpl)))
1820
t.Option("missingkey=error")
21+
var b bytes.Buffer
1922
if err = t.Execute(&b, vars); err != nil {
2023
return err
2124
}
2225
r.Template = b.Bytes()
26+
if debug {
27+
logDebug.Printf("template content:\n" + string(r.Template))
28+
}
2329
return nil
2430
}
2531

0 commit comments

Comments
 (0)