Skip to content

Commit 267ed82

Browse files
authored
[feat] add distributed tracing using OTEL (#372)
* feat: added distributed tracing using OTEL Autoexport Signed-off-by: Mateusz Urbanek <[email protected]> * docs: added tracing chapter to docs Signed-off-by: Mateusz Urbanek <[email protected]> * feat: add gowrap to tools Signed-off-by: Mateusz Urbanek <[email protected]> * feat: add tracing to linodeclient Signed-off-by: Mateusz Urbanek <[email protected]> * fix: simplify the generated code signature Signed-off-by: Mateusz Urbanek <[email protected]> * fixup! fix: simplify the generated code signature * fixup! feat: added distributed tracing using OTEL Autoexport * test: add smoke tests to few parts of code Signed-off-by: Mateusz Urbanek <[email protected]> * chore: add codecov config file Signed-off-by: Mateusz Urbanek <[email protected]> --------- Signed-off-by: Mateusz Urbanek <[email protected]>
1 parent 5e2d469 commit 267ed82

26 files changed

+1580
-71
lines changed

.golangci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ linters:
154154
# - goerr113
155155
- gofmt
156156
- goimports
157-
- gomnd
158157
# - gocyclo
159158
- goprintffuncname
160159
- gosec
@@ -165,6 +164,7 @@ linters:
165164
- maintidx
166165
- makezero
167166
- misspell
167+
- mnd
168168
- nestif
169169
- nilerr
170170
- nilnil

Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ COPY api/ api/
1818
COPY clients/ clients/
1919
COPY controller/ controller/
2020
COPY cloud/ cloud/
21+
COPY observability/ observability/
2122
COPY util/ util/
2223
COPY version/ version/
2324

@@ -35,4 +36,7 @@ WORKDIR /
3536
COPY --from=builder /workspace/manager .
3637
USER 65532:65532
3738

39+
# By default disable traces exporter
40+
ENV OTEL_TRACES_EXPORTER=none
41+
3842
ENTRYPOINT ["/manager"]

Makefile

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ generate-manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole
8585
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
8686

8787
.PHONY: generate-code
88-
generate-code: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
88+
generate-code: controller-gen gowrap ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
89+
go generate ./...
8990
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
9091

9192
.PHONY: generate-mock
@@ -306,6 +307,7 @@ HUSKY ?= $(LOCALBIN)/husky
306307
NILAWAY ?= $(LOCALBIN)/nilaway
307308
GOVULNC ?= $(LOCALBIN)/govulncheck
308309
MOCKGEN ?= $(LOCALBIN)/mockgen
310+
GOWRAP ?= $(CACHE_BIN)/gowrap
309311

310312
## Tool Versions
311313
KUSTOMIZE_VERSION ?= v5.4.1
@@ -320,9 +322,10 @@ HUSKY_VERSION ?= v0.2.16
320322
NILAWAY_VERSION ?= latest
321323
GOVULNC_VERSION ?= v1.1.1
322324
MOCKGEN_VERSION ?= v0.4.0
325+
GOWRAP_VERSION ?= latest
323326

324327
.PHONY: tools
325-
tools: $(KUSTOMIZE) $(CTLPTL) $(CLUSTERCTL) $(CONTROLLER_GEN) $(TILT) $(KIND) $(CHAINSAW) $(ENVTEST) $(HUSKY) $(NILAWAY) $(GOVULNC) $(MOCKGEN)
328+
tools: $(KUSTOMIZE) $(CTLPTL) $(CLUSTERCTL) $(CONTROLLER_GEN) $(TILT) $(KIND) $(CHAINSAW) $(ENVTEST) $(HUSKY) $(NILAWAY) $(GOVULNC) $(MOCKGEN) $(GOWRAP)
326329

327330

328331
.PHONY: kustomize
@@ -375,7 +378,7 @@ $(CHAINSAW): $(CACHE_BIN)
375378

376379
.PHONY: envtest
377380
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
378-
$(ENVTEST): $(LOCALBIN)
381+
$(ENVTEST): $(CACHE_BIN)
379382
GOBIN=$(CACHE_BIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
380383

381384
.PHONY: husky
@@ -400,3 +403,8 @@ mockgen: $(MOCKGEN) ## Download mockgen locally if necessary.
400403
$(MOCKGEN): $(LOCALBIN)
401404
GOBIN=$(LOCALBIN) go install go.uber.org/mock/mockgen@$(MOCKGEN_VERSION)
402405

406+
.PHONY: gowrap
407+
gowrap: $(GOWRAP) ## Download gowrap locally if necessary.
408+
$(GOWRAP): $(CACHE_BIN)
409+
GOBIN=$(CACHE_BIN) go install github.com/hexdigest/gowrap/cmd/gowrap@$(GOWRAP_VERSION)
410+

Tiltfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ if debug == "true":
105105
"capl-compile",
106106
'GOOS=linux CGO_ENABLED=0 go build -gcflags "-N -l" -ldflags="-X github.com/linode/cluster-api-provider-linode/version.version=$VERSION" -a -o bin/manager ./cmd/main.go',
107107
deps=["./main.go", "./start.go", "vendor", "go.mod", "go.sum", "./api", "./cloud", "./cmd", "./controller",
108-
"./util", "./version",],
108+
"./observability", "./util", "./version",],
109109
labels=["CAPL"],
110110
)
111111
docker_build_with_restart(
@@ -147,7 +147,7 @@ if os.getenv("SKIP_DOCKER_BUILD", "false") != "true" and debug != "true":
147147
"docker.io/linode/cluster-api-provider-linode",
148148
context=".",
149149
only=("Dockerfile", "Makefile", "vendor", "go.mod", "go.sum",
150-
"./api", "./clients", "./cloud", "./cmd", "./controller", "./util", "./version",),
150+
"./api", "./clients", "./cloud", "./cmd", "./controller", "./observability", "./util", "./version"),
151151
build_args={"VERSION": os.getenv("VERSION", "")},
152152
)
153153

api/v1alpha1/linodecluster_webhook.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func (r *LinodeCluster) ValidateDelete() (admission.Warnings, error) {
7474
}
7575

7676
func (r *LinodeCluster) validateLinodeCluster(ctx context.Context, client LinodeClient) error {
77+
// TODO: instrument with tracing, might need refactor to preserve readibility
7778
var errs field.ErrorList
7879

7980
if err := r.validateLinodeClusterSpec(ctx, client); err != nil {
@@ -89,6 +90,7 @@ func (r *LinodeCluster) validateLinodeCluster(ctx context.Context, client Linode
8990
}
9091

9192
func (r *LinodeCluster) validateLinodeClusterSpec(ctx context.Context, client LinodeClient) field.ErrorList {
93+
// TODO: instrument with tracing, might need refactor to preserve readibility
9294
var errs field.ErrorList
9395

9496
if err := validateRegion(ctx, client, r.Spec.Region, field.NewPath("spec").Child("region")); err != nil {

api/v1alpha1/linodemachine_webhook.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func (r *LinodeMachine) ValidateDelete() (admission.Warnings, error) {
9494
}
9595

9696
func (r *LinodeMachine) validateLinodeMachine(ctx context.Context, client LinodeClient) error {
97+
// TODO: instrument with tracing, might need refactor to preserve readibility
9798
var errs field.ErrorList
9899

99100
if err := r.validateLinodeMachineSpec(ctx, client); err != nil {
@@ -109,6 +110,7 @@ func (r *LinodeMachine) validateLinodeMachine(ctx context.Context, client Linode
109110
}
110111

111112
func (r *LinodeMachine) validateLinodeMachineSpec(ctx context.Context, client LinodeClient) field.ErrorList {
113+
// TODO: instrument with tracing, might need refactor to preserve readibility
112114
var errs field.ErrorList
113115

114116
if err := validateRegion(ctx, client, r.Spec.Region, field.NewPath("spec").Child("region")); err != nil {

api/v1alpha1/linodeobjectstoragebucket_webhook.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func (r *LinodeObjectStorageBucket) ValidateDelete() (admission.Warnings, error)
8181
}
8282

8383
func (r *LinodeObjectStorageBucket) validateLinodeObjectStorageBucket(ctx context.Context, client LinodeClient) error {
84+
// TODO: instrument with tracing, might need refactor to preserve readibility
8485
var errs field.ErrorList
8586

8687
if err := r.validateLinodeObjectStorageBucketSpec(ctx, client); err != nil {
@@ -96,6 +97,7 @@ func (r *LinodeObjectStorageBucket) validateLinodeObjectStorageBucket(ctx contex
9697
}
9798

9899
func (r *LinodeObjectStorageBucket) validateLinodeObjectStorageBucketSpec(ctx context.Context, client LinodeClient) field.ErrorList {
100+
// TODO: instrument with tracing, might need refactor to preserve readibility
99101
var errs field.ErrorList
100102

101103
if err := validateObjectStorageCluster(ctx, client, r.Spec.Cluster, field.NewPath("spec").Child("cluster")); err != nil {

api/v1alpha1/linodevpc_webhook.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ func (r *LinodeVPC) ValidateDelete() (admission.Warnings, error) {
113113
}
114114

115115
func (r *LinodeVPC) validateLinodeVPC(ctx context.Context, client LinodeClient) error {
116+
// TODO: instrument with tracing, might need refactor to preserve readibility
116117
var errs field.ErrorList
117118

118119
if err := r.validateLinodeVPCSpec(ctx, client); err != nil {
@@ -128,6 +129,7 @@ func (r *LinodeVPC) validateLinodeVPC(ctx context.Context, client LinodeClient)
128129
}
129130

130131
func (r *LinodeVPC) validateLinodeVPCSpec(ctx context.Context, client LinodeClient) field.ErrorList {
132+
// TODO: instrument with tracing, might need refactor to preserve readibility
131133
var errs field.ErrorList
132134

133135
if err := validateRegion(ctx, client, r.Spec.Region, field.NewPath("spec").Child("region"), LinodeVPCCapability); err != nil {

api/v1alpha1/webhook_helpers.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"github.com/linode/linodego"
1212
"k8s.io/apimachinery/pkg/util/validation/field"
1313

14+
"github.com/linode/cluster-api-provider-linode/observability/wrappers/linodeclient"
15+
1416
. "github.com/linode/cluster-api-provider-linode/clients"
1517
)
1618

@@ -21,12 +23,19 @@ const (
2123
defaultClientTimeout = time.Second * 10
2224
)
2325

26+
func mkptr[T any](v T) *T {
27+
return &v
28+
}
29+
2430
var (
2531
// defaultLinodeClient is an unauthenticated Linode client
26-
defaultLinodeClient = linodego.NewClient(&http.Client{Timeout: defaultClientTimeout})
32+
defaultLinodeClient = linodeclient.NewLinodeClientWithTracing(
33+
mkptr(linodego.NewClient(&http.Client{Timeout: defaultClientTimeout})),
34+
)
2735
)
2836

2937
func validateRegion(ctx context.Context, client LinodeClient, id string, path *field.Path, capabilities ...string) *field.Error {
38+
// TODO: instrument with tracing, might need refactor to preserve readibility
3039
region, err := client.GetRegion(ctx, id)
3140
if err != nil {
3241
return field.NotFound(path, id)
@@ -42,6 +51,7 @@ func validateRegion(ctx context.Context, client LinodeClient, id string, path *f
4251
}
4352

4453
func validateLinodeType(ctx context.Context, client LinodeClient, id string, path *field.Path) (*linodego.LinodeType, *field.Error) {
54+
// TODO: instrument with tracing, might need refactor to preserve readibility
4555
plan, err := client.GetType(ctx, id)
4656
if err != nil {
4757
return nil, field.NotFound(path, id)
@@ -61,6 +71,7 @@ func validateLinodeType(ctx context.Context, client LinodeClient, id string, pat
6171
// [Clusters List]: https://www.linode.com/docs/api/object-storage/#clusters-list
6272
// [Cluster View]: https://www.linode.com/docs/api/object-storage/#cluster-view
6373
func validateObjectStorageCluster(ctx context.Context, client LinodeClient, id string, path *field.Path) *field.Error {
74+
// TODO: instrument with tracing, might need refactor to preserve readibility
6475
//nolint:gocritic // prefer no escapes
6576
cexp := regexp.MustCompile("^(([[:lower:]]+-)*[[:lower:]]+)-[[:digit:]]+$")
6677
if !cexp.MatchString(id) {

api/v1alpha2/linodecluster_webhook.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func (r *LinodeCluster) ValidateDelete() (admission.Warnings, error) {
7474
}
7575

7676
func (r *LinodeCluster) validateLinodeCluster(ctx context.Context, client LinodeClient) error {
77+
// TODO: instrument with tracing, might need refactor to preserve readibility
7778
var errs field.ErrorList
7879

7980
if err := r.validateLinodeClusterSpec(ctx, client); err != nil {
@@ -89,6 +90,7 @@ func (r *LinodeCluster) validateLinodeCluster(ctx context.Context, client Linode
8990
}
9091

9192
func (r *LinodeCluster) validateLinodeClusterSpec(ctx context.Context, client LinodeClient) field.ErrorList {
93+
// TODO: instrument with tracing, might need refactor to preserve readibility
9294
var errs field.ErrorList
9395

9496
if err := validateRegion(ctx, client, r.Spec.Region, field.NewPath("spec").Child("region")); err != nil {

api/v1alpha2/webhook_helpers.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"github.com/linode/linodego"
2727
"k8s.io/apimachinery/pkg/util/validation/field"
2828

29+
"github.com/linode/cluster-api-provider-linode/observability/wrappers/linodeclient"
30+
2931
. "github.com/linode/cluster-api-provider-linode/clients"
3032
)
3133

@@ -36,9 +38,15 @@ const (
3638
defaultClientTimeout = time.Second * 10
3739
)
3840

41+
func mkptr[T any](v T) *T {
42+
return &v
43+
}
44+
3945
var (
4046
// defaultLinodeClient is an unauthenticated Linode client
41-
defaultLinodeClient = linodego.NewClient(&http.Client{Timeout: defaultClientTimeout})
47+
defaultLinodeClient = linodeclient.NewLinodeClientWithTracing(
48+
mkptr(linodego.NewClient(&http.Client{Timeout: defaultClientTimeout})),
49+
)
4250
)
4351

4452
func validateRegion(ctx context.Context, client LinodeClient, id string, path *field.Path, capabilities ...string) *field.Error {

cloud/scope/common.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"sigs.k8s.io/controller-runtime/pkg/client"
1515
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1616

17+
"github.com/linode/cluster-api-provider-linode/observability/wrappers/linodeclient"
1718
"github.com/linode/cluster-api-provider-linode/version"
1819

1920
. "github.com/linode/cluster-api-provider-linode/clients"
@@ -24,7 +25,19 @@ const (
2425
defaultClientTimeout = time.Second * 10
2526
)
2627

27-
func CreateLinodeClient(apiKey string, timeout time.Duration) (*linodego.Client, error) {
28+
type Option struct {
29+
set func(client *linodego.Client)
30+
}
31+
32+
func WithRetryCount(c int) Option {
33+
return Option{
34+
set: func(client *linodego.Client) {
35+
client.SetRetryCount(c)
36+
},
37+
}
38+
}
39+
40+
func CreateLinodeClient(apiKey string, timeout time.Duration, opts ...Option) (LinodeClient, error) {
2841
if apiKey == "" {
2942
return nil, errors.New("missing Linode API key")
3043
}
@@ -41,7 +54,13 @@ func CreateLinodeClient(apiKey string, timeout time.Duration) (*linodego.Client,
4154

4255
linodeClient.SetUserAgent(fmt.Sprintf("CAPL/%s", version.GetVersion()))
4356

44-
return &linodeClient, nil
57+
for _, opt := range opts {
58+
opt.set(&linodeClient)
59+
}
60+
61+
return linodeclient.NewLinodeClientWithTracing(
62+
&linodeClient,
63+
), nil
4564
}
4665

4766
func getCredentialDataFromRef(ctx context.Context, crClient K8sClient, credentialsRef corev1.SecretReference, defaultNamespace string) ([]byte, error) {

cloud/scope/machine.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ func NewMachineScope(ctx context.Context, apiKey string, params MachineScopePara
8484
}
8585
apiKey = string(data)
8686
}
87-
linodeClient, err := CreateLinodeClient(apiKey, defaultClientTimeout)
87+
linodeClient, err := CreateLinodeClient(apiKey, defaultClientTimeout,
88+
WithRetryCount(0),
89+
)
8890
if err != nil {
8991
return nil, fmt.Errorf("failed to create linode client: %w", err)
9092
}
91-
linodeClient.SetRetryCount(0)
9293

9394
helper, err := patch.NewHelper(params.LinodeMachine, params.Client)
9495
if err != nil {

cloud/scope/vpc.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ func NewVPCScope(ctx context.Context, apiKey string, params VPCScopeParams) (*VP
6767
}
6868
apiKey = string(data)
6969
}
70-
linodeClient, err := CreateLinodeClient(apiKey, defaultClientTimeout)
70+
linodeClient, err := CreateLinodeClient(apiKey, defaultClientTimeout,
71+
WithRetryCount(0),
72+
)
7173
if err != nil {
7274
return nil, fmt.Errorf("failed to create linode client: %w", err)
7375
}
74-
linodeClient.SetRetryCount(0)
7576

7677
helper, err := patch.NewHelper(params.LinodeVPC, params.Client)
7778
if err != nil {

0 commit comments

Comments
 (0)