mirror of
https://github.com/ceph/ceph
synced 2026-08-02 07:03:18 +00:00
Compare commits
8 Commits
71e3ba64ae
...
8cdc7cff2c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cdc7cff2c | ||
|
|
36ad54815f | ||
|
|
e27a6a5657 | ||
|
|
58cac6f23a | ||
|
|
41e187ebaa | ||
|
|
8c981876c2 | ||
|
|
f531e122e3 | ||
|
|
d8054bd8b6 |
65
.github/pull_request_template.md
vendored
65
.github/pull_request_template.md
vendored
@ -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>
|
||||
14
.github/workflows/check-license.yml
vendored
14
.github/workflows/check-license.yml
vendored
@ -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"
|
||||
54
.github/workflows/create-backport-trackers.yml
vendored
54
.github/workflows/create-backport-trackers.yml
vendored
@ -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 }}
|
||||
18
.github/workflows/needs-rebase.yml
vendored
18
.github/workflows/needs-rebase.yml
vendored
@ -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"
|
||||
10
.github/workflows/pr-check-deps.yml
vendored
10
.github/workflows/pr-check-deps.yml
vendored
@ -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 }}
|
||||
19
.github/workflows/pr-checklist.yml
vendored
19
.github/workflows/pr-checklist.yml
vendored
@ -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
|
||||
28
.github/workflows/pr-triage.yml
vendored
28
.github/workflows/pr-triage.yml
vendored
@ -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 }}"
|
||||
17
.github/workflows/qa-symlink.yml
vendored
17
.github/workflows/qa-symlink.yml
vendored
@ -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
|
||||
25
.github/workflows/retrigger-rtd.yml
vendored
25
.github/workflows/retrigger-rtd.yml
vendored
@ -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"
|
||||
58
.github/workflows/stale.yml
vendored
58
.github/workflows/stale.yml
vendored
@ -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
|
||||
@ -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:
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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 }};
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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)),
|
||||
|
||||
@ -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', [])],
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user