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

remove config hash when namespace is excluded #236

Merged
merged 5 commits into from
Feb 10, 2021
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
66 changes: 41 additions & 25 deletions controllers/instancegroup_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ func (r *InstanceGroupReconciler) Reconcile(ctxt context.Context, req ctrl.Reque
r.Log.Error(err, "reconcile failed")
return ctrl.Result{}, err
}
statusPatch := kubeprovider.MergePatch(*instanceGroup)

// set/unset finalizer
r.SetFinalizer(instanceGroup)
Expand All @@ -132,25 +133,17 @@ func (r *InstanceGroupReconciler) Reconcile(ctxt context.Context, req ctrl.Reque
ConfigRetention: r.ConfigRetention,
}

if !reflect.DeepEqual(r.ConfigMap, &corev1.ConfigMap{}) {
var (
status = instanceGroup.GetStatus()
configHash = kubeprovider.ConfigmapHash(r.ConfigMap)
)
status.SetConfigHash(configHash)

var isExcludedNamespace bool
if !reflect.DeepEqual(*r.ConfigMap, corev1.ConfigMap{}) {
// Configmap exist - apply defaults/boundaries if namespace is not excluded
namespace := instanceGroup.GetNamespace()
if ns, ok := r.Namespaces[namespace]; ok {
nsObject, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&ns)
if err != nil {
return ctrl.Result{}, err
}
unstructuredNamespace := &unstructured.Unstructured{
Object: nsObject,
}
if kubeprovider.HasAnnotation(unstructuredNamespace, provisioners.ConfigurationExclusionAnnotationKey, "true") {
isExcludedNamespace = true
r.Log.Info("namespace excluded from managed configuration", "namespace", namespace)
}
}

if !isExcludedNamespace {
if !r.IsNamespaceAnnotated(namespace, provisioners.ConfigurationExclusionAnnotationKey, "true") {
// namespace is not excluded - proceed with applying defaults/boundaries
var defaultConfig *provisioners.ProvisionerConfiguration
if defaultConfig, err = provisioners.NewProvisionerConfiguration(r.ConfigMap, instanceGroup); err != nil {
return ctrl.Result{}, err
Expand All @@ -162,6 +155,10 @@ func (r *InstanceGroupReconciler) Reconcile(ctxt context.Context, req ctrl.Reque
}

input.InstanceGroup = defaultConfig.InstanceGroup
} else {
// unset config hash if namespace is excluded
r.Log.Info("namespace excluded from managed configuration", "namespace", namespace)
status.SetConfigHash("")
}
}

Expand All @@ -184,34 +181,53 @@ func (r *InstanceGroupReconciler) Reconcile(ctxt context.Context, req ctrl.Reque

if err = input.InstanceGroup.Validate(); err != nil {
ctx.SetState(v1alpha1.ReconcileErr)
r.UpdateStatus(input.InstanceGroup)
r.PatchStatus(input.InstanceGroup, statusPatch)
return ctrl.Result{}, errors.Wrapf(err, "provisioner %v reconcile failed", provisionerKind)
}

if err = HandleReconcileRequest(ctx); err != nil {
ctx.SetState(v1alpha1.ReconcileErr)
r.UpdateStatus(input.InstanceGroup)
r.PatchStatus(input.InstanceGroup, statusPatch)
return ctrl.Result{}, errors.Wrapf(err, "provisioner %v reconcile failed", provisionerKind)
}

if provisioners.IsRetryable(input.InstanceGroup) {
r.Log.Info("reconcile event ended with requeue", "instancegroup", req.NamespacedName, "provisioner", provisionerKind)
r.UpdateStatus(input.InstanceGroup)
r.PatchStatus(input.InstanceGroup, statusPatch)
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
}

r.UpdateStatus(input.InstanceGroup)
r.Log.Info("reconcile event ended", "instancegroup", req.NamespacedName, "provisioner", provisionerKind)
r.PatchStatus(input.InstanceGroup, statusPatch)
r.Finalize(instanceGroup)
return ctrl.Result{}, nil
}

func (r *InstanceGroupReconciler) UpdateStatus(ig *v1alpha1.InstanceGroup) {
r.Log.Info("updating resource status", "instancegroup", ig.NamespacedName())
if err := r.Status().Update(context.Background(), ig); err != nil {
func (r *InstanceGroupReconciler) PatchStatus(instanceGroup *v1alpha1.InstanceGroup, patch client.Patch) {
patchData, _ := patch.Data(instanceGroup)
r.Log.Info("patching resource status", "instancegroup", instanceGroup.NamespacedName(), "patch", string(patchData), "resourceVersion", instanceGroup.GetResourceVersion())
if err := r.Status().Patch(context.Background(), instanceGroup, patch); err != nil {
// avoid error if object already deleted
if kubeprovider.IsStorageError(err) {
return
}
r.Log.Info("failed to update status", "error", err, "instancegroup", ig.NamespacedName())
r.Log.Info("failed to patch status", "error", err, "instancegroup", instanceGroup.NamespacedName())
}
}

func (r *InstanceGroupReconciler) IsNamespaceAnnotated(namespace, key, value string) bool {
if ns, ok := r.Namespaces[namespace]; ok {
nsObject, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&ns)
if err != nil {
r.Log.Error(err, "failed to convert namespace to unstructured", "namespace", namespace)
return false
}
unstructuredNamespace := &unstructured.Unstructured{
Object: nsObject,
}
if kubeprovider.HasAnnotation(unstructuredNamespace, key, value) {
return true
}
}
return false
}
40 changes: 40 additions & 0 deletions controllers/providers/kubernetes/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ package kubernetes
import (
"bytes"
"context"
"encoding/json"
"fmt"
"html/template"
"os"
"os/user"
"reflect"
"strings"

jsonpatch "github.com/evanphx/json-patch"
"github.com/ghodss/yaml"
"github.com/keikoproj/instance-manager/api/v1alpha1"
"github.com/keikoproj/instance-manager/controllers/common"
Expand All @@ -32,10 +35,12 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type KubernetesClientSet struct {
Expand Down Expand Up @@ -253,6 +258,11 @@ func ParseCustomResourceYaml(raw string) (*unstructured.Unstructured, error) {

func ConfigmapHash(cm *corev1.ConfigMap) string {
var buf strings.Builder

if reflect.DeepEqual(*cm, corev1.ConfigMap{}) {
return ""
}

cmStr := cm.String()
buf.WriteString(cmStr[strings.Index(cm.String(), ",Data:")+1:])
return common.StringMD5(buf.String())
Expand All @@ -278,3 +288,33 @@ func IsPathValue(resource unstructured.Unstructured, path, value string) bool {

return false
}

type statusPatch struct {
from v1alpha1.InstanceGroup
}

func (s *statusPatch) Type() types.PatchType {
return types.MergePatchType
}

func (s *statusPatch) Data(obj runtime.Object) ([]byte, error) {
origObj := s.from.DeepCopyObject()
originalJSON, err := json.Marshal(origObj)
if err != nil {
return nil, err
}

modObj := obj.(*v1alpha1.InstanceGroup)
modObj.Spec = v1alpha1.InstanceGroupSpec{}
modifiedJSON, err := json.Marshal(modObj.DeepCopyObject())
if err != nil {
return nil, err
}

return jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
}

func MergePatch(obj v1alpha1.InstanceGroup) client.Patch {
obj.Spec = v1alpha1.InstanceGroupSpec{}
return &statusPatch{obj}
}
2 changes: 0 additions & 2 deletions controllers/provisioners/eks/eks.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ func New(p provisioners.ProvisionerInput) *EksInstanceGroupContext {
configuration = instanceGroup.GetEKSConfiguration()
status = instanceGroup.GetStatus()
strategy = instanceGroup.GetUpgradeStrategy()
configHash = kubeprovider.ConfigmapHash(p.Configuration)
)

ctx := &EksInstanceGroupContext{
Expand All @@ -72,7 +71,6 @@ func New(p provisioners.ProvisionerInput) *EksInstanceGroupContext {
}

instanceGroup.SetState(v1alpha1.ReconcileInit)
status.SetConfigHash(configHash)
status.SetProvisioner(ProvisionerName)
status.SetStrategy(strategy.Type)

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/Masterminds/semver v1.5.0
github.com/aws/aws-sdk-go v1.35.22
github.com/cucumber/godog v0.8.1
github.com/evanphx/json-patch v4.9.0+incompatible
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v0.3.0
github.com/keikoproj/aws-auth v0.0.0-20210105225553-36322b72224f
Expand Down