Skip to content

Commit e18ea6e

Browse files
committed
Parse and apply apiserver OpenTelemetryClientConfiguration
1 parent f68d27a commit e18ea6e

File tree

7 files changed

+580
-0
lines changed

7 files changed

+580
-0
lines changed

cmd/kube-apiserver/app/options/options.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type ServerRunOptions struct {
5353
EgressSelector *genericoptions.EgressSelectorOptions
5454
Metrics *metrics.Options
5555
Logs *logs.Options
56+
OpenTelemetry *genericoptions.OpenTelemetryOptions
5657

5758
AllowPrivileged bool
5859
EnableLogsHandler bool
@@ -103,6 +104,7 @@ func NewServerRunOptions() *ServerRunOptions {
103104
EgressSelector: genericoptions.NewEgressSelectorOptions(),
104105
Metrics: metrics.NewOptions(),
105106
Logs: logs.NewOptions(),
107+
OpenTelemetry: genericoptions.NewOpenTelemetryOptions(),
106108

107109
EnableLogsHandler: true,
108110
EventTTL: 1 * time.Hour,
@@ -152,6 +154,7 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) {
152154
s.Admission.AddFlags(fss.FlagSet("admission"))
153155
s.Metrics.AddFlags(fss.FlagSet("metrics"))
154156
s.Logs.AddFlags(fss.FlagSet("logs"))
157+
s.OpenTelemetry.AddFlags(fss.FlagSet("opentelemetry"))
155158

156159
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
157160
// arrange these text blocks sensibly. Grrr.

cmd/kube-apiserver/app/server.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import (
7272
"k8s.io/kubernetes/pkg/controlplane/reconcilers"
7373
"k8s.io/kubernetes/pkg/controlplane/tunneler"
7474
"k8s.io/kubernetes/pkg/features"
75+
kubefeatures "k8s.io/kubernetes/pkg/features"
7576
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
7677
"k8s.io/kubernetes/pkg/kubeapiserver"
7778
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
@@ -463,6 +464,11 @@ func buildGenericConfig(
463464
if lastErr = s.EgressSelector.ApplyTo(genericConfig); lastErr != nil {
464465
return
465466
}
467+
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.APIServerTracing) {
468+
if lastErr = s.OpenTelemetry.Apply(genericConfig.EgressSelector); lastErr != nil {
469+
return
470+
}
471+
}
466472

467473
genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(legacyscheme.Scheme, extensionsapiserver.Scheme, aggregatorscheme.Scheme))
468474
genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library")
2+
3+
go_library(
4+
name = "go_default_library",
5+
srcs = ["config.go"],
6+
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/opentelemetry",
7+
importpath = "k8s.io/apiserver/pkg/opentelemetry",
8+
visibility = ["//visibility:public"],
9+
deps = [
10+
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
11+
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
12+
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver:go_default_library",
13+
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver/install:go_default_library",
14+
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1:go_default_library",
15+
"//vendor/sigs.k8s.io/yaml:go_default_library",
16+
],
17+
)
18+
19+
filegroup(
20+
name = "package-srcs",
21+
srcs = glob(["**"]),
22+
tags = ["automanaged"],
23+
visibility = ["//visibility:private"],
24+
)
25+
26+
filegroup(
27+
name = "all-srcs",
28+
srcs = [":package-srcs"],
29+
tags = ["automanaged"],
30+
visibility = ["//visibility:public"],
31+
)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package opentelemetry
18+
19+
import (
20+
"fmt"
21+
"io/ioutil"
22+
"net/url"
23+
24+
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/apimachinery/pkg/util/validation/field"
26+
"k8s.io/apiserver/pkg/apis/apiserver"
27+
"k8s.io/apiserver/pkg/apis/apiserver/install"
28+
"k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"
29+
"sigs.k8s.io/yaml"
30+
)
31+
32+
var cfgScheme = runtime.NewScheme()
33+
34+
func init() {
35+
install.Install(cfgScheme)
36+
}
37+
38+
// ReadOpenTelemetryConfiguration reads the opentelemetry configuration from a file
39+
func ReadOpenTelemetryConfiguration(configFilePath string) (*apiserver.OpenTelemetryClientConfiguration, error) {
40+
if configFilePath == "" {
41+
return nil, nil
42+
}
43+
data, err := ioutil.ReadFile(configFilePath)
44+
if err != nil {
45+
return nil, fmt.Errorf("unable to read opentelemetry configuration from %q [%v]", configFilePath, err)
46+
}
47+
var decodedConfig v1alpha1.OpenTelemetryClientConfiguration
48+
err = yaml.Unmarshal(data, &decodedConfig)
49+
if err != nil {
50+
// we got an error where the decode wasn't related to a missing type
51+
return nil, err
52+
}
53+
if decodedConfig.Kind != "OpenTelemetryClientConfiguration" {
54+
return nil, fmt.Errorf("invalid service configuration object %q", decodedConfig.Kind)
55+
}
56+
internalConfig := &apiserver.OpenTelemetryClientConfiguration{}
57+
if err := cfgScheme.Convert(&decodedConfig, internalConfig, nil); err != nil {
58+
// we got an error where the decode wasn't related to a missing type
59+
return nil, err
60+
}
61+
return internalConfig, nil
62+
}
63+
64+
// ValidateOpenTelemetryConfiguration validates the opentelemetry configuration
65+
func ValidateOpenTelemetryConfiguration(config *apiserver.OpenTelemetryClientConfiguration) field.ErrorList {
66+
allErrs := field.ErrorList{}
67+
if config == nil {
68+
// OpenTelemetry is disabled
69+
return allErrs
70+
}
71+
if config.Service != nil && config.URL != nil {
72+
allErrs = append(allErrs, field.Invalid(
73+
field.NewPath("service"),
74+
config.Service,
75+
"Service and URL cannot both be set"))
76+
}
77+
if config.Service != nil {
78+
allErrs = append(allErrs, validateService(config.Service, field.NewPath("service"))...)
79+
}
80+
if config.URL != nil {
81+
allErrs = append(allErrs, validateURL(*config.URL, field.NewPath("url"))...)
82+
}
83+
return allErrs
84+
}
85+
86+
func validateService(service *apiserver.ServiceReference, fldPath *field.Path) field.ErrorList {
87+
allErrors := field.ErrorList{}
88+
89+
if len(service.Name) == 0 {
90+
allErrors = append(allErrors, field.Required(fldPath.Child("name"), "service name is required"))
91+
}
92+
93+
if len(service.Namespace) == 0 {
94+
allErrors = append(allErrors, field.Required(fldPath.Child("namespace"), "service namespace is required"))
95+
}
96+
return allErrors
97+
}
98+
99+
func validateURL(u string, fldPath *field.Path) field.ErrorList {
100+
errs := field.ErrorList{}
101+
_, err := url.Parse(u)
102+
if err != nil {
103+
return append(errs, field.Invalid(
104+
fldPath, u,
105+
fmt.Sprintf("Unable to parse URL: %v", err)))
106+
}
107+
return errs
108+
}

0 commit comments

Comments
 (0)