Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion charts/member-agent-arc/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ spec:
imagePullPolicy: IfNotPresent
image: "{{ .Values.crdinstaller.repository }}:{{ .Values.crdinstaller.tag }}"
args:
- --mode=member
- --mode=arcMember
- --v={{ .Values.crdinstaller.logVerbosity }}
securityContext:
capabilities:
Expand Down
10 changes: 6 additions & 4 deletions cmd/crdinstaller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ import (
"go.goms.io/fleet/cmd/crdinstaller/utils"
)

var mode = flag.String("mode", "", "Mode to run in: 'hub' or 'member' (required)")
var (
mode = flag.String("mode", "", "Mode to run in: 'hub', 'member', 'arcMember', (required)")
)

func main() {
klog.InitFlags(nil)
flag.Parse()

// Validate required flags.
if *mode != "hub" && *mode != "member" {
klog.Fatal("--mode flag must be either 'hub' or 'member'")
if *mode != utils.ModeHub && *mode != utils.ModeMember && *mode != utils.ModeArcMember {
klog.Fatal("--mode flag must be either 'hub' or 'member' or 'arcMember'")
}

klog.Infof("Starting CRD installer in %s mode", *mode)
Expand Down Expand Up @@ -89,7 +91,7 @@ func installCRDs(ctx context.Context, client client.Client, crdPath, mode string

// Install each CRD.
for i := range crdsToInstall {
if err := utils.InstallCRD(ctx, client, &crdsToInstall[i]); err != nil {
if err := utils.InstallCRD(ctx, client, &crdsToInstall[i], mode); err != nil {
return err
}
}
Expand Down
64 changes: 36 additions & 28 deletions cmd/crdinstaller/utils/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
)

const (
// ArcInstallationKey is the key used to indicate if the installation is for ARC AKS cluster.
ArcInstallationKey = "crd-installer.azurefleet.io/arc"
// CRDInstallerLabelKey is the label key used to indicate that a CRD is managed by the installer.
CRDInstallerLabelKey = "crd-installer.azurefleet.io/managed"
// AzureManagedLabelKey is the label key used to indicate that a CRD is managed by an azure resource.
Expand All @@ -32,6 +34,20 @@ const (
FleetLabelValue = "fleet"
)

const (
trueLabelValue = "true"
)

// Mode constants for CRD installer.
const (
// ModeHub installs hub cluster CRDs.
ModeHub = "hub"
// ModeMember installs member cluster CRDs.
ModeMember = "member"
// ModeArcMember installs member cluster CRDs with ARC labels.
ModeArcMember = "arcMember"
)

var (
multiclusterCRD = map[string]bool{
"multicluster.x-k8s.io_clusterprofiles.yaml": true,
Expand All @@ -42,7 +58,7 @@ var (
)

// InstallCRD creates/updates a Custom Resource Definition (CRD) from the provided CRD object.
func InstallCRD(ctx context.Context, client client.Client, crd *apiextensionsv1.CustomResourceDefinition) error {
func InstallCRD(ctx context.Context, client client.Client, crd *apiextensionsv1.CustomResourceDefinition, mode string) error {
klog.V(2).Infof("Installing CRD: %s", crd.Name)

existingCRD := apiextensionsv1.CustomResourceDefinition{
Expand All @@ -59,8 +75,13 @@ func InstallCRD(ctx context.Context, client client.Client, crd *apiextensionsv1.
if existingCRD.Labels == nil {
existingCRD.Labels = make(map[string]string)
}
if mode == ModeArcMember {
// For ARC AKS installation, we want to add an additional label to indicate this is an ARC managed cluster,
// needed for clean up of CRD by kube-addon-manager.
existingCRD.Labels[ArcInstallationKey] = trueLabelValue
}
// Ensure the label for management by the installer is set.
existingCRD.Labels[CRDInstallerLabelKey] = "true"
existingCRD.Labels[CRDInstallerLabelKey] = trueLabelValue
// Also set the Azure managed label to indicate this is managed by Fleet,
// needed for clean up of CRD by kube-addon-manager.
existingCRD.Labels[AzureManagedLabelKey] = FleetLabelValue
Expand Down Expand Up @@ -106,35 +127,22 @@ func CollectCRDs(crdDirectoryPath, mode string, scheme *runtime.Scheme) ([]apiex
// Process based on mode.
crdFileName := filepath.Base(crdpath)

if mode == "member" {
if memberCRD[crdFileName] {
crd, err := GetCRDFromPath(crdpath, scheme)
if err != nil {
return err
}
crdsToInstall = append(crdsToInstall, *crd)
}
// Skip CRDs that are not in the memberCRD map.
return nil
var shouldInstall bool
switch mode {
case ModeMember, ModeArcMember:
shouldInstall = memberCRD[crdFileName]
case ModeHub:
// Install multicluster CRD or CRDs with kubernetes-fleet.io in the filename (excluding member-only CRDs).
// CRD filenames follow the pattern <group>_<plural>.yaml, so we can check the filename.
shouldInstall = multiclusterCRD[crdFileName] || (strings.Contains(crdFileName, "kubernetes-fleet.io") && !memberCRD[crdFileName])
}

crd, err := GetCRDFromPath(crdpath, scheme)
if err != nil {
return err
}

// For hub mode, only collect CRDs whose group has substring kubernetes-fleet.io.
if mode == "hub" {
// special case for multicluster external CRD in hub cluster.
if multiclusterCRD[crdFileName] {
crdsToInstall = append(crdsToInstall, *crd)
return nil
}
group := crd.Spec.Group
// Check if the group contains "kubernetes-fleet.io" substring.
if strings.Contains(group, "kubernetes-fleet.io") && !memberCRD[crdFileName] {
crdsToInstall = append(crdsToInstall, *crd)
if shouldInstall {
crd, err := GetCRDFromPath(crdpath, scheme)
if err != nil {
return err
}
crdsToInstall = append(crdsToInstall, *crd)
}

return nil
Expand Down
26 changes: 22 additions & 4 deletions cmd/crdinstaller/utils/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func runTest(t *testing.T, crdPath string) {
}{
{
name: "hub mode v1beta1 with actual directory",
mode: "hub",
mode: ModeHub,
wantedCRDNames: []string{
"memberclusters.cluster.kubernetes-fleet.io",
"internalmemberclusters.cluster.kubernetes-fleet.io",
Expand Down Expand Up @@ -90,7 +90,7 @@ func runTest(t *testing.T, crdPath string) {
},
{
name: "member mode v1beta1 with actual directory",
mode: "member",
mode: ModeMember,
wantedCRDNames: []string{
"appliedworks.placement.kubernetes-fleet.io",
},
Expand Down Expand Up @@ -157,19 +157,27 @@ func TestInstallCRD(t *testing.T) {
tests := []struct {
name string
crd *apiextensionsv1.CustomResourceDefinition
mode string
wantError bool
}{
{
name: "successful CRD installation",
name: "successful CRD installation with member mode",
crd: testCRD,
mode: ModeMember,
wantError: false,
},
{
name: "successful CRD installation with arcMember mode",
crd: testCRD,
mode: ModeArcMember,
wantError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build()
err := InstallCRD(context.Background(), fakeClient, tt.crd)
err := InstallCRD(context.Background(), fakeClient, tt.crd, tt.mode)

if tt.wantError {
if err == nil {
Expand Down Expand Up @@ -198,6 +206,16 @@ func TestInstallCRD(t *testing.T) {
t.Errorf("Expected CRD label %s to be %q, got %q", AzureManagedLabelKey, FleetLabelValue, installedCRD.Labels[AzureManagedLabelKey])
}

if tt.mode == ModeArcMember {
if installedCRD.Labels[ArcInstallationKey] != "true" {
t.Errorf("Expected CRD label %s to be 'true', got %q", ArcInstallationKey, installedCRD.Labels[ArcInstallationKey])
}
} else {
if _, exists := installedCRD.Labels[ArcInstallationKey]; exists {
t.Errorf("Expected CRD label %s to not exist for non-ARC installation", ArcInstallationKey)
}
}

if diff := cmp.Diff(tt.crd.Spec, installedCRD.Spec); diff != "" {
t.Errorf("CRD spec mismatch (-want +got):\n%s", diff)
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ require (
sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.20
sigs.k8s.io/cluster-inventory-api v0.0.0-20251028164203-2e3fabb46733
sigs.k8s.io/controller-runtime v0.22.4
sigs.k8s.io/yaml v1.6.0
)

require (
Expand Down Expand Up @@ -134,7 +135,6 @@ require (
sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)

replace (
Expand Down
Loading
Loading