Skip to content

Commit 8ff16ad

Browse files
Refactor options handling
- Adds validation - Apply Features flags (profiling): they were set but unused - Adds the possibility to disable the APIServer's own metrics - Improve code documentation and add tests
1 parent 79fcd0c commit 8ff16ad

File tree

3 files changed

+134
-13
lines changed

3 files changed

+134
-13
lines changed

pkg/cmd/builder.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,7 @@ func (b *AdapterBase) InstallFlags() {
100100
b.CustomMetricsAdapterServerOptions = server.NewCustomMetricsAdapterServerOptions()
101101
}
102102

103-
b.SecureServing.AddFlags(b.FlagSet)
104-
b.Authentication.AddFlags(b.FlagSet)
105-
b.Authorization.AddFlags(b.FlagSet)
106-
b.Audit.AddFlags(b.FlagSet)
107-
b.Features.AddFlags(b.FlagSet)
103+
b.CustomMetricsAdapterServerOptions.AddFlags(b.FlagSet)
108104

109105
b.FlagSet.StringVar(&b.RemoteKubeConfigFile, "lister-kubeconfig", b.RemoteKubeConfigFile,
110106
"kubeconfig file pointing at the 'core' kubernetes server with enough rights to list "+
@@ -265,6 +261,10 @@ func (b *AdapterBase) Config() (*apiserver.Config, error) {
265261
}
266262
b.CustomMetricsAdapterServerOptions.OpenAPIConfig = b.OpenAPIConfig
267263

264+
if err := b.CustomMetricsAdapterServerOptions.Validate(); err != nil {
265+
return nil, err
266+
}
267+
268268
config, err := b.CustomMetricsAdapterServerOptions.Config()
269269
if err != nil {
270270
return nil, err

pkg/cmd/server/start.go renamed to pkg/cmd/server/options.go

+35-8
Original file line numberDiff line numberDiff line change
@@ -14,51 +14,75 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
// Package server provides configuration options for the metrics API server.
1718
package server
1819

1920
import (
2021
"fmt"
2122
"net"
2223

24+
"github.com/spf13/pflag"
25+
26+
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2327
genericapiserver "k8s.io/apiserver/pkg/server"
2428
genericoptions "k8s.io/apiserver/pkg/server/options"
2529
openapicommon "k8s.io/kube-openapi/pkg/common"
2630

2731
"sigs.k8s.io/custom-metrics-apiserver/pkg/apiserver"
2832
)
2933

34+
// CustomMetricsAdapterServerOptions contains the of options used to configure
35+
// the metrics API server.
36+
//
37+
// It is based on a subset of [genericoptions.RecommendedOptions].
3038
type CustomMetricsAdapterServerOptions struct {
31-
// genericoptions.ReccomendedOptions - EtcdOptions
3239
SecureServing *genericoptions.SecureServingOptionsWithLoopback
3340
Authentication *genericoptions.DelegatingAuthenticationOptions
3441
Authorization *genericoptions.DelegatingAuthorizationOptions
3542
Audit *genericoptions.AuditOptions
3643
Features *genericoptions.FeatureOptions
3744

38-
// OpenAPIConfig
3945
OpenAPIConfig *openapicommon.Config
46+
EnableMetrics bool
4047
}
4148

49+
// NewCustomMetricsAdapterServerOptions creates a new instance of
50+
// CustomMetricsAdapterServerOptions with its default values.
4251
func NewCustomMetricsAdapterServerOptions() *CustomMetricsAdapterServerOptions {
4352
o := &CustomMetricsAdapterServerOptions{
4453
SecureServing: genericoptions.NewSecureServingOptions().WithLoopback(),
4554
Authentication: genericoptions.NewDelegatingAuthenticationOptions(),
4655
Authorization: genericoptions.NewDelegatingAuthorizationOptions(),
4756
Audit: genericoptions.NewAuditOptions(),
4857
Features: genericoptions.NewFeatureOptions(),
58+
59+
EnableMetrics: true,
4960
}
5061

5162
return o
5263
}
5364

54-
func (o CustomMetricsAdapterServerOptions) Validate(args []string) error {
55-
return nil
65+
// Validate validates CustomMetricsAdapterServerOptions
66+
func (o CustomMetricsAdapterServerOptions) Validate() error {
67+
errors := []error{}
68+
errors = append(errors, o.SecureServing.Validate()...)
69+
errors = append(errors, o.Authentication.Validate()...)
70+
errors = append(errors, o.Authorization.Validate()...)
71+
errors = append(errors, o.Audit.Validate()...)
72+
errors = append(errors, o.Features.Validate()...)
73+
return utilerrors.NewAggregate(errors)
5674
}
5775

58-
func (o *CustomMetricsAdapterServerOptions) Complete() error {
59-
return nil
76+
// AddFlags adds the flags defined for the options, to the given flagset.
77+
func (o *CustomMetricsAdapterServerOptions) AddFlags(fs *pflag.FlagSet) {
78+
o.SecureServing.AddFlags(fs)
79+
o.Authentication.AddFlags(fs)
80+
o.Authorization.AddFlags(fs)
81+
o.Audit.AddFlags(fs)
82+
o.Features.AddFlags(fs)
6083
}
6184

85+
// Config returns configuration for the API server given CustomMetricsAdapterServerOptions
6286
func (o CustomMetricsAdapterServerOptions) Config() (*apiserver.Config, error) {
6387
// TODO have a "real" external address (have an AdvertiseAddress?)
6488
if err := o.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", nil, []net.IP{net.ParseIP("127.0.0.1")}); err != nil {
@@ -69,23 +93,26 @@ func (o CustomMetricsAdapterServerOptions) Config() (*apiserver.Config, error) {
6993
if err := o.SecureServing.ApplyTo(&serverConfig.SecureServing, &serverConfig.LoopbackClientConfig); err != nil {
7094
return nil, err
7195
}
72-
7396
if err := o.Authentication.ApplyTo(&serverConfig.Authentication, serverConfig.SecureServing, nil); err != nil {
7497
return nil, err
7598
}
7699
if err := o.Authorization.ApplyTo(&serverConfig.Authorization); err != nil {
77100
return nil, err
78101
}
79-
80102
if err := o.Audit.ApplyTo(serverConfig); err != nil {
81103
return nil, err
82104
}
105+
if err := o.Features.ApplyTo(serverConfig); err != nil {
106+
return nil, err
107+
}
83108

84109
// enable OpenAPI schemas
85110
if o.OpenAPIConfig != nil {
86111
serverConfig.OpenAPIConfig = o.OpenAPIConfig
87112
}
88113

114+
serverConfig.EnableMetrics = o.EnableMetrics
115+
89116
config := &apiserver.Config{
90117
GenericConfig: serverConfig,
91118
}

pkg/cmd/server/options_test.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
Copyright 2022 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 server
18+
19+
import (
20+
"testing"
21+
22+
"github.com/spf13/pflag"
23+
"github.com/stretchr/testify/assert"
24+
)
25+
26+
func TestOptions(t *testing.T) {
27+
cases := []struct {
28+
testName string
29+
args []string
30+
shouldErr bool
31+
}{
32+
{
33+
testName: "only-secure-port",
34+
args: []string{"--secure-port=6443"}, // default is 443, which requires privileges
35+
shouldErr: false,
36+
},
37+
{
38+
testName: "secure-port-0",
39+
args: []string{"--secure-port=0"}, // means: "don't serve HTTPS at all"
40+
shouldErr: false,
41+
},
42+
{
43+
testName: "invalid-secure-port",
44+
args: []string{"--secure-port=-1"},
45+
shouldErr: true,
46+
},
47+
{
48+
testName: "empty-header",
49+
args: []string{"--secure-port=6443", "--requestheader-username-headers=\" \""},
50+
shouldErr: true,
51+
},
52+
{
53+
testName: "invalid-audit-log-format",
54+
args: []string{"--secure-port=6443", "--audit-log-path=file", "--audit-log-format=txt"},
55+
shouldErr: true,
56+
},
57+
}
58+
59+
for _, c := range cases {
60+
t.Run(c.testName, func(t *testing.T) {
61+
o := NewCustomMetricsAdapterServerOptions()
62+
63+
// Unit tests have no Kubernetes cluster access
64+
o.Authentication.RemoteKubeConfigFileOptional = true
65+
o.Authorization.RemoteKubeConfigFileOptional = true
66+
67+
flagSet := pflag.NewFlagSet("", pflag.PanicOnError)
68+
o.AddFlags(flagSet)
69+
err := flagSet.Parse(c.args)
70+
assert.NoErrorf(t, err, "Error while parsing flags")
71+
72+
err = o.Validate()
73+
if c.shouldErr {
74+
assert.Errorf(t, err, "Expected error while validating options")
75+
} else {
76+
assert.NoErrorf(t, err, "Error while validating options")
77+
}
78+
79+
if err != nil || c.shouldErr {
80+
return
81+
}
82+
83+
config, err := o.Config()
84+
defer func() {
85+
// Close the listener, if any
86+
if config != nil && config.GenericConfig.SecureServing != nil && config.GenericConfig.SecureServing.Listener != nil {
87+
err := config.GenericConfig.SecureServing.Listener.Close()
88+
assert.NoError(t, err)
89+
}
90+
}()
91+
assert.NoErrorf(t, err, "Error creating config")
92+
})
93+
}
94+
}

0 commit comments

Comments
 (0)