Skip to content

Commit 4551230

Browse files
clusterctl wait inventory crd
1 parent 0a9b0fd commit 4551230

File tree

6 files changed

+86
-17
lines changed

6 files changed

+86
-17
lines changed

cmd/clusterctl/pkg/client/client_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ package client
1818

1919
import (
2020
"testing"
21+
"time"
2122

2223
"github.com/pkg/errors"
2324
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/apimachinery/pkg/util/wait"
2426
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
2527
"sigs.k8s.io/cluster-api/cmd/clusterctl/pkg/client/cluster"
2628
"sigs.k8s.io/cluster-api/cmd/clusterctl/pkg/client/config"
@@ -140,7 +142,11 @@ func (f *fakeClient) WithRepository(repositoryClient repository.Client) *fakeCli
140142
func newFakeCluster(kubeconfig string) *fakeClusterClient {
141143
fakeProxy := test.NewFakeProxy()
142144

143-
client := cluster.New("", cluster.InjectProxy(fakeProxy))
145+
pollImmediateWaiter := func(interval, timeout time.Duration, condition wait.ConditionFunc) error {
146+
return nil
147+
}
148+
149+
client := cluster.New("", cluster.InjectProxy(fakeProxy), cluster.InjectPollImmediateWaiter(pollImmediateWaiter))
144150

145151
return &fakeClusterClient{
146152
kubeconfig: kubeconfig,

cmd/clusterctl/pkg/client/cluster/cert_manager.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"github.com/pkg/errors"
2323
apierrors "k8s.io/apimachinery/pkg/api/errors"
2424
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
25-
"k8s.io/apimachinery/pkg/util/wait"
2625
"k8s.io/klog"
2726
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
2827
"sigs.k8s.io/cluster-api/cmd/clusterctl/config"
@@ -46,16 +45,18 @@ type CertMangerClient interface {
4645

4746
// certMangerClient implements CertMangerClient .
4847
type certMangerClient struct {
49-
proxy Proxy
48+
proxy Proxy
49+
pollImmediateWaiter PollImmediateWaiter
5050
}
5151

5252
// Ensure certMangerClient implements the CertMangerClient interface.
5353
var _ CertMangerClient = &certMangerClient{}
5454

5555
// newCertMangerClient returns a certMangerClient.
56-
func newCertMangerClient(proxy Proxy) *certMangerClient {
56+
func newCertMangerClient(proxy Proxy, pollImmediateWaiter PollImmediateWaiter) *certMangerClient {
5757
return &certMangerClient{
58-
proxy: proxy,
58+
proxy: proxy,
59+
pollImmediateWaiter: pollImmediateWaiter,
5960
}
6061
}
6162

@@ -109,7 +110,7 @@ func (cm *certMangerClient) EnsureWebHook() error {
109110
}
110111

111112
// Waits for for the cert-manager WebHook to be available.
112-
if err := wait.PollImmediate(waitCertManagerInterval, waitCertManagerTimeout, func() (bool, error) {
113+
if err := cm.pollImmediateWaiter(waitCertManagerInterval, waitCertManagerTimeout, func() (bool, error) {
113114
webHook, err := cm.getWebHook(c)
114115
if err != nil {
115116
return false, errors.Wrap(err, "failed to get the cert-manager WebHook")

cmd/clusterctl/pkg/client/cluster/client.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ package cluster
1818

1919
import (
2020
"context"
21+
"time"
2122

2223
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
24+
"k8s.io/apimachinery/pkg/util/wait"
2325
"k8s.io/klog/klogr"
2426
"sigs.k8s.io/cluster-api/cmd/clusterctl/pkg/client/config"
2527
"sigs.k8s.io/cluster-api/cmd/clusterctl/pkg/client/repository"
@@ -68,11 +70,15 @@ type Client interface {
6870
ObjectMover() ObjectMover
6971
}
7072

73+
// PollImmediateWaiter tries a condition func until it returns true, an error, or the timeout is reached.
74+
type PollImmediateWaiter func(interval, timeout time.Duration, condition wait.ConditionFunc) error
75+
7176
// clusterClient implements Client.
7277
type clusterClient struct {
7378
kubeconfig string
7479
proxy Proxy
7580
repositoryClientFactory RepositoryClientFactory
81+
pollImmediateWaiter PollImmediateWaiter
7682
}
7783

7884
type RepositoryClientFactory func(provider config.Provider, configVariablesClient config.VariablesClient, options ...repository.Option) (repository.Client, error)
@@ -89,15 +95,15 @@ func (c *clusterClient) Proxy() Proxy {
8995
}
9096

9197
func (c *clusterClient) CertManger() CertMangerClient {
92-
return newCertMangerClient(c.proxy)
98+
return newCertMangerClient(c.proxy, c.pollImmediateWaiter)
9399
}
94100

95101
func (c *clusterClient) ProviderComponents() ComponentsClient {
96102
return newComponentsClient(c.proxy)
97103
}
98104

99105
func (c *clusterClient) ProviderInventory() InventoryClient {
100-
return newInventoryClient(c.proxy)
106+
return newInventoryClient(c.proxy, c.pollImmediateWaiter)
101107
}
102108

103109
func (c *clusterClient) ProviderObjects() ObjectsClient {
@@ -118,6 +124,7 @@ func (c *clusterClient) ObjectMover() ObjectMover {
118124
type NewOptions struct {
119125
injectProxy Proxy
120126
injectRepositoryClientFactory RepositoryClientFactory
127+
injectPollImmediateWaiter PollImmediateWaiter
121128
}
122129

123130
// Option is a configuration option supplied to New
@@ -138,6 +145,13 @@ func InjectRepositoryFactory(factory RepositoryClientFactory) Option {
138145
}
139146
}
140147

148+
// InjectPollImmediateWaiter implements a New Option that allows to override the default PollImmediateWaiter used by clusterctl.
149+
func InjectPollImmediateWaiter(pollImmediateWaiter PollImmediateWaiter) Option {
150+
return func(c *NewOptions) {
151+
c.injectPollImmediateWaiter = pollImmediateWaiter
152+
}
153+
}
154+
141155
// New returns a cluster.Client.
142156
func New(kubeconfig string, options ...Option) Client {
143157
return newClusterClient(kubeconfig, options...)
@@ -161,10 +175,17 @@ func newClusterClient(kubeconfig string, options ...Option) *clusterClient {
161175
repositoryClientFactory = repository.New
162176
}
163177

178+
// if there is an injected PollImmediateWaiter, use it, otherwise use the default one
179+
pollImmediateWaiter := cfg.injectPollImmediateWaiter
180+
if pollImmediateWaiter == nil {
181+
pollImmediateWaiter = wait.PollImmediate
182+
}
183+
164184
return &clusterClient{
165185
kubeconfig: kubeconfig,
166186
proxy: proxy,
167187
repositoryClientFactory: repositoryClientFactory,
188+
pollImmediateWaiter: pollImmediateWaiter,
168189
}
169190
}
170191

cmd/clusterctl/pkg/client/cluster/inventory.go

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ limitations under the License.
1717
package cluster
1818

1919
import (
20+
"time"
21+
2022
"github.com/pkg/errors"
23+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
2124
apierrors "k8s.io/apimachinery/pkg/api/errors"
2225
apimeta "k8s.io/apimachinery/pkg/api/meta"
2326
"k8s.io/apimachinery/pkg/util/sets"
@@ -28,7 +31,12 @@ import (
2831
"sigs.k8s.io/controller-runtime/pkg/client"
2932
)
3033

31-
const embeddedCustomResourceDefinitionPath = "cmd/clusterctl/config/manifest/clusterctl-api.yaml"
34+
const (
35+
embeddedCustomResourceDefinitionPath = "cmd/clusterctl/config/manifest/clusterctl-api.yaml"
36+
37+
waitInventoryCRDInterval = 250 * time.Millisecond
38+
waitInventoryCRDTimeout = 1 * time.Minute
39+
)
3240

3341
// InventoryClient exposes methods to interface with a cluster's provider inventory.
3442
type InventoryClient interface {
@@ -76,16 +84,18 @@ type ManagementGroup struct {
7684

7785
// inventoryClient implements InventoryClient.
7886
type inventoryClient struct {
79-
proxy Proxy
87+
proxy Proxy
88+
pollImmediateWaiter PollImmediateWaiter
8089
}
8190

8291
// ensure inventoryClient implements InventoryClient.
8392
var _ InventoryClient = &inventoryClient{}
8493

8594
// newInventoryClient returns a inventoryClient.
86-
func newInventoryClient(proxy Proxy) *inventoryClient {
95+
func newInventoryClient(proxy Proxy, pollImmediateWaiter PollImmediateWaiter) *inventoryClient {
8796
return &inventoryClient{
88-
proxy: proxy,
97+
proxy: proxy,
98+
pollImmediateWaiter: pollImmediateWaiter,
8999
}
90100
}
91101

@@ -116,7 +126,8 @@ func (p *inventoryClient) EnsureCustomResourceDefinitions() error {
116126
}
117127

118128
// Install the CRDs.
119-
for _, o := range objs {
129+
for i := range objs {
130+
o := objs[i]
120131
klog.V(3).Infof("Creating: %s, %s/%s", o.GroupVersionKind(), o.GetNamespace(), o.GetName())
121132

122133
labels := o.GetLabels()
@@ -126,12 +137,36 @@ func (p *inventoryClient) EnsureCustomResourceDefinitions() error {
126137
labels[clusterctlv1.ClusterctlCoreLabelName] = "inventory"
127138
o.SetLabels(labels)
128139

129-
if err := c.Create(ctx, o.DeepCopy()); err != nil {
140+
if err := c.Create(ctx, &o); err != nil {
130141
if apierrors.IsAlreadyExists(err) {
131142
continue
132143
}
133144
return errors.Wrapf(err, "failed to create clusterctl inventory CRDs component: %s, %s/%s", o.GroupVersionKind(), o.GetNamespace(), o.GetName())
134145
}
146+
147+
// If the object is a CRDs, waits for it being Established.
148+
if apiextensionsv1.SchemeGroupVersion.WithKind("CustomResourceDefinition").GroupKind() == o.GroupVersionKind().GroupKind() {
149+
crdKey, err := client.ObjectKeyFromObject(&o)
150+
if err != nil {
151+
return nil
152+
}
153+
154+
if err := p.pollImmediateWaiter(waitInventoryCRDInterval, waitInventoryCRDTimeout, func() (bool, error) {
155+
crd := &apiextensionsv1.CustomResourceDefinition{}
156+
if err := c.Get(ctx, crdKey, crd); err != nil {
157+
return false, err
158+
}
159+
160+
for _, c := range crd.Status.Conditions {
161+
if c.Type == apiextensionsv1.Established && c.Status == apiextensionsv1.ConditionTrue {
162+
return true, nil
163+
}
164+
}
165+
return false, nil
166+
}); err != nil {
167+
return errors.Wrapf(err, "failed to scale deployment")
168+
}
169+
}
135170
}
136171

137172
return nil

cmd/clusterctl/pkg/client/cluster/inventory_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,19 @@ package cluster
1919
import (
2020
"reflect"
2121
"testing"
22+
"time"
2223

2324
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2425
"k8s.io/apimachinery/pkg/runtime"
26+
"k8s.io/apimachinery/pkg/util/wait"
2527
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
2628
"sigs.k8s.io/cluster-api/cmd/clusterctl/pkg/internal/test"
2729
)
2830

31+
func fakePollImmediateWaiter(interval, timeout time.Duration, condition wait.ConditionFunc) error {
32+
return nil
33+
}
34+
2935
func Test_inventoryClient_EnsureCustomResourceDefinitions(t *testing.T) {
3036
type fields struct {
3137
alreadyHasCRD bool
@@ -52,7 +58,7 @@ func Test_inventoryClient_EnsureCustomResourceDefinitions(t *testing.T) {
5258
}
5359
for _, tt := range tests {
5460
t.Run(tt.name, func(t *testing.T) {
55-
p := newInventoryClient(test.NewFakeProxy())
61+
p := newInventoryClient(test.NewFakeProxy(), fakePollImmediateWaiter)
5662
if tt.fields.alreadyHasCRD {
5763
//forcing creation of metadata before test
5864
if err := p.EnsureCustomResourceDefinitions(); err != nil {
@@ -97,7 +103,7 @@ func Test_inventoryClient_List(t *testing.T) {
97103
}
98104
for _, tt := range tests {
99105
t.Run(tt.name, func(t *testing.T) {
100-
p := newInventoryClient(test.NewFakeProxy().WithObjs(tt.fields.initObjs...))
106+
p := newInventoryClient(test.NewFakeProxy().WithObjs(tt.fields.initObjs...), fakePollImmediateWaiter)
101107
got, err := p.List()
102108
if (err != nil) != tt.wantErr {
103109
t.Errorf("List() error = %v, wantErr %v", err, tt.wantErr)

cmd/clusterctl/pkg/client/cluster/upgrader_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ func Test_providerUpgrader_Plan(t *testing.T) {
426426
repositoryClientFactory: func(provider config.Provider, configVariablesClient config.VariablesClient, options ...repository.Option) (repository.Client, error) {
427427
return repository.New(provider, configVariablesClient, repository.InjectRepository(tt.fields.repository[provider.Name()]))
428428
},
429-
providerInventory: newInventoryClient(tt.fields.proxy),
429+
providerInventory: newInventoryClient(tt.fields.proxy, nil),
430430
}
431431
got, err := u.Plan()
432432
if (err != nil) != tt.wantErr {

0 commit comments

Comments
 (0)