Skip to content

Commit

Permalink
creates CRD for OpAMPBridge resource (open-telemetry#1559)
Browse files Browse the repository at this point in the history
* creates CRD for OpAMPBridge resource

* minor changes

* fixes kustomization.yaml issues

* adds age field to status

* fixes lint issues

* fixes lint issues

* fixes lint issues

Signed-off-by: Avadhut Pisal <avadhutpisal47@gmail.com>

* fixes lint issues

* fix ci issues

* updates bundle

* fixes webhook test issue

* updates bundle

* updates bundle

* adds enum for opamp-bridge capabilities

* fix opamp server endpoint in e2e test case

* fix e2e test case

* fix e2e test case

* validate maximum replica count

* add delete verb to webhook

* code refactoring to move reconciliation implementation in separate package

* resolves merge conflicts

* using common reconciliation implementation for opampbridge

* add test cases

* resolves goimports lint issues

* add validations for capabilities

* removes validation on specific set of capabilities

* change capabilities data type to map

* defaulting required capabilities

* add local e2e image entry for opampbridge in hack

* add OPERATOROPAMPBRIDGE_IMG to prepare-e2e

* fix review comments

* fix e2e hack

* add e2e test-suit to github action

---------

Signed-off-by: Avadhut Pisal <avadhutpisal47@gmail.com>
  • Loading branch information
avadhut123pisal authored Oct 25, 2023
1 parent 1ae2fe6 commit e8df483
Show file tree
Hide file tree
Showing 58 changed files with 14,733 additions and 70 deletions.
16 changes: 16 additions & 0 deletions .chloggen/1368-create-operator-bridge-crd-in-operator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: 'enhancement'

# The name of the component, or a single word describing the area of concern, (e.g. operator, target allocator, github action)
component: operator-opamp-bridge

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "Creates the CRD for the OpAMPBridge resource"

# One or more tracking issues related to the change
issues: [1368]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
1 change: 1 addition & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
- e2e-autoscale
- e2e-multi-instrumentation
- e2e-pdb
- e2e-opampbridge

steps:
- name: Set up Go
Expand Down
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,14 @@ e2e-log-operator:
e2e-multi-instrumentation:
$(KUTTL) test --config kuttl-test-multi-instr.yaml

# OpAMPBridge CR end-to-tests
.PHONY: e2e-opampbridge
e2e-opampbridge:
$(KUTTL) test --config kuttl-test-opampbridge.yaml

.PHONY: prepare-e2e
prepare-e2e: kuttl set-image-controller container container-target-allocator container-operator-opamp-bridge start-kind cert-manager install-metrics-server load-image-all deploy
TARGETALLOCATOR_IMG=$(TARGETALLOCATOR_IMG) OPERATOR_IMG=$(IMG) SED_BIN="$(SED)" ./hack/modify-test-images.sh
TARGETALLOCATOR_IMG=$(TARGETALLOCATOR_IMG) OPERATOROPAMPBRIDGE_IMG=$(OPERATOROPAMPBRIDGE_IMG) OPERATOR_IMG=$(IMG) SED_BIN="$(SED)" ./hack/modify-test-images.sh

.PHONY: enable-prometheus-feature-flag
enable-prometheus-feature-flag:
Expand Down
12 changes: 12 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@ resources:
webhooks:
defaulting: true
webhookVersion: v1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: opentelemetry.io
kind: OpAMPBridge
path: github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1
version: v1alpha1
webhooks:
defaulting: true
validation: true
webhookVersion: v1
version: "3"
35 changes: 35 additions & 0 deletions apis/v1alpha1/opampbridge_capabilities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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

type (
// OpAMPBridgeCapability represents capability supported by OpAMP Bridge.
// +kubebuilder:validation:Enum=AcceptsRemoteConfig;ReportsEffectiveConfig;ReportsOwnTraces;ReportsOwnMetrics;ReportsOwnLogs;AcceptsOpAMPConnectionSettings;AcceptsOtherConnectionSettings;AcceptsRestartCommand;ReportsHealth;ReportsRemoteConfig
OpAMPBridgeCapability string
)

const (
OpAMPBridgeCapabilityReportsStatus OpAMPBridgeCapability = "ReportsStatus"
OpAMPBridgeCapabilityAcceptsRemoteConfig OpAMPBridgeCapability = "AcceptsRemoteConfig"
OpAMPBridgeCapabilityReportsEffectiveConfig OpAMPBridgeCapability = "ReportsEffectiveConfig"
OpAMPBridgeCapabilityReportsOwnTraces OpAMPBridgeCapability = "ReportsOwnTraces"
OpAMPBridgeCapabilityReportsOwnMetrics OpAMPBridgeCapability = "ReportsOwnMetrics"
OpAMPBridgeCapabilityReportsOwnLogs OpAMPBridgeCapability = "ReportsOwnLogs"
OpAMPBridgeCapabilityAcceptsOpAMPConnectionSettings OpAMPBridgeCapability = "AcceptsOpAMPConnectionSettings"
OpAMPBridgeCapabilityAcceptsOtherConnectionSettings OpAMPBridgeCapability = "AcceptsOtherConnectionSettings"
OpAMPBridgeCapabilityAcceptsRestartCommand OpAMPBridgeCapability = "AcceptsRestartCommand"
OpAMPBridgeCapabilityReportsHealth OpAMPBridgeCapability = "ReportsHealth"
OpAMPBridgeCapabilityReportsRemoteConfig OpAMPBridgeCapability = "ReportsRemoteConfig"
)
141 changes: 141 additions & 0 deletions apis/v1alpha1/opampbridge_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// 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 (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// OpAMPBridgeSpec defines the desired state of OpAMPBridge.
type OpAMPBridgeSpec struct {
// OpAMP backend Server endpoint
// +required
Endpoint string `json:"endpoint"`
// Capabilities supported by the OpAMP Bridge
// +required
Capabilities map[OpAMPBridgeCapability]bool `json:"capabilities"`
// ComponentsAllowed is a list of allowed OpenTelemetry components for each pipeline type (receiver, processor, etc.)
// +optional
ComponentsAllowed map[string][]string `json:"componentsAllowed,omitempty"`
// Resources to set on the OpAMPBridge pods.
// +optional
Resources v1.ResourceRequirements `json:"resources,omitempty"`
// NodeSelector to schedule OpAMPBridge pods.
// +optional
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
// Replicas is the number of pod instances for the OpAMPBridge.
// +optional
// +kubebuilder:validation:Maximum=1
Replicas *int32 `json:"replicas,omitempty"`
// SecurityContext will be set as the container security context.
// +optional
SecurityContext *v1.SecurityContext `json:"securityContext,omitempty"`
// PodSecurityContext will be set as the pod security context.
// +optional
PodSecurityContext *v1.PodSecurityContext `json:"podSecurityContext,omitempty"`
// PodAnnotations is the set of annotations that will be attached to
// OpAMPBridge 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 OpAMPBridge.
// +optional
ServiceAccount string `json:"serviceAccount,omitempty"`
// Image indicates the container image to use for the OpAMPBridge.
// +optional
Image string `json:"image,omitempty"`
// UpgradeStrategy represents how the operator will handle upgrades to the CR when a newer version of the operator is deployed
// +optional
UpgradeStrategy UpgradeStrategy `json:"upgradeStrategy"`
// ImagePullPolicy indicates the pull policy to be used for retrieving the container image (Always, Never, IfNotPresent)
// +optional
ImagePullPolicy v1.PullPolicy `json:"imagePullPolicy,omitempty"`
// VolumeMounts represents the mount points to use in the underlying OpAMPBridge deployment(s)
// +optional
// +listType=atomic
VolumeMounts []v1.VolumeMount `json:"volumeMounts,omitempty"`
// Ports allows a set of ports to be exposed by the underlying v1.Service.
// +optional
// +listType=atomic
Ports []v1.ServicePort `json:"ports,omitempty"`
// ENV vars to set on the OpAMPBridge Pods.
// +optional
Env []v1.EnvVar `json:"env,omitempty"`
// List of sources to populate environment variables on the OpAMPBridge Pods.
// +optional
EnvFrom []v1.EnvFromSource `json:"envFrom,omitempty"`
// Toleration to schedule OpAMPBridge pods.
// +optional
Tolerations []v1.Toleration `json:"tolerations,omitempty"`
// Volumes represents which volumes to use in the underlying OpAMPBridge deployment(s).
// +optional
// +listType=atomic
Volumes []v1.Volume `json:"volumes,omitempty"`
// HostNetwork indicates if the pod should run in the host networking namespace.
// +optional
HostNetwork bool `json:"hostNetwork,omitempty"`
// If specified, indicates the pod's priority.
// If not specified, the pod priority will be default or zero if there is no
// default.
// +optional
PriorityClassName string `json:"priorityClassName,omitempty"`
// If specified, indicates the pod's scheduling constraints
// +optional
Affinity *v1.Affinity `json:"affinity,omitempty"`
// TopologySpreadConstraints embedded kubernetes pod configuration option,
// controls how pods are spread across your cluster among failure-domains
// such as regions, zones, nodes, and other user-defined topology domains
// https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
// +optional
TopologySpreadConstraints []v1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"`
}

// OpAMPBridgeStatus defines the observed state of OpAMPBridge.
type OpAMPBridgeStatus struct {
// Version of the managed OpAMP Bridge (operand)
// +optional
Version string `json:"version,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".status.version",description="OpenTelemetry Version"
// +kubebuilder:printcolumn:name="Endpoint",type="string",JSONPath=".spec.endpoint"
// +operator-sdk:csv:customresourcedefinitions:displayName="OpAMP Bridge"
// +operator-sdk:csv:customresourcedefinitions:resources={{Pod,v1},{Deployment,apps/v1},{ConfigMaps,v1},{Service,v1}}

// OpAMPBridge is the Schema for the opampbridges API.
type OpAMPBridge struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec OpAMPBridgeSpec `json:"spec,omitempty"`
Status OpAMPBridgeStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// OpAMPBridgeList contains a list of OpAMPBridge.
type OpAMPBridgeList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []OpAMPBridge `json:"items"`
}

func init() {
SchemeBuilder.Register(&OpAMPBridge{}, &OpAMPBridgeList{})
}
120 changes: 120 additions & 0 deletions apis/v1alpha1/opampbridge_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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 (
"fmt"
"strings"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// log is for logging in this package.
var opampbridgelog = logf.Log.WithName("opampbridge-resource")

func (r *OpAMPBridge) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}

//+kubebuilder:webhook:path=/mutate-opentelemetry-io-v1alpha1-opampbridge,mutating=true,failurePolicy=fail,sideEffects=None,groups=opentelemetry.io,resources=opampbridges,verbs=create;update,versions=v1alpha1,name=mopampbridge.kb.io,admissionReviewVersions=v1

var _ webhook.Defaulter = &OpAMPBridge{}

// Default implements webhook.Defaulter so a webhook will be registered for the type.
func (r *OpAMPBridge) Default() {
opampbridgelog.Info("default", "name", r.Name)
if len(r.Spec.UpgradeStrategy) == 0 {
r.Spec.UpgradeStrategy = UpgradeStrategyAutomatic
}

if r.Labels == nil {
r.Labels = map[string]string{}
}
if r.Labels["app.kubernetes.io/managed-by"] == "" {
r.Labels["app.kubernetes.io/managed-by"] = "opentelemetry-operator"
}

one := int32(1)
if r.Spec.Replicas == nil {
r.Spec.Replicas = &one
}

// ReportsStatus Capability must be set
if r.Spec.Capabilities == nil {
r.Spec.Capabilities = make(map[OpAMPBridgeCapability]bool)
}
enabled, found := r.Spec.Capabilities[OpAMPBridgeCapabilityReportsStatus]
if !enabled || !found {
r.Spec.Capabilities[OpAMPBridgeCapabilityReportsStatus] = true
}
}

//+kubebuilder:webhook:path=/validate-opentelemetry-io-v1alpha1-opampbridge,mutating=false,failurePolicy=fail,sideEffects=None,groups=opentelemetry.io,resources=opampbridges,verbs=create;update;delete,versions=v1alpha1,name=vopampbridge.kb.io,admissionReviewVersions=v1

var _ webhook.Validator = &OpAMPBridge{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (r *OpAMPBridge) ValidateCreate() (admission.Warnings, error) {
opampbridgelog.Info("validate create", "name", r.Name)
return nil, r.validateCRDSpec()
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
func (r *OpAMPBridge) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
opampbridgelog.Info("validate update", "name", r.Name)
return nil, r.validateCRDSpec()
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
func (r *OpAMPBridge) ValidateDelete() (admission.Warnings, error) {
opampbridgelog.Info("validate delete", "name", r.Name)
return nil, nil
}

func (r *OpAMPBridge) validateCRDSpec() error {

// check required fields

if len(strings.TrimSpace(r.Spec.Endpoint)) == 0 {
return fmt.Errorf("the OpAMP server endpoint is not specified")
}

if len(r.Spec.Capabilities) == 0 {
return fmt.Errorf("the capabilities supported by OpAMP Bridge are not specified")
}

// validate port config
for _, p := range r.Spec.Ports {
nameErrs := validation.IsValidPortName(p.Name)
numErrs := validation.IsValidPortNum(int(p.Port))
if len(nameErrs) > 0 || len(numErrs) > 0 {
return fmt.Errorf("the OpAMPBridge Spec Ports configuration is incorrect, port name '%s' errors: %s, num '%d' errors: %s",
p.Name, nameErrs, p.Port, numErrs)
}
}

// check for maximum replica count
if r.Spec.Replicas != nil && *r.Spec.Replicas > 1 {
return fmt.Errorf("replica count must not be greater than 1")
}
return nil
}
Loading

0 comments on commit e8df483

Please sign in to comment.