github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/pkg/kubernetes/boom.go (about)

     1  package kubernetes
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/caos/orbos/mntr"
     7  	"github.com/caos/orbos/pkg/kubernetes/k8s"
     8  	"github.com/caos/orbos/pkg/labels"
     9  	"gopkg.in/yaml.v3"
    10  	apps "k8s.io/api/apps/v1"
    11  	core "k8s.io/api/core/v1"
    12  	rbac "k8s.io/api/rbac/v1"
    13  	mach "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    15  	"k8s.io/apimachinery/pkg/util/intstr"
    16  )
    17  
    18  func EnsureBoomArtifacts(
    19  	monitor mntr.Monitor,
    20  	apiLabels *labels.API,
    21  	client ClientInt,
    22  	version string,
    23  	tolerations k8s.Tolerations,
    24  	nodeselector map[string]string,
    25  	resources *k8s.Resources,
    26  	imageRegistry string,
    27  	gitops bool,
    28  ) error {
    29  
    30  	monitor.WithFields(map[string]interface{}{
    31  		"boom": version,
    32  	}).Debug("Ensuring boom artifacts")
    33  
    34  	if version == "" {
    35  		return nil
    36  	}
    37  
    38  	nameLabels := toNameLabels(apiLabels, "boom")
    39  	k8sNameLabels := labels.MustK8sMap(nameLabels)
    40  
    41  	if err := client.ApplyServiceAccount(&core.ServiceAccount{
    42  		ObjectMeta: mach.ObjectMeta{
    43  			Name:      nameLabels.Name(),
    44  			Namespace: "caos-system",
    45  			Labels:    k8sNameLabels,
    46  		},
    47  	}); err != nil {
    48  		return err
    49  	}
    50  
    51  	if err := client.ApplyClusterRole(&rbac.ClusterRole{
    52  		ObjectMeta: mach.ObjectMeta{
    53  			Name:   nameLabels.Name(),
    54  			Labels: k8sNameLabels,
    55  		},
    56  		Rules: []rbac.PolicyRule{{
    57  			APIGroups: []string{"*"},
    58  			Resources: []string{"*"},
    59  			Verbs:     []string{"*"},
    60  		}},
    61  	}); err != nil {
    62  		return err
    63  	}
    64  
    65  	if err := client.ApplyClusterRoleBinding(&rbac.ClusterRoleBinding{
    66  		ObjectMeta: mach.ObjectMeta{
    67  			Name:   nameLabels.Name(),
    68  			Labels: k8sNameLabels,
    69  		},
    70  
    71  		RoleRef: rbac.RoleRef{
    72  			APIGroup: "rbac.authorization.k8s.io",
    73  			Kind:     "ClusterRole",
    74  			Name:     nameLabels.Name(),
    75  		},
    76  		Subjects: []rbac.Subject{{
    77  			Kind:      "ServiceAccount",
    78  			Name:      nameLabels.Name(),
    79  			Namespace: "caos-system",
    80  		}},
    81  	}); err != nil {
    82  		return err
    83  	}
    84  
    85  	k8sPodSelector := labels.MustK8sMap(labels.DeriveNameSelector(nameLabels, false))
    86  
    87  	if !gitops {
    88  		crd := `apiVersion: apiextensions.k8s.io/v1beta1
    89  kind: CustomResourceDefinition
    90  metadata:
    91    annotations:
    92      controller-gen.kubebuilder.io/version: v0.2.2
    93    creationTimestamp: null
    94    name: booms.caos.ch
    95  spec:
    96    group: caos.ch
    97    names:
    98      kind: Boom
    99      listKind: BoomList
   100      plural: booms
   101      singular: boom
   102    scope: ""
   103    validation:
   104      openAPIV3Schema:
   105        properties:
   106          apiVersion:
   107            description: 'APIVersion defines the versioned schema of this representation
   108              of an object. Servers should convert recognized schemas to the latest
   109              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
   110            type: string
   111          kind:
   112            description: 'Kind is a string value representing the REST resource this
   113              object represents. Servers may infer this from the endpoint the client
   114              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
   115            type: string
   116          metadata:
   117            type: object
   118          spec:
   119            type: object
   120          status:
   121            type: object
   122        type: object
   123    version: v1
   124    versions:
   125    - name: v1
   126      served: true
   127      storage: true
   128    - name: v1beta1
   129      served: true
   130      storage: false
   131    - name: v1beta2
   132      served: true
   133      storage: false
   134  status:
   135    acceptedNames:
   136      kind: ""
   137      plural: ""
   138    conditions: []
   139    storedVersions: []`
   140  
   141  		crdDefinition := &unstructured.Unstructured{}
   142  		if err := yaml.Unmarshal([]byte(crd), &crdDefinition.Object); err != nil {
   143  			return err
   144  		}
   145  
   146  		if err := client.ApplyCRDResource(
   147  			crdDefinition,
   148  		); err != nil {
   149  			return err
   150  		}
   151  		monitor.WithFields(map[string]interface{}{
   152  			"version": version,
   153  		}).Debug("BOOM crd ensured")
   154  	}
   155  
   156  	var (
   157  		cmd          = []string{"/orbctl", "start", "boom", "--kubeconfig", ""}
   158  		volumes      []core.Volume
   159  		volumeMounts []core.VolumeMount
   160  	)
   161  	if gitops {
   162  		cmd = append(cmd, "--gitops", "-f", "/secrets/orbconfig")
   163  		volumes = []core.Volume{{
   164  			Name: "orbconfig",
   165  			VolumeSource: core.VolumeSource{
   166  				Secret: &core.SecretVolumeSource{
   167  					SecretName: "caos",
   168  				},
   169  			},
   170  		}}
   171  		volumeMounts = []core.VolumeMount{{
   172  			Name:      "orbconfig",
   173  			ReadOnly:  true,
   174  			MountPath: "/secrets",
   175  		}}
   176  	}
   177  
   178  	if _, _, analyticsEnabled := mntr.Environment(); !analyticsEnabled {
   179  		cmd = append(cmd, "--disable-analytics")
   180  	}
   181  
   182  	deployment := &apps.Deployment{
   183  		ObjectMeta: mach.ObjectMeta{
   184  			Name:      nameLabels.Name(),
   185  			Namespace: "caos-system",
   186  			Labels:    k8sNameLabels,
   187  		},
   188  		Spec: apps.DeploymentSpec{
   189  			Replicas: int32Ptr(1),
   190  			Selector: &mach.LabelSelector{
   191  				MatchLabels: k8sPodSelector,
   192  			},
   193  			Template: core.PodTemplateSpec{
   194  				ObjectMeta: mach.ObjectMeta{
   195  					Labels: labels.MustK8sMap(labels.AsSelectable(nameLabels)),
   196  				},
   197  				Spec: core.PodSpec{
   198  					ServiceAccountName: nameLabels.Name(),
   199  					Containers: []core.Container{{
   200  						Name:            "boom",
   201  						ImagePullPolicy: core.PullIfNotPresent,
   202  						Image:           fmt.Sprintf("%s/caos/orbos:%s", imageRegistry, version),
   203  						Command:         cmd,
   204  						Args:            []string{},
   205  						Ports: []core.ContainerPort{{
   206  							Name:          "metrics",
   207  							ContainerPort: 2112,
   208  							Protocol:      "TCP",
   209  						}},
   210  						VolumeMounts: volumeMounts,
   211  						Resources:    core.ResourceRequirements(*resources),
   212  					}},
   213  					NodeSelector:                  nodeselector,
   214  					Tolerations:                   tolerations.K8s(),
   215  					Volumes:                       volumes,
   216  					TerminationGracePeriodSeconds: int64Ptr(10),
   217  				},
   218  			},
   219  		},
   220  	}
   221  
   222  	if err := client.ApplyDeployment(deployment, true); err != nil {
   223  		return err
   224  	}
   225  	monitor.WithFields(map[string]interface{}{
   226  		"version": version,
   227  	}).Debug("BOOM deployment ensured")
   228  
   229  	if err := client.ApplyService(&core.Service{
   230  		ObjectMeta: mach.ObjectMeta{
   231  			Name:      nameLabels.Name(),
   232  			Namespace: "caos-system",
   233  			Labels:    k8sPodSelector,
   234  		},
   235  		Spec: core.ServiceSpec{
   236  			Ports: []core.ServicePort{{
   237  				Name:       "metrics",
   238  				Protocol:   "TCP",
   239  				Port:       2112,
   240  				TargetPort: intstr.FromInt(2112),
   241  			}},
   242  			Selector: k8sPodSelector,
   243  			Type:     core.ServiceTypeClusterIP,
   244  		},
   245  	}); err != nil {
   246  		return err
   247  	}
   248  	monitor.Debug("BOOM service ensured")
   249  
   250  	return nil
   251  }