Skip to content

Commit 2ca743d

Browse files
feat: add clusterProfile status fields (#321)
* add k8version and CAData to the clusterProfile Signed-off-by: Ryan Zhang <[email protected]> * resolve go.mod Signed-off-by: Ryan Zhang <[email protected]> * fix UT Signed-off-by: Ryan Zhang <[email protected]> * fix the UT and e2e Signed-off-by: Ryan Zhang <[email protected]> * fix the race Signed-off-by: Ryan Zhang <[email protected]> --------- Signed-off-by: Ryan Zhang <[email protected]>
1 parent 2830501 commit 2ca743d

File tree

19 files changed

+820
-124
lines changed

19 files changed

+820
-124
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Implementation: Kubernetes Version Collection with TTL Caching
2+
3+
## Overview
4+
Add a `collectK8sVersion` function to the Azure property provider that collects the Kubernetes server version using the discoveryClient with a 15-minute TTL cache to minimize API calls.
5+
6+
## Plan
7+
8+
### Phase 1: Add Cache Fields
9+
**Task 1.1: Add cache-related fields to PropertyProvider struct**
10+
- Add `cachedK8sVersion` string field to store the cached version
11+
- Add `k8sVersionCacheTime` time.Time field to track when the cache was last updated
12+
- Add `k8sVersionCacheTTL` time.Duration field set to 15 minutes
13+
- Add a mutex for thread-safe access to cached values
14+
15+
### Phase 2: Implement collectK8sVersion Function
16+
**Task 2.1: Implement the collectK8sVersion function**
17+
- Check if cached version exists and is still valid (within TTL)
18+
- If cache is valid, return cached version
19+
- If cache is expired or empty, call discoveryClient.ServerVersion()
20+
- Update cache with new version and current timestamp
21+
- Return the version as a property with observation time
22+
23+
### Phase 3: Integrate into Collect Method
24+
**Task 3.1: Call collectK8sVersion in Collect method**
25+
- Add call to collectK8sVersion in the Collect method
26+
- Store the k8s version in the properties map
27+
28+
### Phase 4: Write Unit Tests
29+
**Task 4.1: Create unit tests for collectK8sVersion**
30+
- Test cache hit scenario (cached version within TTL)
31+
- Test cache miss scenario (no cached version)
32+
- Test cache expiration scenario (cached version expired)
33+
- Test error handling from discoveryClient
34+
- Test thread safety of cache access
35+
36+
### Phase 5: Verify Tests Pass
37+
**Task 5.1: Run unit tests**
38+
- Execute `go test` for the provider package
39+
- Verify all tests pass
40+
41+
## Success Criteria
42+
- [x] Cache fields added to PropertyProvider struct
43+
- [x] collectK8sVersion function implemented with TTL logic
44+
- [x] Function integrated into Collect method
45+
- [x] Unit tests created and passing
46+
- [x] Thread-safe implementation verified
47+
48+
## Implementation Notes
49+
- Using sync.RWMutex for thread-safe cache access
50+
- TTL set to 15 minutes as specified
51+
- Uses the standard `propertyprovider.K8sVersionProperty` constant instead of creating a new one
52+
- Changed `discoveryClient` field type from `discovery.DiscoveryInterface` to `discovery.ServerVersionInterface` for better testability and to only depend on the interface we actually need
53+
- Fixed test nil pointer issue by conditionally setting the discoveryClient field only when it's non-nil
54+
55+
## Final Implementation Summary
56+
All tasks completed successfully. The `collectK8sVersion` function now:
57+
1. Caches the Kubernetes version with a 15-minute TTL
58+
2. Uses thread-safe mutex locks for concurrent access
59+
3. Properly handles nil discovery client cases
60+
4. Returns early if cache is still valid to minimize API calls
61+
5. Updates cache atomically when fetching new version
62+
6. Has comprehensive unit tests covering all scenarios including cache hits, misses, expiration, errors, and concurrency
63+
64+
## Integration Test Updates
65+
Updated integration tests to ignore the new k8s version property in comparisons:
66+
- Added `ignoreK8sVersionProperty` using `cmpopts.IgnoreMapEntries` to filter out the k8s version from test expectations
67+
- Integration tests now pass successfully (33 specs all passed)
68+
- The k8s version is being collected correctly from the test Kubernetes environment, validating the implementation works end-to-end
69+
70+
## Test Results
71+
- Unit tests: ✅ 8/8 passed (7 in TestCollectK8sVersion + 1 in TestCollectK8sVersionConcurrency)
72+
- Integration tests: ✅ 33/33 specs passed
73+
- All scenarios validated including cache behavior, TTL expiration, error handling, and thread safety
74+
75+
## Refactoring
76+
Simplified the implementation by removing the `k8sVersionCacheTTL` instance field from PropertyProvider:
77+
- Removed the `k8sVersionCacheTTL time.Duration` field from the struct
78+
- Updated `collectK8sVersion` to use the `K8sVersionCacheTTL` constant directly
79+
- Removed field initialization from `New()` and `NewWithPricingProvider()` constructors
80+
- Updated unit tests to remove the field from test PropertyProvider instances
81+
- All tests still pass after refactoring ✅

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ ut-coverage.xml
3434
*~
3535

3636
.vscode/
37+
.qoder/

CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ make e2e-tests
3434

3535
# Run custom E2E tests with labels
3636
make e2e-tests-custom
37+
38+
# Clean up E2E environment
39+
make clean-e2e-tests
3740
```
3841

42+
3943
### Code Quality
4044
```bash
4145
# Run linting (required before commits)

config/crd/bases/multicluster.x-k8s.io_clusterprofiles.yaml

Lines changed: 193 additions & 29 deletions
Large diffs are not rendered by default.

go.mod

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
77
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1
88
github.com/Azure/karpenter-provider-azure v1.5.1
9-
github.com/crossplane/crossplane-runtime v1.17.0
9+
github.com/crossplane/crossplane-runtime v1.20.0
1010
github.com/evanphx/json-patch/v5 v5.9.11
1111
github.com/google/go-cmp v0.7.0
1212
github.com/onsi/ginkgo/v2 v2.23.4
@@ -24,20 +24,20 @@ require (
2424
golang.org/x/sync v0.18.0
2525
golang.org/x/time v0.11.0
2626
gomodules.xyz/jsonpatch/v2 v2.4.0
27-
k8s.io/api v0.32.3
28-
k8s.io/apiextensions-apiserver v0.32.3
29-
k8s.io/apimachinery v0.32.3
30-
k8s.io/client-go v0.32.3
31-
k8s.io/component-base v0.32.3
27+
k8s.io/api v0.34.1
28+
k8s.io/apiextensions-apiserver v0.34.1
29+
k8s.io/apimachinery v0.34.1
30+
k8s.io/client-go v0.34.1
31+
k8s.io/component-base v0.34.1
3232
k8s.io/component-helpers v0.32.3
3333
k8s.io/klog/v2 v2.130.1
3434
k8s.io/kubectl v0.32.3
3535
k8s.io/metrics v0.32.3
36-
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
36+
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
3737
sigs.k8s.io/cloud-provider-azure v1.32.4
3838
sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.20
39-
sigs.k8s.io/cluster-inventory-api v0.0.0-20240730014211-ef0154379848
40-
sigs.k8s.io/controller-runtime v0.20.4
39+
sigs.k8s.io/cluster-inventory-api v0.0.0-20251028164203-2e3fabb46733
40+
sigs.k8s.io/controller-runtime v0.21.0
4141
)
4242

4343
require (
@@ -62,22 +62,20 @@ require (
6262
github.com/blang/semver/v4 v4.0.0 // indirect
6363
github.com/cespare/xxhash/v2 v2.3.0 // indirect
6464
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
65-
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
65+
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
6666
github.com/fsnotify/fsnotify v1.9.0 // indirect
67-
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
67+
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
6868
github.com/go-errors/errors v1.4.2 // indirect
6969
github.com/go-logr/logr v1.4.3 // indirect
7070
github.com/go-logr/zapr v1.3.0 // indirect
71-
github.com/go-openapi/jsonpointer v0.21.0 // indirect
71+
github.com/go-openapi/jsonpointer v0.21.1 // indirect
7272
github.com/go-openapi/jsonreference v0.21.0 // indirect
7373
github.com/go-openapi/swag v0.23.1 // indirect
7474
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
7575
github.com/gogo/protobuf v1.3.2 // indirect
7676
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
77-
github.com/golang/protobuf v1.5.4 // indirect
7877
github.com/google/btree v1.1.3 // indirect
79-
github.com/google/gnostic-models v0.6.8 // indirect
80-
github.com/google/gofuzz v1.2.0 // indirect
78+
github.com/google/gnostic-models v0.7.0 // indirect
8179
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
8280
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
8381
github.com/google/uuid v1.6.0 // indirect
@@ -88,7 +86,7 @@ require (
8886
github.com/mailru/easyjson v0.9.0 // indirect
8987
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
9088
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
91-
github.com/modern-go/reflect2 v1.0.2 // indirect
89+
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
9290
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
9391
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
9492
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
@@ -109,10 +107,12 @@ require (
109107
go.uber.org/automaxprocs v1.6.0 // indirect
110108
go.uber.org/mock v0.5.1 // indirect
111109
go.uber.org/multierr v1.11.0 // indirect
110+
go.yaml.in/yaml/v2 v2.4.2 // indirect
111+
go.yaml.in/yaml/v3 v3.0.4 // indirect
112112
golang.org/x/crypto v0.45.0 // indirect
113113
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
114114
golang.org/x/net v0.47.0 // indirect
115-
golang.org/x/oauth2 v0.27.0 // indirect
115+
golang.org/x/oauth2 v0.29.0 // indirect
116116
golang.org/x/sys v0.38.0 // indirect
117117
golang.org/x/term v0.37.0 // indirect
118118
golang.org/x/text v0.31.0 // indirect
@@ -122,13 +122,14 @@ require (
122122
gopkg.in/inf.v0 v0.9.1 // indirect
123123
gopkg.in/yaml.v3 v3.0.1 // indirect
124124
k8s.io/cli-runtime v0.32.3 // indirect
125-
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
126-
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
125+
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
126+
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
127127
sigs.k8s.io/karpenter v1.5.0 // indirect
128128
sigs.k8s.io/kustomize/api v0.18.0 // indirect
129129
sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect
130-
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
131-
sigs.k8s.io/yaml v1.4.0 // indirect
130+
sigs.k8s.io/randfill v1.0.0 // indirect
131+
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
132+
sigs.k8s.io/yaml v1.6.0 // indirect
132133
)
133134

134135
replace (

0 commit comments

Comments
 (0)