diff --git a/pkg/kubernetes/client/apply.go b/pkg/kubernetes/client/apply.go index e7b1c5e80..a166d84c0 100644 --- a/pkg/kubernetes/client/apply.go +++ b/pkg/kubernetes/client/apply.go @@ -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 { - // 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") @@ -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)) -} diff --git a/pkg/kubernetes/reconcile.go b/pkg/kubernetes/reconcile.go index ffc0d6f3e..3d23b38a9 100644 --- a/pkg/kubernetes/reconcile.go +++ b/pkg/kubernetes/reconcile.go @@ -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 /, // provided the manifests match the given regular expressions. It finds each manifest by // recursively walking the jsonnet structure. @@ -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 { + 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() })