Skip to content

Commit

Permalink
Target Allocator implementation (Part 1 - OTEL Operator Enhancements) (
Browse files Browse the repository at this point in the history
…open-telemetry#351)

Co-authored-by: Alexis Perez <perzmen@amazon.com>
Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
  • Loading branch information
3 people authored and hero committed Dec 12, 2021
1 parent 61370ce commit a729deb
Show file tree
Hide file tree
Showing 46 changed files with 1,390 additions and 99 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/publish-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
- name: Set env vars for the job
run: |
grep -v '\#' versions.txt | grep opentelemetry-collector | awk -F= '{print "OTELCOL_VERSION="$2}' >> $GITHUB_ENV
grep -v '\#' versions.txt | grep targetallocator | awk -F= '{print "TARGETALLOCATOR_VERSION="$2}' >> $GITHUB_ENV
echo "VERSION_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
echo "VERSION=$(git describe --tags | sed 's/^v//')" >> $GITHUB_ENV
Expand Down Expand Up @@ -72,5 +73,6 @@ jobs:
VERSION=${{ env.VERSION }}
VERSION_DATE=${{ env.VERSION_DATE }}
OTELCOL_VERSION=${{ env.OTELCOL_VERSION }}
TARGETALLOCATOR_VERSION=${{ env.TARGETALLOCATOR_VERSION }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ ARG VERSION_PKG
ARG VERSION
ARG VERSION_DATE
ARG OTELCOL_VERSION
ARG TARGETALLOCATOR_VERSION

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -ldflags="-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION}" -a -o manager main.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -ldflags="-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION} -X ${VERSION_PKG}.targetAllocator=${TARGETALLOCATOR_VERSION}" -a -o manager main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
Expand Down
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ VERSION_DATE ?= $(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
VERSION_PKG ?= "github.com/open-telemetry/opentelemetry-operator/internal/version"
OTELCOL_VERSION ?= "$(shell grep -v '\#' versions.txt | grep opentelemetry-collector | awk -F= '{print $$2}')"
OPERATOR_VERSION ?= "$(shell grep -v '\#' versions.txt | grep operator | awk -F= '{print $$2}')"
LD_FLAGS ?= "-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION}"
TARGETALLOCATOR_VERSION ?= "$(shell grep -v '\#' versions.txt | grep targetallocator | awk -F= '{print $$2}')"
LD_FLAGS ?= "-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION} -X ${VERSION_PKG}.targetAllocator=${TARGETALLOCATOR_VERSION}"

# Image URL to use all building/pushing image targets
IMG_PREFIX ?= quay.io/${USER}
Expand Down Expand Up @@ -122,7 +123,7 @@ set-test-image-vars:

# Build the container image, used only for local dev purposes
container:
docker build -t ${IMG} --build-arg VERSION_PKG=${VERSION_PKG} --build-arg VERSION=${VERSION} --build-arg VERSION_DATE=${VERSION_DATE} --build-arg OTELCOL_VERSION=${OTELCOL_VERSION} .
docker build -t ${IMG} --build-arg VERSION_PKG=${VERSION_PKG} --build-arg VERSION=${VERSION} --build-arg VERSION_DATE=${VERSION_DATE} --build-arg OTELCOL_VERSION=${OTELCOL_VERSION} --build-arg TARGETALLOCATOR_VERSION=${TARGETALLOCATOR_VERSION} .

# Push the container image, used only for local dev purposes
container-push:
Expand Down
16 changes: 16 additions & 0 deletions api/v1alpha1/opentelemetrycollector_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ type OpenTelemetryCollectorSpec struct {
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true
Image string `json:"image,omitempty"`

// TargetAllocator indicates a value which determines whether to spawn a target allocation resource or not.
// +optional
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true
TargetAllocator OpenTelemetryTargetAllocatorSpec `json:"targetAllocator,omitempty"`

// Mode represents how the collector should be deployed (deployment, daemonset, statefulset or sidecar)
// +optional
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true
Expand Down Expand Up @@ -116,6 +121,17 @@ type OpenTelemetryCollectorStatus struct {
Messages []string `json:"messages,omitempty"`
}

// OpenTelemetryTargetAllocatorSpec defines the configurations for the Prometheus target allocator.
type OpenTelemetryTargetAllocatorSpec struct {
// Enabled indicates whether to use a target allocation mechanism for Prometheus targets or not.
// +optional
Enabled bool `json:"enabled,omitempty"`

// Image indicates the container image to use for the OpenTelemetry TargetAllocator.
// +optional
Image string `json:"image,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=otelcol;otelcols
// +kubebuilder:subresource:status
Expand Down
15 changes: 15 additions & 0 deletions api/v1alpha1/opentelemetrycollector_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"

ta "github.com/open-telemetry/opentelemetry-operator/pkg/targetallocator/adapters"
)

// log is for logging in this package.
Expand Down Expand Up @@ -91,5 +93,18 @@ func (r *OpenTelemetryCollector) validateCRDSpec() error {
return fmt.Errorf("the OpenTelemetry Collector mode is set to %s, which does not support the attribute 'tolerations'", r.Spec.Mode)
}

// validate target allocation
if r.Spec.TargetAllocator.Enabled && r.Spec.Mode != ModeStatefulSet {
return fmt.Errorf("the OpenTelemetry Collector mode is set to %s, which does not support the target allocation deployment", r.Spec.Mode)
}

// validate Prometheus config for target allocation
if r.Spec.TargetAllocator.Enabled {
_, err := ta.ConfigToPromConfig(r.Spec.Config)
if err != nil {
return fmt.Errorf("the OpenTelemetry Spec Prometheus configuration is incorrect, %s", err)
}
}

return nil
}
16 changes: 16 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,19 @@ spec:
description: ServiceAccount indicates the name of an existing service
account to use with this instance.
type: string
targetAllocator:
description: TargetAllocator indicates a value which determines whether
to spawn a target allocation resource or not.
properties:
enabled:
description: Enabled indicates whether to use a target allocation
mechanism for Prometheus targets or not.
type: boolean
image:
description: Image indicates the container image to use for the
OpenTelemetry TargetAllocator.
type: string
type: object
tolerations:
description: Toleration to schedule OpenTelemetry Collector pods.
This is only relevant to daemonsets, statefulsets and deployments
Expand Down
13 changes: 13 additions & 0 deletions config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,19 @@ spec:
description: ServiceAccount indicates the name of an existing service
account to use with this instance.
type: string
targetAllocator:
description: TargetAllocator indicates a value which determines whether
to spawn a target allocation resource or not.
properties:
enabled:
description: Enabled indicates whether to use a target allocation
mechanism for Prometheus targets or not.
type: boolean
image:
description: Image indicates the container image to use for the
OpenTelemetry TargetAllocator.
type: string
type: object
tolerations:
description: Toleration to schedule OpenTelemetry Collector pods.
This is only relevant to daemonsets, statefulsets and deployments
Expand Down
58 changes: 39 additions & 19 deletions internal/config/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ import (
)

const (
defaultAutoDetectFrequency = 5 * time.Second
defaultCollectorConfigMapEntry = "collector.yaml"
defaultAutoDetectFrequency = 5 * time.Second
defaultCollectorConfigMapEntry = "collector.yaml"
defaultTargetAllocatorConfigMapEntry = "targetallocator.yaml"
)

// Config holds the static configuration for this operator.
Expand All @@ -44,21 +45,24 @@ type Config struct {
onChange []func() error

// config state
collectorImage string
collectorConfigMapEntry string
platform platform.Platform
version version.Version
collectorImage string
collectorConfigMapEntry string
targetAllocatorImage string
targetAllocatorConfigMapEntry string
platform platform.Platform
version version.Version
}

// New constructs a new configuration based on the given options.
func New(opts ...Option) Config {
// initialize with the default values
o := options{
autoDetectFrequency: defaultAutoDetectFrequency,
collectorConfigMapEntry: defaultCollectorConfigMapEntry,
logger: logf.Log.WithName("config"),
platform: platform.Unknown,
version: version.Get(),
autoDetectFrequency: defaultAutoDetectFrequency,
collectorConfigMapEntry: defaultCollectorConfigMapEntry,
targetAllocatorConfigMapEntry: defaultTargetAllocatorConfigMapEntry,
logger: logf.Log.WithName("config"),
platform: platform.Unknown,
version: version.Get(),
}
for _, opt := range opts {
opt(&o)
Expand All @@ -70,15 +74,21 @@ func New(opts ...Option) Config {
o.collectorImage = fmt.Sprintf("otel/opentelemetry-collector:%s", o.version.OpenTelemetryCollector)
}

if len(o.targetAllocatorImage) == 0 {
o.targetAllocatorImage = fmt.Sprintf("quay.io/opentelemetry/target-allocator:%s", o.version.TargetAllocator)
}

return Config{
autoDetect: o.autoDetect,
autoDetectFrequency: o.autoDetectFrequency,
collectorImage: o.collectorImage,
collectorConfigMapEntry: o.collectorConfigMapEntry,
logger: o.logger,
onChange: o.onChange,
platform: o.platform,
version: o.version,
autoDetect: o.autoDetect,
autoDetectFrequency: o.autoDetectFrequency,
collectorImage: o.collectorImage,
collectorConfigMapEntry: o.collectorConfigMapEntry,
targetAllocatorImage: o.targetAllocatorImage,
targetAllocatorConfigMapEntry: o.targetAllocatorConfigMapEntry,
logger: o.logger,
onChange: o.onChange,
platform: o.platform,
version: o.version,
}
}

Expand Down Expand Up @@ -155,6 +165,16 @@ func (c *Config) CollectorConfigMapEntry() string {
return c.collectorConfigMapEntry
}

// TargetAllocatorImage represents the flag to override the OpenTelemetry TargetAllocator container image.
func (c *Config) TargetAllocatorImage() string {
return c.targetAllocatorImage
}

// TargetAllocatorConfigMapEntry represents the configuration file name for the TargetAllocator. Immutable.
func (c *Config) TargetAllocatorConfigMapEntry() string {
return c.targetAllocatorConfigMapEntry
}

// Platform represents the type of the platform this operator is running.
func (c *Config) Platform() platform.Platform {
return c.platform
Expand Down
29 changes: 21 additions & 8 deletions internal/config/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ import (
type Option func(c *options)

type options struct {
autoDetect autodetect.AutoDetect
autoDetectFrequency time.Duration
collectorImage string
collectorConfigMapEntry string
logger logr.Logger
onChange []func() error
platform platform.Platform
version version.Version
autoDetect autodetect.AutoDetect
autoDetectFrequency time.Duration
targetAllocatorImage string
collectorImage string
collectorConfigMapEntry string
targetAllocatorConfigMapEntry string
logger logr.Logger
onChange []func() error
platform platform.Platform
version version.Version
}

func WithAutoDetect(a autodetect.AutoDetect) Option {
Expand All @@ -48,6 +50,12 @@ func WithAutoDetectFrequency(t time.Duration) Option {
o.autoDetectFrequency = t
}
}
func WithTargetAllocatorImage(s string) Option {
return func(o *options) {
o.targetAllocatorImage = s
}
}

func WithCollectorImage(s string) Option {
return func(o *options) {
o.collectorImage = s
Expand All @@ -58,6 +66,11 @@ func WithCollectorConfigMapEntry(s string) Option {
o.collectorConfigMapEntry = s
}
}
func WithTargetAllocatorConfigMapEntry(s string) Option {
return func(o *options) {
o.targetAllocatorConfigMapEntry = s
}
}
func WithLogger(logger logr.Logger) Option {
return func(o *options) {
o.logger = logger
Expand Down
23 changes: 19 additions & 4 deletions internal/version/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ import (
)

var (
version string
buildDate string
otelCol string
version string
buildDate string
otelCol string
targetAllocator string
)

// Version holds this Operator's version as well as the version of some of the components it uses.
Expand All @@ -32,6 +33,7 @@ type Version struct {
BuildDate string `json:"build-date"`
OpenTelemetryCollector string `json:"opentelemetry-collector-version"`
Go string `json:"go-version"`
TargetAllocator string `json:"target-allocator-version"`
}

// Get returns the Version object with the relevant information.
Expand All @@ -41,16 +43,18 @@ func Get() Version {
BuildDate: buildDate,
OpenTelemetryCollector: OpenTelemetryCollector(),
Go: runtime.Version(),
TargetAllocator: TargetAllocator(),
}
}

func (v Version) String() string {
return fmt.Sprintf(
"Version(Operator='%v', BuildDate='%v', OpenTelemetryCollector='%v', Go='%v')",
"Version(Operator='%v', BuildDate='%v', OpenTelemetryCollector='%v', Go='%v', TargetAllocator='%v')",
v.Operator,
v.BuildDate,
v.OpenTelemetryCollector,
v.Go,
v.TargetAllocator,
)
}

Expand All @@ -64,3 +68,14 @@ func OpenTelemetryCollector() string {
// fallback value, useful for tests
return "0.0.0"
}

// TargetAllocator returns the default TargetAllocator to use when no versions are specified via CLI or configuration.
func TargetAllocator() string {
if len(targetAllocator) > 0 {
// this should always be set, as it's specified during the build
return targetAllocator
}

// fallback value, useful for tests
return "0.0.0"
}
15 changes: 15 additions & 0 deletions internal/version/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,18 @@ func TestVersionFromBuild(t *testing.T) {
assert.Equal(t, otelCol, OpenTelemetryCollector())
assert.Contains(t, Get().String(), otelCol)
}

func TestTargetAllocatorFallbackVersion(t *testing.T) {
assert.Equal(t, "0.0.0", TargetAllocator())
}

func TestTargetAllocatorVersionFromBuild(t *testing.T) {
// prepare
targetAllocator = "0.0.2" // set during the build
defer func() {
targetAllocator = ""
}()

assert.Equal(t, targetAllocator, TargetAllocator())
assert.Contains(t, Get().String(), targetAllocator)
}
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func main() {
logger.Info("Starting the OpenTelemetry Operator",
"opentelemetry-operator", v.Operator,
"opentelemetry-collector", v.OpenTelemetryCollector,
"opentelemetry-targetallocator", v.TargetAllocator,
"build-date", v.BuildDate,
"go-version", v.Go,
"go-arch", runtime.GOARCH,
Expand Down
Loading

0 comments on commit a729deb

Please sign in to comment.