Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort kubernetes objects before applying. #244

Merged
merged 3 commits into from
Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions pkg/kubernetes/client/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,11 @@ import (
"os"
"strings"

funk "github.com/thoas/go-funk"

"github.com/grafana/tanka/pkg/kubernetes/manifest"
)

// Apply applies the given yaml to the cluster
func (k Kubectl) Apply(data manifest.List, opts ApplyOpts) error {
sh0rez marked this conversation as resolved.
Show resolved Hide resolved
// create namespaces first to succeed first try
ns := filterNamespace(data)
if len(ns) > 0 {
if err := k.apply(ns, opts); err != nil {
return err
}
}

return k.apply(data, opts)
}

func (k Kubectl) apply(data manifest.List, opts ApplyOpts) error {
argv := []string{"-f", "-"}
if opts.Force {
argv = append(argv, "--force")
Expand All @@ -40,9 +26,3 @@ func (k Kubectl) apply(data manifest.List, opts ApplyOpts) error {

return cmd.Run()
}

func filterNamespace(in manifest.List) manifest.List {
return manifest.List(funk.Filter(in, func(i manifest.Manifest) bool {
return strings.ToLower(i.Kind()) == "namespace"
}).([]manifest.Manifest))
}
62 changes: 62 additions & 0 deletions pkg/kubernetes/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,44 @@ import (
"github.com/grafana/tanka/pkg/spec/v1alpha1"
)

// Order in which install different kinds of Kubernetes objects.
// Inspired by https://github.com/helm/helm/blob/8c84a0bc0376650bc3d7334eef0c46356c22fa36/pkg/releaseutil/kind_sorter.go
var kindOrder = []string{
"Namespace",
"NetworkPolicy",
"ResourceQuota",
"LimitRange",
"PodSecurityPolicy",
"PodDisruptionBudget",
"ServiceAccount",
"Secret",
"ConfigMap",
"StorageClass",
"PersistentVolume",
"PersistentVolumeClaim",
"CustomResourceDefinition",
"ClusterRole",
"ClusterRoleList",
"ClusterRoleBinding",
"ClusterRoleBindingList",
"Role",
"RoleList",
"RoleBinding",
"RoleBindingList",
"Service",
"DaemonSet",
"Pod",
"ReplicationController",
"ReplicaSet",
"Deployment",
"HorizontalPodAutoscaler",
"StatefulSet",
"Job",
"CronJob",
"Ingress",
"APIService",
}

// Reconcile extracts kubernetes Manifests from raw evaluated jsonnet <kind>/<name>,
// provided the manifests match the given regular expressions. It finds each manifest by
// recursively walking the jsonnet structure.
Expand Down Expand Up @@ -49,9 +87,33 @@ func Reconcile(raw map[string]interface{}, spec v1alpha1.Spec, targets []*regexp

// Stable output order
sort.SliceStable(out, func(i int, j int) bool {
sh0rez marked this conversation as resolved.
Show resolved Hide resolved
var io, jo int

// anything that is not in kindOrder will get to the end of the install list.
for io = 0; io < len(kindOrder); io++ {
if out[i].Kind() == kindOrder[io] {
break
}
}

for jo = 0; jo < len(kindOrder); jo++ {
if out[j].Kind() == kindOrder[jo] {
break
}
}

// If Kind of both objects are at different indexes of kindOrder, sort by them
if io != jo {
return io < jo
}

// If the Kinds themselves are different (e.g. both of the Kinds are not in
// the kindOrder), order alphabetically.
if out[i].Kind() != out[j].Kind() {
return out[i].Kind() < out[j].Kind()
}

// Otherwise, order the objects by name.
return out[i].Metadata().Name() < out[j].Metadata().Name()
})

Expand Down