Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: kubernetes-sigs/controller-runtime
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.15.0
Choose a base ref
...
head repository: kubernetes-sigs/controller-runtime
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.15.1
Choose a head ref
  • 8 commits
  • 11 files changed
  • 8 contributors

Commits on May 24, 2023

  1. Fix logs in unstructured client

    Poor12 authored and k8s-infra-cherrypick-robot committed May 24, 2023
    Copy the full SHA
    c9cefc7 View commit details
  2. Merge pull request #2344 from k8s-infra-cherrypick-robot/cherry-pick-…

    …2343-to-release-0.15
    
    [release-0.15] ✨Fix logs in unstructured client
    k8s-ci-robot authored May 24, 2023
    Copy the full SHA
    1a82503 View commit details
  3. [release-0.15] 🐛 fix unspecified KindsFor version (#2347)

    * Fix unspecified KindsFor version
    
    * Dont allocate empty list
    
    Co-authored-by: Alvaro Aleman <alvaroaleman@users.noreply.github.com>
    
    * Test all four relevant interface methods, and do not assert count
    
    * Attempt to format correctly in web editor
    
    * Remove request count asserts
    
    * Remove non-version item asserts
    
    ---------
    
    Co-authored-by: Amund Tenstad <github@amund.io>
    Co-authored-by: Alvaro Aleman <alvaroaleman@users.noreply.github.com>
    3 people authored May 24, 2023
    Copy the full SHA
    530dde0 View commit details

Commits on Jun 11, 2023

  1. 🐛 fakeClient.Status().Update(...) cannot recognize resource version c…

    …onflicts
    
    The fake client of subresource is unable to correctly handle the case of
    resource version conflict when updating. The phenomenon is that it did
    not return a 409 status error.
    
    Signed-off-by: iiiceoo <iiiceoo@foxmail.com>
    iiiceoo authored and k8s-infra-cherrypick-robot committed Jun 11, 2023
    Copy the full SHA
    37c58ae View commit details
  2. Merge pull request #2372 from k8s-infra-cherrypick-robot/cherry-pick-…

    …2365-to-release-0.15
    
    [release-0.15] 🐛 fakeClient.Status().Update(...) cannot recognize resource version conflicts
    k8s-ci-robot authored Jun 11, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    111c938 View commit details

Commits on Jun 12, 2023

  1. [release-0.15] 🐛 hasLabels and matchingLabels step on each other (#2373)

    * fix: hasLabels and matchingLabels step on each other
    
    * remove testcase with invalid input
    
    ---------
    
    Co-authored-by: Shanshan.Ying <shanshan.ying@apecloud.com>
    k8s-infra-cherrypick-robot and shanshanying authored Jun 12, 2023
    Copy the full SHA
    0e37217 View commit details

Commits on Aug 4, 2023

  1. 🐛 Fix Defaulting of the User Agent

    This broke when we added the HTTP client, because the user-agent gets
    set by a roundtripper that is constructed within `rest.HTTPClientFor`.
    As a result, we have to default it before we do that. Currently, it ends
    up being defaulted to `Go-http-client` which is not very useful.
    alvaroaleman committed Aug 4, 2023
    Copy the full SHA
    3de9624 View commit details
  2. Merge pull request #2436 from alvaroaleman/fix-ua-3

    [release-0.15] 🐛 Fix Defaulting of the User Agent
    k8s-ci-robot authored Aug 4, 2023
    Copy the full SHA
    40203bf View commit details
5 changes: 5 additions & 0 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
@@ -236,6 +236,11 @@ func New(config *rest.Config, opts Options) (Cache, error) {
}

func defaultOpts(config *rest.Config, opts Options) (Options, error) {
config = rest.CopyConfig(config)
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}

logger := log.WithName("setup")

// Use the rest HTTP client for the provided config if unset
6 changes: 6 additions & 0 deletions pkg/client/apiutil/restmapper.go
Original file line number Diff line number Diff line change
@@ -152,6 +152,12 @@ func (m *mapper) getMapper() meta.RESTMapper {
// addKnownGroupAndReload reloads the mapper with updated information about missing API group.
// versions can be specified for partial updates, for instance for v1beta1 version only.
func (m *mapper) addKnownGroupAndReload(groupName string, versions ...string) error {
// versions will here be [""] if the forwarded Version value of
// GroupVersionResource (in calling method) was not specified.
if len(versions) == 1 && versions[0] == "" {
versions = nil
}

// If no specific versions are set by user, we will scan all available ones for the API group.
// This operation requires 2 requests: /api and /apis, but only once. For all subsequent calls
// this data will be taken from cache.
28 changes: 28 additions & 0 deletions pkg/client/apiutil/restmapper_test.go
Original file line number Diff line number Diff line change
@@ -404,6 +404,34 @@ func TestLazyRestMapperProvider(t *testing.T) {
g.Expect(crt.GetRequestCount()).To(gmg.Equal(6))
})

t.Run("LazyRESTMapper should work correctly if the version isn't specified", func(t *testing.T) {
g := gmg.NewWithT(t)

httpClient, err := rest.HTTPClientFor(restCfg)
g.Expect(err).NotTo(gmg.HaveOccurred())

lazyRestMapper, err := apiutil.NewDynamicRESTMapper(restCfg, httpClient)
g.Expect(err).NotTo(gmg.HaveOccurred())

kind, err := lazyRestMapper.KindFor(schema.GroupVersionResource{Group: "networking.k8s.io", Resource: "ingress"})
g.Expect(err).NotTo(gmg.HaveOccurred())
g.Expect(kind.Version).ToNot(gmg.BeEmpty())

kinds, err := lazyRestMapper.KindsFor(schema.GroupVersionResource{Group: "authentication.k8s.io", Resource: "tokenreviews"})
g.Expect(err).NotTo(gmg.HaveOccurred())
g.Expect(kinds).ToNot(gmg.BeEmpty())
g.Expect(kinds[0].Version).ToNot(gmg.BeEmpty())

resorce, err := lazyRestMapper.ResourceFor(schema.GroupVersionResource{Group: "scheduling.k8s.io", Resource: "priorityclasses"})
g.Expect(err).NotTo(gmg.HaveOccurred())
g.Expect(resorce.Version).ToNot(gmg.BeEmpty())

resorces, err := lazyRestMapper.ResourcesFor(schema.GroupVersionResource{Group: "policy", Resource: "poddisruptionbudgets"})
g.Expect(err).NotTo(gmg.HaveOccurred())
g.Expect(kinds).ToNot(gmg.BeEmpty())
g.Expect(resorces[0].Version).ToNot(gmg.BeEmpty())
})

t.Run("LazyRESTMapper can fetch CRDs if they were created at runtime", func(t *testing.T) {
g := gmg.NewWithT(t)

8 changes: 6 additions & 2 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
@@ -110,14 +110,18 @@ func newClient(config *rest.Config, options Options) (*client, error) {
return nil, fmt.Errorf("must provide non-nil rest.Config to client.New")
}

config = rest.CopyConfig(config)
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}

if !options.WarningHandler.SuppressWarnings {
// surface warnings
logger := log.Log.WithName("KubeAPIWarningLogger")
// Set a WarningHandler, the default WarningHandler
// is log.KubeAPIWarningLogger with deduplication enabled.
// See log.KubeAPIWarningLoggerOptions for considerations
// regarding deduplication.
config = rest.CopyConfig(config)
config.WarningHandler = log.NewKubeAPIWarningLogger(
logger,
log.KubeAPIWarningLoggerOptions{
@@ -160,7 +164,7 @@ func newClient(config *rest.Config, options Options) (*client, error) {
unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
}

rawMetaClient, err := metadata.NewForConfigAndClient(config, options.HTTPClient)
rawMetaClient, err := metadata.NewForConfigAndClient(metadata.ConfigFor(config), options.HTTPClient)
if err != nil {
return nil, fmt.Errorf("unable to construct metadata-only client for use as part of client: %w", err)
}
4 changes: 2 additions & 2 deletions pkg/client/fake/client.go
Original file line number Diff line number Diff line change
@@ -992,11 +992,11 @@ func copyNonStatusFrom(old, new runtime.Object) error {
}
}

newClientObject.SetResourceVersion(rv)

if err := fromMapStringAny(newMapStringAny, new); err != nil {
return fmt.Errorf("failed to convert back from map[string]any: %w", err)
}
newClientObject.SetResourceVersion(rv)

return nil
}

5 changes: 3 additions & 2 deletions pkg/client/fake/client_test.go
Original file line number Diff line number Diff line change
@@ -1431,14 +1431,15 @@ var _ = Describe("Fake client", func() {
It("should return a conflict error when an incorrect RV is used on status update", func() {
obj := &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node",
Name: "node",
ResourceVersion: trackerAddResourceVersion,
},
}
cl := NewClientBuilder().WithStatusSubresource(obj).WithObjects(obj).Build()

obj.Status.Phase = corev1.NodeRunning
obj.ResourceVersion = "invalid"
err := cl.Update(context.Background(), obj)
err := cl.Status().Update(context.Background(), obj)
Expect(apierrors.IsConflict(err)).To(BeTrue())
})

20 changes: 15 additions & 5 deletions pkg/client/options.go
Original file line number Diff line number Diff line change
@@ -513,8 +513,15 @@ type MatchingLabels map[string]string
// ApplyToList applies this configuration to the given list options.
func (m MatchingLabels) ApplyToList(opts *ListOptions) {
// TODO(directxman12): can we avoid reserializing this over and over?
sel := labels.SelectorFromValidatedSet(map[string]string(m))
opts.LabelSelector = sel
if opts.LabelSelector == nil {
opts.LabelSelector = labels.NewSelector()
}
// If there's already a selector, we need to AND the two together.
noValidSel := labels.SelectorFromValidatedSet(map[string]string(m))
reqs, _ := noValidSel.Requirements()
for _, req := range reqs {
opts.LabelSelector = opts.LabelSelector.Add(req)
}
}

// ApplyToDeleteAllOf applies this configuration to the given an List options.
@@ -528,14 +535,17 @@ type HasLabels []string

// ApplyToList applies this configuration to the given list options.
func (m HasLabels) ApplyToList(opts *ListOptions) {
sel := labels.NewSelector()
if opts.LabelSelector == nil {
opts.LabelSelector = labels.NewSelector()
}
// TODO: ignore invalid labels will result in an empty selector.
// This is inconsistent to the that of MatchingLabels.
for _, label := range m {
r, err := labels.NewRequirement(label, selection.Exists, nil)
if err == nil {
sel = sel.Add(*r)
opts.LabelSelector = opts.LabelSelector.Add(*r)
}
}
opts.LabelSelector = sel
}

// ApplyToDeleteAllOf applies this configuration to the given an List options.
45 changes: 45 additions & 0 deletions pkg/client/options_test.go
Original file line number Diff line number Diff line change
@@ -237,6 +237,19 @@ var _ = Describe("MatchingLabels", func() {
expectedErrMsg := `values[0][k]: Invalid value: "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui": must be no more than 63 characters`
Expect(err.Error()).To(Equal(expectedErrMsg))
})

It("Should add matchingLabels to existing selector", func() {
listOpts := &client.ListOptions{}

matchingLabels := client.MatchingLabels(map[string]string{"k": "v"})
matchingLabels2 := client.MatchingLabels(map[string]string{"k2": "v2"})

matchingLabels.ApplyToList(listOpts)
Expect(listOpts.LabelSelector.String()).To(Equal("k=v"))

matchingLabels2.ApplyToList(listOpts)
Expect(listOpts.LabelSelector.String()).To(Equal("k=v,k2=v2"))
})
})

var _ = Describe("FieldOwner", func() {
@@ -292,3 +305,35 @@ var _ = Describe("ForceOwnership", func() {
Expect(*o.Force).To(Equal(true))
})
})

var _ = Describe("HasLabels", func() {
It("Should produce hasLabels in given order", func() {
listOpts := &client.ListOptions{}

hasLabels := client.HasLabels([]string{"labelApe", "labelFox"})
hasLabels.ApplyToList(listOpts)
Expect(listOpts.LabelSelector.String()).To(Equal("labelApe,labelFox"))
})

It("Should add hasLabels to existing hasLabels selector", func() {
listOpts := &client.ListOptions{}

hasLabel := client.HasLabels([]string{"labelApe"})
hasLabel.ApplyToList(listOpts)

hasOtherLabel := client.HasLabels([]string{"labelFox"})
hasOtherLabel.ApplyToList(listOpts)
Expect(listOpts.LabelSelector.String()).To(Equal("labelApe,labelFox"))
})

It("Should add hasLabels to existing matchingLabels", func() {
listOpts := &client.ListOptions{}

matchingLabels := client.MatchingLabels(map[string]string{"k": "v"})
matchingLabels.ApplyToList(listOpts)

hasLabel := client.HasLabels([]string{"labelApe"})
hasLabel.ApplyToList(listOpts)
Expect(listOpts.LabelSelector.String()).To(Equal("k=v,labelApe"))
})
})
8 changes: 4 additions & 4 deletions pkg/client/unstructured_client.go
Original file line number Diff line number Diff line change
@@ -224,11 +224,11 @@ func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...

func (uc *unstructuredClient) GetSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceGetOption) error {
if _, ok := obj.(runtime.Unstructured); !ok {
return fmt.Errorf("unstructured client did not understand object: %T", subResource)
return fmt.Errorf("unstructured client did not understand object: %T", obj)
}

if _, ok := subResourceObj.(runtime.Unstructured); !ok {
return fmt.Errorf("unstructured client did not understand object: %T", obj)
return fmt.Errorf("unstructured client did not understand object: %T", subResourceObj)
}

if subResourceObj.GetName() == "" {
@@ -255,11 +255,11 @@ func (uc *unstructuredClient) GetSubResource(ctx context.Context, obj, subResour

func (uc *unstructuredClient) CreateSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceCreateOption) error {
if _, ok := obj.(runtime.Unstructured); !ok {
return fmt.Errorf("unstructured client did not understand object: %T", subResourceObj)
return fmt.Errorf("unstructured client did not understand object: %T", obj)
}

if _, ok := subResourceObj.(runtime.Unstructured); !ok {
return fmt.Errorf("unstructured client did not understand object: %T", obj)
return fmt.Errorf("unstructured client did not understand object: %T", subResourceObj)
}

if subResourceObj.GetName() == "" {
9 changes: 8 additions & 1 deletion pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
@@ -179,6 +179,13 @@ func New(config *rest.Config, opts ...Option) (Cluster, error) {
return nil, errors.New("must specify Config")
}

originalConfig := config

config = rest.CopyConfig(config)
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}

options := Options{}
for _, opt := range opts {
opt(&options)
@@ -275,7 +282,7 @@ func New(config *rest.Config, opts ...Option) (Cluster, error) {
}

return &cluster{
config: config,
config: originalConfig,
httpClient: options.HTTPClient,
scheme: options.Scheme,
cache: cache,
9 changes: 9 additions & 0 deletions pkg/manager/manager.go
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ package manager
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
@@ -391,6 +392,9 @@ type LeaderElectionRunnable interface {

// New returns a new Manager for creating Controllers.
func New(config *rest.Config, options Options) (Manager, error) {
if config == nil {
return nil, errors.New("must specify Config")
}
// Set default values for options fields
options = setOptionsDefaults(options)

@@ -412,6 +416,11 @@ func New(config *rest.Config, options Options) (Manager, error) {
return nil, err
}

config = rest.CopyConfig(config)
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}

// Create the recorder provider to inject event recorders for the components.
// TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific
// to the particular controller that it's being injected into, rather than a generic one like is here.