Skip to content

Commit

Permalink
Fix missing rev if list turns into a get.
Browse files Browse the repository at this point in the history
Replace Gets() with lists that filter on name.
  • Loading branch information
fasaxc committed Dec 19, 2024
1 parent 3130b5f commit dda0f92
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 191 deletions.
40 changes: 12 additions & 28 deletions libcalico-go/lib/backend/k8s/resources/customresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import (
"github.com/projectcalico/calico/libcalico-go/lib/backend/api"
"github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion"
"github.com/projectcalico/calico/libcalico-go/lib/backend/model"
cerrors "github.com/projectcalico/calico/libcalico-go/lib/errors"
)

// customK8sResourceClient implements the K8sResourceClient interface and provides a generic
Expand Down Expand Up @@ -343,40 +342,25 @@ func (c *customK8sResourceClient) List(ctx context.Context, list model.ListInter
})
logContext.Debug("Received List request")

// Attempt to convert the ListInterface to a Key. If possible, the parameters
// indicate a fully qualified resource, and we'll need to use Get instead of
// List.
if key := c.listInterfaceToKey(list); key != nil {
logContext.Debug("Performing List using Get")
kvps := []*model.KVPair{}
if kvp, err := c.Get(ctx, key, revision); err != nil {
// The error will already be a Calico error type. Ignore
// error that it doesn't exist - we'll return an empty
// list.
if _, ok := err.(cerrors.ErrorResourceDoesNotExist); !ok {
logContext.WithField("Resource", c.resource).WithError(err).Debug("Error listing resource")
return nil, err
}
return &model.KVPairList{
KVPairs: kvps,
Revision: revision,
}, nil
} else {
kvps = append(kvps, kvp)
return &model.KVPairList{
KVPairs: kvps,
Revision: revision,
}, nil
}
}

// If it is a namespaced resource, then we'll need the namespace.
namespace := list.(model.ResourceListOptions).Namespace
key := c.listInterfaceToKey(list)

// listFunc performs a list with the given options.
listFunc := func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
out := reflect.New(c.k8sListType).Interface().(ResourceList)

if key != nil {
// Being asked to list a single resource, add the filter.
key := key.(model.ResourceKey)
name, err := c.keyToName(key)
if err != nil {
logContext.WithError(err).Error("Failed to convert key to name of resource.")
return nil, err
}
opts.FieldSelector = fmt.Sprintf("metadata.name=%s", name)
}

// Build the request.
req := c.restClient.Get().
NamespaceIfScoped(namespace, c.namespaced).
Expand Down
29 changes: 7 additions & 22 deletions libcalico-go/lib/backend/k8s/resources/k8sservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,31 +93,16 @@ func (c *serviceClient) Get(ctx context.Context, key model.Key, revision string)
func (c *serviceClient) List(ctx context.Context, list model.ListInterface, revision string) (*model.KVPairList, error) {
log.Debug("Received List request on Kubernetes Service type")
rl := list.(model.ResourceListOptions)
kvps := []*model.KVPair{}

if rl.Name != "" {
// The service is already fully qualified, so perform a Get instead.
// If the entry does not exist then we just return an empty list.
kvp, err := c.Get(ctx, model.ResourceKey{Name: rl.Name, Namespace: rl.Namespace, Kind: model.KindKubernetesService}, revision)
if err != nil {
if _, ok := err.(cerrors.ErrorResourceDoesNotExist); !ok {
return nil, err
}
return &model.KVPairList{
KVPairs: kvps,
Revision: revision,
}, nil
}

kvps = append(kvps, kvp)
return &model.KVPairList{
KVPairs: kvps,
Revision: revision,
}, nil
}

// Listing all services.
listFunc := func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if rl.Name != "" {
// Filtering to a single Service.
opts.FieldSelector = fields.AndSelectors(
fields.OneTermEqualSelector("metadata.name", rl.Name),
fields.OneTermEqualSelector("metadata.namespace", rl.Namespace),
).String()
}
return c.clientSet.CoreV1().Services(rl.Namespace).List(ctx, opts)
}
convertFunc := func(r Resource) ([]*model.KVPair, error) {
Expand Down
26 changes: 4 additions & 22 deletions libcalico-go/lib/backend/k8s/resources/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,31 +140,13 @@ func (c *nodeClient) List(ctx context.Context, list model.ListInterface, revisio
logContext := log.WithField("Resource", "Node")
logContext.Debug("Received List request")
nl := list.(model.ResourceListOptions)
kvps := []*model.KVPair{}

if nl.Name != "" {
// The node is already fully qualified, so perform a Get instead.
// If the entry does not exist then we just return an empty list.
kvp, err := c.Get(ctx, model.ResourceKey{Name: nl.Name, Kind: libapiv3.KindNode}, revision)
if err != nil {
if _, ok := err.(cerrors.ErrorResourceDoesNotExist); !ok {
return nil, err
}
return &model.KVPairList{
KVPairs: kvps,
Revision: revision,
}, nil
}

kvps = append(kvps, kvp)
return &model.KVPairList{
KVPairs: kvps,
Revision: revision,
}, nil
}

// List all nodes.
listFunc := func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if nl.Name != "" {
// Filtering to a single node.
opts.FieldSelector = fields.OneTermEqualSelector("metadata.name", nl.Name).String()
}
nodes, err := c.clientSet.CoreV1().Nodes().List(ctx, opts)
if err != nil {
return nil, err
Expand Down
73 changes: 53 additions & 20 deletions libcalico-go/lib/backend/k8s/resources/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,34 +160,42 @@ func (c *profileClient) List(ctx context.Context, list model.ListInterface, revi
logContext.Debug("Received List request")
nl := list.(model.ResourceListOptions)

// If a name is specified, then do an exact lookup.
if nl.Name == resources.DefaultAllowProfileName {
// Special case, we synthesize the default allow profile. Revision
// is always 1, and it cannot change (a watch on that profile returns
// no events).
return &model.KVPairList{
KVPairs: []*model.KVPair{resources.DefaultAllowProfile()},
Revision: "1",
}, nil
}

var nsName, saName string
if nl.Name != "" {
kvps := []*model.KVPair{}
kvp, err := c.Get(ctx, model.ResourceKey{Name: nl.Name, Kind: nl.Kind}, revision)
// If we're listing a specific profile, then we need to determine
// whether it's a namespace or service account.
var err error
nsName, saName, err = c.parseProfileName(nl.Name)
if err != nil {
if _, ok := err.(cerrors.ErrorResourceDoesNotExist); !ok {
return nil, err
}
return &model.KVPairList{
KVPairs: kvps,
Revision: revision,
}, nil
return nil, err
}

kvps = append(kvps, kvp)
return &model.KVPairList{
KVPairs: kvps,
Revision: revision,
}, nil
}

nsRev, saRev, err := c.SplitProfileRevision(revision)
if err != nil {
return nil, err
}

// Enumerate all namespaces, paginated.
// Enumerate matching namespaces, paginated.
listFunc := func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
if saName != "" {
// We've been asked to list a particular service account, skip
// listing namespaces.
return &v1.NamespaceList{}, nil
}
if nsName != "" {
opts.FieldSelector = fields.OneTermEqualSelector("metadata.name", nsName).String()
}
return c.clientSet.CoreV1().Namespaces().List(ctx, opts)
}
convertFunc := func(r Resource) ([]*model.KVPair, error) {
Expand All @@ -203,9 +211,17 @@ func (c *profileClient) List(ctx context.Context, list model.ListInterface, revi
return nil, err
}

// Enumerate all service accounts, paginated.
// Enumerate matching service accounts, paginated.
listFunc = func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
return c.clientSet.CoreV1().ServiceAccounts(v1.NamespaceAll).List(ctx, opts)
if nsName != "" && saName == "" {
// We've been asked to list a particular namespace, skip
// listing service accounts.
return &v1.ServiceAccountList{}, nil
}
if saName != "" {
opts.FieldSelector = fields.OneTermEqualSelector("metadata.name", saName).String()
}
return c.clientSet.CoreV1().ServiceAccounts(nsName).List(ctx, opts)
}
convertFunc = func(r Resource) ([]*model.KVPair, error) {
sa := r.(*v1.ServiceAccount)
Expand All @@ -221,14 +237,31 @@ func (c *profileClient) List(ctx context.Context, list model.ListInterface, revi
}

// Return a merged KVPairList including both results as well as the default-allow profile.
kvps := append([]*model.KVPair{resources.DefaultAllowProfile()}, nsKVPs.KVPairs...)
var kvps []*model.KVPair
if nsName == "" {
kvps = append(kvps, resources.DefaultAllowProfile())
}
kvps = append(kvps, nsKVPs.KVPairs...)
kvps = append(kvps, saKVPs.KVPairs...)
return &model.KVPairList{
KVPairs: kvps,
Revision: c.JoinProfileRevisions(nsKVPs.Revision, saKVPs.Revision),
}, nil
}

func (c *profileClient) parseProfileName(name string) (ns, sa string, err error) {
ns, err = c.ProfileNameToNamespace(name)
if err == nil {
return
}
ns, sa, err = c.ProfileNameToServiceAccount(name)
if err == nil {
return
}
err = fmt.Errorf("profile name neither namespace or service account %s", name)
return
}

func (c *profileClient) EnsureInitialized() error {
return nil
}
Expand Down
Loading

0 comments on commit dda0f92

Please sign in to comment.