From c7cb7faaaa332e58777642a03e190d8353583821 Mon Sep 17 00:00:00 2001 From: Benedikt Bongartz Date: Wed, 11 Sep 2024 14:53:08 +0200 Subject: [PATCH] apis/v1alpha1: initialize sampler CR Signed-off-by: Benedikt Bongartz --- apis/v1alpha1/sampler_types.go | 247 +++++++++++++++++++++++++ apis/v1alpha1/zz_generated.deepcopy.go | 225 +++++++++++++++++++++- 2 files changed, 471 insertions(+), 1 deletion(-) create mode 100644 apis/v1alpha1/sampler_types.go diff --git a/apis/v1alpha1/sampler_types.go b/apis/v1alpha1/sampler_types.go new file mode 100644 index 0000000000..93bbcf2bff --- /dev/null +++ b/apis/v1alpha1/sampler_types.go @@ -0,0 +1,247 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import ( + "time" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ( + // RoutingType describes how traffic to be sampled is distributed. + // +kubebuilder:validation:Enum=traceid;service + SamplerRoutingType string +) + +const ( + // SamplerRoutingTypeTraceID specifies that traffic gets distributed based on the provided traceid. + SamplerRoutingTypeTraceID SamplerRoutingType = "traceid" + // SamplerRoutingTypeService specifies that traffic gets distributed based on the provided service name. + SamplerRoutingTypeService SamplerRoutingType = "service" +) + +// SamplerSpec defines the desired state of Sampler. +type SamplerSpec struct { + // Policies taken into account when making sampling decision. + // + // +optional + // +kubebuilder:validation:Optional + Policies []SamplerPolicySpec `json:"policies,omitempty"` + // RoutingKey describes how traffic to be sampled is distributed. + // + // +kubebuilder:default:=traceid + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Routing Key" + RoutingKey SamplerRoutingType `json:"routingKey,omitempty"` + // DecisionWait defines the time since the first span of a trace before + // making a sampling decision. + // Default is 30s. + // + // +optional + // +kubebuilder:validation:Optional + // +kubebuilder:default:=30000000000 + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Time frame to make a dicision" + DecisionWait time.Duration `json:"decision_wait" yaml:"decision_wait"` + // NumTraces defines the number of traces kept in memory. + // + // +optional + // +kubebuilder:validation:Optional + // +kubebuilder:default:=5000 + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Number of traces kept in memory" + NumTraces uint64 `json:"num_traces" yaml:"num_traces"` + // ExpectedNewTracesPerSec defines the expected number of new traces. + // It helps in allocating data structure. + // + // +optional + // +kubebuilder:validation:Optional + // +kubebuilder:default:=5000 + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Expected new traces per second" + ExpectedNewTracesPerSec uint64 `json:"expected_new_traces_per_sec" yaml:"expected_new_traces_per_sec"` + // DecisionCache configuration. + // + // +optional + DecisionCache SamplerPolicyDecisionCacheSpec `json:"decision_cache" yaml:"decision_cache"` + // Template defines requirements for a set of setup components. + // + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Sampling Component Templates" + Components SamplerTemplateSpec `json:"components,omitempty"` + // Telemetry defines the telemetry settings for the sampling system. + // + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Telemetry Settings" + Telemetry SamplerTelemetrySpec `json:"telemetry,omitempty"` + // Exporter defines the exporter configuration. + // NOTE: currently only otlp exporter settings are supported. + // + // +requiered + Exporter v1beta1.AnyConfig `json:"exporter" yaml:"exporter"` +} + +// SamplerPolicySpec describes a specific sampling policy. +type SamplerPolicySpec struct { + // Name of policy. + // + // +kubebuilder:validation:Required + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:io.kubernetes:Secret",displayName="Policy Name" + Name string `json:"name" yaml:"name"` + // NumTraces defines the number of traces kept in memory. + // + // +kubebuilder:validation:Required + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:io.kubernetes:Secret",displayName="Policy Type" + Type SamplerType `json:"type" yaml:"type"` + // Config of a specific policy that will be applied. + // + // +optional + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:io.kubernetes:Secret",displayName="Policy Configuration" + Config v1beta1.AnyConfig `json:"-" yaml:",inline"` +} + +// SamplerPolicyDecisionCacheSpec defines the settings for the decision cache. +type SamplerPolicyDecisionCacheSpec struct { + // SampledCacheSize configures the amount of trace IDs to be kept in an LRU + // cache, persisting the "keep" decisions for traces that may have already + // been released from memory. + // By default, the size is 0 and the cache is inactive. + // If using, configure this as much higher than num_traces so decisions for + // trace IDs are kept longer than the span data for the trace. + // + // +optional + // +kubebuilder:validation:Optional + // +kubebuilder:default:=0 + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Sampled Cache Size" + SampledCacheSize uint64 `json:"sampled_cache_size" yaml:"sampled_cache_size"` +} + +// SamplerTelemetrySpec defines the telemetry settings for the sampling system. +type SamplerTelemetrySpec struct { + // TODO(@frzifus): provide telemetry settings + // e.g.: serviceMonitor, spanMetrics ... +} + +// SamplerTemplateSpec defines the template of all requirements to configure +// scheduling of all components to be deployed. +type SamplerTemplateSpec struct { + // Loadbalancer defines the loadbalancer component spec. + // + // +optional + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Loadbalancer pods" + Loadbalancer SamplerComponentSpec `json:"loadbalancer,omitempty"` + // Sampler defines the sampler component spec. + // + // +optional + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Sampler pods" + Sampler SamplerComponentSpec `json:"sampler,omitempty"` +} + +// SamplerComponentSpec defines specific schedule settings for sampler components. +type SamplerComponentSpec struct { + // ManagementState defines if the CR should be managed by the operator or not. + // Default is managed. + // + // +required + // +kubebuilder:validation:Required + // +kubebuilder:default:=managed + ManagementState ManagementStateType `json:"managementState,omitempty"` + // Resources to set on the OpenTelemetry Collector pods. + // +optional + Resources v1.ResourceRequirements `json:"resources,omitempty"` + // NodeSelector to schedule OpenTelemetry Collector pods. + // This is only relevant to daemonset, statefulset, and deployment mode + // +optional + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // If specified, indicates the pod's scheduling constraints + // +optional + Affinity *v1.Affinity `json:"affinity,omitempty"` + // Toleration to schedule OpenTelemetry Collector pods. + // This is only relevant to daemonset, statefulset, and deployment mode + // + // +optional + Tolerations []v1.Toleration `json:"tolerations,omitempty"` + // Replicas is the number of pod instances for the underlying OpenTelemetry Collector. Set this if your are not using autoscaling + // +optional + Replicas *int32 `json:"replicas,omitempty"` + // Autoscaler specifies the pod autoscaling configuration to use + // for the OpenTelemetryCollector workload. + // + // +optional + Autoscaler *AutoscalerSpec `json:"autoscaler,omitempty"` + // SecurityContext configures the container security context for + // the opentelemetry-collector container. + // + // In deployment, daemonset, or statefulset mode, this controls + // the security context settings for the primary application + // container. + // + // In sidecar mode, this controls the security context for the + // injected sidecar container. + // + // +optional + SecurityContext *v1.SecurityContext `json:"securityContext,omitempty"` + // PodSecurityContext configures the pod security context for the + // opentelemetry-collector pod, when running as a deployment, daemonset, + // or statefulset. + // + // In sidecar mode, the opentelemetry-operator will ignore this setting. + // + // +optional + PodSecurityContext *v1.PodSecurityContext `json:"podSecurityContext,omitempty"` + // PodAnnotations is the set of annotations that will be attached to + // Collector and Target Allocator pods. + // + // +optional + PodAnnotations map[string]string `json:"podAnnotations,omitempty"` + // ServiceAccount indicates the name of an existing service account to use with this instance. When set, + // the operator will not automatically create a ServiceAccount for the collector. + // + // +optional + ServiceAccount string `json:"serviceAccount,omitempty"` +} + +// SamplerStatus defines the observed state of Sampler. +type SamplerStatus struct { + // TODO(@frzifus): add status fields. +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Sampler is the Schema for the samplers API. +type Sampler struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SamplerSpec `json:"spec,omitempty"` + Status SamplerStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// SamplerList contains a list of Sampler. +type SamplerList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SamplerConfig `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Sampler{}, &SamplerList{}) +} diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index 74b0b28951..af7bb60644 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -1227,11 +1227,100 @@ func (in *Resource) DeepCopy() *Resource { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SamplerConfig) DeepCopyInto(out *SamplerConfig) { +func (in *Sampler) DeepCopyInto(out *Sampler) { *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sampler. +func (in *Sampler) DeepCopy() *Sampler { + if in == nil { + return nil + } + out := new(Sampler) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Sampler) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerComponentSpec) DeepCopyInto(out *SamplerComponentSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(v1.Affinity) + (*in).DeepCopyInto(*out) + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int32) + **out = **in + } + if in.Autoscaler != nil { + in, out := &in.Autoscaler, &out.Autoscaler + *out = new(AutoscalerSpec) + (*in).DeepCopyInto(*out) + } + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(v1.SecurityContext) + (*in).DeepCopyInto(*out) + } + if in.PodSecurityContext != nil { + in, out := &in.PodSecurityContext, &out.PodSecurityContext + *out = new(v1.PodSecurityContext) + (*in).DeepCopyInto(*out) + } + if in.PodAnnotations != nil { + in, out := &in.PodAnnotations, &out.PodAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerComponentSpec. +func (in *SamplerComponentSpec) DeepCopy() *SamplerComponentSpec { + if in == nil { + return nil + } + out := new(SamplerComponentSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerConfig) DeepCopyInto(out *SamplerConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerConfig. func (in *SamplerConfig) DeepCopy() *SamplerConfig { if in == nil { return nil @@ -1241,6 +1330,140 @@ func (in *SamplerConfig) DeepCopy() *SamplerConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerList) DeepCopyInto(out *SamplerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SamplerConfig, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerList. +func (in *SamplerList) DeepCopy() *SamplerList { + if in == nil { + return nil + } + out := new(SamplerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SamplerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerPolicyDecisionCacheSpec) DeepCopyInto(out *SamplerPolicyDecisionCacheSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerPolicyDecisionCacheSpec. +func (in *SamplerPolicyDecisionCacheSpec) DeepCopy() *SamplerPolicyDecisionCacheSpec { + if in == nil { + return nil + } + out := new(SamplerPolicyDecisionCacheSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerPolicySpec) DeepCopyInto(out *SamplerPolicySpec) { + *out = *in + in.Config.DeepCopyInto(&out.Config) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerPolicySpec. +func (in *SamplerPolicySpec) DeepCopy() *SamplerPolicySpec { + if in == nil { + return nil + } + out := new(SamplerPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerSpec) DeepCopyInto(out *SamplerSpec) { + *out = *in + if in.Policies != nil { + in, out := &in.Policies, &out.Policies + *out = make([]SamplerPolicySpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.DecisionCache = in.DecisionCache + in.Components.DeepCopyInto(&out.Components) + out.Telemetry = in.Telemetry + in.Exporter.DeepCopyInto(&out.Exporter) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerSpec. +func (in *SamplerSpec) DeepCopy() *SamplerSpec { + if in == nil { + return nil + } + out := new(SamplerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerStatus) DeepCopyInto(out *SamplerStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerStatus. +func (in *SamplerStatus) DeepCopy() *SamplerStatus { + if in == nil { + return nil + } + out := new(SamplerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerTelemetrySpec) DeepCopyInto(out *SamplerTelemetrySpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerTelemetrySpec. +func (in *SamplerTelemetrySpec) DeepCopy() *SamplerTelemetrySpec { + if in == nil { + return nil + } + out := new(SamplerTelemetrySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamplerTemplateSpec) DeepCopyInto(out *SamplerTemplateSpec) { + *out = *in + in.Loadbalancer.DeepCopyInto(&out.Loadbalancer) + in.Sampler.DeepCopyInto(&out.Sampler) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamplerTemplateSpec. +func (in *SamplerTemplateSpec) DeepCopy() *SamplerTemplateSpec { + if in == nil { + return nil + } + out := new(SamplerTemplateSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ScaleSubresourceStatus) DeepCopyInto(out *ScaleSubresourceStatus) { *out = *in