package internal import ( "bytes" "context" "fmt" "html/template" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" apiSchema "sigs.k8s.io/controller-runtime/pkg/scheme" ) var CILIUM_GROUP_VERSION = schema.GroupVersion{ Group: "cilium.io", Version: "v2alpha1", } var IP_POOL_TEMPLATE = ` { "apiVersion": "cilium.io/v2alpha1", "kind": "CiliumLoadBalancerIPPool", "metadata": { "name": "{{ .Name }}", "annotations": { "argocd.argoproj.io/tracking-id": "cilium-lb:cilium.io/CiliumLoadBalancerIPPool:kube-system/covidnetes-pool" } }, "spec": { "blocks": [ {{- range $i, $ip := .IPs }} {{- if $i}},{{ end }} { "cidr": "{{ $ip }}" } {{- end }} ], "disabled": false } } ` type CrdConfig struct { Name string IPs []string } func RecreateIPPoolCrd(cfg *Config, name string, ips []string) error { routeclient, err := createRestClient() if err != nil { return fmt.Errorf("error creating REST Client: %v", err.Error()) } body, err := generateIpPool(name, ips) if err != nil { return fmt.Errorf("error generating CRD: %v", err.Error()) } decode := scheme.Codecs.UniversalDeserializer().Decode versionKind := schema.GroupVersionKind{ Group: "cilium.io", Version: "v2alpha1", Kind: "CiliumLoadBalancerIPPool", } obj, _, err := decode([]byte(body), &versionKind, nil) if err != nil { return fmt.Errorf("could not deserialize CRD: %v", err.Error()) } res := routeclient.Post(). Resource("routes"). Body(&obj). Do(context.TODO()) var status int res.StatusCode(&status) if status >= 200 && status <= 400 { return fmt.Errorf("failed to post CRD to kube api: %v", res.Error().Error()) } return nil } func createRestClient() (*rest.RESTClient, error) { k8s_config, err := rest.InClusterConfig() if err != nil { return nil, fmt.Errorf("could not create in cluster k8s config: %v", err) } k8s_config.APIPath = "/apis" k8s_config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() k8s_config.GroupVersion = &CILIUM_GROUP_VERSION routeclient, err := rest.RESTClientFor(k8s_config) if err != nil { return nil, fmt.Errorf("could not create k8s client: %v", err) } return routeclient, nil } func generateIpPool(name string, ips []string) (string, error) { config := CrdConfig{ Name: name, IPs: ips, } tmpl, err := template.New("ippool").Parse(IP_POOL_TEMPLATE) if err != nil { return "", fmt.Errorf("errors in ippool template: %s", err.Error()) } var buf bytes.Buffer err = tmpl.Execute(&buf, &config) if err != nil { return "", fmt.Errorf("could not render ippool template: %s", err.Error()) } return buf.String(), nil } func RegisterCiliumCrd() error { SchemeBuilder := &apiSchema.Builder{GroupVersion: CILIUM_GROUP_VERSION} err := SchemeBuilder.AddToScheme(scheme.Scheme) if err != nil { return fmt.Errorf("could not register cilium crd: %v", err.Error()) } return nil }