apiserver/etcd3: fix segv during metric collection

Fix a segfault when collecting the storage size metrics when the getters
used to collect the data on etcd haven't been initialized properly. This
happens when the EtcdOptions are not applied which is the case for
aggregated apiservers that don't care about storage.

Signed-off-by: Damien Grisonnet <dgrisonn@redhat.com>
This commit is contained in:
Damien Grisonnet 2023-08-10 17:01:17 +02:00
parent 18c3c7efb3
commit c6efaf16c1
2 changed files with 59 additions and 1 deletions

View File

@ -85,7 +85,7 @@ var (
[]string{"endpoint"},
)
storageSizeDescription = compbasemetrics.NewDesc("apiserver_storage_size_bytes", "Size of the storage database file physically allocated in bytes.", []string{"cluster"}, nil, compbasemetrics.ALPHA, "")
storageMonitor = &monitorCollector{}
storageMonitor = &monitorCollector{monitorGetter: func() ([]Monitor, error) { return nil, nil }}
etcdEventsReceivedCounts = compbasemetrics.NewCounterVec(
&compbasemetrics.CounterOpts{
Subsystem: "apiserver",

View File

@ -17,6 +17,7 @@ limitations under the License.
package metrics
import (
"context"
"errors"
"strings"
"testing"
@ -179,3 +180,60 @@ etcd_request_errors_total{operation="foo",type="bar"} 1
})
}
}
func TestStorageSizeCollector(t *testing.T) {
registry := metrics.NewKubeRegistry()
registry.CustomMustRegister(storageMonitor)
testCases := []struct {
desc string
getterOverride func() ([]Monitor, error)
err error
want string
}{
{
desc: "fake etcd getter",
getterOverride: func() ([]Monitor, error) {
return []Monitor{fakeEtcdMonitor{storageSize: 1e9}}, nil
},
err: nil,
want: `# HELP apiserver_storage_size_bytes [ALPHA] Size of the storage database file physically allocated in bytes.
# TYPE apiserver_storage_size_bytes gauge
apiserver_storage_size_bytes{cluster="etcd-0"} 1e+09
`,
},
{
desc: "getters not configured",
getterOverride: nil,
err: nil,
want: ``,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer registry.Reset()
if test.getterOverride != nil {
oldGetter := storageMonitor.monitorGetter
defer SetStorageMonitorGetter(oldGetter)
SetStorageMonitorGetter(test.getterOverride)
}
if err := testutil.GatherAndCompare(registry, strings.NewReader(test.want), "apiserver_storage_size_bytes"); err != nil {
t.Fatal(err)
}
})
}
}
type fakeEtcdMonitor struct {
storageSize int64
}
func (m fakeEtcdMonitor) Monitor(_ context.Context) (StorageMetrics, error) {
return StorageMetrics{Size: m.storageSize}, nil
}
func (m fakeEtcdMonitor) Close() error {
return nil
}