Skip to content

Commit 7c3af36

Browse files
chore: backport (Feb 24, 2026) (#1259)
2 parents 12a125e + a855052 commit 7c3af36

22 files changed

Lines changed: 1197 additions & 108 deletions

File tree

.github/workflows/chart.yml

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ name: Helm Chart Publisher
22

33
on:
44
push:
5-
branches:
6-
- main
7-
paths:
8-
- ".github/workflows/chart.yml"
9-
- "charts/**"
10-
create:
11-
# Publish semver tags as releases.
12-
tags: [ 'v*.*.*' ]
13-
5+
tags:
6+
- "v*.*.*"
7+
workflow_dispatch:
8+
inputs:
9+
tag:
10+
description: "Release tag (e.g., v1.0.0)"
11+
required: true
12+
type: string
1413
permissions:
1514
contents: write
1615
packages: write
@@ -19,7 +18,13 @@ env:
1918
REGISTRY: ghcr.io
2019

2120
jobs:
21+
export-registry:
22+
uses: ./.github/workflows/setup-release.yml
23+
with:
24+
tag: ${{ inputs.tag || github.ref_name }}
25+
2226
publish-github-pages:
27+
needs: export-registry
2328
runs-on: ubuntu-latest
2429
steps:
2530
- uses: actions/checkout@v6.0.2
@@ -35,51 +40,48 @@ jobs:
3540
linting: on
3641

3742
publish-oci:
43+
needs: export-registry
3844
runs-on: ubuntu-latest
3945
steps:
4046
- name: Checkout code
4147
uses: actions/checkout@v6.0.2
4248

4349
- name: Login to GitHub Container Registry
44-
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
50+
uses: docker/login-action@v3.6.0
4551
with:
4652
registry: ${{ env.REGISTRY }}
4753
username: ${{ github.actor }}
4854
password: ${{ secrets.GITHUB_TOKEN }}
4955

50-
- name: Package and push Helm charts to GHCR
56+
- name: Package and push Helm charts to GHCR via Makefile
5157
run: |
5258
set -euo pipefail
53-
54-
# Convert repository name to lowercase for OCI registry
55-
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
56-
57-
# Determine version to use
58-
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
59-
# Use release tag as version (strip 'v' prefix)
60-
CHART_VERSION=${GITHUB_REF#refs/tags/v}
61-
echo "Using release tag version: ${CHART_VERSION}"
62-
else
63-
# Use version from Chart.yaml for non-tag pushes
64-
CHART_VERSION=$(grep '^version:' charts/hub-agent/Chart.yaml | awk '{print $2}')
65-
echo "Using Chart.yaml version: ${CHART_VERSION}"
66-
fi
67-
68-
# Package and push hub-agent chart
69-
echo "📦 Packaging hub-agent chart..."
70-
helm package charts/hub-agent --version ${CHART_VERSION} --app-version ${CHART_VERSION}
71-
72-
echo "🚀 Pushing hub-agent to OCI registry..."
73-
helm push hub-agent-${CHART_VERSION}.tgz oci://${{ env.REGISTRY }}/${REPO_LOWER}/charts
74-
75-
# Package and push member-agent chart
76-
echo "📦 Packaging member-agent chart..."
77-
helm package charts/member-agent --version ${CHART_VERSION} --app-version ${CHART_VERSION}
78-
79-
echo "🚀 Pushing member-agent to OCI registry..."
80-
helm push member-agent-${CHART_VERSION}.tgz oci://${{ env.REGISTRY }}/${REPO_LOWER}/charts
81-
82-
echo ""
83-
echo "✅ Helm charts published to OCI registry!"
84-
echo "📍 Hub Agent: oci://${{ env.REGISTRY }}/${REPO_LOWER}/charts/hub-agent:${CHART_VERSION}"
85-
echo "📍 Member Agent: oci://${{ env.REGISTRY }}/${REPO_LOWER}/charts/member-agent:${CHART_VERSION}"
59+
60+
RELEASE_VERSION="${{ needs.export-registry.outputs.version }}"
61+
62+
OCI_REGISTRY="${{ needs.export-registry.outputs.registry }}/charts"
63+
make helm-push REGISTRY="${OCI_REGISTRY}" TAG="${RELEASE_VERSION}"
64+
65+
- name: Verify chart appVersion matches release tag
66+
run: |
67+
set -euo pipefail
68+
69+
RELEASE_VERSION="${{ needs.export-registry.outputs.version }}"
70+
CHART_VERSION="${RELEASE_VERSION}"
71+
EXPECTED_APP_VERSION="${RELEASE_VERSION}"
72+
73+
rm -rf .helm-verify
74+
mkdir -p .helm-verify
75+
76+
for chart in hub-agent member-agent; do
77+
helm pull "oci://${{ needs.export-registry.outputs.registry }}/charts/${chart}" --version "${CHART_VERSION}" --destination .helm-verify >/dev/null
78+
packaged=".helm-verify/${chart}-${CHART_VERSION}.tgz"
79+
actual_app_version=$(tar -xOf "${packaged}" "${chart}/Chart.yaml" | awk -F': ' '/^appVersion:/ {gsub(/"/, "", $2); print $2}')
80+
if [[ "${actual_app_version}" != "${EXPECTED_APP_VERSION}" ]]; then
81+
echo "ERROR: ${chart} appVersion (${actual_app_version}) does not match release tag (${EXPECTED_APP_VERSION})"
82+
exit 1
83+
fi
84+
echo "✅ ${chart} appVersion=${actual_app_version} matches release tag=${EXPECTED_APP_VERSION}"
85+
done
86+
87+
rm -rf .helm-verify
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Setup Release
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
tag:
7+
description: "Release tag (e.g., v1.0.0)"
8+
required: true
9+
type: string
10+
outputs:
11+
registry:
12+
description: "OCI registry repository path (e.g., ghcr.io/org/repo)"
13+
value: ${{ jobs.export.outputs.registry }}
14+
tag:
15+
description: "Release tag (e.g., v1.0.0)"
16+
value: ${{ jobs.export.outputs.tag }}
17+
version:
18+
description: "Release version without v prefix (e.g., 1.0.0)"
19+
value: ${{ jobs.export.outputs.version }}
20+
21+
env:
22+
REGISTRY: ghcr.io
23+
24+
jobs:
25+
export:
26+
runs-on: ubuntu-latest
27+
outputs:
28+
registry: ${{ steps.setup.outputs.registry }}
29+
tag: ${{ steps.setup.outputs.tag }}
30+
version: ${{ steps.setup.outputs.version }}
31+
steps:
32+
- id: setup
33+
run: |
34+
TAG="${{ inputs.tag }}"
35+
if [[ ! "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then
36+
echo "Error: Invalid release tag '${TAG}'. Expected format: v*.*.*"
37+
exit 1
38+
fi
39+
40+
# registry must be in lowercase
41+
echo "registry=$(echo "${{ env.REGISTRY }}/${{ github.repository }}" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
42+
echo "tag=${TAG}" >> $GITHUB_OUTPUT
43+
echo "version=${TAG#v}" >> $GITHUB_OUTPUT
44+
echo "Release tag: ${TAG}, version: ${TAG#v}"

apis/cluster/v1beta1/internalmembercluster_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ type InternalMemberClusterStatus struct {
7575
// +optional
7676
ResourceUsage ResourceUsage `json:"resourceUsage,omitempty"`
7777

78+
// Namespaces is a map of namespace names to their associated work names for namespaces
79+
// that are managed by Fleet (i.e., have AppliedWork owner references when created).
80+
// The key is the namespace name and the value is the work name from the AppliedWork owner reference.
81+
// If the namespace does not have an AppliedWork owner reference, the value will be an empty string.
82+
// This field is populated by the property provider when namespace collection is enabled.
83+
// +optional
84+
Namespaces map[string]string `json:"namespaces,omitempty"`
85+
7886
// AgentStatus is an array of current observed status, each corresponding to one member agent running in the member cluster.
7987
// +optional
8088
AgentStatus []AgentStatus `json:"agentStatus,omitempty"`

apis/cluster/v1beta1/zz_generated.deepcopy.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/hub-agent/README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,10 @@ _See [helm install](https://helm.sh/docs/helm/helm_install/) for command documen
8989
| Parameter | Description | Default |
9090
|:------------------------------------------|:------------------------------------------------------------------------------------------|:-------------------------------------------------|
9191
| `replicaCount` | Number of hub-agent replicas to deploy | `1` |
92-
| `image.repository` | Image repository | `ghcr.io/azure/azure/fleet/hub-agent` |
92+
| `image.repository` | Image repository | `ghcr.io/kubefleet-dev/kubefleet/hub-agent` |
9393
| `image.pullPolicy` | Image pull policy | `Always` |
94-
| `image.tag` | Image release tag | `v0.1.0` |
94+
| `image.tag` | Image release tag (empty uses chart `appVersion`) | `""` |
9595
| `namespace` | Namespace where this chart is installed | `fleet-system` |
96-
| `serviceAccount.create` | Whether to create a service account | `true` |
97-
| `serviceAccount.name` | Service account name | `hub-agent-sa` |
9896
| `resources` | Resource requests/limits for the container | limits: 500m CPU, 1Gi; requests: 100m CPU, 128Mi |
9997
| `affinity` | Node affinity for hub-agent pods | `{}` |
10098
| `tolerations` | Tolerations for hub-agent pods | `[]` |
@@ -103,15 +101,22 @@ _See [helm install](https://helm.sh/docs/helm/helm_install/) for command documen
103101
| `webhookServiceName` | Webhook service name | `fleetwebhook` |
104102
| `enableGuardRail` | Enable guard rail webhook configurations | `true` |
105103
| `webhookClientConnectionType` | Connection type for webhook client (service or url) | `service` |
106-
| `useCertManager` | Use cert-manager for webhook certificate management (requires `enableWorkload=true`) | `false` |
107-
| `webhookCertSecretName` | Name of the Secret where cert-manager stores the certificate | `fleet-webhook-server-cert` |
104+
| `useCertManager` | Use cert-manager for webhook certificate management (requires `enableWorkload=true`) | `false` |
105+
| `webhookCertSecretName` | Name of the Secret where cert-manager stores the certificate (required when enabled) | `unset` |
108106
| `enableV1Beta1APIs` | Watch for v1beta1 APIs | `true` |
107+
| `enableClusterInventoryAPI` | Enable cluster inventory APIs | `true` |
108+
| `enableStagedUpdateRunAPIs` | Enable staged update run APIs | `true` |
109+
| `enableEvictionAPIs` | Enable eviction APIs | `true` |
110+
| `enablePprof` | Enable pprof endpoint | `true` |
111+
| `pprofPort` | pprof server port | `6065` |
109112
| `hubAPIQPS` | QPS for fleet-apiserver (not including events/node heartbeat) | `250` |
110113
| `hubAPIBurst` | Burst for fleet-apiserver (not including events/node heartbeat) | `1000` |
111114
| `MaxConcurrentClusterPlacement` | Max concurrent ClusterResourcePlacement operations | `100` |
112115
| `ConcurrentResourceChangeSyncs` | Max concurrent resourceChange reconcilers | `20` |
113-
| `logFileMaxSize` | Max log file size before rotation | `1000000` |
116+
| `logFileMaxSize` | Max log file size before rotation (optional) | `unset` |
114117
| `MaxFleetSizeSupported` | Max number of member clusters supported | `100` |
118+
| `forceDeleteWaitTime` | Grace period before force-deleting resources | `15m0s` |
119+
| `clusterUnhealthyThreshold` | Threshold duration for marking a cluster unhealthy | `3m0s` |
115120
| `resourceSnapshotCreationMinimumInterval` | The minimum interval at which resource snapshots could be created. | `30s` |
116121
| `resourceChangesCollectionDuration` | The duration for collecting resource changes into one snapshot. | `15s` |
117122
| `enableWorkload` | Enable kubernetes builtin workload to run in hub cluster. | `false` |

charts/hub-agent/values.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
replicaCount: 1
66

77
image:
8-
repository: ghcr.io/azure/fleet/hub-agent
8+
repository: ghcr.io/kubefleet-dev/kubefleet/hub-agent
99
pullPolicy: Always
1010
# Overrides the image tag whose default is the chart appVersion.
11-
tag: main
11+
tag: ""
1212

1313
# CRD installer configuration.
1414
crdInstaller:

charts/member-agent/templates/deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ spec:
145145
{{- end }}
146146
{{- if not .Values.useCAAuth }}
147147
- name: refresh-token
148-
image: "{{ .Values.refreshtoken.repository }}:{{ .Values.refreshtoken.tag }}"
148+
image: "{{ .Values.refreshtoken.repository }}:{{ .Values.refreshtoken.tag | default .Chart.AppVersion }}"
149149
imagePullPolicy: {{ .Values.refreshtoken.pullPolicy }}
150150
args:
151151
{{- $provider := .Values.config.provider }}

charts/member-agent/values.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
replicaCount: 1
22

33
image:
4-
repository: ghcr.io/azure/fleet/member-agent
4+
repository: ghcr.io/kubefleet-dev/kubefleet/member-agent
55
pullPolicy: Always
6-
tag: main
6+
tag: ""
77

88
# CRD installer configuration.
99
crdInstaller:
@@ -17,9 +17,9 @@ crdInstaller:
1717
logVerbosity: 5
1818

1919
refreshtoken:
20-
repository: ghcr.io/azure/fleet/refresh-token
20+
repository: ghcr.io/kubefleet-dev/kubefleet/refresh-token
2121
pullPolicy: Always
22-
tag: main
22+
tag: ""
2323

2424
resources:
2525
limits:

cmd/memberagent/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ var (
101101
workApplierRequeueRateLimiterMaxFastBackoffDelaySeconds = flag.Float64("work-applier-requeue-rate-limiter-max-fast-backoff-delay-seconds", 900, "If set, the work applier will not back off longer than this value in seconds when it is in the fast backoff stage.")
102102
workApplierRequeueRateLimiterSkipToFastBackoffForAvailableOrDiffReportedWorkObjs = flag.Bool("work-applier-requeue-rate-limiter-skip-to-fast-backoff-for-available-or-diff-reported-work-objs", true, "If set, the rate limiter will skip the slow backoff stage and start fast backoff immediately for work objects that are available or have diff reported.")
103103

104+
// Property feature gates when the property provider is not none.
105+
enableNamespaceCollectionInPropertyProvider = flag.Bool("enable-namespace-collection-in-property-provider", false, "If set, the property provider will collect the namespaces in the member cluster.")
106+
104107
// Work applier priority queue settings.
105108
enableWorkApplierPriorityQueue = flag.Bool("enable-work-applier-priority-queue", false, "If set, the work applier will use a priority queue to process work objects.")
106109
workApplierPriorityLinearEquationCoeffA = flag.Int("work-applier-priority-linear-equation-coeff-a", -3, "The work applier sets the priority for a Work object processing attempt using the linear equation: priority = A * (work object age in minutes) + B. This flag sets the coefficient A in the equation.")
@@ -459,7 +462,7 @@ func Start(ctx context.Context, hubCfg, memberConfig *rest.Config, hubOpts, memb
459462
// the specific instance wins the leader election.
460463
klog.V(1).InfoS("Property Provider is azure, loading cloud config", "cloudConfigFile", *cloudConfigFile)
461464
// TODO (britaniar): load cloud config for Azure property provider.
462-
pp = azure.New(region, *isAzProviderCostPropertiesEnabled, *isAzProviderAvailableResPropertiesEnabled)
465+
pp = azure.New(region, *isAzProviderCostPropertiesEnabled, *isAzProviderAvailableResPropertiesEnabled, *enableNamespaceCollectionInPropertyProvider)
463466
default:
464467
// Fall back to not using any property provider if the provided type is none or
465468
// not recognizable.

config/crd/bases/cluster.kubernetes-fleet.io_internalmemberclusters.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,16 @@ spec:
486486
- type
487487
type: object
488488
type: array
489+
namespaces:
490+
additionalProperties:
491+
type: string
492+
description: |-
493+
Namespaces is a map of namespace names to their associated work names for namespaces
494+
that are managed by Fleet (i.e., have AppliedWork owner references when created).
495+
The key is the namespace name and the value is the work name from the AppliedWork owner reference.
496+
If the namespace does not have an AppliedWork owner reference, the value will be an empty string.
497+
This field is populated by the property provider when namespace collection is enabled.
498+
type: object
489499
properties:
490500
additionalProperties:
491501
description: PropertyValue is the value of a cluster property.

0 commit comments

Comments
 (0)