Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add service entries #201

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/v1/inline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ type HostSpec struct {
type ServiceMeshSpec struct {
// +kubebuilder:validation:Optional
Enabled bool `json:"enabled,omitempty"`
// +kubebuilder:validation:Optional
Namespace string `json:"namespace,omitempty"`
// +kubebuilder:validation:Optional
Configmap string `json:"configmap,omitempty"`
}

type Prometheus struct {
Expand Down
2 changes: 2 additions & 0 deletions api/v1/instanaagent_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ func (in *InstanaAgent) Default() {
optional.ValueOrDefault(&in.Spec.K8sSensor.ImageSpec.Tag, "latest")
optional.ValueOrDefault(&in.Spec.K8sSensor.ImageSpec.PullPolicy, corev1.PullAlways)
optional.ValueOrDefault(&in.Spec.K8sSensor.DeploymentSpec.Replicas, 3)
optional.ValueOrDefault(&in.Spec.Agent.ServiceMesh.Namespace, "istio-system")
optional.ValueOrDefault(&in.Spec.Agent.ServiceMesh.Configmap, "istio")
}

// +kubebuilder:object:root=true
Expand Down
25 changes: 25 additions & 0 deletions api/v1/instanaagent_types_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/*
(c) Copyright IBM Corp. 2024
(c) Copyright Instana Inc.

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.
*/

package v1

import (
Expand Down Expand Up @@ -51,6 +68,10 @@ func TestInstanaAgent_Default(t *testing.T) {
Replicas: 2,
},
},
ServiceMesh: ServiceMeshSpec{
Namespace: "istio-system",
Configmap: "istio",
},
}

tests := []struct {
Expand Down Expand Up @@ -100,6 +121,10 @@ func TestInstanaAgent_Default(t *testing.T) {
Replicas: 3,
},
},
ServiceMesh: ServiceMeshSpec{
Namespace: "istio-system",
Configmap: "istio",
},
},
},
{
Expand Down
7 changes: 7 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ rules:
- get
- patch
- update
- apiGroups:
- networking.istio.io
resources:
- serviceentries
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
Expand Down
19 changes: 19 additions & 0 deletions config/samples/instana_v1_extended_instanaagent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ spec:
# agent.serviceMesh.enabled sets the Instana agent's communication direction with JVMs.
# To allow communication to be directed to the agent, set this variable to true.
enabled: true
# Namespace where istio is installed. Defaults to istio-system. This may have to be changed for OpenShift ServiceMesh
namespace: istio-system
# ConfigMap for mesh. Defaults to istio. This may have to be changed for OpenShift ServiceMesh
configmap: istio

# agent.host.repository sets a host path to be mounted as the agent maven repository (for debugging or development purposes)
# host:
Expand Down Expand Up @@ -227,3 +231,18 @@ spec:
memory: 3072Mi
# kubernetes.deployment.pod.limits.cpu sets the CPU units allocation limits for the agent pods.
cpu: 4

zones:
# Configure use of zones to use tolerations as the basis to associate a specific daemonset per tainted node pool
- name: pool-01
tolerations:
- key: "pool"
operator: "Equal"
value: "pool-01"
effect: "NoExecute"
- name: pool-02
tolerations:
- key: "pool"
operator: "Equal"
value: "pool-02"
effect: "NoExecute"
12 changes: 12 additions & 0 deletions controllers/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/service"
agentserviceaccount "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/serviceaccount"
backends "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/backends"
"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/serviceentry"
"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/builder"
k8ssensorconfigmap "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/k8s-sensor/configmap"
k8ssensordeployment "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/k8s-sensor/deployment"
Expand Down Expand Up @@ -83,6 +84,8 @@ func (r *InstanaAgentReconciler) applyResources(
ctx context.Context,
agent *instanav1.InstanaAgent,
isOpenShift bool,
isIstioRegistryOnlyEnabled bool,
nodeIPs []string,
operatorUtils operator_utils.OperatorUtils,
statusManager status.AgentStatusManager,
keysSecret *corev1.Secret,
Expand All @@ -91,6 +94,14 @@ func (r *InstanaAgentReconciler) applyResources(
log := r.loggerFor(ctx, agent)
log.V(1).Info("applying Kubernetes resources for agent")

var serviceEntriesBuilders []builder.ObjectBuilder

if isIstioRegistryOnlyEnabled {
for _, nodeIP := range nodeIPs {
serviceEntriesBuilders = append(serviceEntriesBuilders, serviceentry.NewServiceEntriesBuilder(agent, nodeIP))
}
}

builders := append(
getDaemonSetBuilders(agent, isOpenShift, statusManager),
headlessservice.NewHeadlessServiceBuilder(agent),
Expand All @@ -108,6 +119,7 @@ func (r *InstanaAgentReconciler) applyResources(
)

builders = append(builders, getK8sSensorDeployments(agent, isOpenShift, statusManager, k8SensorBackends)...)
builders = append(builders, serviceEntriesBuilders...)

if err := operatorUtils.ApplyAll(builders...); err != nil {
log.Error(err, "failed to apply kubernetes resources for agent")
Expand Down
16 changes: 16 additions & 0 deletions controllers/controllers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ var (
},
key: agentNamespace,
}
agentServiceEntries = object{
gvk: schema.GroupVersionKind{
Version: "networking.istio.io/v1alpha3",
Kind: "ServiceEntry",
},
}
)

// number of k8sensor resources used for diffing whether the controller functions properly
Expand Down Expand Up @@ -316,6 +322,16 @@ func (suite *InstanaAgentControllerTestSuite) TestInstanaAgentCR() {
"Should contain all objects in the schema",
)

require.Eventually(suite.T(),
suite.all(
suite.notExist,
agentServiceEntries,
),
10*time.Second,
time.Second,
"Should not contain ServiceEntries by default",
)

agentNew := agent.DeepCopy()
agentNew.Spec.K8sSensor.PodDisruptionBudget.Enabled = pointer.To(false)
agentNew.Spec.Agent.KeysSecret = "test"
Expand Down
8 changes: 8 additions & 0 deletions controllers/instanaagent_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,17 @@ func (r *InstanaAgentReconciler) reconcile(

k8SensorBackends := r.getK8SensorBackends(agent)

isIstioRegistryOnlyEnabled, nodeIPs, isIstioRegistryOnlyEnabledRes := r.getIstioOutboundConfigAndNodeIps(ctx, agent.Spec.ServiceMesh.Namespace, agent.Spec.ServiceMesh.Configmap)
if isIstioRegistryOnlyEnabledRes.suppliesReconcileResult() {
return isIstioRegistryOnlyEnabledRes
}

if applyResourcesRes := r.applyResources(
ctx,
agent,
isOpenShift,
isIstioRegistryOnlyEnabled,
nodeIPs,
operatorUtils,
statusManager,
keysSecret,
Expand Down Expand Up @@ -168,6 +175,7 @@ func (r *InstanaAgentReconciler) reconcile(
// +kubebuilder:rbac:groups=apps.openshift.io,resources=deploymentconfigs,verbs=get;list;watch
// +kubebuilder:rbac:groups=security.openshift.io,resourceNames=privileged,resources=securitycontextconstraints,verbs=use
// +kubebuilder:rbac:groups=policy,resourceNames=instana-agent-k8sensor,resources=podsecuritypolicies,verbs=use
// +kubebuilder:rbac:groups=networking.istio.io,resources=serviceentries,verbs=create;patch

func (r *InstanaAgentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
res ctrl.Result,
Expand Down
73 changes: 73 additions & 0 deletions controllers/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,26 @@ package controllers
import (
"context"
"strconv"
"fmt"
"strings"

"github.com/go-logr/logr"
"gopkg.in/yaml.v3"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
logf "sigs.k8s.io/controller-runtime/pkg/log"

instanav1 "github.com/instana/instana-agent-operator/api/v1"
backends "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/backends"
"github.com/instana/instana-agent-operator/pkg/k8s/operator/operator_utils"
)

type IstioMeshConfig struct {
OutboundTrafficPolicy struct {
Mode string `yaml:"mode"`
} `yaml:"outboundTrafficPolicy"`
}

func (r *InstanaAgentReconciler) isOpenShift(ctx context.Context, operatorUtils operator_utils.OperatorUtils) (
bool,
reconcileReturn,
Expand Down Expand Up @@ -62,6 +73,68 @@ func (r *InstanaAgentReconciler) getK8SensorBackends(agent *instanav1.InstanaAge
)
}
return k8SensorBackends
func (r *InstanaAgentReconciler) getIstioOutboundConfigAndNodeIps(ctx context.Context, namespace string, configmap string) (
bool,
[]string,
reconcileReturn,
) {
log := logf.FromContext(ctx)
var nodeIPs []string

log.Info("Check if REGISTRY_ONLY is enabled")
isIstioRegistryOnlyEnabled := r.checkRegistryOnlyMode(ctx, namespace, configmap)

if isIstioRegistryOnlyEnabled {
nodes, err := r.client.ListNodes(ctx)
if err != nil {
log.Error(err, "could not list nodes for generating ServiceEntries")
}
nodeIPs = getNodeIPs(nodes)
}

return isIstioRegistryOnlyEnabled, nodeIPs, reconcileContinue()
}

func (r *InstanaAgentReconciler) checkRegistryOnlyMode(ctx context.Context, namespace string, configmap string) bool {
istioConfigMap := &corev1.ConfigMap{}
log := logf.FromContext(ctx)
log.Info(fmt.Sprintf("Checking Istio ConfigMap %s in namespace %s for outbound traffic policy", configmap, namespace))
err := r.client.Get(ctx, types.NamespacedName{Name: configmap, Namespace: namespace}, istioConfigMap)
if err != nil {
log.Error(err, "Failed fetching istio ConfigMap")
return false
}
if istioConfigMap.Data == nil {
log.Info(fmt.Sprintf("Istio configmap %s in namespace %s data in nil", configmap, namespace))
return false
}
meshConfigData, ok := istioConfigMap.Data["mesh"]
if !ok {
return false
}

var meshConfig IstioMeshConfig
log.Info("Unmarshalling config data")
err = yaml.Unmarshal([]byte(meshConfigData), &meshConfig)
if err != nil {
log.Error(err, "Unmarshalling config data ERROR")
return false
}
log.Info("Checking if policy is REGISTRY_ONLY")

return strings.EqualFold(meshConfig.OutboundTrafficPolicy.Mode, "REGISTRY_ONLY")
}

func getNodeIPs(nodes *corev1.NodeList) []string {
var nodeIPs []string
for _, node := range nodes.Items {
for _, address := range node.Status.Addresses {
if address.Type == corev1.NodeInternalIP {
nodeIPs = append(nodeIPs, address.Address)
}
}
}
return nodeIPs
}

func (r *InstanaAgentReconciler) loggerFor(ctx context.Context, agent *instanav1.InstanaAgent) logr.Logger {
Expand Down
11 changes: 7 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ require (
golang.org/x/net v0.34.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.15.4
istio.io/api v1.24.2-0.20241206152109-43afb8563706
istio.io/client-go v1.24.2
k8s.io/api v0.30.3
k8s.io/apimachinery v0.30.3
k8s.io/client-go v0.30.3
Expand Down Expand Up @@ -135,17 +137,18 @@ require (
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/oauth2 v0.17.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.58.3 // indirect
google.golang.org/protobuf v1.33.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect
google.golang.org/grpc v1.64.1 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apiextensions-apiserver v0.30.3 // indirect
Expand Down
22 changes: 14 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -517,13 +517,15 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No=
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ=
google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
Expand All @@ -534,8 +536,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Expand All @@ -557,6 +559,10 @@ helm.sh/helm/v3 v3.15.4 h1:UFHd6oZ1IN3FsUZ7XNhOQDyQ2QYknBNWRHH57e9cbHY=
helm.sh/helm/v3 v3.15.4/go.mod h1:phOwlxqGSgppCY/ysWBNRhG3MtnpsttOzxaTK+Mt40E=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
istio.io/api v1.24.2-0.20241206152109-43afb8563706 h1:ozWjpvlfA1qFPPOolmqPtus+WwI0rX8uSLqoD+M6C0g=
istio.io/api v1.24.2-0.20241206152109-43afb8563706/go.mod h1:MQnRok7RZ20/PE56v0LxmoWH0xVxnCQPNuf9O7PAN1I=
istio.io/client-go v1.24.2 h1:JTTfBV6dv+AAW+AfccyrdX4T1f9CpsXd1Yzo1s/IYAI=
istio.io/client-go v1.24.2/go.mod h1:dgZ9EmJzh1EECzf6nQhwNL4R6RvlyeH/RXeNeNp/MRg=
k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U=
Expand Down
Loading