Skip to content

Commit fce1d62

Browse files
committedAug 28, 2019
Initial prototype
Signed-off-by: Juraci Paixão Kröhling <juraci@kroehling.de>
0 parents  commit fce1d62

40 files changed

+2411
-0
lines changed
 

‎.gitignore

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Temporary Build Files
2+
build/_output
3+
build/_test
4+
# Created by https://www.gitignore.io/api/go,vim,emacs,visualstudiocode
5+
### Emacs ###
6+
# -*- mode: gitignore; -*-
7+
*~
8+
\#*\#
9+
/.emacs.desktop
10+
/.emacs.desktop.lock
11+
*.elc
12+
auto-save-list
13+
tramp
14+
.\#*
15+
# Org-mode
16+
.org-id-locations
17+
*_archive
18+
# flymake-mode
19+
*_flymake.*
20+
# eshell files
21+
/eshell/history
22+
/eshell/lastdir
23+
# elpa packages
24+
/elpa/
25+
# reftex files
26+
*.rel
27+
# AUCTeX auto folder
28+
/auto/
29+
# cask packages
30+
.cask/
31+
dist/
32+
# Flycheck
33+
flycheck_*.el
34+
# server auth directory
35+
/server/
36+
# projectiles files
37+
.projectile
38+
projectile-bookmarks.eld
39+
# directory configuration
40+
.dir-locals.el
41+
# saveplace
42+
places
43+
# url cache
44+
url/cache/
45+
# cedet
46+
ede-projects.el
47+
# smex
48+
smex-items
49+
# company-statistics
50+
company-statistics-cache.el
51+
# anaconda-mode
52+
anaconda-mode/
53+
### Go ###
54+
# Binaries for programs and plugins
55+
*.exe
56+
*.exe~
57+
*.dll
58+
*.so
59+
*.dylib
60+
# Test binary, build with 'go test -c'
61+
*.test
62+
# Output of the go coverage tool, specifically when used with LiteIDE
63+
*.out
64+
### Vim ###
65+
# swap
66+
.sw[a-p]
67+
.*.sw[a-p]
68+
# session
69+
Session.vim
70+
# temporary
71+
.netrwhist
72+
# auto-generated tag files
73+
tags
74+
### VisualStudioCode ###
75+
.vscode/*
76+
.history
77+
# End of https://www.gitignore.io/api/go,vim,emacs,visualstudiocode

‎CONTRIBUTING.md

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# How to Contribute to the OpenTelemetry Operator for Kubernetes
2+
3+
We'd love your help!
4+
5+
This project is [Apache 2.0 licensed](LICENSE) and accepts contributions via GitHub pull requests. This document outlines some of the conventions on development workflow, commit message formatting, contact points and other resources to make it easier to get your contribution accepted.
6+
7+
We gratefully welcome improvements to documentation as well as to code.
8+
9+
## Certificate of Origin
10+
11+
By contributing to this project you agree to the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). This document was created by the Linux Kernel community and is a simple statement that you, as a contributor, have the legal right to make the contribution. See the [DCO](DCO) file for details.
12+
13+
## Getting Started
14+
15+
This project is a regular [Kubernetes Operator](https://coreos.com/operators/) built using the Operator SDK. Refer to the Operator SDK documentation to understand the basic architecture of this operator.
16+
17+
### Installing the Operator SDK command line tool
18+
19+
Follow the installation guidelines from [Operator SDK GitHub page](https://github.com/operator-framework/operator-sdk).
20+
21+
### Developing
22+
23+
As usual for operators following the Operator SDK in recent versions, the dependencies are managed using [`go modules`](https://golang.org/doc/go1.11#modules). Refer to that project's documentation for instructions on how to add or update dependencies.
24+
25+
The first step is to get a local Kubernetes instance up and running. The recommended approach is using `minikube`. Refer to the Kubernetes' [documentation](https://kubernetes.io/docs/tasks/tools/install-minikube/) for instructions on how to install it.
26+
27+
Once `minikube` is installed, it can be started with:
28+
29+
```
30+
minikube start
31+
```
32+
33+
NOTE: Make sure to read the documentation to learn the performance switches that can be applied to your platform.
34+
35+
Once minikube has finished starting, get the Operator running:
36+
37+
```
38+
make run
39+
```
40+
41+
At this point, a Jaeger instance can be installed:
42+
43+
```
44+
kubectl apply -f deploy/examples/simplest.yaml
45+
kubectl get otelsvcs
46+
kubectl get pods
47+
```
48+
49+
To remove the instance:
50+
51+
```
52+
kubectl delete -f deploy/examples/simplest.yaml
53+
```
54+
55+
#### Model changes
56+
57+
The Operator SDK generates the `pkg/apis/opentelemetry/v1alpha1//zz_generated.*.go` files via the command `make generate`. This should be executed whenever there's a model change (`pkg/apis/opentelemetry/v1alpha1//opentelemetryservice_types.go`)
58+
59+
#### Tests
60+
61+
Right now, there are no tests on this repo yet. This will change really soon.

‎LICENSE

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
Apache License
2+
Version 2.0, January 2004
3+
http://www.apache.org/licenses/
4+
5+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6+
7+
1. Definitions.
8+
9+
"License" shall mean the terms and conditions for use, reproduction,
10+
and distribution as defined by Sections 1 through 9 of this document.
11+
12+
"Licensor" shall mean the copyright owner or entity authorized by
13+
the copyright owner that is granting the License.
14+
15+
"Legal Entity" shall mean the union of the acting entity and all
16+
other entities that control, are controlled by, or are under common
17+
control with that entity. For the purposes of this definition,
18+
"control" means (i) the power, direct or indirect, to cause the
19+
direction or management of such entity, whether by contract or
20+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
21+
outstanding shares, or (iii) beneficial ownership of such entity.
22+
23+
"You" (or "Your") shall mean an individual or Legal Entity
24+
exercising permissions granted by this License.
25+
26+
"Source" form shall mean the preferred form for making modifications,
27+
including but not limited to software source code, documentation
28+
source, and configuration files.
29+
30+
"Object" form shall mean any form resulting from mechanical
31+
transformation or translation of a Source form, including but
32+
not limited to compiled object code, generated documentation,
33+
and conversions to other media types.
34+
35+
"Work" shall mean the work of authorship, whether in Source or
36+
Object form, made available under the License, as indicated by a
37+
copyright notice that is included in or attached to the work
38+
(an example is provided in the Appendix below).
39+
40+
"Derivative Works" shall mean any work, whether in Source or Object
41+
form, that is based on (or derived from) the Work and for which the
42+
editorial revisions, annotations, elaborations, or other modifications
43+
represent, as a whole, an original work of authorship. For the purposes
44+
of this License, Derivative Works shall not include works that remain
45+
separable from, or merely link (or bind by name) to the interfaces of,
46+
the Work and Derivative Works thereof.
47+
48+
"Contribution" shall mean any work of authorship, including
49+
the original version of the Work and any modifications or additions
50+
to that Work or Derivative Works thereof, that is intentionally
51+
submitted to Licensor for inclusion in the Work by the copyright owner
52+
or by an individual or Legal Entity authorized to submit on behalf of
53+
the copyright owner. For the purposes of this definition, "submitted"
54+
means any form of electronic, verbal, or written communication sent
55+
to the Licensor or its representatives, including but not limited to
56+
communication on electronic mailing lists, source code control systems,
57+
and issue tracking systems that are managed by, or on behalf of, the
58+
Licensor for the purpose of discussing and improving the Work, but
59+
excluding communication that is conspicuously marked or otherwise
60+
designated in writing by the copyright owner as "Not a Contribution."
61+
62+
"Contributor" shall mean Licensor and any individual or Legal Entity
63+
on behalf of whom a Contribution has been received by Licensor and
64+
subsequently incorporated within the Work.
65+
66+
2. Grant of Copyright License. Subject to the terms and conditions of
67+
this License, each Contributor hereby grants to You a perpetual,
68+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69+
copyright license to reproduce, prepare Derivative Works of,
70+
publicly display, publicly perform, sublicense, and distribute the
71+
Work and such Derivative Works in Source or Object form.
72+
73+
3. Grant of Patent License. Subject to the terms and conditions of
74+
this License, each Contributor hereby grants to You a perpetual,
75+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76+
(except as stated in this section) patent license to make, have made,
77+
use, offer to sell, sell, import, and otherwise transfer the Work,
78+
where such license applies only to those patent claims licensable
79+
by such Contributor that are necessarily infringed by their
80+
Contribution(s) alone or by combination of their Contribution(s)
81+
with the Work to which such Contribution(s) was submitted. If You
82+
institute patent litigation against any entity (including a
83+
cross-claim or counterclaim in a lawsuit) alleging that the Work
84+
or a Contribution incorporated within the Work constitutes direct
85+
or contributory patent infringement, then any patent licenses
86+
granted to You under this License for that Work shall terminate
87+
as of the date such litigation is filed.
88+
89+
4. Redistribution. You may reproduce and distribute copies of the
90+
Work or Derivative Works thereof in any medium, with or without
91+
modifications, and in Source or Object form, provided that You
92+
meet the following conditions:
93+
94+
(a) You must give any other recipients of the Work or
95+
Derivative Works a copy of this License; and
96+
97+
(b) You must cause any modified files to carry prominent notices
98+
stating that You changed the files; and
99+
100+
(c) You must retain, in the Source form of any Derivative Works
101+
that You distribute, all copyright, patent, trademark, and
102+
attribution notices from the Source form of the Work,
103+
excluding those notices that do not pertain to any part of
104+
the Derivative Works; and
105+
106+
(d) If the Work includes a "NOTICE" text file as part of its
107+
distribution, then any Derivative Works that You distribute must
108+
include a readable copy of the attribution notices contained
109+
within such NOTICE file, excluding those notices that do not
110+
pertain to any part of the Derivative Works, in at least one
111+
of the following places: within a NOTICE text file distributed
112+
as part of the Derivative Works; within the Source form or
113+
documentation, if provided along with the Derivative Works; or,
114+
within a display generated by the Derivative Works, if and
115+
wherever such third-party notices normally appear. The contents
116+
of the NOTICE file are for informational purposes only and
117+
do not modify the License. You may add Your own attribution
118+
notices within Derivative Works that You distribute, alongside
119+
or as an addendum to the NOTICE text from the Work, provided
120+
that such additional attribution notices cannot be construed
121+
as modifying the License.
122+
123+
You may add Your own copyright statement to Your modifications and
124+
may provide additional or different license terms and conditions
125+
for use, reproduction, or distribution of Your modifications, or
126+
for any such Derivative Works as a whole, provided Your use,
127+
reproduction, and distribution of the Work otherwise complies with
128+
the conditions stated in this License.
129+
130+
5. Submission of Contributions. Unless You explicitly state otherwise,
131+
any Contribution intentionally submitted for inclusion in the Work
132+
by You to the Licensor shall be under the terms and conditions of
133+
this License, without any additional terms or conditions.
134+
Notwithstanding the above, nothing herein shall supersede or modify
135+
the terms of any separate license agreement you may have executed
136+
with Licensor regarding such Contributions.
137+
138+
6. Trademarks. This License does not grant permission to use the trade
139+
names, trademarks, service marks, or product names of the Licensor,
140+
except as required for reasonable and customary use in describing the
141+
origin of the Work and reproducing the content of the NOTICE file.
142+
143+
7. Disclaimer of Warranty. Unless required by applicable law or
144+
agreed to in writing, Licensor provides the Work (and each
145+
Contributor provides its Contributions) on an "AS IS" BASIS,
146+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147+
implied, including, without limitation, any warranties or conditions
148+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149+
PARTICULAR PURPOSE. You are solely responsible for determining the
150+
appropriateness of using or redistributing the Work and assume any
151+
risks associated with Your exercise of permissions under this License.
152+
153+
8. Limitation of Liability. In no event and under no legal theory,
154+
whether in tort (including negligence), contract, or otherwise,
155+
unless required by applicable law (such as deliberate and grossly
156+
negligent acts) or agreed to in writing, shall any Contributor be
157+
liable to You for damages, including any direct, indirect, special,
158+
incidental, or consequential damages of any character arising as a
159+
result of this License or out of the use or inability to use the
160+
Work (including but not limited to damages for loss of goodwill,
161+
work stoppage, computer failure or malfunction, or any and all
162+
other commercial damages or losses), even if such Contributor
163+
has been advised of the possibility of such damages.
164+
165+
9. Accepting Warranty or Additional Liability. While redistributing
166+
the Work or Derivative Works thereof, You may choose to offer,
167+
and charge a fee for, acceptance of support, warranty, indemnity,
168+
or other liability obligations and/or rights consistent with this
169+
License. However, in accepting such obligations, You may act only
170+
on Your own behalf and on Your sole responsibility, not on behalf
171+
of any other Contributor, and only if You agree to indemnify,
172+
defend, and hold each Contributor harmless for any liability
173+
incurred by, or claims asserted against, such Contributor by reason
174+
of your accepting any such warranty or additional liability.
175+
176+
END OF TERMS AND CONDITIONS
177+
178+
APPENDIX: How to apply the Apache License to your work.
179+
180+
To apply the Apache License to your work, attach the following
181+
boilerplate notice, with the fields enclosed by brackets "[]"
182+
replaced with your own identifying information. (Don't include
183+
the brackets!) The text should be enclosed in the appropriate
184+
comment syntax for the file format. We also recommend that a
185+
file or class name and description of purpose be included on the
186+
same "printed page" as the copyright notice for easier
187+
identification within third-party archives.
188+
189+
Copyright [yyyy] [name of copyright owner]
190+
191+
Licensed under the Apache License, Version 2.0 (the "License");
192+
you may not use this file except in compliance with the License.
193+
You may obtain a copy of the License at
194+
195+
http://www.apache.org/licenses/LICENSE-2.0
196+
197+
Unless required by applicable law or agreed to in writing, software
198+
distributed under the License is distributed on an "AS IS" BASIS,
199+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200+
See the License for the specific language governing permissions and
201+
limitations under the License.

‎Makefile

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
OPERATOR_NAME ?= opentelemetry-operator
2+
OPERATOR_VERSION ?= "$(shell git describe --tags)"
3+
VERSION_DATE ?= $(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
4+
5+
GO_FLAGS ?= GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GO111MODULE=on
6+
KUBERNETES_CONFIG ?= "$(HOME)/.kube/config"
7+
WATCH_NAMESPACE ?= ""
8+
BIN_DIR ?= "build/_output/bin"
9+
10+
NAMESPACE ?= "$(USER)"
11+
BUILD_IMAGE ?= "$(NAMESPACE)/$(OPERATOR_NAME):latest"
12+
OUTPUT_BINARY ?= "$(BIN_DIR)/$(OPERATOR_NAME)"
13+
VERSION_PKG ?= "github.com/open-telemetry/opentelemetry-operator/version"
14+
LD_FLAGS ?= "-X=$(VERSION_PKG).Version=$(OPERATOR_VERSION)"
15+
16+
PACKAGES := $(shell go list ./cmd/... ./pkg/...)
17+
18+
.DEFAULT_GOAL := build
19+
20+
.PHONY: check
21+
check:
22+
@echo Checking...
23+
@go fmt $(PACKAGES) > $(FMT_LOG)
24+
25+
.PHONY: ensure-generate-is-noop
26+
ensure-generate-is-noop: generate
27+
@git diff -s --exit-code pkg/apis/opentelemetry/v1alpha1/zz_generated.*.go || (echo "Build failed: a model has been changed but the deep copy functions aren't up to date. Run 'make generate' and update your PR." && exit 1)
28+
29+
.PHONY: format
30+
format:
31+
@echo Formatting code...
32+
@go fmt $(PACKAGES)
33+
34+
.PHONY: lint
35+
lint:
36+
@echo Linting...
37+
@$(GOPATH)/bin/golint -set_exit_status=1 $(PACKAGES)
38+
39+
.PHONY: security
40+
security:
41+
@echo Security...
42+
@$(GOPATH)/bin/gosec -quiet $(PACKAGES) 2>/dev/null
43+
44+
.PHONY: build
45+
build: format
46+
@echo Building...
47+
@operator-sdk build ${BUILD_IMAGE} --go-build-args "-ldflags ${LD_FLAGS}"
48+
49+
.PHONY: run
50+
run: crd
51+
@operator-sdk up local OPERATOR_NAME=$(OPERATOR_NAME) --go-ldflags "-X $(VERSION_PKG).Version=$(OPERATOR_VERSION) -X $(VERSION_PKG).BuildDate=$(VERSION_DATE)"
52+
53+
.PHONY: run-debug
54+
run-debug: crd
55+
@operator-sdk up local --operator-flags "--log-level=debug" OPERATOR_NAME=$(OPERATOR_NAME)
56+
57+
.PHONY: clean
58+
clean:
59+
@echo Cleaning...
60+
61+
.PHONY: crd
62+
crd:
63+
@kubectl create -f deploy/crds/opentelemetry_v1alpha1_opentelemetryservice_crd.yaml 2>&1 | grep -v "already exists" || true
64+
65+
.PHONY: generate
66+
generate:
67+
@operator-sdk generate k8s
68+
@operator-sdk generate openapi
69+
70+
.PHONY: test
71+
test:
72+
@echo Running tests...
73+
74+
.PHONY: all
75+
all: check format lint security build test
76+
77+
.PHONY: ci
78+
ci: ensure-generate-is-noop all
79+
80+
.PHONY: scorecard
81+
scorecard:
82+
@operator-sdk scorecard --cr-manifest deploy/examples/simplest.yaml --csv-path deploy/olm-catalog/jaeger.clusterserviceversion.yaml --init-timeout 30
83+
84+
.PHONY: install-tools
85+
install-tools:
86+
@go get -u \
87+
golang.org/x/lint/golint \
88+
github.com/securego/gosec/cmd/gosec

‎README.md

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
[![Go Report Card][goreport-img]][goreport] [![GoDoc][godoc-img]][godoc]
2+
3+
# OpenTelemetry Operator for Kubernetes
4+
5+
The OpenTelemetry Operator is an implementation of a [Kubernetes Operator](https://coreos.com/operators/).
6+
7+
At this point, it has [OpenTelemetry Service](https://github.com/open-telemetry/opentelemetry-service) as the only managed component.
8+
9+
## Getting started
10+
11+
To install the operator, run:
12+
```
13+
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/crds/opentelemetry_v1alpha1_opentelemetryservice_crd.yaml
14+
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/service_account.yaml
15+
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/role.yaml
16+
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/role_binding.yaml
17+
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/operator.yaml
18+
```
19+
20+
Once the `opentelemetry-operator` deployment is ready, create an OpenTelemetry Service (otelsvc) instance, like:
21+
22+
```
23+
kubectl apply -f - <<EOF
24+
apiVersion: opentelemetry.io/v1alpha1
25+
kind: OpenTelemetryService
26+
metadata:
27+
name: simplest
28+
spec:
29+
config: |
30+
receivers:
31+
jaeger:
32+
33+
processors:
34+
queued-retry:
35+
36+
exporters:
37+
logging:
38+
39+
pipelines:
40+
traces:
41+
receivers: [jaeger]
42+
processors: [queued-retry]
43+
exporters: [logging]
44+
```
45+
46+
This will create an OpenTelemetry Service instance named `simplest`, exposing a `jaeger-grpc` port to consume spans from your instrumented applications and exporting those spans via `jaeger-grpc` to a remote Jaeger collector.
47+
48+
The `config` node holds the `YAML` that should be passed down as-is to the underlying OpenTelemetry Service instances. Refer to the [OpenTelemetry Service](https://github.com/open-telemetry/opentelemetry-service) documentation for a reference of the possible entries.
49+
50+
At this point, the Operator does *not* validate the contents of the configuration file: if the configuration is invalid, the instance will still be created but the underlying OpenTelemetry Service might crash.
51+
52+
## Contributing and Developing
53+
54+
Please see [CONTRIBUTING.md](CONTRIBUTING.md).
55+
56+
## License
57+
58+
[Apache 2.0 License](./LICENSE).
59+
60+
[goreport-img]: https://goreportcard.com/badge/github.com/jpkrohling/opentelemetry-operator
61+
[goreport]: https://goreportcard.com/report/github.com/jpkrohling/opentelemetry-operator
62+
[godoc-img]: https://godoc.org/github.com/jpkrohling/opentelemetry-operator?status.svg
63+
[godoc]: https://godoc.org/github.com/jpkrohling/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1#OpenTelemetryService

‎build/Dockerfile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM registry.access.redhat.com/ubi7/ubi-minimal:latest
2+
3+
ENV OPERATOR=/usr/local/bin/opentelemetry-operator \
4+
USER_UID=1001 \
5+
USER_NAME=opentelemetry-operator
6+
7+
# install operator binary
8+
COPY build/_output/bin/opentelemetry-operator ${OPERATOR}
9+
10+
COPY build/bin /usr/local/bin
11+
RUN /usr/local/bin/user_setup
12+
13+
ENTRYPOINT ["/usr/local/bin/entrypoint"]
14+
15+
USER ${USER_UID}

‎build/bin/entrypoint

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/sh -e
2+
3+
# This is documented here:
4+
# https://docs.openshift.com/container-platform/3.11/creating_images/guidelines.html#openshift-specific-guidelines
5+
6+
if ! whoami &>/dev/null; then
7+
if [ -w /etc/passwd ]; then
8+
echo "${USER_NAME:-opentelemetry-operator}:x:$(id -u):$(id -g):${USER_NAME:-opentelemetry-operator} user:${HOME}:/sbin/nologin" >> /etc/passwd
9+
fi
10+
fi
11+
12+
exec ${OPERATOR} $@

‎build/bin/user_setup

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/sh
2+
set -x
3+
4+
# ensure $HOME exists and is accessible by group 0 (we don't know what the runtime UID will be)
5+
mkdir -p ${HOME}
6+
chown ${USER_UID}:0 ${HOME}
7+
chmod ug+rwx ${HOME}
8+
9+
# runtime user will need to be able to self-insert in /etc/passwd
10+
chmod g+rw /etc/passwd
11+
12+
# no need for this script to remain in the image after running
13+
rm $0

‎cmd/manager/main.go

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"fmt"
7+
"os"
8+
"runtime"
9+
10+
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
11+
_ "k8s.io/client-go/plugin/pkg/client/auth"
12+
"k8s.io/client-go/rest"
13+
14+
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
15+
kubemetrics "github.com/operator-framework/operator-sdk/pkg/kube-metrics"
16+
"github.com/operator-framework/operator-sdk/pkg/leader"
17+
"github.com/operator-framework/operator-sdk/pkg/log/zap"
18+
"github.com/operator-framework/operator-sdk/pkg/metrics"
19+
"github.com/operator-framework/operator-sdk/pkg/restmapper"
20+
sdkVersion "github.com/operator-framework/operator-sdk/version"
21+
"github.com/spf13/pflag"
22+
v1 "k8s.io/api/core/v1"
23+
"k8s.io/apimachinery/pkg/util/intstr"
24+
"sigs.k8s.io/controller-runtime/pkg/client/config"
25+
"sigs.k8s.io/controller-runtime/pkg/manager"
26+
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
27+
"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
28+
29+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis"
30+
"github.com/open-telemetry/opentelemetry-operator/pkg/controller"
31+
"github.com/open-telemetry/opentelemetry-operator/version"
32+
)
33+
34+
// Change below variables to serve metrics on different host or port.
35+
var (
36+
metricsHost = "0.0.0.0"
37+
metricsPort int32 = 8383
38+
operatorMetricsPort int32 = 8686
39+
)
40+
var log = logf.Log.WithName("cmd")
41+
42+
func printVersion() {
43+
log.Info("Starting the OpenTelemetry Operator",
44+
"opentelemetry-operator", version.Version,
45+
"build-date", version.BuildDate,
46+
"go-version", runtime.Version(),
47+
"go-arch", runtime.GOARCH,
48+
"go-os", runtime.GOOS,
49+
"operator-sdk-version", sdkVersion.Version,
50+
)
51+
}
52+
53+
func main() {
54+
// Add the zap logger flag set to the CLI. The flag set must
55+
// be added before calling pflag.Parse().
56+
pflag.CommandLine.AddFlagSet(zap.FlagSet())
57+
58+
// Add flags registered by imported packages (e.g. glog and
59+
// controller-runtime)
60+
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
61+
62+
pflag.Parse()
63+
64+
// Use a zap logr.Logger implementation. If none of the zap
65+
// flags are configured (or if the zap flag set is not being
66+
// used), this defaults to a production zap logger.
67+
//
68+
// The logger instantiated here can be changed to any logger
69+
// implementing the logr.Logger interface. This logger will
70+
// be propagated through the whole operator, generating
71+
// uniform and structured logs.
72+
logf.SetLogger(zap.Logger())
73+
74+
printVersion()
75+
76+
namespace, err := k8sutil.GetWatchNamespace()
77+
if err != nil {
78+
log.Error(err, "Failed to get watch namespace")
79+
os.Exit(1)
80+
}
81+
82+
// Get a config to talk to the apiserver
83+
cfg, err := config.GetConfig()
84+
if err != nil {
85+
log.Error(err, "")
86+
os.Exit(1)
87+
}
88+
89+
ctx := context.TODO()
90+
// Become the leader before proceeding
91+
err = leader.Become(ctx, "opentelemetry-operator-lock")
92+
if err != nil {
93+
log.Error(err, "")
94+
os.Exit(1)
95+
}
96+
97+
// Create a new Cmd to provide shared dependencies and start components
98+
mgr, err := manager.New(cfg, manager.Options{
99+
Namespace: namespace,
100+
MapperProvider: restmapper.NewDynamicRESTMapper,
101+
MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort),
102+
})
103+
if err != nil {
104+
log.Error(err, "")
105+
os.Exit(1)
106+
}
107+
108+
log.Info("Registering Components.")
109+
110+
// Setup Scheme for all resources
111+
if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
112+
log.Error(err, "")
113+
os.Exit(1)
114+
}
115+
116+
// Setup all Controllers
117+
if err := controller.AddToManager(mgr); err != nil {
118+
log.Error(err, "")
119+
os.Exit(1)
120+
}
121+
122+
if err = serveCRMetrics(cfg); err != nil {
123+
log.Info("Could not generate and serve custom resource metrics", "error", err.Error())
124+
}
125+
126+
// Add to the below struct any other metrics ports you want to expose.
127+
servicePorts := []v1.ServicePort{
128+
{Port: metricsPort, Name: metrics.OperatorPortName, Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: metricsPort}},
129+
{Port: operatorMetricsPort, Name: metrics.CRPortName, Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: operatorMetricsPort}},
130+
}
131+
// Create Service object to expose the metrics port(s).
132+
service, err := metrics.CreateMetricsService(ctx, cfg, servicePorts)
133+
if err != nil {
134+
log.Info("Could not create metrics Service", "error", err.Error())
135+
}
136+
137+
// CreateServiceMonitors will automatically create the prometheus-operator ServiceMonitor resources
138+
// necessary to configure Prometheus to scrape metrics from this operator.
139+
services := []*v1.Service{service}
140+
_, err = metrics.CreateServiceMonitors(cfg, namespace, services)
141+
if err != nil {
142+
log.Info("Could not create ServiceMonitor object", "error", err.Error())
143+
// If this operator is deployed to a cluster without the prometheus-operator running, it will return
144+
// ErrServiceMonitorNotPresent, which can be used to safely skip ServiceMonitor creation.
145+
if err == metrics.ErrServiceMonitorNotPresent {
146+
log.Info("Install prometheus-operator in your cluster to create ServiceMonitor objects", "error", err.Error())
147+
}
148+
}
149+
150+
log.Info("Starting the Cmd.")
151+
152+
// Start the Cmd
153+
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
154+
log.Error(err, "Manager exited non-zero")
155+
os.Exit(1)
156+
}
157+
}
158+
159+
// serveCRMetrics gets the Operator/CustomResource GVKs and generates metrics based on those types.
160+
// It serves those metrics on "http://metricsHost:operatorMetricsPort".
161+
func serveCRMetrics(cfg *rest.Config) error {
162+
// Below function returns filtered operator/CustomResource specific GVKs.
163+
// For more control override the below GVK list with your own custom logic.
164+
filteredGVK, err := k8sutil.GetGVKsFromAddToScheme(apis.AddToScheme)
165+
if err != nil {
166+
return err
167+
}
168+
// Get the namespace the operator is currently deployed in.
169+
operatorNs, err := k8sutil.GetOperatorNamespace()
170+
if err != nil {
171+
return err
172+
}
173+
// To generate metrics in other namespaces, add the values below.
174+
ns := []string{operatorNs}
175+
// Generate and serve custom resource specific metrics.
176+
err = kubemetrics.GenerateAndServeCRMetrics(cfg, ns, filteredGVK, metricsHost, operatorMetricsPort)
177+
if err != nil {
178+
return err
179+
}
180+
return nil
181+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: opentelemetry.io/v1alpha1
2+
kind: OpenTelemetryService
3+
metadata:
4+
name: example-opentelemetryservice
5+
spec:
6+
replicas: 3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: opentelemetryservices.opentelemetry.io
5+
spec:
6+
group: opentelemetry.io
7+
names:
8+
kind: OpenTelemetryService
9+
listKind: OpenTelemetryServiceList
10+
plural: opentelemetryservices
11+
shortNames:
12+
- otelsvc
13+
- otelsvcs
14+
singular: opentelemetryservice
15+
scope: Namespaced
16+
subresources:
17+
scale:
18+
specReplicasPath: .spec.replicas
19+
statusReplicasPath: .status.replicas
20+
status: {}
21+
validation:
22+
openAPIV3Schema:
23+
properties:
24+
apiVersion:
25+
description: 'APIVersion defines the versioned schema of this representation
26+
of an object. Servers should convert recognized schemas to the latest
27+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
28+
type: string
29+
kind:
30+
description: 'Kind is a string value representing the REST resource this
31+
object represents. Servers may infer this from the endpoint the client
32+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
33+
type: string
34+
metadata:
35+
type: object
36+
spec:
37+
properties:
38+
config:
39+
description: +required
40+
type: string
41+
replicas:
42+
format: int32
43+
type: integer
44+
type: object
45+
status:
46+
properties:
47+
replicas:
48+
format: int32
49+
type: integer
50+
required:
51+
- replicas
52+
type: object
53+
version: v1alpha1
54+
versions:
55+
- name: v1alpha1
56+
served: true
57+
storage: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
apiVersion: operators.coreos.com/v1alpha1
2+
kind: ClusterServiceVersion
3+
metadata:
4+
annotations:
5+
alm-examples: '[{"apiVersion":"opentelemetry.io/v1alpha1","kind":"OpenTelemetryService","metadata":{"name":"example-opentelemetryservice"},"spec":{"size":3}}]'
6+
capabilities: Basic Install
7+
name: opentelemetry-operator.v0.0.1
8+
namespace: placeholder
9+
spec:
10+
apiservicedefinitions: {}
11+
customresourcedefinitions: {}
12+
description: Placeholder description
13+
displayName: Opentelemetry Operator
14+
install:
15+
spec:
16+
deployments:
17+
- name: opentelemetry-operator
18+
spec:
19+
replicas: 1
20+
selector:
21+
matchLabels:
22+
name: opentelemetry-operator
23+
strategy: {}
24+
template:
25+
metadata:
26+
labels:
27+
name: opentelemetry-operator
28+
spec:
29+
containers:
30+
- command:
31+
- opentelemetry-operator
32+
env:
33+
- name: WATCH_NAMESPACE
34+
valueFrom:
35+
fieldRef:
36+
fieldPath: metadata.annotations['olm.targetNamespaces']
37+
- name: POD_NAME
38+
valueFrom:
39+
fieldRef:
40+
fieldPath: metadata.name
41+
- name: OPERATOR_NAME
42+
value: opentelemetry-operator
43+
image: REPLACE_IMAGE
44+
imagePullPolicy: Always
45+
name: opentelemetry-operator
46+
resources: {}
47+
serviceAccountName: opentelemetry-operator
48+
permissions:
49+
- rules:
50+
- apiGroups:
51+
- ""
52+
resources:
53+
- pods
54+
- services
55+
- services/finalizers
56+
- endpoints
57+
- persistentvolumeclaims
58+
- events
59+
- configmaps
60+
- secrets
61+
verbs:
62+
- '*'
63+
- apiGroups:
64+
- apps
65+
resources:
66+
- deployments
67+
- daemonsets
68+
- replicasets
69+
- statefulsets
70+
verbs:
71+
- '*'
72+
- apiGroups:
73+
- monitoring.coreos.com
74+
resources:
75+
- servicemonitors
76+
verbs:
77+
- get
78+
- create
79+
- apiGroups:
80+
- apps
81+
resourceNames:
82+
- opentelemetry-operator
83+
resources:
84+
- deployments/finalizers
85+
verbs:
86+
- update
87+
- apiGroups:
88+
- ""
89+
resources:
90+
- pods
91+
verbs:
92+
- get
93+
- apiGroups:
94+
- apps
95+
resources:
96+
- replicasets
97+
verbs:
98+
- get
99+
- apiGroups:
100+
- opentelemetry.io
101+
resources:
102+
- '*'
103+
verbs:
104+
- '*'
105+
serviceAccountName: opentelemetry-operator
106+
strategy: deployment
107+
installModes:
108+
- supported: true
109+
type: OwnNamespace
110+
- supported: true
111+
type: SingleNamespace
112+
- supported: false
113+
type: MultiNamespace
114+
- supported: true
115+
type: AllNamespaces
116+
keywords:
117+
- tracing
118+
- distributed tracing
119+
- monitoring
120+
- troubleshooting
121+
maintainers:
122+
- email: juraci.github@kroehling.de
123+
name: Juraci Paixão Kröhling
124+
maturity: alpha
125+
provider:
126+
name: OpenTelemetry
127+
version: 0.0.1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: opentelemetryservices.opentelemetry.io
5+
spec:
6+
group: opentelemetry.io
7+
names:
8+
kind: OpenTelemetryService
9+
listKind: OpenTelemetryServiceList
10+
plural: opentelemetryservices
11+
singular: opentelemetryservice
12+
scope: Namespaced
13+
subresources:
14+
status: {}
15+
validation:
16+
openAPIV3Schema:
17+
properties:
18+
apiVersion:
19+
description: 'APIVersion defines the versioned schema of this representation
20+
of an object. Servers should convert recognized schemas to the latest
21+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
22+
type: string
23+
kind:
24+
description: 'Kind is a string value representing the REST resource this
25+
object represents. Servers may infer this from the endpoint the client
26+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
27+
type: string
28+
metadata:
29+
type: object
30+
spec:
31+
type: object
32+
status:
33+
type: object
34+
version: v1alpha1
35+
versions:
36+
- name: v1alpha1
37+
served: true
38+
storage: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
channels:
2+
- currentCSV: opentelemetry-operator.v0.0.1
3+
name: alpha
4+
defaultChannel: alpha
5+
packageName: opentelemetry-operator

‎deploy/operator.yaml

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: opentelemetry-operator
5+
spec:
6+
replicas: 1
7+
selector:
8+
matchLabels:
9+
name: opentelemetry-operator
10+
template:
11+
metadata:
12+
labels:
13+
name: opentelemetry-operator
14+
spec:
15+
serviceAccountName: opentelemetry-operator
16+
containers:
17+
- name: opentelemetry-operator
18+
image: quay.io/jpkroehling/opentelemetry-operator:latest
19+
command:
20+
- opentelemetry-operator
21+
imagePullPolicy: Always
22+
env:
23+
- name: WATCH_NAMESPACE
24+
valueFrom:
25+
fieldRef:
26+
fieldPath: metadata.namespace
27+
- name: POD_NAME
28+
valueFrom:
29+
fieldRef:
30+
fieldPath: metadata.name
31+
- name: OPERATOR_NAME
32+
value: "opentelemetry-operator"

‎deploy/role.yaml

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: Role
3+
metadata:
4+
creationTimestamp: null
5+
name: opentelemetry-operator
6+
rules:
7+
- apiGroups:
8+
- ""
9+
resources:
10+
- pods
11+
- services
12+
- services/finalizers
13+
- endpoints
14+
- persistentvolumeclaims
15+
- events
16+
- configmaps
17+
- secrets
18+
verbs:
19+
- '*'
20+
- apiGroups:
21+
- apps
22+
resources:
23+
- deployments
24+
- daemonsets
25+
- replicasets
26+
- statefulsets
27+
verbs:
28+
- '*'
29+
- apiGroups:
30+
- monitoring.coreos.com
31+
resources:
32+
- servicemonitors
33+
verbs:
34+
- get
35+
- create
36+
- apiGroups:
37+
- apps
38+
resourceNames:
39+
- opentelemetry-operator
40+
resources:
41+
- deployments/finalizers
42+
verbs:
43+
- update
44+
- apiGroups:
45+
- ""
46+
resources:
47+
- pods
48+
verbs:
49+
- get
50+
- apiGroups:
51+
- apps
52+
resources:
53+
- replicasets
54+
verbs:
55+
- get
56+
- apiGroups:
57+
- opentelemetry.io
58+
resources:
59+
- '*'
60+
verbs:
61+
- '*'

‎deploy/role_binding.yaml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
kind: RoleBinding
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
metadata:
4+
name: opentelemetry-operator
5+
subjects:
6+
- kind: ServiceAccount
7+
name: opentelemetry-operator
8+
roleRef:
9+
kind: Role
10+
name: opentelemetry-operator
11+
apiGroup: rbac.authorization.k8s.io

‎deploy/service_account.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
apiVersion: v1
2+
kind: ServiceAccount
3+
metadata:
4+
name: opentelemetry-operator

‎examples/simplest.yaml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apiVersion: opentelemetry.io/v1alpha1
2+
kind: OpenTelemetryService
3+
metadata:
4+
name: simplest
5+
spec:
6+
config: |
7+
receivers:
8+
jaeger:
9+
10+
processors:
11+
queued-retry:
12+
13+
exporters:
14+
logging:
15+
16+
pipelines:
17+
traces:
18+
receivers: [jaeger]
19+
processors: [queued-retry]
20+
exporters: [logging]

‎go.mod

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module github.com/open-telemetry/opentelemetry-operator
2+
3+
require (
4+
github.com/NYTimes/gziphandler v1.0.1 // indirect
5+
github.com/go-openapi/spec v0.19.0
6+
github.com/operator-framework/operator-sdk v0.10.1-0.20190827134739-8e55eb7da610
7+
github.com/spf13/pflag v1.0.3
8+
gopkg.in/yaml.v2 v2.2.2
9+
k8s.io/api v0.0.0-20190612125737-db0771252981
10+
k8s.io/apimachinery v0.0.0-20190612125636-6a5db36e93ad
11+
k8s.io/client-go v11.0.0+incompatible
12+
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208
13+
sigs.k8s.io/controller-runtime v0.1.12
14+
sigs.k8s.io/controller-tools v0.1.10
15+
)
16+
17+
// Pinned to kubernetes-1.13.4
18+
replace (
19+
k8s.io/api => k8s.io/api v0.0.0-20190222213804-5cb15d344471
20+
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190228180357-d002e88f6236
21+
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628
22+
k8s.io/client-go => k8s.io/client-go v0.0.0-20190228174230-b40b2a5939e4
23+
)
24+
25+
replace (
26+
github.com/coreos/prometheus-operator => github.com/coreos/prometheus-operator v0.29.0
27+
// Pinned to v2.9.2 (kubernetes-1.13.1) so https://proxy.golang.org can
28+
// resolve it correctly.
29+
github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.0.0-20190424153033-d3245f150225
30+
k8s.io/kube-state-metrics => k8s.io/kube-state-metrics v1.6.0
31+
sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.1.12
32+
sigs.k8s.io/controller-tools => sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde
33+
)
34+
35+
replace github.com/operator-framework/operator-sdk => github.com/operator-framework/operator-sdk v0.10.0

‎go.sum

+546
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package apis
2+
3+
import (
4+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1"
5+
)
6+
7+
func init() {
8+
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
9+
AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme)
10+
}

‎pkg/apis/apis.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package apis
2+
3+
import (
4+
"k8s.io/apimachinery/pkg/runtime"
5+
)
6+
7+
// AddToSchemes may be used to add all resources defined in the project to a Scheme
8+
var AddToSchemes runtime.SchemeBuilder
9+
10+
// AddToScheme adds all Resources to the Scheme
11+
func AddToScheme(s *runtime.Scheme) error {
12+
return AddToSchemes.AddToScheme(s)
13+
}

‎pkg/apis/opentelemetry/const.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package opentelemetry
2+
3+
// ContextEntry represents a key in the context map
4+
type ContextEntry string
5+
6+
// ConfigMapEntry represents an entry in a config map
7+
type ConfigMapEntry string
8+
9+
// Instance is the OpenTelemetryService CR (instance) that is the current target of the reconciliation
10+
const Instance ContextEntry = "__instance"
11+
12+
// CollectorConfigMapEntry represents the configuration file name for the collector
13+
const CollectorConfigMapEntry = "collector.yaml"

‎pkg/apis/opentelemetry/group.go

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Package opentelemetry contains opentelemetry API versions.
2+
//
3+
// This file ensures Go source parsers acknowledge the opentelemetry package
4+
// and any child packages. It can be removed if any other Go source files are
5+
// added to this package.
6+
package opentelemetry
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Package v1alpha1 contains API Schema definitions for the opentelemetry v1alpha1 API group
2+
// +k8s:deepcopy-gen=package,register
3+
// +groupName=opentelemetry.io
4+
package v1alpha1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package v1alpha1
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
)
6+
7+
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
8+
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
9+
10+
// OpenTelemetryServiceSpec defines the desired state of OpenTelemetryService
11+
// +k8s:openapi-gen=true
12+
type OpenTelemetryServiceSpec struct {
13+
// +optional
14+
Replicas *int32 `json:"replicas,omitempty"`
15+
16+
// +required
17+
Config string `json:"config,omitempty"`
18+
}
19+
20+
// OpenTelemetryServiceStatus defines the observed state of OpenTelemetryService
21+
// +k8s:openapi-gen=true
22+
type OpenTelemetryServiceStatus struct {
23+
Replicas int32 `json:"replicas"`
24+
}
25+
26+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
27+
28+
// OpenTelemetryService is the Schema for the opentelemetryservices API
29+
// +k8s:openapi-gen=true
30+
// +kubebuilder:resource:shortName=otelsvc;otelsvcs
31+
// +kubebuilder:subresource:status
32+
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas
33+
type OpenTelemetryService struct {
34+
metav1.TypeMeta `json:",inline"`
35+
metav1.ObjectMeta `json:"metadata,omitempty"`
36+
37+
Spec OpenTelemetryServiceSpec `json:"spec,omitempty"`
38+
Status OpenTelemetryServiceStatus `json:"status,omitempty"`
39+
}
40+
41+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
42+
43+
// OpenTelemetryServiceList contains a list of OpenTelemetryService
44+
type OpenTelemetryServiceList struct {
45+
metav1.TypeMeta `json:",inline"`
46+
metav1.ListMeta `json:"metadata,omitempty"`
47+
Items []OpenTelemetryService `json:"items"`
48+
}
49+
50+
func init() {
51+
SchemeBuilder.Register(&OpenTelemetryService{}, &OpenTelemetryServiceList{})
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// NOTE: Boilerplate only. Ignore this file.
2+
3+
// Package v1alpha1 contains API Schema definitions for the opentelemetry v1alpha1 API group
4+
// +k8s:deepcopy-gen=package,register
5+
// +groupName=opentelemetry.io
6+
package v1alpha1
7+
8+
import (
9+
"k8s.io/apimachinery/pkg/runtime/schema"
10+
"sigs.k8s.io/controller-runtime/pkg/runtime/scheme"
11+
)
12+
13+
var (
14+
// SchemeGroupVersion is group version used to register these objects
15+
SchemeGroupVersion = schema.GroupVersion{Group: "opentelemetry.io", Version: "v1alpha1"}
16+
17+
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
18+
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
19+
)

‎pkg/apis/opentelemetry/v1alpha1/zz_generated.deepcopy.go

+107
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// +build !ignore_autogenerated
2+
3+
// This file was autogenerated by openapi-gen. Do not edit it manually!
4+
5+
package v1alpha1
6+
7+
import (
8+
spec "github.com/go-openapi/spec"
9+
common "k8s.io/kube-openapi/pkg/common"
10+
)
11+
12+
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
13+
return map[string]common.OpenAPIDefinition{
14+
"./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryService": schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryService(ref),
15+
"./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryServiceSpec": schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryServiceSpec(ref),
16+
"./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryServiceStatus": schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryServiceStatus(ref),
17+
}
18+
}
19+
20+
func schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryService(ref common.ReferenceCallback) common.OpenAPIDefinition {
21+
return common.OpenAPIDefinition{
22+
Schema: spec.Schema{
23+
SchemaProps: spec.SchemaProps{
24+
Description: "OpenTelemetryService is the Schema for the opentelemetryservices API",
25+
Properties: map[string]spec.Schema{
26+
"kind": {
27+
SchemaProps: spec.SchemaProps{
28+
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
29+
Type: []string{"string"},
30+
Format: "",
31+
},
32+
},
33+
"apiVersion": {
34+
SchemaProps: spec.SchemaProps{
35+
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
36+
Type: []string{"string"},
37+
Format: "",
38+
},
39+
},
40+
"metadata": {
41+
SchemaProps: spec.SchemaProps{
42+
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
43+
},
44+
},
45+
"spec": {
46+
SchemaProps: spec.SchemaProps{
47+
Ref: ref("./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryServiceSpec"),
48+
},
49+
},
50+
"status": {
51+
SchemaProps: spec.SchemaProps{
52+
Ref: ref("./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryServiceStatus"),
53+
},
54+
},
55+
},
56+
},
57+
},
58+
Dependencies: []string{
59+
"./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryServiceSpec", "./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryServiceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
60+
}
61+
}
62+
63+
func schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryServiceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
64+
return common.OpenAPIDefinition{
65+
Schema: spec.Schema{
66+
SchemaProps: spec.SchemaProps{
67+
Description: "OpenTelemetryServiceSpec defines the desired state of OpenTelemetryService",
68+
Properties: map[string]spec.Schema{
69+
"replicas": {
70+
SchemaProps: spec.SchemaProps{
71+
Type: []string{"integer"},
72+
Format: "int32",
73+
},
74+
},
75+
"config": {
76+
SchemaProps: spec.SchemaProps{
77+
Type: []string{"string"},
78+
Format: "",
79+
},
80+
},
81+
},
82+
},
83+
},
84+
Dependencies: []string{},
85+
}
86+
}
87+
88+
func schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryServiceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
89+
return common.OpenAPIDefinition{
90+
Schema: spec.Schema{
91+
SchemaProps: spec.SchemaProps{
92+
Description: "OpenTelemetryServiceStatus defines the observed state of OpenTelemetryService",
93+
Properties: map[string]spec.Schema{
94+
"replicas": {
95+
SchemaProps: spec.SchemaProps{
96+
Type: []string{"integer"},
97+
Format: "int32",
98+
},
99+
},
100+
},
101+
Required: []string{"replicas"},
102+
},
103+
},
104+
Dependencies: []string{},
105+
}
106+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package controller
2+
3+
import (
4+
"github.com/open-telemetry/opentelemetry-operator/pkg/controller/opentelemetryservice"
5+
)
6+
7+
func init() {
8+
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
9+
AddToManagerFuncs = append(AddToManagerFuncs, opentelemetryservice.Add)
10+
}

‎pkg/controller/controller.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package controller
2+
3+
import (
4+
"sigs.k8s.io/controller-runtime/pkg/manager"
5+
)
6+
7+
// AddToManagerFuncs is a list of functions to add all Controllers to the Manager
8+
var AddToManagerFuncs []func(manager.Manager) error
9+
10+
// AddToManager adds all Controllers to the Manager
11+
func AddToManager(m manager.Manager) error {
12+
for _, f := range AddToManagerFuncs {
13+
if err := f(m); err != nil {
14+
return err
15+
}
16+
}
17+
return nil
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package opentelemetryservice
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry"
8+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1"
9+
)
10+
11+
// commonLabels return the common labels to all objects that are part of a managed OpenTelemetryService
12+
func commonLabels(ctx context.Context) map[string]string {
13+
instance := ctx.Value(opentelemetry.Instance).(*v1alpha1.OpenTelemetryService)
14+
base := instance.Labels
15+
if nil == base {
16+
base = map[string]string{}
17+
}
18+
19+
base["app.kubernetes.io/managed-by"] = "opentelemetry-operator"
20+
base["app.kubernetes.io/instance"] = fmt.Sprintf("%s.%s", instance.Namespace, instance.Name)
21+
base["app.kubernetes.io/part-of"] = "opentelemetry"
22+
base["app.kubernetes.io/component"] = "opentelemetry-service"
23+
24+
return base
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package opentelemetryservice
2+
3+
import (
4+
corev1 "k8s.io/api/core/v1"
5+
"sigs.k8s.io/controller-runtime/pkg/controller"
6+
"sigs.k8s.io/controller-runtime/pkg/handler"
7+
"sigs.k8s.io/controller-runtime/pkg/manager"
8+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
9+
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
10+
"sigs.k8s.io/controller-runtime/pkg/source"
11+
12+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1"
13+
)
14+
15+
var log = logf.Log.WithName("controller_opentelemetryservice")
16+
17+
/**
18+
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
19+
* business logic. Delete these comments after modifying this file.*
20+
*/
21+
22+
// Add creates a new OpenTelemetryService Controller and adds it to the Manager. The Manager will set fields on the Controller
23+
// and Start it when the Manager is Started.
24+
func Add(mgr manager.Manager) error {
25+
return add(mgr, newReconciler(mgr))
26+
}
27+
28+
// newReconciler returns a new reconcile.Reconciler
29+
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
30+
return &ReconcileOpenTelemetryService{client: mgr.GetClient(), scheme: mgr.GetScheme()}
31+
}
32+
33+
// add adds a new Controller to mgr with r as the reconcile.Reconciler
34+
func add(mgr manager.Manager, r reconcile.Reconciler) error {
35+
// Create a new controller
36+
c, err := controller.New("opentelemetryservice-controller", mgr, controller.Options{Reconciler: r})
37+
if err != nil {
38+
return err
39+
}
40+
41+
// Watch for changes to primary resource OpenTelemetryService
42+
err = c.Watch(&source.Kind{Type: &v1alpha1.OpenTelemetryService{}}, &handler.EnqueueRequestForObject{})
43+
if err != nil {
44+
return err
45+
}
46+
47+
// TODO(user): Modify this to be the types you create that are owned by the primary resource
48+
// Watch for changes to secondary resource Pods and requeue the owner OpenTelemetryService
49+
err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{
50+
IsController: true,
51+
OwnerType: &v1alpha1.OpenTelemetryService{},
52+
})
53+
if err != nil {
54+
return err
55+
}
56+
57+
return nil
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package opentelemetryservice
2+
3+
import (
4+
"context"
5+
6+
"k8s.io/apimachinery/pkg/api/errors"
7+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
"k8s.io/apimachinery/pkg/runtime"
9+
"sigs.k8s.io/controller-runtime/pkg/client"
10+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
11+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
12+
13+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry"
14+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1"
15+
)
16+
17+
// blank assignment to verify that ReconcileOpenTelemetryService implements reconcile.Reconciler
18+
var _ reconcile.Reconciler = &ReconcileOpenTelemetryService{}
19+
20+
// ReconcileOpenTelemetryService reconciles a OpenTelemetryService object
21+
type ReconcileOpenTelemetryService struct {
22+
// This client, initialized using mgr.Client() above, is a split client
23+
// that reads objects from the cache and writes to the apiserver
24+
client client.Client
25+
scheme *runtime.Scheme
26+
}
27+
28+
// Reconcile reads that state of the cluster for a OpenTelemetryService object and makes changes based on the state read
29+
// and what is in the OpenTelemetryService.Spec
30+
func (r *ReconcileOpenTelemetryService) Reconcile(request reconcile.Request) (reconcile.Result, error) {
31+
reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
32+
reqLogger.Info("Reconciling OpenTelemetryService")
33+
34+
// Fetch the OpenTelemetryService instance
35+
instance := &v1alpha1.OpenTelemetryService{}
36+
err := r.client.Get(context.Background(), request.NamespacedName, instance)
37+
if err != nil {
38+
if errors.IsNotFound(err) {
39+
// Request object not found, could have been deleted after reconcile request.
40+
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
41+
// Return and don't requeue
42+
return reconcile.Result{}, nil
43+
}
44+
// Error reading the object - requeue the request.
45+
return reconcile.Result{}, err
46+
}
47+
48+
// set the execution context for this reconcile loop
49+
ctx := context.WithValue(context.Background(), opentelemetry.Instance, instance)
50+
51+
if err := r.handleReconcile(ctx); err != nil {
52+
return reconcile.Result{}, err
53+
}
54+
55+
return reconcile.Result{}, nil
56+
}
57+
58+
// handleReconcile compares the existing state vs. the expected state and performs the necessary actions to make the two match
59+
func (r *ReconcileOpenTelemetryService) handleReconcile(ctx context.Context) error {
60+
funcs := []func(context.Context) error{
61+
r.reconcileConfigMap,
62+
r.reconcileService,
63+
r.reconcileDeployment,
64+
}
65+
66+
for _, f := range funcs {
67+
if err := f(ctx); err != nil {
68+
return err
69+
}
70+
}
71+
72+
return nil
73+
}
74+
75+
// setControllerReference should be used by the individual reconcile functions to establish the ownership of the underlying resources
76+
func (r *ReconcileOpenTelemetryService) setControllerReference(ctx context.Context, object v1.Object) error {
77+
instance := ctx.Value(opentelemetry.Instance).(*v1alpha1.OpenTelemetryService)
78+
return controllerutil.SetControllerReference(instance, object, r.scheme)
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package opentelemetryservice
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
corev1 "k8s.io/api/core/v1"
8+
"k8s.io/apimachinery/pkg/api/errors"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/apimachinery/pkg/types"
11+
12+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry"
13+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1"
14+
)
15+
16+
// reconcileDeployment reconciles the deployment(s) required for the instance in the current context
17+
func (r *ReconcileOpenTelemetryService) reconcileConfigMap(ctx context.Context) error {
18+
desired, err := configMap(ctx)
19+
if err != nil {
20+
return err
21+
}
22+
23+
r.setControllerReference(ctx, desired)
24+
25+
expected := &corev1.ConfigMap{}
26+
err = r.client.Get(ctx, types.NamespacedName{Name: desired.Name, Namespace: desired.Namespace}, expected)
27+
if err != nil && errors.IsNotFound(err) {
28+
if err := r.client.Create(ctx, desired); err != nil {
29+
return err
30+
}
31+
} else if err != nil {
32+
return err
33+
}
34+
35+
// it exists already, merge the two if the end result isn't identical to the existing one
36+
// TODO(jpkroehling)
37+
38+
return nil
39+
}
40+
41+
func configMap(ctx context.Context) (*corev1.ConfigMap, error) {
42+
instance := ctx.Value(opentelemetry.Instance).(*v1alpha1.OpenTelemetryService)
43+
name := fmt.Sprintf("%s-collector", instance.Name)
44+
45+
labels := commonLabels(ctx)
46+
labels["app.kubernetes.io/name"] = name
47+
48+
return &corev1.ConfigMap{
49+
ObjectMeta: metav1.ObjectMeta{
50+
Name: name,
51+
Namespace: instance.Namespace,
52+
Labels: labels,
53+
Annotations: instance.Annotations,
54+
},
55+
Data: map[string]string{
56+
opentelemetry.CollectorConfigMapEntry: instance.Spec.Config,
57+
},
58+
}, nil
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package opentelemetryservice
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
appsv1 "k8s.io/api/apps/v1"
8+
corev1 "k8s.io/api/core/v1"
9+
"k8s.io/apimachinery/pkg/api/errors"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/types"
12+
13+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry"
14+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1"
15+
)
16+
17+
// reconcileDeployment reconciles the deployment(s) required for the instance in the current context
18+
func (r *ReconcileOpenTelemetryService) reconcileDeployment(ctx context.Context) error {
19+
desired := deployment(ctx)
20+
r.setControllerReference(ctx, desired)
21+
22+
expected := &appsv1.Deployment{}
23+
err := r.client.Get(ctx, types.NamespacedName{Name: desired.Name, Namespace: desired.Namespace}, expected)
24+
if err != nil && errors.IsNotFound(err) {
25+
if err := r.client.Create(ctx, desired); err != nil {
26+
return err
27+
}
28+
} else if err != nil {
29+
return err
30+
}
31+
32+
// it exists already, merge the two if the end result isn't identical to the existing one
33+
// TODO(jpkroehling)
34+
35+
return nil
36+
}
37+
38+
func deployment(ctx context.Context) *appsv1.Deployment {
39+
instance := ctx.Value(opentelemetry.Instance).(*v1alpha1.OpenTelemetryService)
40+
name := fmt.Sprintf("%s-collector", instance.Name)
41+
42+
labels := commonLabels(ctx)
43+
labels["app.kubernetes.io/name"] = name
44+
45+
specAnnotations := instance.Annotations
46+
specAnnotations["prometheus.io/scrape"] = "true"
47+
specAnnotations["prometheus.io/port"] = "8888"
48+
specAnnotations["prometheus.io/path"] = "/metrics"
49+
50+
return &appsv1.Deployment{
51+
ObjectMeta: metav1.ObjectMeta{
52+
Name: name,
53+
Namespace: instance.Namespace,
54+
Labels: labels,
55+
Annotations: instance.Annotations,
56+
},
57+
Spec: appsv1.DeploymentSpec{
58+
Replicas: instance.Spec.Replicas,
59+
Selector: &metav1.LabelSelector{
60+
MatchLabels: labels,
61+
},
62+
Template: corev1.PodTemplateSpec{
63+
ObjectMeta: metav1.ObjectMeta{
64+
Labels: labels,
65+
Annotations: specAnnotations,
66+
},
67+
Spec: corev1.PodSpec{
68+
Containers: []corev1.Container{{
69+
Name: "opentelemetry-service",
70+
Image: "quay.io/jpkroehling/opentelemetry-service:latest",
71+
VolumeMounts: []corev1.VolumeMount{{
72+
Name: name,
73+
MountPath: "/conf",
74+
}},
75+
Args: []string{
76+
fmt.Sprintf("--config=/conf/%s", opentelemetry.CollectorConfigMapEntry),
77+
},
78+
}},
79+
Volumes: []corev1.Volume{{
80+
Name: name,
81+
VolumeSource: corev1.VolumeSource{
82+
ConfigMap: &corev1.ConfigMapVolumeSource{
83+
LocalObjectReference: corev1.LocalObjectReference{Name: name},
84+
Items: []corev1.KeyToPath{{
85+
Key: opentelemetry.CollectorConfigMapEntry,
86+
Path: opentelemetry.CollectorConfigMapEntry,
87+
}},
88+
},
89+
},
90+
}},
91+
},
92+
},
93+
},
94+
}
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package opentelemetryservice
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry"
8+
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1"
9+
corev1 "k8s.io/api/core/v1"
10+
"k8s.io/apimachinery/pkg/api/errors"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/types"
13+
"k8s.io/apimachinery/pkg/util/intstr"
14+
)
15+
16+
// reconcileService reconciles the service(s) required for the instance in the current context
17+
func (r *ReconcileOpenTelemetryService) reconcileService(ctx context.Context) error {
18+
desired := service(ctx)
19+
r.setControllerReference(ctx, desired)
20+
21+
expected := &corev1.Service{}
22+
err := r.client.Get(ctx, types.NamespacedName{Name: desired.Name, Namespace: desired.Namespace}, expected)
23+
if err != nil && errors.IsNotFound(err) {
24+
if err := r.client.Create(ctx, desired); err != nil {
25+
return err
26+
}
27+
} else if err != nil {
28+
return err
29+
}
30+
31+
// it exists already, merge the two if the end result isn't identical to the existing one
32+
// TODO(jpkroehling)
33+
34+
return nil
35+
}
36+
37+
func service(ctx context.Context) *corev1.Service {
38+
instance := ctx.Value(opentelemetry.Instance).(*v1alpha1.OpenTelemetryService)
39+
name := fmt.Sprintf("%s-collector", instance.Name)
40+
41+
labels := commonLabels(ctx)
42+
labels["app.kubernetes.io/name"] = name
43+
44+
// by coincidence, the selector is the same as the label, but note that the selector points to the deployment
45+
// whereas 'labels' refers to the service
46+
selector := labels
47+
48+
return &corev1.Service{
49+
ObjectMeta: metav1.ObjectMeta{
50+
Name: name,
51+
Namespace: instance.Namespace,
52+
Labels: labels,
53+
Annotations: instance.Annotations,
54+
},
55+
Spec: corev1.ServiceSpec{
56+
Selector: selector,
57+
ClusterIP: "",
58+
Ports: []corev1.ServicePort{
59+
{
60+
Name: "jaeger-grpc",
61+
Port: 14250,
62+
TargetPort: intstr.FromInt(14250),
63+
},
64+
},
65+
},
66+
}
67+
68+
}

‎tools.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// +build tools
2+
3+
package tools
4+
5+
import (
6+
_ "sigs.k8s.io/controller-tools/pkg/crd/generator"
7+
)

‎version/version.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package version
2+
3+
var (
4+
// Version of this operator
5+
Version string
6+
7+
// BuildDate of this operator
8+
BuildDate string
9+
)

0 commit comments

Comments
 (0)
Please sign in to comment.