Compare commits

...

8 Commits

Author SHA1 Message Date
Ericmzhang
8cdc7cff2c
Merge ddb0211214 into 36ad54815f 2026-07-31 19:43:29 +00:00
Patrick Donnelly
36ad54815f
Merge PR #70675 into tentacle
* refs/pull/70675/head:
	mgr/nfs: Updated enable_nfsv3 check while export creation
	mgr/nfs: set nfs export protocols based on cluster's protocol settings
	mgr/cephadm: Updated NFS default protocol to v4 and v3 is enabled only when enable_nfsv3 is set in the spec

Reviewed-by: Adam King <adking@redhat.com>
2026-07-31 13:05:09 -04:00
Patrick Donnelly
e27a6a5657
Merge PR #70719 into tentacle
* refs/pull/70719/head:
	tentacle: remove pull_request_template
	tentacle: remove github workflows

Reviewed-by: Yuri Weinstein <yweins@redhat.com>
2026-07-30 15:32:44 -04:00
Shweta Bhosale
58cac6f23a
mgr/nfs: Updated enable_nfsv3 check while export creation
Fixes: https://tracker.ceph.com/issues/74492
Signed-off-by: Shweta Bhosale <Shweta.Bhosale1@ibm.com>
(cherry picked from commit 64732c127d)
2026-07-30 13:52:22 -04:00
Shweta Bhosale
41e187ebaa
mgr/nfs: set nfs export protocols based on cluster's protocol settings
Fixes: https://tracker.ceph.com/issues/74492

Signed-off-by: Shweta Bhosale <Shweta.Bhosale1@ibm.com>
(cherry picked from commit 44c1362028)

 Conflicts:
	src/pybind/mgr/nfs/export.py - due to code refactoring in main
2026-07-30 13:52:22 -04:00
Shweta Bhosale
8c981876c2
mgr/cephadm: Updated NFS default protocol to v4 and v3 is enabled only when enable_nfsv3 is set in the spec
Fixes: https://tracker.ceph.com/issues/74492
Signed-off-by: Shweta Bhosale <Shweta.Bhosale1@ibm.com>
(cherry picked from commit 9b0becfdf2)

 Conflicts:
	doc/cephadm/services/nfs.rst - due to documentation related to RDMA
	doc/mgr/nfs.rst - due to params related to RDMA
	src/pybind/mgr/cephadm/services/nfs.py - due to other extra params
	src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 - due to RDMA
	src/pybind/mgr/cephadm/tests/services/test_ingress.py - not exists on tentacle
	src/pybind/mgr/cephadm/tests/services/test_nfs.py - not exists on tentacle
	src/pybind/mgr/nfs/cluster.py - due to other nfs parameters which are not supported in tentacle
	src/pybind/mgr/nfs/module.py - due to other nfs parameters which are not supported in tentacle
	src/python-common/ceph/deployment/service_spec.py - due to extra variable not supported in tentacle
2026-07-30 13:52:22 -04:00
Patrick Donnelly
f531e122e3
tentacle: remove pull_request_template
It's not required for backports.

Signed-off-by: Patrick Donnelly <pdonnell@ibm.com>
2026-07-30 11:05:32 -04:00
Patrick Donnelly
d8054bd8b6
tentacle: remove github workflows
These workflows (with pull_request) are confusing the CI checks for
release branches. Remove all of them and let `main` be the sole
definition.

Signed-off-by: Patrick Donnelly <pdonnell@ibm.com>
2026-07-30 11:02:11 -04:00
21 changed files with 96 additions and 324 deletions

View File

@ -1,65 +0,0 @@
<!--
- Please give your pull request a title like
[component]: [short description]
- Please use this format for each git commit message:
[component]: [short description]
[A longer multiline description]
Fixes: [ticket URL on tracker.ceph.com, create one if necessary]
Signed-off-by: [Your Name] <[your email]>
For examples, use "git log".
-->
## Contribution Guidelines
- To sign and title your commits, please refer to [Submitting Patches to Ceph](https://github.com/ceph/ceph/blob/main/SubmittingPatches.rst).
- If you are submitting a fix for a stable branch (e.g. "quincy"), please refer to [Submitting Patches to Ceph - Backports](https://github.com/ceph/ceph/blob/master/SubmittingPatches-backports.rst) for the proper workflow.
- When filling out the below checklist, you may click boxes directly in the GitHub web UI. When entering or editing the entire PR message in the GitHub web UI editor, you may also select a checklist item by adding an `x` between the brackets: `[x]`. Spaces and capitalization matter when checking off items this way.
## Checklist
- Tracker (select at least one)
- [ ] References tracker ticket
- [ ] Very recent bug; references commit where it was introduced
- [ ] New feature (ticket optional)
- [ ] Doc update (no ticket needed)
- [ ] Code cleanup (no ticket needed)
- Component impact
- [ ] Affects [Dashboard](https://tracker.ceph.com/projects/dashboard/issues/new), opened tracker ticket
- [ ] Affects [Orchestrator](https://tracker.ceph.com/projects/orchestrator/issues/new), opened tracker ticket
- [ ] No impact that needs to be tracked
- Documentation (select at least one)
- [ ] Updates relevant documentation
- [ ] No doc update is appropriate
- Tests (select at least one)
- [ ] Includes [unit test(s)](https://docs.ceph.com/en/latest/dev/developer_guide/tests-unit-tests/)
- [ ] Includes [integration test(s)](https://docs.ceph.com/en/latest/dev/developer_guide/testing_integration_tests/)
- [ ] Includes bug reproducer
- [ ] No tests
<details>
<summary>Show available Jenkins commands</summary>
- `jenkins test classic perf` [Jenkins Job](https://jenkins.ceph.com/view/all/job/ceph-perf-classic/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-perf-pull-requests/config/definitions/ceph-perf-pull-requests.yml)
- `jenkins test crimson perf` [Jenkins Job](https://jenkins.ceph.com/view/all/job/ceph-perf-crimson/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-perf-pull-requests/config/definitions/ceph-perf-pull-requests.yml)
- `jenkins test signed` [Jenkins Job](https://jenkins.ceph.com/job/ceph-pr-commits/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-pr-commits/config/definitions/ceph-pr-commits.yml)
- `jenkins test make check` [Jenkins Job](https://jenkins.ceph.com/job/ceph-pull-requests/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-pull-requests/config/definitions/ceph-pull-requests.yml)
- `jenkins test make check arm64` [Jenkins Job](https://jenkins.ceph.com/job/ceph-pull-requests-arm64/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-pull-requests-arm64/config/definitions/ceph-pull-requests-arm64.yml)
- `jenkins test submodules` [Jenkins Job](https://jenkins.ceph.com/view/all/job/ceph-pr-submodules/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-pr-submodules/config/definitions/ceph-pr-commits.yml)
- `jenkins test dashboard` [Jenkins Job](https://jenkins.ceph.com/view/all/job/ceph-dashboard-pull-requests/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-dashboard-pull-requests/config/definitions/ceph-dashboard-pull-requests.yml)
- `jenkins test dashboard cephadm` [Jenkins Job](https://jenkins.ceph.com/view/all/job/ceph-dashboard-cephadm-e2e/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-dashboard-cephadm-e2e/config/definitions/ceph-dashboard-cephadm-e2e.yml)
- `jenkins test api` [Jenkins Job](https://jenkins.ceph.com/view/all/job/ceph-api/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-pr-api/config/definitions/ceph-pr-api.yml)
- `jenkins test docs` [ReadTheDocs](https://readthedocs.org/projects/ceph/) | [Github Workflow Definition](https://github.com/ceph/ceph/blob/main/.readthedocs.yml)
- `jenkins test ceph-volume all` [Jenkins Jobs](https://jenkins.ceph.com/view/ceph-volume%20PR/) | [Jenkins Jobs Definition](https://github.com/ceph/ceph-build/blob/main/ceph-volume-cephadm-prs/config/definitions/ceph-volume-pr.yml)
- `jenkins test windows` [Jenkins Job](https://jenkins.ceph.com/job/ceph-windows-pull-requests/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-windows-pull-requests/config/definitions/ceph-windows-pull-requests.yml)
- `jenkins test rook e2e` [Jenkins Job](https://jenkins.ceph.com/view/all/job/ceph-orchestrator-rook-e2e/) | [Jenkins Job Definition](https://github.com/ceph/ceph-build/blob/main/ceph-rook-e2e/config/definitions/ceph-orchestrator-rook-e2e.yml)
</details>

View File

@ -1,14 +0,0 @@
---
name: "Check for Incompatible Licenses"
on: [pull_request]
jobs:
pull_request:
name: "Check for Incompatible Licenses"
runs-on: ubuntu-latest
steps:
- name: Check Pull Request
uses: JJ/github-pr-contains-action@526dfe784d8604ea1c39b6c26609074de95b1ffd # releases/v14.1
with:
github-token: ${{github.token}}
diffDoesNotContain: "GNU General Public License"

View File

@ -1,54 +0,0 @@
---
name: Issue Backporting
on:
# To manually trigger this: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch
# View past runs and output: https://github.com/ceph/ceph/actions/workflows/create-backport-trackers.yml
workflow_dispatch:
inputs:
issues:
description: 'whitespace-separated list of issue numbers'
type: string
default: ''
debug:
description: '--debug: Show debug-level messages'
default: false
type: boolean
resolveParent:
description: '--resolve-parent: Resolve parent issue if all backports resolved/rejected'
default: false
type: boolean
force:
description: >
--force: When issue numbers provided, process them even if not in
'Pending Backport' status.
Otherwise, process all issues in 'Pending Backport' status even if
already processed (tag 'backport_processed' added)'
default: false
type: boolean
dryRun:
description: '--dry-run: Do not write anything to Redmine'
default: false
type: boolean
schedule:
# Every 5 minutes: https://crontab.guru/every-5-minutes
- cron: '*/5 * * * *'
jobs:
create-backports:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
sparse-checkout: |
src/script/backport-create-issue
src/script/requirements.backport-create-issue.txt
sparse-checkout-cone-mode: false
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
with:
python-version: '>=3.6 <3.12'
cache: 'pip'
cache-dependency-path: src/script/requirements.backport-create-issue.txt
- run: pip install -r src/script/requirements.backport-create-issue.txt
- run: python3 src/script/backport-create-issue ${{ inputs.debug && '--debug' || '' }} ${{ inputs.resolveParent && '--resolve-parent' || '' }} ${{ inputs.force && '--force' || '' }} ${{ inputs.dryRun && '--dry-run' || '' }} ${{ inputs.issues }}
env:
REDMINE_API_KEY: ${{ secrets.REDMINE_API_KEY_BACKPORT_BOT }}

View File

@ -1,18 +0,0 @@
---
name: "Pull Request Needs Rebase?"
on:
pull_request_target:
types: [opened, synchronize, reopened]
jobs:
needs-rebase:
runs-on: ubuntu-latest
steps:
# eps1lon/actions-label-merge-conflict@v2.0.1
# (NOTE: pinning the action to a given commit is a security best-practice:
# https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/security-hardening-for-github-actions)
- name: Check if PR needs rebase
uses: eps1lon/actions-label-merge-conflict@b8bf8341285ec9a4567d4318ba474fee998a6919
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"
dirtyLabel: "needs-rebase"
commentOnDirty: "This pull request can no longer be automatically merged: a rebase is needed and changes have to be manually resolved"

View File

@ -1,10 +0,0 @@
name: Check PR dependencies
on: [pull_request_target]
jobs:
check_dependencies:
runs-on: ubuntu-latest
name: Check PR Dependencies
steps:
- uses: gregsdennis/dependencies-action@f98d55eee1f66e7aaea4a60e71892736ae2548c7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,19 +0,0 @@
---
name: "Pull Request Checklist"
on:
pull_request:
types:
- edited
- opened
- reopened
jobs:
pr_checklist:
runs-on: ubuntu-latest
name: Verify
steps:
- name: Sleep for 30 seconds
run: sleep 30s
shell: bash
- name: Action
id: checklist
uses: ceph/ceph-pr-checklist-action@32e92d1a2a7c9991ed51de5fccb2296551373d60

View File

@ -1,28 +0,0 @@
---
name: "Pull Request Triage"
on: pull_request_target
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
pr-triage:
runs-on: ubuntu-latest
steps:
- name: Assign labels based on modified files
# https://github.com/marketplace/actions/labeler?version=v4.0.2
uses: actions/labeler@5c7539237e04b714afd8ad9b4aed733815b9fab4
with:
sync-labels: ''
repo-token: "${{ secrets.GITHUB_TOKEN }}"
- name: Assign to Dashboard project
# https://github.com/marketplace/actions/add-to-github-projects?version=v0.5.0
uses: actions/add-to-project@31b3f3ccdc584546fc445612dec3f38ff5edb41c
with:
project-url: https://github.com/orgs/ceph/projects/2
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
labeled: dashboard
- name: Assign milestone based on target brach name
# https://github.com/marketplace/actions/pull-request-milestone?version=v1.3.0
uses: iyu/actions-milestone@e93115c90ff7bcddee71086e9253f1b6a5f4b48a
with:
configuration-path: .github/milestone.yml
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -1,17 +0,0 @@
---
name: "Check for missing .qa links"
on: [pull_request]
jobs:
pull_request:
name: "Check for missing .qa links"
runs-on: ubuntu-latest
steps:
- name: checkout ceph.git
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
with:
path: ceph
- name: verify .qa links
run: ./src/script/verify-qa
working-directory: ceph

View File

@ -1,25 +0,0 @@
name: Retrigger RTD build on PR comment
on:
issue_comment:
types: [created]
permissions:
contents: read
pull-requests: read
jobs:
retrigger-rtd:
if: github.event.issue.pull_request &&
(contains(github.event.comment.body, 'jenkins test docs') ||
contains(github.event.comment.body, 'jenkins rebuild docs') ||
contains(github.event.comment.body, 'jenkins retrigger docs'))
runs-on: ubuntu-latest
steps:
- name: Trigger Read the Docs build
run: |
curl -X POST \
"https://readthedocs.org/api/v3/projects/ceph/versions/${{ github.event.issue.number }}/builds/" \
-H "Authorization: Token ${{ secrets.READTHEDOCS_API_TOKEN }}" \
-H "Content-Type: application/json"

View File

@ -1,58 +0,0 @@
# Configuration for stale action workflow - https://github.com/actions/stale
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '0 * * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
with:
# PAT for GitHub API authentication
repo-token: "${{ secrets.GITHUB_TOKEN }}"
# Comment on the staled PRs
stale-pr-message: >
This pull request has been automatically marked as stale because it
has not had any activity for 60 days. It will be closed if no further
activity occurs for another 30 days.
If you are a maintainer or core committer, please follow-up on this
pull request to identify what steps should be taken by the author to move this
proposed change forward.
If you are the author of this pull request, thank you for your proposed
contribution. If you believe this change is still appropriate, please
ensure that any feedback has been addressed and ask for a code review.
# Comment on the staled PRs while closed
close-pr-message: >
This pull request has been automatically closed because there has
been no activity for 90 days. Please feel free to reopen this pull
request (or open a new one) if the proposed change is still
appropriate. Thank you for your contribution!
# Idle number of days before making PRs stale (exempts Issues)
days-before-pr-stale: 60
# Idle number of days before closing stale PRs (exempts Issues)
days-before-pr-close: 30
# Label to apply on staled PRs
stale-pr-label: 'stale'
# Labels on PRs exempted from stale
exempt-pr-labels: 'pinned,security'
# Exempt all PRs with milestones from stale (also exempts Issues)
exempt-all-pr-milestones: true
# Max number of operations per run
operations-per-run: 100
# Change the order used to fetch the issues and pull requests from GitHub
# So we now start with the oldest PRs and work our way backwards
ascending: true

View File

@ -49,9 +49,14 @@ Alternatively, an NFS service can be applied using a YAML specification.
- host2
spec:
port: 12345
monitoring_port: 567
enable_nfsv3: true
In this example, we run the server on the non-default ``port`` of
12345 (instead of the default 2049) on ``host1`` and ``host2``.
By default, only the NFSv4 protocol is enabled. NFSv3 can be enabled by setting
``enable_nfsv3`` to ``true`` in the service specification.
The specification can then be applied by running the following command:

View File

@ -31,7 +31,7 @@ Create NFS Ganesha Cluster
.. prompt:: bash #
ceph nfs cluster create <cluster_id> [<placement>] [--ingress] [--virtual_ip <value>] [--ingress-mode {default|keepalive-only|haproxy-standard|haproxy-protocol}] [--port <int>]
ceph nfs cluster create <cluster_id> [<placement>] [--ingress] [--virtual_ip <value>] [--ingress-mode {default|keepalive-only|haproxy-standard|haproxy-protocol}] [--port <int>] [--enable-nfsv3]
This creates a common recovery pool for all NFS Ganesha daemons, new user based on
``cluster_id``, and a common NFS Ganesha config RADOS object.
@ -62,6 +62,9 @@ cluster)::
NFS can be deployed on a port other than 2049 (the default) with ``--port <port>``.
By default, only NFS v4 protocol is enabled. To enable both NFS v3 and v4 protocols,
add the ``--enable-nfsv3`` flag.
To deploy NFS with a high-availability front-end (virtual IP and load balancer), add the
``--ingress`` flag and specify a virtual IP address. This will deploy a combination
of keepalived and haproxy to provide an high-availability NFS frontend for the NFS

View File

@ -129,6 +129,7 @@ class NFSService(CephService):
"nfs_idmap_conf": nfs_idmap_conf,
"enable_nlm": str(spec.enable_nlm).lower(),
"cluster_id": self.mgr._cluster_fsid,
"protocols": "3, 4" if spec.enable_nfsv3 else "4"
}
if spec.enable_haproxy_protocol:
context["haproxy_hosts"] = self._haproxy_hosts()

View File

@ -2,7 +2,7 @@
NFS_CORE_PARAM {
Enable_NLM = {{ enable_nlm }};
Enable_RQUOTA = false;
Protocols = 3, 4;
Protocols = {{ protocols }};
mount_path_pseudo = true;
Enable_UDP = false;
NFS_Port = {{ port }};

View File

@ -3391,7 +3391,7 @@ class TestIngressService:
'NFS_CORE_PARAM {\n'
' Enable_NLM = true;\n'
' Enable_RQUOTA = false;\n'
' Protocols = 3, 4;\n'
' Protocols = 4;\n'
' mount_path_pseudo = true;\n'
' Enable_UDP = false;\n'
' NFS_Port = 2049;\n'
@ -3518,6 +3518,32 @@ class TestIngressService:
)
assert nfs_generated_conf == nfs_expected_conf
@patch("cephadm.serve.CephadmServe._run_cephadm")
@patch("cephadm.services.nfs.NFSService.fence_old_ranks", MagicMock())
@patch("cephadm.services.nfs.NFSService.run_grace_tool", MagicMock())
@patch("cephadm.services.nfs.NFSService.purge", MagicMock())
@patch("cephadm.services.nfs.NFSService.create_rados_config_obj", MagicMock())
def test_nfs_enable_nfsv3(self, _run_cephadm, cephadm_module: CephadmOrchestrator):
_run_cephadm.side_effect = async_side_effect(('{}', '', 0))
with with_host(cephadm_module, 'test'):
# Test with enable_nfsv3=False (default)
nfs_spec = NFSServiceSpec(service_id="foo", placement=PlacementSpec(hosts=['test']))
with with_service(cephadm_module, nfs_spec) as _:
nfs_generated_conf, _ = service_registry.get_service('nfs').generate_config(
CephadmDaemonDeploySpec(host='test', daemon_id='foo.test.0.0', service_name=nfs_spec.service_name()))
ganesha_conf = nfs_generated_conf['files']['ganesha.conf']
assert "Protocols = 4;" in ganesha_conf
# Test with enable_nfsv3=True
nfs_spec = NFSServiceSpec(service_id="foo", placement=PlacementSpec(hosts=['test']),
enable_nfsv3=True)
with with_service(cephadm_module, nfs_spec) as _:
nfs_generated_conf, _ = service_registry.get_service('nfs').generate_config(
CephadmDaemonDeploySpec(host='test', daemon_id='foo.test.0.0', service_name=nfs_spec.service_name()))
ganesha_conf = nfs_generated_conf['files']['ganesha.conf']
assert "Protocols = 3, 4;" in ganesha_conf
class TestCephFsMirror:
@patch("cephadm.serve.CephadmServe._run_cephadm")

View File

@ -65,6 +65,7 @@ class NFSCluster:
virtual_ip: Optional[str] = None,
ingress_mode: Optional[IngressType] = None,
port: Optional[int] = None,
enable_nfsv3: bool = False,
) -> None:
if not port:
port = 2049 # default nfs port
@ -98,7 +99,8 @@ class NFSCluster:
# use non-default port so we don't conflict with ingress
port=ganesha_port,
virtual_ip=virtual_ip_for_ganesha,
enable_haproxy_protocol=enable_haproxy_protocol)
enable_haproxy_protocol=enable_haproxy_protocol,
enable_nfsv3=enable_nfsv3)
completion = self.mgr.apply_nfs(spec)
orchestrator.raise_if_exception(completion)
ispec = IngressSpec(service_type='ingress',
@ -116,7 +118,8 @@ class NFSCluster:
# standalone nfs
spec = NFSServiceSpec(service_type='nfs', service_id=cluster_id,
placement=PlacementSpec.from_string(placement),
port=port)
port=port,
enable_nfsv3=enable_nfsv3)
completion = self.mgr.apply_nfs(spec)
orchestrator.raise_if_exception(completion)
log.debug("Successfully deployed nfs daemons with cluster id %s and placement %s",
@ -140,6 +143,7 @@ class NFSCluster:
ingress: Optional[bool] = None,
ingress_mode: Optional[IngressType] = None,
port: Optional[int] = None,
enable_nfsv3: bool = False,
) -> None:
try:
if virtual_ip:
@ -163,7 +167,14 @@ class NFSCluster:
self.create_empty_rados_obj(cluster_id)
if cluster_id not in available_clusters(self.mgr):
self._call_orch_apply_nfs(cluster_id, placement, virtual_ip, ingress_mode, port)
self._call_orch_apply_nfs(
cluster_id,
placement,
virtual_ip,
ingress_mode,
port,
enable_nfsv3=enable_nfsv3,
)
return
raise NonFatalError(f"{cluster_id} cluster already exists")
except Exception as e:

View File

@ -227,6 +227,25 @@ class ExportMgr:
self.rados_pool = POOL_NAME
self._exports: Optional[Dict[str, List[Export]]] = export_ls
def _get_cluster_protocols(self, cluster_id: str) -> List[int]:
"""Get the list of supported NFS protocols for a cluster.
"""
try:
import orchestrator
from ceph.deployment.service_spec import NFSServiceSpec
completion = self.mgr.describe_service(service_type='nfs', service_name=f'nfs.{cluster_id}')
services = orchestrator.raise_if_exception(completion)
for service in services:
if service.spec:
spec = cast(NFSServiceSpec, service.spec)
if getattr(spec, 'enable_nfsv3', False):
return [3, 4]
return [4]
except Exception as e:
log.debug(f"Failed to get cluster protocols for {cluster_id}: {e}, defaulting to v4 only")
return [4]
@property
def exports(self) -> Dict[str, List[Export]]:
if self._exports is None:
@ -749,6 +768,8 @@ class ExportMgr:
_validate_cmount_path(cmount_path, path) # type: ignore
pseudo_path = normalize_path(pseudo_path)
# Get the protocols based on cluster's enable_nfsv3 setting
protocols = self._get_cluster_protocols(cluster_id)
if not self._fetch_export(cluster_id, pseudo_path):
export = self.create_export_from_dict(
@ -766,6 +787,7 @@ class ExportMgr:
},
"clients": clients,
"sectype": sectype,
"protocols": protocols,
},
earmark_resolver
)
@ -797,6 +819,9 @@ class ExportMgr:
if not bucket and not user_id:
raise ErrorResponse("Must specify either bucket or user_id")
# Get the protocols based on cluster's enable_nfsv3 setting
protocols = self._get_cluster_protocols(cluster_id)
if not self._fetch_export(cluster_id, pseudo_path):
export = self.create_export_from_dict(
cluster_id,
@ -812,6 +837,7 @@ class ExportMgr:
},
"clients": clients,
"sectype": sectype,
"protocols": protocols,
}
)
log.debug("creating rgw export %s", export)
@ -868,6 +894,10 @@ class ExportMgr:
else:
new_export_dict['fsal']['cmount_path'] = '/'
# Set protocols based on cluster's enable_nfsv3 setting if not explicitly specified
if 'protocols' not in new_export_dict:
new_export_dict['protocols'] = self._get_cluster_protocols(cluster_id)
new_export = self.create_export_from_dict(
cluster_id,
new_export_dict.get('export_id', self._gen_export_id(cluster_id)),

View File

@ -464,7 +464,7 @@ class Export:
ex_dict.get('access_type', 'RO'),
ex_dict.get('squash', 'no_root_squash'),
ex_dict.get('security_label', True),
ex_dict.get('protocols', [3, 4]),
ex_dict.get('protocols', [4]),
ex_dict.get('transports', ['TCP']),
FSAL.from_dict(ex_dict.get('fsal', {})),
[Client.from_dict(client) for client in ex_dict.get('clients', [])],

View File

@ -133,11 +133,13 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
ingress: Optional[bool] = None,
virtual_ip: Optional[str] = None,
ingress_mode: Optional[IngressType] = None,
port: Optional[int] = None) -> None:
port: Optional[int] = None,
enable_nfsv3: bool = False) -> None:
"""Create an NFS Cluster"""
return self.nfs.create_nfs_cluster(cluster_id=cluster_id, placement=placement,
virtual_ip=virtual_ip, ingress=ingress,
ingress_mode=ingress_mode, port=port)
ingress_mode=ingress_mode, port=port,
enable_nfsv3=enable_nfsv3)
@NFSCLICommand('nfs cluster rm', perm='rw')
@object_format.EmptyResponder()

View File

@ -116,7 +116,7 @@ EXPORT {
Path = /;
Pseudo = /cephfs_b/;
Access_Type = RW;
Protocols = 4;
Protocols = 3, 4;
Attr_Expiration_Time = 0;
FSAL {
@ -406,7 +406,7 @@ NFS_CORE_PARAM {
assert export.pseudo == "/cephfs_b/"
assert export.access_type == "RW"
assert export.squash == "no_root_squash"
assert export.protocols == [4]
assert export.protocols == [3, 4]
assert export.fsal.name == "CEPH"
assert export.fsal.user_id == "nfs.foo.b.lgudhr"
assert export.fsal.fs_name == "b"
@ -1017,7 +1017,7 @@ NFS_CORE_PARAM {
assert export.pseudo == "/mybucket"
assert export.access_type == "none"
assert export.squash == "none"
assert export.protocols == [3, 4]
assert export.protocols == [4]
assert export.transports == ["TCP"]
assert export.fsal.name == "RGW"
assert export.fsal.user_id == "bucket_owner_user"
@ -1060,7 +1060,7 @@ NFS_CORE_PARAM {
assert export.pseudo == "/mybucket"
assert export.access_type == "none"
assert export.squash == "none"
assert export.protocols == [3, 4]
assert export.protocols == [4]
assert export.transports == ["TCP"]
assert export.fsal.name == "RGW"
assert export.fsal.access_key_id == "the_access_key"
@ -1102,7 +1102,7 @@ NFS_CORE_PARAM {
assert export.pseudo == "/mybucket"
assert export.access_type == "none"
assert export.squash == "none"
assert export.protocols == [3, 4]
assert export.protocols == [4]
assert export.transports == ["TCP"]
assert export.fsal.name == "RGW"
assert export.fsal.access_key_id == "the_access_key"
@ -1151,7 +1151,7 @@ NFS_CORE_PARAM {
assert export.pseudo == "/cephfs2"
assert export.access_type == "none"
assert export.squash == "none"
assert export.protocols == [3, 4]
assert export.protocols == [4]
assert export.transports == ["TCP"]
assert export.fsal.name == "CEPH"
assert export.fsal.user_id == "nfs.foo.myfs.86ca58ef"
@ -1190,7 +1190,7 @@ NFS_CORE_PARAM {
assert export.pseudo == "/cephfs3"
assert export.access_type == "RW"
assert export.squash == "root"
assert export.protocols == [3, 4]
assert export.protocols == [4]
assert export.fsal.name == "CEPH"
assert export.fsal.user_id == "nfs.foo.myfs.86ca58ef"
assert export.fsal.cephx_key == "thekeyforclientabc"

View File

@ -1185,6 +1185,7 @@ class NFSServiceSpec(ServiceSpec):
extra_entrypoint_args: Optional[GeneralArgList] = None,
idmap_conf: Optional[Dict[str, Dict[str, str]]] = None,
custom_configs: Optional[List[CustomConfig]] = None,
enable_nfsv3: bool = False,
):
assert service_type == 'nfs'
super(NFSServiceSpec, self).__init__(
@ -1199,6 +1200,7 @@ class NFSServiceSpec(ServiceSpec):
self.enable_haproxy_protocol = enable_haproxy_protocol
self.idmap_conf = idmap_conf
self.enable_nlm = enable_nlm
self.enable_nfsv3 = enable_nfsv3
def get_port_start(self) -> List[int]:
if self.port: