mirror of https://github.com/hashicorp/consul
Backport of catalog: improve the bound workload identity encoding on services into release/1.18.x (#20467)
catalog: improve the bound workload identity encoding on services (#20458) The endpoints controller currently encodes the list of unique workload identities referenced by all workload matched by a Service into a special data-bearing status condition on that Service. This allows a downstream controller to avoid an expensive watch on the ServiceEndpoints type just to get this data. The current encoding does not lend itself well to machine parsing, which is what the field is meant for, so this PR simplifies the encoding from: "blah blah: " + strings.Join(ids, ",") + "." to strings.Join(ids, ",") It also provides an exported utility function to easily extract this data. Co-authored-by: R.B. Boyer <4903+rboyer@users.noreply.github.com>pull/20469/head
parent
f3b80ddcba
commit
a49f2d0d59
@ -0,0 +1,46 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/consul/proto-public/pbresource"
|
||||
)
|
||||
|
||||
// GetBoundIdentities returns the unique list of workload identity references
|
||||
// encoded into a data-bearing status condition on a Service resource by the
|
||||
// endpoints controller.
|
||||
//
|
||||
// This allows a controller to skip watching ServiceEndpoints (which is
|
||||
// expensive) to discover this data.
|
||||
func GetBoundIdentities(res *pbresource.Resource) []string {
|
||||
if res.GetStatus() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
status, ok := res.GetStatus()[ControllerID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var encoded string
|
||||
for _, cond := range status.GetConditions() {
|
||||
if cond.GetType() == StatusConditionBoundIdentities && cond.GetState() == pbresource.Condition_STATE_TRUE {
|
||||
encoded = cond.GetMessage()
|
||||
break
|
||||
}
|
||||
}
|
||||
if encoded == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
identities := strings.Split(encoded, ",")
|
||||
|
||||
// Ensure determinstic sort so we don't get into infinite-reconcile
|
||||
sort.Strings(identities)
|
||||
|
||||
return identities
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package endpoints_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hashicorp/consul/internal/catalog/internal/controllers/endpoints"
|
||||
"github.com/hashicorp/consul/internal/resource"
|
||||
"github.com/hashicorp/consul/internal/resource/demo"
|
||||
rtest "github.com/hashicorp/consul/internal/resource/resourcetest"
|
||||
"github.com/hashicorp/consul/proto-public/pbresource"
|
||||
pbdemo "github.com/hashicorp/consul/proto/private/pbdemo/v2"
|
||||
)
|
||||
|
||||
func TestGetBoundIdentities(t *testing.T) {
|
||||
tenancy := resource.DefaultNamespacedTenancy()
|
||||
|
||||
build := func(conds ...*pbresource.Condition) *pbresource.Resource {
|
||||
b := rtest.Resource(demo.TypeV2Artist, "artist").
|
||||
WithTenancy(tenancy).
|
||||
WithData(t, &pbdemo.Artist{Name: "very arty"})
|
||||
if len(conds) > 0 {
|
||||
b.WithStatus(endpoints.ControllerID, &pbresource.Status{
|
||||
Conditions: conds,
|
||||
})
|
||||
}
|
||||
return b.Build()
|
||||
}
|
||||
|
||||
run := endpoints.GetBoundIdentities
|
||||
|
||||
require.Empty(t, run(build(nil)))
|
||||
require.Empty(t, run(build(&pbresource.Condition{
|
||||
Type: endpoints.StatusConditionBoundIdentities,
|
||||
State: pbresource.Condition_STATE_TRUE,
|
||||
Message: "",
|
||||
})))
|
||||
require.Equal(t, []string{"foo"}, run(build(&pbresource.Condition{
|
||||
Type: endpoints.StatusConditionBoundIdentities,
|
||||
State: pbresource.Condition_STATE_TRUE,
|
||||
Message: "foo",
|
||||
})))
|
||||
require.Empty(t, run(build(&pbresource.Condition{
|
||||
Type: endpoints.StatusConditionBoundIdentities,
|
||||
State: pbresource.Condition_STATE_FALSE,
|
||||
Message: "foo",
|
||||
})))
|
||||
require.Equal(t, []string{"bar", "foo"}, run(build(&pbresource.Condition{
|
||||
Type: endpoints.StatusConditionBoundIdentities,
|
||||
State: pbresource.Condition_STATE_TRUE,
|
||||
Message: "bar,foo", // proper order
|
||||
})))
|
||||
require.Equal(t, []string{"bar", "foo"}, run(build(&pbresource.Condition{
|
||||
Type: endpoints.StatusConditionBoundIdentities,
|
||||
State: pbresource.Condition_STATE_TRUE,
|
||||
Message: "foo,bar", // incorrect order gets fixed
|
||||
})))
|
||||
|
||||
}
|
Loading…
Reference in new issue