diff --git a/Documentation/CRDs/specification.md b/Documentation/CRDs/specification.md index d0135b67f..4dc23c711 100644 --- a/Documentation/CRDs/specification.md +++ b/Documentation/CRDs/specification.md @@ -8259,6 +8259,19 @@ bool +port
+ +int32 + + + +(Optional) +

The port the NFS server (NFS-Ganesha) will listen on for NFS clients. Defaults to 2049. +Useful when host networking is enabled and the default NFS port is already in use.

+ + + + livenessProbe
diff --git a/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml index 423d3daf5..6c3487827 100644 --- a/deploy/charts/rook-ceph/templates/resources.yaml +++ b/deploy/charts/rook-ceph/templates/resources.yaml @@ -11515,6 +11515,14 @@ spec: type: array type: object x-kubernetes-preserve-unknown-fields: true + port: + description: |- + The port the NFS server (NFS-Ganesha) will listen on for NFS clients. Defaults to 2049. + Useful when host networking is enabled and the default NFS port is already in use. + format: int32 + maximum: 65535 + minimum: 1 + type: integer priorityClassName: description: PriorityClassName sets the priority class on the pods type: string diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml index 316291836..6bdfb9d69 100644 --- a/deploy/examples/crds.yaml +++ b/deploy/examples/crds.yaml @@ -11508,6 +11508,14 @@ spec: type: array type: object x-kubernetes-preserve-unknown-fields: true + port: + description: |- + The port the NFS server (NFS-Ganesha) will listen on for NFS clients. Defaults to 2049. + Useful when host networking is enabled and the default NFS port is already in use. + format: int32 + maximum: 65535 + minimum: 1 + type: integer priorityClassName: description: PriorityClassName sets the priority class on the pods type: string diff --git a/pkg/apis/ceph.rook.io/v1/nfs.go b/pkg/apis/ceph.rook.io/v1/nfs.go index 37d5a3cf7..469d37c85 100644 --- a/pkg/apis/ceph.rook.io/v1/nfs.go +++ b/pkg/apis/ceph.rook.io/v1/nfs.go @@ -49,6 +49,17 @@ func (n *CephNFS) IsHostNetwork(c *ClusterSpec) bool { return c.Network.IsHost() } +// DefaultNFSPort is the default port NFS-Ganesha listens on for NFS clients. +const DefaultNFSPort int32 = 2049 + +// GetPort returns the NFS listen port, or the default (2049) if unset. +func (n *CephNFS) GetPort() int32 { + if n.Spec.Server.Port != 0 { + return n.Spec.Server.Port + } + return DefaultNFSPort +} + func (sec *NFSSecuritySpec) Validate() error { if sec == nil { return nil diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go index 18c802758..0dfe7fb73 100755 --- a/pkg/apis/ceph.rook.io/v1/types.go +++ b/pkg/apis/ceph.rook.io/v1/types.go @@ -3070,6 +3070,13 @@ type GaneshaServerSpec struct { // +optional HostNetwork *bool `json:"hostNetwork,omitempty"` + // The port the NFS server (NFS-Ganesha) will listen on for NFS clients. Defaults to 2049. + // Useful when host networking is enabled and the default NFS port is already in use. + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 + // +optional + Port int32 `json:"port,omitempty"` + // A liveness-probe to verify that Ganesha server has valid run-time state. // If LivenessProbe.Disabled is false and LivenessProbe.Probe is nil uses default probe. // +optional diff --git a/pkg/operator/ceph/nfs/config.go b/pkg/operator/ceph/nfs/config.go index af7bd8da0..e98b34dca 100644 --- a/pkg/operator/ceph/nfs/config.go +++ b/pkg/operator/ceph/nfs/config.go @@ -109,12 +109,14 @@ func getGaneshaConfig(n *cephv1.CephNFS, version cephver.CephVersion, name strin nodeID := getNFSNodeID(n, name) userID := getNFSUserID(nodeID) url := getRadosURL(n) + port := n.GetPort() return ` NFS_CORE_PARAM { Enable_NLM = false; Enable_RQUOTA = false; Protocols = 4; allow_set_io_flusher_fail = true; + NFS_Port = ` + fmt.Sprintf("%d", port) + `; } MDCACHE { diff --git a/pkg/operator/ceph/nfs/spec.go b/pkg/operator/ceph/nfs/spec.go index 5a593c592..d9492936e 100644 --- a/pkg/operator/ceph/nfs/spec.go +++ b/pkg/operator/ceph/nfs/spec.go @@ -30,7 +30,6 @@ import ( "github.com/rook/rook/pkg/util/log" apps "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" - kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -41,13 +40,13 @@ const ( AppName = "rook-ceph-nfs" ganeshaContainerName = "nfs-ganesha" ganeshaConfigVolume = "ganesha-config" - nfsPort = 2049 ganeshaPid = "/var/run/ganesha/ganesha.pid" nfsGaneshaMetricsPort = 9587 ) func (r *ReconcileCephNFS) generateCephNFSService(nfs *cephv1.CephNFS, cfg daemonConfig) *v1.Service { labels := getLabels(nfs, cfg.ID, true) + nfsPort := nfs.GetPort() svc := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ @@ -92,16 +91,13 @@ func (r *ReconcileCephNFS) createCephNFSService(nfs *cephv1.CephNFS, cfg daemonC return errors.Wrapf(err, "failed to set owner reference to ceph nfs %q", s) } - svc, err := r.context.Clientset.CoreV1().Services(nfs.Namespace).Create(r.opManagerContext, s, metav1.CreateOptions{}) + // Update the svc if it already exists so a changed spec.server.port takes effect. + svc, err := k8sutil.CreateOrUpdateService(r.opManagerContext, r.context.Clientset, nfs.Namespace, s) if err != nil { - if !kerrors.IsAlreadyExists(err) { - return errors.Wrap(err, "failed to create ganesha service") - } - log.NamedInfo(nsName, logger, "ceph nfs service already created") - return nil + return errors.Wrap(err, "failed to create or update ganesha service") } - log.NamedInfo(nsName, logger, "ceph nfs service running at %s:%d", svc.Spec.ClusterIP, nfsPort) + log.NamedInfo(nsName, logger, "ceph nfs service running at %s:%d", svc.Spec.ClusterIP, nfs.GetPort()) return nil } @@ -262,10 +258,12 @@ func (r *ReconcileCephNFS) daemonContainer(nfs *cephv1.CephNFS, cfg daemonConfig func (r *ReconcileCephNFS) defaultGaneshaLivenessProbe(nfs *cephv1.CephNFS) *v1.Probe { failureThreshold := int32(10) + nfsPort := nfs.GetPort() cephVersionWithRpcinfo := version.CephVersion{Major: 18, Minor: 2, Extra: 1} if r.clusterInfo.CephVersion.IsAtLeast(cephVersionWithRpcinfo) { // liveness-probe using rpcinfo utility - return controller.GenerateLivenessProbeViaRpcinfo(nfsPort, failureThreshold) + //nolint:gosec // G115: port is CRD-validated to 1-65535 + return controller.GenerateLivenessProbeViaRpcinfo(uint16(nfsPort), failureThreshold) } // liveness-probe using K8s builtin TCP-socket action return controller.GenerateLivenessProbeTcpPort(nfsPort, failureThreshold)