Skip to content

Commit

Permalink
Merge pull request #78 from arehmandev/master
Browse files Browse the repository at this point in the history
Added dryrun, added retry for checking deploy status and added examples
  • Loading branch information
gambol99 committed Jun 15, 2018
2 parents 5f43bcb + e74fac8 commit bbf1be6
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 53 deletions.
50 changes: 27 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ You can fail an ongoing deployment if there's been a new deployment by adding `-
## Templating

You can add the flag --debug-templates to render templates at run time.
Check the examples folder for more info.

[Sprig](https://masterminds.github.io/sprig/) is used to add templating functions.

Expand All @@ -108,29 +109,31 @@ can also be used to iterate over returned list.
# split.yaml
---
apiVersion: v1
data:
foo:
{{ range split .LIST "," }}
- {{.}}
{{ end }}
kind: ConfigMap
metadata:
name: list
data:
foo:
{{ range split .LIST "," }}
- {{ . }}
{{- end -}}
```

```
$ export LIST="one,two,three"
$ ./kd -f split.yaml -- --dry-run -o yaml
$ ./kd -f split.yaml --dryrun --debug-templates
[INFO] 2017/10/18 15:08:09 main.go:241: deploying configmap/list
[INFO] 2017/10/18 15:08:09 main.go:248: apiVersion: v1
data:
foo:
- one
- two
- three
---
apiVersion: v1
kind: ConfigMap
metadata:
name: list
data:
foo:
- one
- two
- three
```
### file
Expand All @@ -141,32 +144,33 @@ metadata:
# file.yaml
---
apiVersion: v1
data:
foo:
{{ file .BAR }}
kind: ConfigMap
metadata:
name: list
data:
foo:
{{ file .BAR | indent 4}}
```

```
$ cat <<EOF > config.yaml
- one
- two
- three
- one
- two
- three
EOF
$ export BAR=${PWD}/config.yaml
$ ./kd -f file.yaml -- --dry-run -o yaml
$ ./kd -f file.yaml --dryrun --debug-templates
[INFO] 2017/10/18 15:08:09 main.go:241: deploying configmap/list
[INFO] 2017/10/18 15:08:09 main.go:248: apiVersion: v1
data:
foo:
- one
- two
- three
apiVersion: v1
kind: ConfigMap
metadata:
name: list
data:
foo:
- one
- two
- three
```

## Configuration
Expand Down
14 changes: 14 additions & 0 deletions examples/example.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

export NGINX_IMAGE_TAG="1.11-alpine"
#kd -c mykube -namespace testing -f nginx-deployment.yaml --debug-templates --dryrun

export LIST="ENTRY1,ENTRY2,ENTRY3,ENTRY4"
#kd -c mykube -n testing -f split.yaml --debug-templates --dryrun

export BAR="${PWD}/vars/config"
#kd -c mykube -n testing -f file.yaml --debug-templates --dryrun

kd -f . --debug-templates --dryrun

echo "Dry run example complete"
9 changes: 9 additions & 0 deletions examples/file.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: list
data:
foo:
{{ file .BAR | indent 4 }}

26 changes: 26 additions & 0 deletions examples/nginx-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 5
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:{{.NGINX_IMAGE_TAG}}
ports:
- containerPort: 80
resources:
limits:
cpu: "0.1"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
timeoutSeconds: 1
11 changes: 11 additions & 0 deletions examples/split.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: list
data:
foo:
{{ range split .LIST "," }}
- {{ . }}
{{- end -}}

3 changes: 3 additions & 0 deletions examples/vars/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- one
- two
- three
76 changes: 55 additions & 21 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ import (
yaml "gopkg.in/yaml.v2"
)

const DeployDelaySeconds = 3
const (
// DeployDelaySeconds - delay between deployments
DeployDelaySeconds = 3
// MaxHealthcheckRetries - Amount of times to retry checking of resource after deployment
MaxHealthcheckRetries = 3
// HealthCheckSleepDuration - the amount of time to sleep (seconds) between healthcehck retries
HealthCheckSleepDuration = time.Duration(int64(2)) * time.Second
)

var (
// Version is set at compile time, passing -ldflags "-X main.Version=<build version>"
Expand All @@ -27,6 +34,9 @@ var (
logInfo *log.Logger
logError *log.Logger
logDebug *log.Logger

// dryRun Defaults to false
dryRun bool
)

func init() {
Expand All @@ -53,6 +63,12 @@ func main() {
Usage: "debug template output",
EnvVar: "DEBUG_TEMPLATES,PLUGIN_DEBUG_TEMPLATES",
},
cli.BoolFlag{
Name: "dryrun",
Usage: "if true, kd will exit prior to deployment",
EnvVar: "DRY_RUN",
Destination: &dryRun,
},
cli.BoolFlag{
Name: "insecure-skip-tls-verify",
Usage: "if true, the server's certificate will not be checked for validity",
Expand Down Expand Up @@ -196,8 +212,12 @@ func run(c *cli.Context) error {
if err := yaml.Unmarshal(r.Template, &r); err != nil {
return err
}
if err := deploy(c, r); err != nil {
return err

// Only perform deploy if dry-run is not set to true
if !dryRun {
if err := deploy(c, r); err != nil {
return err
}
}
}
return nil
Expand Down Expand Up @@ -269,10 +289,10 @@ func isWatchableResouce(r *ObjectResource) bool {
included := false
watchable := []string{"Deployment", "StatefulSet", "DaemonSet", "Job"}
for _, item := range watchable {
if item == r.Kind {
included = true
break
}
if item == r.Kind {
included = true
break
}
}
return included
}
Expand Down Expand Up @@ -301,19 +321,33 @@ func watchResource(c *cli.Context, r *ObjectResource) error {

og := r.DeploymentStatus.ObservedGeneration
ready := false
var availableResourceCount int32 = 0
var unavailableResourceCount int32 = 0
var availableResourceCount int32
var unavailableResourceCount int32

for {
select {
case <-timeout:
return fmt.Errorf("%s rolling update %q timed out after %s", r.Kind, r.Name, c.Duration("timeout").String())
case <-ticker.C:
r.DeploymentStatus = DeploymentStatus{}
// @TODO should a one-off error (perhaps network issue) cause us to completly fail?
if err := updateResourceStatus(c, r); err != nil {
return err

// Retry on error until max retries is met
for attempt := 0; attempt < MaxHealthcheckRetries; attempt++ {
if err := updateResourceStatus(c, r); err != nil {

// Return error on final try
if attempt == (MaxHealthcheckRetries - 1) {
return err
}

// Sleep between retries
time.Sleep(HealthCheckSleepDuration)

} else {
break
}
}

if c.Bool("debug") {
logDebug.Printf("fetching %s %q status: %+v", r.Kind, r.Name, r.DeploymentStatus)
}
Expand All @@ -322,33 +356,33 @@ func watchResource(c *cli.Context, r *ObjectResource) error {

switch r.Kind {
case "Deployment":
if (r.DeploymentStatus.UnavailableReplicas == 0 && r.DeploymentStatus.AvailableReplicas == r.DeploymentStatus.Replicas) &&
r.DeploymentStatus.Replicas == r.DeploymentStatus.UpdatedReplicas {
if (r.DeploymentStatus.UnavailableReplicas == 0 && r.DeploymentStatus.AvailableReplicas == r.DeploymentStatus.Replicas) &&
r.DeploymentStatus.Replicas == r.DeploymentStatus.UpdatedReplicas {
ready = true
}
availableResourceCount = r.DeploymentStatus.AvailableReplicas
unavailableResourceCount = r.DeploymentStatus.UnavailableReplicas

case "StatefulSet":
if (r.DeploymentStatus.ReadyReplicas == r.ObjectSpec.Replicas) &&
r.DeploymentStatus.CurrentRevision == r.DeploymentStatus.UpdateRevision {
if (r.DeploymentStatus.ReadyReplicas == r.ObjectSpec.Replicas) &&
r.DeploymentStatus.CurrentRevision == r.DeploymentStatus.UpdateRevision {
ready = true
}
availableResourceCount = r.DeploymentStatus.ReadyReplicas
unavailableResourceCount = r.ObjectSpec.Replicas-r.DeploymentStatus.ReadyReplicas
unavailableResourceCount = r.ObjectSpec.Replicas - r.DeploymentStatus.ReadyReplicas

case "DaemonSet":
if (r.DeploymentStatus.DesiredNumberScheduled == r.DeploymentStatus.NumberAvailable) &&
(r.DeploymentStatus.UpdatedNumberScheduled == r.DeploymentStatus.DesiredNumberScheduled) {
if (r.DeploymentStatus.DesiredNumberScheduled == r.DeploymentStatus.NumberAvailable) &&
(r.DeploymentStatus.UpdatedNumberScheduled == r.DeploymentStatus.DesiredNumberScheduled) {
ready = true
}
availableResourceCount = r.DeploymentStatus.NumberAvailable
unavailableResourceCount = r.DeploymentStatus.DesiredNumberScheduled-r.DeploymentStatus.UpdatedNumberScheduled
unavailableResourceCount = r.DeploymentStatus.DesiredNumberScheduled - r.DeploymentStatus.UpdatedNumberScheduled

case "Job":
if r.DeploymentStatus.Succeeded == 1 {
availableResourceCount = 1
ready = true
ready = true
}
unavailableResourceCount = 1
}
Expand Down
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestListDirectory(t *testing.T) {
{
name: "Check yaml files exist",
input: "test/TestListDirectory/",
want: []string{"test/TestListDirectory/a.yaml", "test/TestListDirectory/b.yaml", "test/TestListDirectory/empty.yaml"},
want: []string{"test/TestListDirectory/1-resource.yaml", "test/TestListDirectory/2-resource.yaml", "test/TestListDirectory/a.yaml", "test/TestListDirectory/b.yaml", "test/TestListDirectory/empty.yaml"},
},
}

Expand Down
1 change: 1 addition & 0 deletions render.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/Masterminds/sprig"
)

// Render - the function used for rendering templates (with Sprig support)
func Render(tmpl string, vars map[string]string) (string, error) {
fm := sprig.TxtFuncMap()
// Preserve old KD functionality (strings param order vs sprig)
Expand Down
16 changes: 8 additions & 8 deletions render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ func readfile(filepath string) string {
}

func TestRender(t *testing.T) {
test_data := make(map[string]string)
test_data["MY_LIST"] = "one,two,three"
test_data["FILE_PATH"] = "test/complex-file.pem"
testData := make(map[string]string)
testData["MY_LIST"] = "one,two,three"
testData["FILE_PATH"] = "test/complex-file.pem"

cases := []struct {
name string
Expand All @@ -39,31 +39,31 @@ func TestRender(t *testing.T) {
{
name: "Check list variables are rendered",
inputdata: readfile("test/list-prerendered.yaml"),
inputvars: test_data,
inputvars: testData,
want: readfile("test/list-rendered.yaml"),
},
{
name: "Check file function is rendered",
inputdata: readfile("test/file-prerendered.yaml"),
inputvars: test_data,
inputvars: testData,
want: readfile("test/file-rendered.yaml"),
},
{
name: "Check contains function works as expected",
inputdata: readfile("test/contains-prerendered.yaml"),
inputvars: test_data,
inputvars: testData,
want: readfile("test/contains-rendered.yaml"),
},
{
name: "Check hasPrefix function works as expected",
inputdata: readfile("test/hasPrefix-prerendered.yaml"),
inputvars: test_data,
inputvars: testData,
want: readfile("test/hasPrefix-rendered.yaml"),
},
{
name: "Check hasSuffix function works as expected",
inputdata: readfile("test/hasSuffix-prerendered.yaml"),
inputvars: test_data,
inputvars: testData,
want: readfile("test/hasSuffix-rendered.yaml"),
},
}
Expand Down
2 changes: 2 additions & 0 deletions test/TestListDirectory/1-resource.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
noop: nil
2 changes: 2 additions & 0 deletions test/TestListDirectory/2-resource.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
noop: nil
1 change: 1 addition & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type DeploymentStatus struct {
Succeeded int32 `yaml:"succeeded,omitempty"`
}

// ObjectSpec - fields used for setting StatefulSet update behaviour
type ObjectSpec struct {
// UpdateStrategy indicates the StatefulSetUpdateStrategy that will be employed to update Pods in the StatefulSet when a revision is made to Template.
UpdateStrategy `yaml:"updateStrategy,omitempty"`
Expand Down

0 comments on commit bbf1be6

Please sign in to comment.