Skip to content

Commit

Permalink
allow overriding stat name via Upstream label
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenctl committed Feb 24, 2025
1 parent 9c6688e commit 433233f
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 20 deletions.
6 changes: 6 additions & 0 deletions changelog/v1.19.0-beta11/stat-name-label.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
changelog:
- type: NON_USER_FACING
description: >-
Allow using the label `~internal.solo.io/cluster-stat-name` to manually set
the alt_stat_name on the Envoy cluster that will result from an Upstream.
This allows synthetic Upstreams to specify parseable alt_stat_name.
14 changes: 7 additions & 7 deletions projects/gloo/pkg/translator/translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2507,8 +2507,8 @@ var _ = Describe("Translator", func() {
)

BeforeEach(func() {
testUpstream1 := createStaticUpstream("test1", "gloo-system")
testUpstream2 := createStaticUpstream("test2", "gloo-system")
testUpstream1 := createStaticUpstream("test1", "gloo-system", nil)
testUpstream2 := createStaticUpstream("test2", "gloo-system", nil)

weightedDestNoWeightPassed := createWeightedDestination(false, 0, testUpstream1)
weightedDestZeroWeight = createWeightedDestination(true, 0, testUpstream1)
Expand Down Expand Up @@ -3929,9 +3929,7 @@ var _ = Describe("Translator", func() {
})

Context("Aggregate Listeners", func() {

It("should translate empty aggragate listener", func() {

proxy = &v1.Proxy{
Metadata: &core.Metadata{
Name: "test",
Expand Down Expand Up @@ -3967,9 +3965,7 @@ var _ = Describe("Translator", func() {
//
// lis := snap.GetResources(types.ListenerTypeV3).Items["http"].ResourceProto().(*listenerv3.Listener)
// Expect(lis).NotTo(BeNil())

})

})
Context("Custom filters", func() {
It("http", func() {
Expand Down Expand Up @@ -4105,11 +4101,15 @@ func (e *endpointPluginMock) Name() string {
func (e *endpointPluginMock) Init(params plugins.InitParams) {
}

func createStaticUpstream(name, namespace string) *v1.Upstream {
func createStaticUpstream(name, namespace string, labels map[string]string) *v1.Upstream {
if labels == nil {
labels = map[string]string{}
}
return &v1.Upstream{
Metadata: &core.Metadata{
Name: name,
Namespace: namespace,
Labels: labels,
},
UpstreamType: &v1.Upstream_Static{
Static: &v1static.UpstreamSpec{
Expand Down
42 changes: 35 additions & 7 deletions projects/gloo/pkg/translator/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,35 @@ import (
"github.com/solo-io/solo-kit/pkg/api/v1/resources/core"
)

// ClusterStatNameLabel allows synthetic upstreams to override the
// stat name at the time of their generation.
const ClusterStatNameLabel = "internal.solo.io/cluster-stat-name"

// FormatClusterStatName produces a parseable alt_stat_name.
func FormatClusterStatName(
prefix string,
upstreamName,
upstreamNamespace,
serviceNamespace,
ServiceName string,
servicePort uint32,
) string {
stat := fmt.Sprintf(
"%s_%s_%s_%s_%v",
upstreamName,
upstreamNamespace,
serviceNamespace,
ServiceName,
servicePort,
)
if prefix != "" {
return prefix + stat
}
return stat
}

// UpstreamToClusterName converts an Upstream ref to a cluster name to be used in envoy.
func UpstreamToClusterName(upstream *core.ResourceRef) string {

// For non-namespaced resources, return only name
if upstream.GetNamespace() == "" {
return upstream.GetName()
Expand All @@ -39,10 +65,12 @@ func UpstreamToClusterStatsName(upstream *gloov1.Upstream) string {
case *v1.Upstream_Kube:
upstreamName := upstream.GetMetadata().GetName()
// Add an identifying prefix if it's a "real" upstream (fake upstreams already have such a prefix).
var prefix string
if !kubernetes.IsFakeKubeUpstream(upstreamName) {
upstreamName = fmt.Sprintf("%s%s", kubernetes.KubeUpstreamStatsPrefix, upstreamName)
prefix = kubernetes.KubeUpstreamStatsPrefix
}
statsName = fmt.Sprintf("%s_%s_%s_%s_%v",
statsName = FormatClusterStatName(
prefix,
upstreamName,
upstream.GetMetadata().GetNamespace(),
upstreamType.Kube.GetServiceNamespace(),
Expand All @@ -51,6 +79,10 @@ func UpstreamToClusterStatsName(upstream *gloov1.Upstream) string {
)
}

if override, ok := upstream.GetMetadata().GetLabels()[ClusterStatNameLabel]; ok && override != "" {
statsName = override
}

// although envoy will do this before emitting stats, we sanitize here because some of our tests call
// this function to get expected stats names
return strings.ReplaceAll(statsName, ":", "_")
Expand All @@ -60,7 +92,6 @@ func UpstreamToClusterStatsName(upstream *gloov1.Upstream) string {
// (this is currently only used in the tunneling plugin and the old UI)
// This does the inverse of UpstreamToClusterName
func ClusterToUpstreamRef(cluster string) (*core.ResourceRef, error) {

split := strings.Split(cluster, "_")
if len(split) > 2 || len(split) < 1 {
return nil, errors.Errorf("unable to convert cluster %s back to upstream ref", cluster)
Expand All @@ -77,7 +108,6 @@ func ClusterToUpstreamRef(cluster string) (*core.ResourceRef, error) {
}

func NewFilterWithTypedConfig(name string, config proto.Message) (*envoy_config_listener_v3.Filter, error) {

s := &envoy_config_listener_v3.Filter{
Name: name,
}
Expand Down Expand Up @@ -137,14 +167,12 @@ func IsIpv4Address(bindAddress string) (validIpv4, strictIPv4 bool, err error) {
if bindIP == nil {
// If bindAddress is not a valid textual representation of an IP address
return false, false, errors.Errorf("bindAddress %s is not a valid IP address", bindAddress)

} else if bindIP.To4() == nil {
// If bindIP is not an IPv4 address, To4 returns nil.
// so this is not an acceptable ipv4
return false, false, nil
}
return true, isPureIPv4Address(bindAddress), nil

}

// isPureIPv4Address checks the string to see if it is
Expand Down
13 changes: 7 additions & 6 deletions projects/gloo/pkg/translator/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import (
"github.com/solo-io/solo-kit/pkg/api/v1/resources/core"
)

var _ = Describe("Utils", func() {

var _ = FDescribe("Utils", func() {
It("empty namespace: should convert upstream to cluster name and back properly", func() {
ref := &core.ResourceRef{Name: "name", Namespace: ""}
clusterName := translator.UpstreamToClusterName(ref)
Expand All @@ -30,15 +29,17 @@ var _ = Describe("Utils", func() {
})

Context("UpstreamToClusterStatsName", func() {

DescribeTable("converting upstream to cluster stats name",
func(us *gloov1.Upstream, expectedStatsName string) {
statsName := translator.UpstreamToClusterStatsName(us)
Expect(statsName).To(Equal(expectedStatsName))
},
Entry("real kube upstream", createKubeUpstream(true, "name", "ns", "svcName", "svcNs", 123), "kube-upstream_name_ns_svcNs_svcName_123"),
Entry("fake kube upstream", createKubeUpstream(false, "name", "ns", "svcName", "svcNs", 123), "kube-svc_name_ns_svcNs_svcName_123"),
Entry("non-kube upstream", createStaticUpstream("name", "ns"), "name_ns"),
Entry("non-kube upstream", createStaticUpstream("name", "ns", nil), "name_ns"),
Entry("non-kube upstream", createStaticUpstream("name", "ns", map[string]string{
translator.ClusterStatNameLabel: translator.FormatClusterStatName("istio_se_", "usname", "usns", "svcns", "svcName", 123),
}), "istio_se_usname_usns_svcns_svcName_123"),
)
})

Expand All @@ -61,11 +62,11 @@ var _ = Describe("Utils", func() {
Entry("ipv6 returns false", "::", false, false, nil),
Entry("ipv4 mapped in ipv6", "::ffff:0.0.0.0", true, false, nil),
)

})

func createKubeUpstream(isReal bool, name string, namespace string,
svcName string, svcNamespace string, svcPort uint32) *gloov1.Upstream {
svcName string, svcNamespace string, svcPort uint32,
) *gloov1.Upstream {
if !isReal {
name = upstreams_kube.FakeUpstreamNamePrefix + name
}
Expand Down

0 comments on commit 433233f

Please sign in to comment.