test:add sample-external-metrics-server to agnhost

Signed-off-by: Omer Aplatony <omerap12@gmail.com>
This commit is contained in:
Omer Aplatony
2026-02-04 06:08:45 +00:00
parent 0cf6c382a0
commit a29d099dd4
10 changed files with 59 additions and 186 deletions

View File

@@ -165,6 +165,35 @@ Usage:
```
### external-metrics
Starts an HTTPS server that implements the external metrics API for testing Horizontal Pod Autoscaler (HPA) with external metrics. The server provides a mock implementation of the `external.metrics.k8s.io` API group.
The server comes with two pre-configured metrics:
- `queue_messages_ready` (value: 100)
- `http_requests_total` (value: 500)
The server exposes the following endpoints:
- `/apis/external.metrics.k8s.io/v1beta1/namespaces/{namespace}/{metric-name}`: Get external metric values (supports label selectors via query parameter)
- `/healthz` and `/readyz`: Health check endpoints
- `/create/{metric-name}?value={value}&labels={key1=value1,key2=value2}&fail={true|false}`: Create a new metric with optional labels
- `/set/{metric-name}?value={value}&labels={key1=value1,key2=value2}`: Update an existing metric's value
- `/fail/{metric-name}?fail={true|false}&labels={key1=value1,key2=value2}`: Configure a metric to return errors
The subcommand can accept the following flags:
- `port` (default: `6443`): Port number for the HTTPS server.
- `service-name` (default: `external-metrics-server`): Name of the external metrics service.
- `service-namespace` (default: `default`): Namespace of the external metrics service.
The server generates self-signed TLS certificates automatically on startup.
Usage:
```console
kubectl exec test-agnhost -- /agnhost external-metrics [--port <port>] [--service-name <name>] [--service-namespace <namespace>]
```
### fake-gitserver
Fakes a git server. When doing `git clone http://localhost:8000`, you will clone an empty git

View File

@@ -1 +1 @@
2.62.2
2.63.0

View File

@@ -27,6 +27,7 @@ import (
crdconvwebhook "k8s.io/kubernetes/test/images/agnhost/crd-conversion-webhook"
"k8s.io/kubernetes/test/images/agnhost/dns"
"k8s.io/kubernetes/test/images/agnhost/entrypoint-tester"
externalmetrics "k8s.io/kubernetes/test/images/agnhost/external-metrics"
"k8s.io/kubernetes/test/images/agnhost/fakegitserver"
"k8s.io/kubernetes/test/images/agnhost/fakeregistryserver"
grpchealthchecking "k8s.io/kubernetes/test/images/agnhost/grpc-health-checking"
@@ -98,6 +99,7 @@ func main() {
rootCmd.AddCommand(mtlsclient.CmdMtlsClient)
rootCmd.AddCommand(mtlsserver.CmdMtlsServer)
rootCmd.AddCommand(nonewprivs.CmdNoNewPrivs)
rootCmd.AddCommand(externalmetrics.CmdExternalMetricsServer)
// NOTE(claudiub): Some tests are passing logging related flags, so we need to be able to
// accept them. This will also include them in the printed help.
code := cli.Run(rootCmd)

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package main
package externalmetrics
import (
"fmt"

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package main
package externalmetrics
import (
"context"
@@ -22,39 +22,50 @@ import (
"fmt"
"net"
"net/http"
"os"
"strings"
"time"
"github.com/spf13/pflag"
"github.com/spf13/cobra"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/options"
"k8s.io/klog/v2"
netutils "k8s.io/utils/net"
)
// CmdExternalMetricsServer is used by agnhost Cobra.
var CmdExternalMetricsServer = &cobra.Command{
Use: "external-metrics",
Short: "Starts an external metrics server for testing",
Long: "Starts an HTTPS server that implements the external metrics API for testing HPA with external metrics",
Args: cobra.MaximumNArgs(0),
Run: main,
}
var provider *metricProvider
func main() {
flags := pflag.NewFlagSet("sample-external-metrics", pflag.ExitOnError)
klog.InitFlags(nil)
var (
port int
serviceName string
serviceNs string
)
func init() {
CmdExternalMetricsServer.Flags().IntVar(&port, "port", 6443, "Port number.")
CmdExternalMetricsServer.Flags().StringVar(&serviceName, "service-name", "external-metrics-server", "Name of the external metrics service.")
CmdExternalMetricsServer.Flags().StringVar(&serviceNs, "service-namespace", "default", "Namespace of the external metrics service.")
}
func main(cmd *cobra.Command, args []string) {
// Initialize the metric provider
provider = NewConfigurableProvider()
// Create some default metrics
provider.createMetric("queue_messages_ready", nil, 100, false)
provider.createMetric("http_requests_total", nil, 500, false)
secureServing := options.NewSecureServingOptions()
secureServing.BindPort = 6443
secureServing.BindPort = port
secureServing.ServerCert.CertDirectory = "/tmp/cert"
secureServing.ServerCert.PairName = "apiserver"
secureServing.AddFlags(flags)
if err := flags.Parse(os.Args[1:]); err != nil {
klog.Fatalf("Error parsing flags: %v", err)
}
// Generate self-signed TLS certificates if none exist. This allows the server to run with HTTPS
// without requiring manually provisioned certificates. The certs are valid for "localhost" and
// the loopback IP 127.0.0.1. The second parameter (nil) means no additional alternate names.
@@ -96,6 +107,7 @@ func main() {
<-listenerStoppedCh
<-stoppedCh
}
func healthz(w http.ResponseWriter, r *http.Request) {

View File

@@ -1,5 +0,0 @@
linux/amd64=registry.k8s.io/build-image/debian-base-amd64:bookworm-v1.0.6
linux/ppc64le=registry.k8s.io/build-image/debian-base-ppc64le:bookworm-v1.0.6
linux/s390x=registry.k8s.io/build-image/debian-base-s390x:bookworm-v1.0.6
windows/amd64/1809=mcr.microsoft.com/windows/nanoserver:1809
windows/amd64/ltsc2022=mcr.microsoft.com/windows/nanoserver:ltsc2022

View File

@@ -1,20 +0,0 @@
# Copyright The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
ARG BASEIMAGE
FROM $BASEIMAGE
ADD sample-external-metrics-server /sample-external-metrics-server
EXPOSE 6443
ENTRYPOINT ["/sample-external-metrics-server"]

View File

@@ -1,26 +0,0 @@
# Copyright The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
SRCS = sample-external-metrics-server
OS ?= linux
ARCH ?= amd64
TARGET ?= $(CURDIR)
GOLANG_VERSION ?= latest
SRC_DIR = $(notdir $(shell pwd))
export
bin:
../image-util.sh bin $(SRCS)
.PHONY: bin

View File

@@ -1,118 +0,0 @@
# Test Metrics Server
A Kubernetes external metrics API server for testing and development purposes. This server implements the `external.metrics.k8s.io` API and provides endpoints to dynamically create, update, and configure metrics for testing HPA (Horizontal Pod Autoscaler) and other metric-based scenarios.
## API Endpoints
### Health Checks
#### Check Server Health
```bash
curl -k https://localhost:6443/healthz
curl -k https://localhost:6443/readyz
```
### Kubernetes External Metrics API
#### List API Groups
```bash
curl -k https://localhost:6443/apis/external.metrics.k8s.io
```
#### List Available Resources
```bash
curl -k https://localhost:6443/apis/external.metrics.k8s.io/v1beta1
```
#### Get Metric Value
```bash
# Query a specific metric
curl -k https://localhost:6443/apis/external.metrics.k8s.io/v1beta1/namespaces/default/queue_messages_ready
# Query a metric with label selector
curl -k "https://localhost:6443/apis/external.metrics.k8s.io/v1beta1/namespaces/production/error_rate?labelSelector=env=prod,region=us-west"
# Or via kubectl
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/queue_messages_ready"
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/error_rate?labelSelector=env=prod"
```
**Error Response (Metric Not Found):**
```bash
curl -k https://localhost:6443/apis/external.metrics.k8s.io/v1beta1/namespaces/default/nonexistent_metric
# HTTP 404: no metric name called nonexistent_metric
```
**Error Response (Metric Configured to Fail):**
```bash
# HTTP 500: metric queue_messages_ready is configured to fail
```
---
### Metric Management
#### Create a New Metric
```bash
# Create a metric with value 250
curl -k "https://localhost:6443/create/my_custom_metric?value=250"
# Create a metric with labels
curl -k "https://localhost:6443/create/error_rate?value=25&labels=env=prod,region=us-west"
# Create a metric that will fail
curl -k "https://localhost:6443/create/failing_metric?value=100&fail=true"
# Create a metric with labels that will fail
curl -k "https://localhost:6443/create/error_rate?value=50&labels=env=staging&fail=true"
```
#### Update Metric Value
```bash
# Update the value of an existing metric
curl -k "https://localhost:6443/set/queue_messages_ready?value=500"
```
```bash
# Update the value of an existing labels metric
curl -k "https://localhost:6443/set/queue_messages_ready?value=500&labels=env=staging"
```
**Error Response (Metric Not Found):**
```bash
curl -k "https://localhost:6443/set/nonexistent_metric?value=100"
# HTTP 404: metric nonexistent_metric not found
```
#### Configure Metric Failure State
```bash
# Make a metric fail (return HTTP 500)
curl -k "https://localhost:6443/fail/queue_messages_ready?fail=true"
# Make a metric succeed again
curl -k "https://localhost:6443/fail/queue_messages_ready?fail=false"
# Make a metric with specific labels fail
curl -k "https://localhost:6443/fail/error_rate?fail=true&labels=env=prod,region=us-west"
# Make a labeled metric succeed again
curl -k "https://localhost:6443/fail/error_rate?fail=false&labels=env=prod,region=us-west"
```
### Querying Metrics with Labels
```bash
# Get all response_time metrics (returns all label variants)
curl -k "https://localhost:6443/apis/external.metrics.k8s.io/v1beta1/namespaces/default/response_time"
# Get only prod environment metrics
curl -k "https://localhost:6443/apis/external.metrics.k8s.io/v1beta1/namespaces/default/response_time?labelSelector=env=prod"
# Get specific metric with exact label match
curl -k "https://localhost:6443/apis/external.metrics.k8s.io/v1beta1/namespaces/default/response_time?labelSelector=env=prod,service=api"
```
## Default Metrics
The server starts with two pre-configured metrics:
1. **queue_messages_ready** - Initial value: 100
2. **http_requests_total** - Initial value: 500

View File

@@ -1 +0,0 @@
1.0.0