github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/pkg/kubernetes/resources/ambassador/host/adapt.go (about)

     1  package host
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/caos/orbos/mntr"
     7  	"github.com/caos/orbos/pkg/kubernetes"
     8  	"github.com/caos/orbos/pkg/kubernetes/resources"
     9  	macherrs "k8s.io/apimachinery/pkg/api/errors"
    10  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    11  )
    12  
    13  const (
    14  	group   = "getambassador.io"
    15  	version = "v2"
    16  	kind    = "Host"
    17  )
    18  
    19  type Arguments struct {
    20  	Monitor          mntr.Monitor
    21  	Namespace        string
    22  	Name             string
    23  	Labels           map[string]string
    24  	Hostname         string
    25  	Authority        string
    26  	PrivateKeySecret string
    27  	Selector         map[string]string
    28  	TlsSecret        string
    29  }
    30  
    31  //type AdaptFuncToEnsureFunc func(monitor mntr.Monitor, namespace, name string, labels map[string]string, hostname string, authority string, privateKeySecret string, selector map[string]string, tlsSecret string) (resources.QueryFunc, error)
    32  
    33  func AdaptFuncToEnsure(params *Arguments) (resources.QueryFunc, error) {
    34  
    35  	labelInterfaceValues := make(map[string]interface{})
    36  	for k, v := range params.Labels {
    37  		labelInterfaceValues[k] = v
    38  	}
    39  
    40  	acme := map[string]interface{}{
    41  		"authority": params.Authority,
    42  	}
    43  	if params.PrivateKeySecret != "" {
    44  		acme["privateKeySecret"] = map[string]interface{}{
    45  			"name": params.PrivateKeySecret,
    46  		}
    47  	}
    48  
    49  	selectorInterfaceValues := make(map[string]interface{}, 0)
    50  	for k, v := range params.Selector {
    51  		selectorInterfaceValues[k] = v
    52  	}
    53  
    54  	spec := map[string]interface{}{
    55  		"hostname": params.Hostname,
    56  		"selector": map[string]interface{}{
    57  			"matchLabels": selectorInterfaceValues,
    58  		},
    59  		"ambassador_id": []interface{}{"default"},
    60  		"acmeProvider":  acme,
    61  	}
    62  
    63  	if params.TlsSecret != "" {
    64  		spec["tlsSecret"] = map[string]interface{}{
    65  			"name": params.TlsSecret,
    66  		}
    67  	}
    68  
    69  	crd := &unstructured.Unstructured{
    70  		Object: map[string]interface{}{
    71  			"kind":       kind,
    72  			"apiVersion": group + "/" + version,
    73  			"metadata": map[string]interface{}{
    74  				"name":      params.Name,
    75  				"namespace": params.Namespace,
    76  				"labels":    labelInterfaceValues,
    77  				"annotations": map[string]interface{}{
    78  					"aes_res_changed": "true",
    79  				},
    80  			},
    81  			"spec": spec,
    82  		}}
    83  
    84  	return func(k8sClient kubernetes.ClientInt, _ map[string]interface{}) (resources.EnsureFunc, error) {
    85  		ensure := func(k8sClient kubernetes.ClientInt) error {
    86  			return k8sClient.ApplyNamespacedCRDResource(group, version, kind, params.Namespace, params.Name, crd)
    87  		}
    88  		crdName := "hosts.getambassador.io"
    89  		_, ok, err := k8sClient.CheckCRD(crdName)
    90  		if err != nil {
    91  			return nil, err
    92  		}
    93  		if !ok {
    94  			params.Monitor.WithField("name", crdName).Info("crd definition not found, skipping")
    95  			return func(k8sClient kubernetes.ClientInt) error { return nil }, nil
    96  		}
    97  
    98  		existing, err := k8sClient.GetNamespacedCRDResource(group, version, kind, params.Namespace, params.Name)
    99  		if err != nil && !macherrs.IsNotFound(err) {
   100  			return nil, err
   101  		}
   102  		err = nil
   103  
   104  		if existing == nil {
   105  			return ensure, nil
   106  		}
   107  
   108  		if contains(existing.Object, crd.Object) {
   109  			// Noop
   110  			return func(clientInt kubernetes.ClientInt) error { return nil }, nil
   111  		}
   112  
   113  		return ensure, nil
   114  	}, nil
   115  }
   116  
   117  // The order matters!!
   118  // TODO: Is this reusable?
   119  func contains(set, subset map[string]interface{}) bool {
   120  
   121  	if len(set) < len(subset) {
   122  		return false
   123  	}
   124  
   125  	for k, subsetValue := range subset {
   126  		setValue, ok := set[k]
   127  		if !ok {
   128  			return false
   129  		}
   130  		setValueMap, setValueIsMap := setValue.(map[string]interface{})
   131  		subsetValueMap, subsetValueIsMap := subsetValue.(map[string]interface{})
   132  		if setValueIsMap != subsetValueIsMap {
   133  			return false
   134  		}
   135  		if subsetValueIsMap {
   136  			if contains(setValueMap, subsetValueMap) {
   137  				continue
   138  			}
   139  			return false
   140  		}
   141  		if !reflect.DeepEqual(setValue, subsetValue) {
   142  			return false
   143  		}
   144  	}
   145  
   146  	return true
   147  }
   148  
   149  func AdaptFuncToDestroy(namespace, name string) (resources.DestroyFunc, error) {
   150  	return func(client kubernetes.ClientInt) error {
   151  		return client.DeleteNamespacedCRDResource(group, version, kind, namespace, name)
   152  	}, nil
   153  }