diff --git a/charts/fleet-agent/templates/deployment.yaml b/charts/fleet-agent/templates/deployment.yaml index a9033b2892..a13d85abee 100644 --- a/charts/fleet-agent/templates/deployment.yaml +++ b/charts/fleet-agent/templates/deployment.yaml @@ -89,6 +89,9 @@ spec: - name: kube emptyDir: {} serviceAccountName: fleet-agent + {{- if .Values.fleetAgent.hostNetwork }} + hostNetwork: true + {{- end }} nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} {{- if .Values.fleetAgent.nodeSelector }} {{ toYaml .Values.fleetAgent.nodeSelector | indent 8 }} diff --git a/charts/fleet-agent/values.yaml b/charts/fleet-agent/values.yaml index cca576418d..201016ec72 100644 --- a/charts/fleet-agent/values.yaml +++ b/charts/fleet-agent/values.yaml @@ -44,6 +44,9 @@ fleetAgent: nodeSelector: {} ## List of node taints to tolerate (requires Kubernetes >= 1.6) tolerations: [] + ## HostNetwork setting for the agent deployment. + ## When set allows for provisioning of network related bundles (CNI configuration) in a cluster without CNI. + hostNetwork: false kubectl: ## Node labels for pod assignment ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ diff --git a/charts/fleet-crd/templates/crds.yaml b/charts/fleet-crd/templates/crds.yaml index 5b9062781f..b8e325b180 100644 --- a/charts/fleet-crd/templates/crds.yaml +++ b/charts/fleet-crd/templates/crds.yaml @@ -5440,6 +5440,13 @@ spec: either be predefined, or generated when importing the cluster.' nullable: true type: string + hostNetwork: + description: 'HostNetwork sets the agent StatefulSet to use hostNetwork: + true setting. + + Allows for provisioning of network related bundles (CNI configuration).' + nullable: true + type: boolean kubeConfigSecret: description: 'KubeConfigSecret is the name of the secret containing the kubeconfig for the downstream cluster. diff --git a/internal/cmd/controller/agentmanagement/agent/manifest.go b/internal/cmd/controller/agentmanagement/agent/manifest.go index 8de1c097ad..b8bb72822d 100644 --- a/internal/cmd/controller/agentmanagement/agent/manifest.go +++ b/internal/cmd/controller/agentmanagement/agent/manifest.go @@ -37,6 +37,7 @@ type ManifestOptions struct { SystemDefaultRegistry string AgentAffinity *corev1.Affinity AgentResources *corev1.ResourceRequirements + HostNetwork bool } // Manifest builds and returns a deployment manifest for the fleet-agent with a @@ -298,6 +299,9 @@ func agentApp(namespace string, agentScope string, opts ManifestOptions) *appsv1 // additional tolerations from cluster app.Spec.Template.Spec.Tolerations = append(app.Spec.Template.Spec.Tolerations, opts.AgentTolerations...) + // Set hostNetwork + app.Spec.Template.Spec.HostNetwork = opts.HostNetwork + // overwrite affinity if present on cluster if opts.AgentAffinity != nil { app.Spec.Template.Spec.Affinity = opts.AgentAffinity diff --git a/internal/cmd/controller/agentmanagement/agent/manifest_test.go b/internal/cmd/controller/agentmanagement/agent/manifest_test.go index 1aab99104d..e4497c2fab 100644 --- a/internal/cmd/controller/agentmanagement/agent/manifest_test.go +++ b/internal/cmd/controller/agentmanagement/agent/manifest_test.go @@ -104,6 +104,54 @@ func TestManifestAgentTolerations(t *testing.T) { } } +func TestManifestAgentHostNetwork(t *testing.T) { + const namespace = "fleet-system" + const scope = "test-scope" + baseOpts := ManifestOptions{ + AgentEnvVars: []corev1.EnvVar{}, + AgentImage: "rancher/fleet:1.2.3", + AgentImagePullPolicy: "Always", + AgentTolerations: []corev1.Toleration{}, + CheckinInterval: "1s", + PrivateRepoURL: "private.rancher.com:5000", + SystemDefaultRegistry: "default.rancher.com", + } + + for _, testCase := range []struct { + name string + getOpts func() ManifestOptions + expectedNetwork bool + }{ + { + name: "DefaultSetting", + getOpts: func() ManifestOptions { + return baseOpts + }, + expectedNetwork: false, + }, + { + name: "With hostNetwork", + getOpts: func() ManifestOptions { + withHostNetwork := baseOpts + withHostNetwork.HostNetwork = true + return withHostNetwork + }, + expectedNetwork: true, + }, + } { + t.Run(testCase.name, func(t *testing.T) { + agent := getAgentFromManifests(namespace, scope, testCase.getOpts()) + if agent == nil { + t.Fatal("there were no deployments returned from the manifests") + } + + if !cmp.Equal(agent.Spec.Template.Spec.HostNetwork, testCase.expectedNetwork) { + t.Fatalf("hostNetwork is not as expected: %v", agent.Spec.Template.Spec.HostNetwork) + } + }) + } +} + func TestManifestAgentAffinity(t *testing.T) { const namespace = "fleet-system" diff --git a/internal/cmd/controller/agentmanagement/controllers/cluster/import.go b/internal/cmd/controller/agentmanagement/controllers/cluster/import.go index ecfe90787d..4297fbb28a 100644 --- a/internal/cmd/controller/agentmanagement/controllers/cluster/import.go +++ b/internal/cmd/controller/agentmanagement/controllers/cluster/import.go @@ -1,6 +1,7 @@ package cluster import ( + "cmp" "context" "crypto/sha256" "encoding/json" @@ -32,6 +33,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "k8s.io/utils/ptr" ) var ( @@ -323,6 +325,7 @@ func (i *importHandler) importCluster(cluster *fleet.Cluster, status fleet.Clust PrivateRepoURL: cluster.Spec.PrivateRepoURL, AgentAffinity: cluster.Spec.AgentAffinity, AgentResources: cluster.Spec.AgentResources, + HostNetwork: *cmp.Or(cluster.Spec.HostNetwork, ptr.To(false)), }, }) if err != nil { diff --git a/pkg/apis/fleet.cattle.io/v1alpha1/cluster_types.go b/pkg/apis/fleet.cattle.io/v1alpha1/cluster_types.go index d50d7ecf3b..234c8c4101 100644 --- a/pkg/apis/fleet.cattle.io/v1alpha1/cluster_types.go +++ b/pkg/apis/fleet.cattle.io/v1alpha1/cluster_types.go @@ -125,6 +125,12 @@ type ClusterSpec struct { // +nullable // AgentResources sets the resources for the cluster's agent deployment. AgentResources *corev1.ResourceRequirements `json:"agentResources,omitempty"` + + // +nullable + // +optional + // HostNetwork sets the agent StatefulSet to use hostNetwork: true setting. + // Allows for provisioning of network related bundles (CNI configuration). + HostNetwork *bool `json:"hostNetwork,omitempty"` } type ClusterStatus struct { diff --git a/pkg/apis/fleet.cattle.io/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/fleet.cattle.io/v1alpha1/zz_generated.deepcopy.go index 94071846ed..9c3b6295cd 100644 --- a/pkg/apis/fleet.cattle.io/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/fleet.cattle.io/v1alpha1/zz_generated.deepcopy.go @@ -1037,6 +1037,11 @@ func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { *out = new(corev1.ResourceRequirements) (*in).DeepCopyInto(*out) } + if in.HostNetwork != nil { + in, out := &in.HostNetwork, &out.HostNetwork + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec.