From: Fabian Grünbichler Date: Mon, 14 Aug 2017 06:44:16 +0000 (+0200) Subject: update sources to v12.1.3 X-Git-Url: https://git.proxmox.com/?p=ceph.git;a=commitdiff_plain;h=d2e6a577eb19928d58b31d1b6e096ca0f03c4052 update sources to v12.1.3 --- diff --git a/ceph/CMakeLists.txt b/ceph/CMakeLists.txt index f04d09925..0aaf7dbc6 100644 --- a/ceph/CMakeLists.txt +++ b/ceph/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8.11) project(ceph) -set(VERSION 12.1.2) +set(VERSION 12.1.3) if(POLICY CMP0046) # Tweak policies (this one disables "missing" dependency warning) diff --git a/ceph/PendingReleaseNotes b/ceph/PendingReleaseNotes index d705d58fa..ac1a79f6d 100644 --- a/ceph/PendingReleaseNotes +++ b/ceph/PendingReleaseNotes @@ -1,249 +1,13 @@ ->= 12.0.0 ------- -* The "journaler allow split entries" config setting has been removed. -* The 'apply' mode of cephfs-journal-tool has been removed -* Added new configuration "public bind addr" to support dynamic environments - like Kubernetes. When set the Ceph MON daemon could bind locally to an IP - address and advertise a different IP address "public addr" on the network. -* RGW: bucket index resharding now uses the reshard namespace in upgrade scenarios as well - this is a changed behaviour from RC1 where a new pool for reshard was created +>= 12.1.2 +--------- +* When running 'df' on a CephFS filesystem comprising exactly one data pool, + the result now reflects the file storage space used and available in that + data pool (fuse client only). +* Added new commands "pg force-recovery" and "pg-force-backfill". Use them + to boost recovery or backfill priority of specified pgs, so they're + recovered/backfilled before any other. Note that these commands don't + interrupt ongoing recovery/backfill, but merely queue specified pgs + before others so they're recovered/backfilled as soon as possible. + New commands "pg cancel-force-recovery" and "pg cancel-force-backfill" + restore default recovery/backfill priority of previously forced pgs. -12.0.0 ------- - - * When assigning a network to the public network and not to - the cluster network the network specification of the public - network will be used for the cluster network as well. - In older versions this would lead to cluster services - being bound to 0.0.0.0:, thus making the - cluster service even more publicly available than the - public services. When only specifying a cluster network it - will still result in the public services binding to 0.0.0.0. - -* Some variants of the omap_get_keys and omap_get_vals librados - functions have been deprecated in favor of omap_get_vals2 and - omap_get_keys2. The new methods include an output argument - indicating whether there are additional keys left to fetch. - Previously this had to be inferred from the requested key count vs - the number of keys returned, but this breaks with new OSD-side - limits on the number of keys or bytes that can be returned by a - single omap request. These limits were introduced by kraken but - are effectively disabled by default (by setting a very large limit - of 1 GB) because users of the newly deprecated interface cannot - tell whether they should fetch more keys or not. In the case of - the standalone calls in the C++ interface - (IoCtx::get_omap_{keys,vals}), librados has been updated to loop on - the client side to provide a correct result via multiple calls to - the OSD. In the case of the methods used for building - multi-operation transactions, however, client-side looping is not - practical, and the methods have been deprecated. Note that use of - either the IoCtx methods on older librados versions or the - deprecated methods on any version of librados will lead to - incomplete results if/when the new OSD limits are enabled. - -* In previous versions, if a client sent an op to the wrong OSD, the OSD - would reply with ENXIO. The rationale here is that the client or OSD is - clearly buggy and we want to surface the error as clearly as possible. - We now only send the ENXIO reply if the osd_enxio_on_misdirected_op option - is enabled (it's off by default). This means that a VM using librbd that - previously would have gotten an EIO and gone read-only will now see a - blocked/hung IO instead. - -* When configuring ceph-fuse mounts in /etc/fstab, a new syntax is - available that uses "ceph.=" in the options column, instead - of putting configuration in the device column. The old style syntax - still works. See the documentation page "Mount CephFS in your - file systems table" for details. - -12.0.1 ------- - -* The original librados rados_objects_list_open (C) and objects_begin - (C++) object listing API, deprecated in Hammer, has finally been - removed. Users of this interface must update their software to use - either the rados_nobjects_list_open (C) and nobjects_begin (C++) API or - the new rados_object_list_begin (C) and object_list_begin (C++) API - before updating the client-side librados library to Luminous. - - Object enumeration (via any API) with the latest librados version - and pre-Hammer OSDs is no longer supported. Note that no in-tree - Ceph services rely on object enumeration via the deprecated APIs, so - only external librados users might be affected. - - The newest (and recommended) rados_object_list_begin (C) and - object_list_begin (C++) API is only usable on clusters with the - SORTBITWISE flag enabled (Jewel and later). (Note that this flag is - required to be set before upgrading beyond Jewel.) - -* The rados copy-get-classic operation has been removed since it has not been - used by the OSD since before hammer. It is unlikely any librados user is - using this operation explicitly since there is also the more modern copy-get. - -* The RGW api for getting object torrent has changed its params from 'get_torrent' - to 'torrent' so that it can be compatible with Amazon S3. Now the request for - object torrent is like 'GET /ObjectName?torrent'. - -* The configuration option "osd pool erasure code stripe width" has - been replaced by "osd pool erasure code stripe unit", and given the - ability to be overridden by the erasure code profile setting - "stripe_unit". For more details see "Erasure Code Profiles" in the - documentation. - -* rbd and cephfs can use erasure coding with bluestore. This may be - enabled by setting 'allow_ec_overwrites' to 'true' for a pool. Since - this relies on bluestore's checksumming to do deep scrubbing, - enabling this on a pool stored on filestore is not allowed. - -* The 'rados df' JSON output now prints numeric values as numbers instead of - strings. - -* There was a bug introduced in Jewel (#19119) that broke the mapping behavior - when an "out" OSD that still existed in the CRUSH map was removed with 'osd rm'. - This could result in 'misdirected op' and other errors. The bug is now fixed, - but the fix itself introduces the same risk because the behavior may vary between - clients and OSDs. To avoid problems, please ensure that all OSDs are removed - from the CRUSH map before deleting them. That is, be sure to do:: - - ceph osd crush rm osd.123 - - before:: - - ceph osd rm osd.123 - -12.0.2 ------- - -* The original librados rados_objects_list_open (C) and objects_begin - (C++) object listing API, deprecated in Hammer, has finally been - removed. Users of this interface must update their software to use - either the rados_nobjects_list_open (C) and nobjects_begin (C++) API or - the new rados_object_list_begin (C) and object_list_begin (C++) API - before updating the client-side librados library to Luminous. - - Object enumeration (via any API) with the latest librados version - and pre-Hammer OSDs is no longer supported. Note that no in-tree - Ceph services rely on object enumeration via the deprecated APIs, so - only external librados users might be affected. - - The newest (and recommended) rados_object_list_begin (C) and - object_list_begin (C++) API is only usable on clusters with the - SORTBITWISE flag enabled (Jewel and later). (Note that this flag is - required to be set before upgrading beyond Jewel.) -* CephFS clients without the 'p' flag in their authentication capability - string will no longer be able to set quotas or any layout fields. This - flag previously only restricted modification of the pool and namespace - fields in layouts. -* CephFS directory fragmentation (large directory support) is enabled - by default on new filesystems. To enable it on existing filesystems - use "ceph fs set allow_dirfrags". -* CephFS will generate a health warning if you have fewer standby daemons - than it thinks you wanted. By default this will be 1 if you ever had - a standby, and 0 if you did not. You can customize this using - ``ceph fs set standby_count_wanted ``. Setting it - to zero will effectively disable the health check. -* The "ceph mds tell ..." command has been removed. It is superceded - by "ceph tell mds. ..." - -12.1.0 ------- - -* The ``mon_osd_max_op_age`` option has been renamed to - ``mon_osd_warn_op_age`` (default: 32 seconds), to indicate we - generate a warning at this age. There is also a new - ``mon_osd_err_op_age_ratio`` that is a expressed as a multitple of - ``mon_osd_warn_op_age`` (default: 128, for roughly 60 minutes) to - control when an error is generated. - -* The default maximum size for a single RADOS object has been reduced from - 100GB to 128MB. The 100GB limit was completely impractical in practice - while the 128MB limit is a bit high but not unreasonable. If you have an - application written directly to librados that is using objects larger than - 128MB you may need to adjust ``osd_max_object_size``. - -* The semantics of the 'rados ls' and librados object listing - operations have always been a bit confusing in that "whiteout" - objects (which logically don't exist and will return ENOENT if you - try to access them) are included in the results. Previously - whiteouts only occurred in cache tier pools. In luminous, logically - deleted but snapshotted objects now result in a whiteout object, and - as a result they will appear in 'rados ls' results, even though - trying to read such an object will result in ENOENT. The 'rados - listsnaps' operation can be used in such a case to enumerate which - snapshots are present. - - This may seem a bit strange, but is less strange than having a - deleted-but-snapshotted object not appear at all and be completely - hidden from librados's ability to enumerate objects. Future - versions of Ceph will likely include an alternative object - enumeration interface that makes it more natural and efficient to - enumerate all objects along with their snapshot and clone metadata. - -* The deprecated 'crush_ruleset' property has finally been removed; please use - 'crush_rule' instead for the 'osd pool get ...' and 'osd pool set ..' commands. - -* The 'osd pool default crush replicated ruleset' option has been - removed and replaced by the 'osd pool default crush rule' option. - By default it is -1, which means the mon will pick the first type - replicated rule in the CRUSH map for replicated pools. Erasure - coded pools have rules that are automatically created for them if they are - not specified at pool creation time. - -* The `status` ceph-mgr module is enabled by default, and initially provides two - commands: `ceph tell mgr osd status` and `ceph tell mgr fs status`. These - are high level colorized views to complement the existing CLI. - -12.1.1 ------- - -* choose_args encoding has been changed to make it architecture-independent. - If you deployed Luminous dev releases or 12.1.0 rc release and made use of - the CRUSH choose_args feature, you need to remove all choose_args mappings - from your CRUSH map before starting the upgrade. - -* The 'ceph health' structured output (JSON or XML) no longer contains - a 'timechecks' section describing the time sync status. This - information is now available via the 'ceph time-sync-status' - command. - -* Certain extra fields in the 'ceph health' structured output that - used to appear if the mons were low on disk space (which duplicated - the information in the normal health warning messages) are now gone. - -* The "ceph -w" output no longer contains audit log entries by default. - Add a "--watch-channel=audit" or "--watch-channel=*" to see them. - -12.1.2 ------- - -* New "ceph -w" behavior - the "ceph -w" output no longer contains I/O rates, - available space, pg info, etc. because these are no longer logged to the - central log (which is what "ceph -w" shows). The same information can be - obtained by running "ceph pg stat"; alternatively, I/O rates per pool can - be determined using "ceph osd pool stats". Although these commands do not - self-update like "ceph -w" did, they do have the ability to return formatted - output by providing a "--format=" option. - -* Pools are now expected to be associated with the application using them. - Upon completing the upgrade to Luminous, the cluster will attempt to associate - existing pools to known applications (i.e. CephFS, RBD, and RGW). In-use pools - that are not associated to an application will generate a health warning. Any - unassociated pools can be manually associated using the new - "ceph osd pool application enable" command. For more details see - "Associate Pool to Application" in the documentation. - -* ceph-mgr now has a Zabbix plugin. Using zabbix_sender it sends trapper - events to a Zabbix server containing high-level information of the Ceph - cluster. This makes it easy to monitor a Ceph cluster's status and send - out notifications in case of a malfunction. - -* The 'mon_warn_osd_usage_min_max_delta' config option has been - removed and the associated health warning has been disabled because - it does not address clusters undergoing recovery or CRUSH rules that do - not target all devices in the cluster. - -* Specifying user authorization capabilities for RBD clients has been - simplified. The general syntax for using RBD capability profiles is - "mon 'profile rbd' osd 'profile rbd[-read-only][ pool={pool-name}[, ...]]'". - For more details see "User Management" in the documentation. - -* ``ceph config-key put`` has been deprecated in favor of ``ceph config-key set``. \ No newline at end of file diff --git a/ceph/alpine/APKBUILD b/ceph/alpine/APKBUILD index e080499d8..c3a300c88 100644 --- a/ceph/alpine/APKBUILD +++ b/ceph/alpine/APKBUILD @@ -1,7 +1,7 @@ # Contributor: John Coyle # Maintainer: John Coyle pkgname=ceph -pkgver=12.1.2 +pkgver=12.1.3 pkgrel=0 pkgdesc="Ceph is a distributed object store and file system" pkgusers="ceph" @@ -63,7 +63,7 @@ makedepends=" xmlstarlet yasm " -source="ceph-12.1.2.tar.bz2" +source="ceph-12.1.3.tar.bz2" subpackages=" $pkgname-base $pkgname-common @@ -116,7 +116,7 @@ _sysconfdir=/etc _udevrulesdir=/etc/udev/rules.d _python_sitelib=/usr/lib/python2.7/site-packages -builddir=$srcdir/ceph-12.1.2 +builddir=$srcdir/ceph-12.1.3 build() { export CEPH_BUILD_VIRTUALENV=$builddir diff --git a/ceph/ceph.spec b/ceph/ceph.spec index 993c00cd8..8473b8ac0 100644 --- a/ceph/ceph.spec +++ b/ceph/ceph.spec @@ -13,7 +13,7 @@ # This file is under the GNU Lesser General Public License, version 2.1 # # Please submit bugfixes or comments via http://tracker.ceph.com/ -# +# %bcond_without ocf %bcond_without cephfs_java %if 0%{?suse_version} @@ -61,7 +61,7 @@ # main package definition ################################################################################# Name: ceph -Version: 12.1.2 +Version: 12.1.3 Release: 0%{?dist} %if 0%{?fedora} || 0%{?rhel} Epoch: 2 @@ -76,7 +76,7 @@ License: LGPL-2.1 and CC-BY-SA-1.0 and GPL-2.0 and BSL-1.0 and BSD-3-Clause and Group: System/Filesystems %endif URL: http://ceph.com/ -Source0: http://ceph.com/download/ceph-12.1.2.tar.bz2 +Source0: http://ceph.com/download/ceph-12.1.3.tar.bz2 %if 0%{?suse_version} %if 0%{?is_opensuse} ExclusiveArch: x86_64 aarch64 ppc64 ppc64le @@ -172,7 +172,7 @@ BuildRequires: python-PrettyTable BuildRequires: python-Sphinx BuildRequires: rdma-core-devel %endif -%if 0%{?fedora} || 0%{?rhel} +%if 0%{?fedora} || 0%{?rhel} Requires: systemd BuildRequires: boost-random BuildRequires: btrfs-progs @@ -772,7 +772,7 @@ python-rbd, python-rgw or python-cephfs instead. # common ################################################################################# %prep -%autosetup -p1 -n ceph-12.1.2 +%autosetup -p1 -n ceph-12.1.3 %build %if 0%{with cephfs_java} @@ -910,6 +910,7 @@ mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-osd mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-mds mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-rgw mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-mgr +mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-rbd %if 0%{?suse_version} # create __pycache__ directories and their contents @@ -933,6 +934,8 @@ rm -rf %{buildroot} %{_libexecdir}/systemd/system-preset/50-ceph.preset %{_sbindir}/ceph-create-keys %{_sbindir}/ceph-disk +%{_sbindir}/ceph-volume +%{_sbindir}/ceph-volume-systemd %{_sbindir}/rcceph %dir %{_libexecdir}/ceph %{_libexecdir}/ceph/ceph_common.sh @@ -961,9 +964,13 @@ rm -rf %{buildroot} %config %{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/ceph-osd-mds %endif %{_unitdir}/ceph-disk@.service +%{_unitdir}/ceph-volume@.service %{_unitdir}/ceph.target %{python_sitelib}/ceph_detect_init* %{python_sitelib}/ceph_disk* +%dir %{python_sitelib}/ceph_volume +%{python_sitelib}/ceph_volume/* +%{python_sitelib}/ceph_volume-* %{_mandir}/man8/ceph-deploy.8* %{_mandir}/man8/ceph-detect-init.8* %{_mandir}/man8/ceph-create-keys.8* @@ -978,6 +985,7 @@ rm -rf %{buildroot} %attr(750,ceph,ceph) %dir %{_localstatedir}/lib/ceph/bootstrap-mds %attr(750,ceph,ceph) %dir %{_localstatedir}/lib/ceph/bootstrap-rgw %attr(750,ceph,ceph) %dir %{_localstatedir}/lib/ceph/bootstrap-mgr +%attr(750,ceph,ceph) %dir %{_localstatedir}/lib/ceph/bootstrap-rbd %post base /sbin/ldconfig @@ -989,6 +997,7 @@ fi %endif %if 0%{?fedora} || 0%{?rhel} %systemd_post ceph-disk@\*.service ceph.target +%systemd_post ceph-volume@\*.service ceph.target %endif if [ $1 -eq 1 ] ; then /usr/bin/systemctl start ceph.target >/dev/null 2>&1 || : @@ -1000,6 +1009,7 @@ fi %endif %if 0%{?fedora} || 0%{?rhel} %systemd_preun ceph-disk@\*.service ceph.target +%systemd_preun ceph-volume@\*.service ceph.target %endif %postun base @@ -1020,7 +1030,7 @@ if [ $FIRST_ARG -ge 1 ] ; then source $SYSCONF_CEPH fi if [ "X$CEPH_AUTO_RESTART_ON_UPGRADE" = "Xyes" ] ; then - /usr/bin/systemctl try-restart ceph-disk@\*.service > /dev/null 2>&1 || : + /usr/bin/systemctl try-restart ceph-disk@\*.service ceph-volume@\*.service > /dev/null 2>&1 || : fi fi diff --git a/ceph/ceph.spec.in b/ceph/ceph.spec.in index 93aabf827..66babf6c2 100644 --- a/ceph/ceph.spec.in +++ b/ceph/ceph.spec.in @@ -13,7 +13,7 @@ # This file is under the GNU Lesser General Public License, version 2.1 # # Please submit bugfixes or comments via http://tracker.ceph.com/ -# +# %bcond_without ocf %bcond_without cephfs_java %if 0%{?suse_version} @@ -172,7 +172,7 @@ BuildRequires: python-PrettyTable BuildRequires: python-Sphinx BuildRequires: rdma-core-devel %endif -%if 0%{?fedora} || 0%{?rhel} +%if 0%{?fedora} || 0%{?rhel} Requires: systemd BuildRequires: boost-random BuildRequires: btrfs-progs @@ -910,6 +910,7 @@ mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-osd mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-mds mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-rgw mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-mgr +mkdir -p %{buildroot}%{_localstatedir}/lib/ceph/bootstrap-rbd %if 0%{?suse_version} # create __pycache__ directories and their contents @@ -933,6 +934,8 @@ rm -rf %{buildroot} %{_libexecdir}/systemd/system-preset/50-ceph.preset %{_sbindir}/ceph-create-keys %{_sbindir}/ceph-disk +%{_sbindir}/ceph-volume +%{_sbindir}/ceph-volume-systemd %{_sbindir}/rcceph %dir %{_libexecdir}/ceph %{_libexecdir}/ceph/ceph_common.sh @@ -961,9 +964,13 @@ rm -rf %{buildroot} %config %{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/ceph-osd-mds %endif %{_unitdir}/ceph-disk@.service +%{_unitdir}/ceph-volume@.service %{_unitdir}/ceph.target %{python_sitelib}/ceph_detect_init* %{python_sitelib}/ceph_disk* +%dir %{python_sitelib}/ceph_volume +%{python_sitelib}/ceph_volume/* +%{python_sitelib}/ceph_volume-* %{_mandir}/man8/ceph-deploy.8* %{_mandir}/man8/ceph-detect-init.8* %{_mandir}/man8/ceph-create-keys.8* @@ -978,6 +985,7 @@ rm -rf %{buildroot} %attr(750,ceph,ceph) %dir %{_localstatedir}/lib/ceph/bootstrap-mds %attr(750,ceph,ceph) %dir %{_localstatedir}/lib/ceph/bootstrap-rgw %attr(750,ceph,ceph) %dir %{_localstatedir}/lib/ceph/bootstrap-mgr +%attr(750,ceph,ceph) %dir %{_localstatedir}/lib/ceph/bootstrap-rbd %post base /sbin/ldconfig @@ -989,6 +997,7 @@ fi %endif %if 0%{?fedora} || 0%{?rhel} %systemd_post ceph-disk@\*.service ceph.target +%systemd_post ceph-volume@\*.service ceph.target %endif if [ $1 -eq 1 ] ; then /usr/bin/systemctl start ceph.target >/dev/null 2>&1 || : @@ -1000,6 +1009,7 @@ fi %endif %if 0%{?fedora} || 0%{?rhel} %systemd_preun ceph-disk@\*.service ceph.target +%systemd_preun ceph-volume@\*.service ceph.target %endif %postun base @@ -1020,7 +1030,7 @@ if [ $FIRST_ARG -ge 1 ] ; then source $SYSCONF_CEPH fi if [ "X$CEPH_AUTO_RESTART_ON_UPGRADE" = "Xyes" ] ; then - /usr/bin/systemctl try-restart ceph-disk@\*.service > /dev/null 2>&1 || : + /usr/bin/systemctl try-restart ceph-disk@\*.service ceph-volume@\*.service > /dev/null 2>&1 || : fi fi diff --git a/ceph/cmake/modules/Distutils.cmake b/ceph/cmake/modules/Distutils.cmake index d6de8da27..24d1a5065 100644 --- a/ceph/cmake/modules/Distutils.cmake +++ b/ceph/cmake/modules/Distutils.cmake @@ -1,13 +1,15 @@ include(CMakeParseArguments) function(distutils_install_module name) - set(py_srcs setup.py README.rst requirements.txt test-requirements.txt ${name}) + set(py_srcs setup.py README.rst requirements.txt test-requirements.txt bin ${name}) foreach(src ${py_srcs}) - list(APPEND py_clone ${CMAKE_CURRENT_BINARY_DIR}/${src}) - add_custom_command( - OUTPUT ${src} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${src} - COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${src}) + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${src}) + list(APPEND py_clone ${CMAKE_CURRENT_BINARY_DIR}/${src}) + add_custom_command( + OUTPUT ${src} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${src} + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${src}) + endif() endforeach() add_custom_target(${name}-clone ALL DEPENDS ${py_clone}) diff --git a/ceph/debian/ceph-base.dirs b/ceph/debian/ceph-base.dirs index a60a331ca..2ae686002 100644 --- a/ceph/debian/ceph-base.dirs +++ b/ceph/debian/ceph-base.dirs @@ -2,4 +2,5 @@ var/lib/ceph/bootstrap-mds var/lib/ceph/bootstrap-mgr var/lib/ceph/bootstrap-osd var/lib/ceph/bootstrap-rgw +var/lib/ceph/bootstrap-rbd var/lib/ceph/tmp diff --git a/ceph/debian/ceph-osd.install b/ceph/debian/ceph-osd.install index b87ec1715..bda15ad17 100644 --- a/ceph/debian/ceph-osd.install +++ b/ceph/debian/ceph-osd.install @@ -10,6 +10,9 @@ usr/lib/libos_tp.so* usr/lib/libosd_tp.so* usr/lib/python*/dist-packages/ceph_disk* usr/sbin/ceph-disk +usr/sbin/ceph-volume +usr/lib/python*/dist-packages/ceph_volume/* +usr/lib/python*/dist-packages/ceph_volume-* usr/share/man/man8/ceph-clsinfo.8 usr/share/man/man8/ceph-disk.8 usr/share/man/man8/ceph-osd.8 diff --git a/ceph/debian/changelog b/ceph/debian/changelog index 25b6f5830..481ec56e4 100644 --- a/ceph/debian/changelog +++ b/ceph/debian/changelog @@ -1,3 +1,9 @@ +ceph (12.1.3-1) stable; urgency=medium + + * New upstream release + + -- Ceph Release Team Thu, 10 Aug 2017 19:22:38 +0000 + ceph (12.1.2-1) stable; urgency=medium * New upstream release diff --git a/ceph/debian/rules b/ceph/debian/rules index 2e4ec9d22..92bc0b587 100755 --- a/ceph/debian/rules +++ b/ceph/debian/rules @@ -96,10 +96,12 @@ override_dh_installinit: install -m0644 systemd/ceph-mon@.service debian/ceph-mon/lib/systemd/system install -m0644 systemd/ceph-osd@.service debian/ceph-osd/lib/systemd/system install -m0644 systemd/ceph-disk@.service debian/ceph-osd/lib/systemd/system + install -m0644 systemd/ceph-volume@.service debian/ceph-osd/lib/systemd/system install -m0644 systemd/rbdmap.service debian/ceph-common/lib/systemd/system sed -i s./etc/sysconfig/./etc/default/.g debian/ceph-mon/lib/systemd/system/ceph-mon@.service sed -i s./etc/sysconfig/./etc/default/.g debian/ceph-osd/lib/systemd/system/ceph-osd@.service sed -i s./etc/sysconfig/./etc/default/.g debian/ceph-osd/lib/systemd/system/ceph-disk@.service + sed -i s./etc/sysconfig/./etc/default/.g debian/ceph-osd/lib/systemd/system/ceph-volume@.service install -m0644 systemd/ceph-mon.target debian/ceph-mon/lib/systemd/system install -m0644 systemd/ceph-osd.target debian/ceph-osd/lib/systemd/system diff --git a/ceph/doc/cephfs/client-auth.rst b/ceph/doc/cephfs/client-auth.rst index bf9f35584..fbf694b51 100644 --- a/ceph/doc/cephfs/client-auth.rst +++ b/ceph/doc/cephfs/client-auth.rst @@ -25,19 +25,18 @@ Syntax ------ To grant rw access to the specified directory only, we mention the specified -directory while creating key for a client following the undermentioned syntax. :: +directory while creating key for a client using the following syntax. :: -./ceph auth get-or-create client.*client_name* mon 'allow r' mds 'allow r, allow rw path=/*specified_directory*' osd 'allow rw pool=data' + ceph fs authorize *filesystem_name* client.*client_name* /*specified_directory* rw -for example, to restrict client ``foo`` to writing only in the ``bar`` directory, -we will use: :: +for example, to restrict client ``foo`` to writing only in the ``bar`` directory of filesystem ``cephfs``, use :: -./ceph auth get-or-create client.foo mon 'allow r' mds 'allow r, allow rw path=/bar' osd 'allow rw pool=data' + ceph fs authorize cephfs client.foo / r /bar rw To completely restrict the client to the ``bar`` directory, omit the -unqualified "allow r" clause: :: +root directory :: -./ceph auth get-or-create client.foo mon 'allow r' mds 'allow rw path=/bar' osd 'allow rw pool=data' + ceph fs authorize cephfs client.foo /bar rw Note that if a client's read access is restricted to a path, they will only be able to mount the filesystem when specifying a readable path in the @@ -47,13 +46,13 @@ mount command (see below). See `User Management - Add a User to a Keyring`_. for additional details on user management To restrict a client to the specfied sub-directory only, we mention the specified -directory while mounting following the undermentioned syntax. :: +directory while mounting using the following syntax. :: -./ceph-fuse -n client.*client_name* *mount_path* -r *directory_to_be_mounted* + ./ceph-fuse -n client.*client_name* *mount_path* -r *directory_to_be_mounted* for example, to restrict client ``foo`` to ``mnt/bar`` directory, we will use. :: -./ceph-fuse -n client.foo mnt -r /bar + ./ceph-fuse -n client.foo mnt -r /bar Free space reporting -------------------- @@ -74,32 +73,6 @@ If quotas are not enabled, or no quota is set on the sub-directory mounted, then the overall usage of the filesystem will be reported irrespective of the value of this setting. -OSD restriction -=============== - -To prevent clients from writing or reading data to pools other than -those in use for CephFS, set an OSD authentication capability that -restricts access to the CephFS data pool(s): - -:: - - client.0 - key: AQAz7EVWygILFRAAdIcuJ12opU/JKyfFmxhuaw== - caps: [mds] allow rw - caps: [mon] allow r - caps: [osd] allow rw pool=data1, allow rw pool=data2 - -.. note:: - - Without a corresponding MDS path restriction, the OSD capabilities above do - **not** restrict file deletions outside of the ``data1`` and ``data2`` - pools. - -You may also restrict clients from writing data by using 'r' instead of -'rw' in OSD capabilities. This does not affect the ability of the client -to update filesystem metadata for these files, but it will prevent them -from persistently writing data in a way that would be visible to other clients. - Layout and Quota restriction (the 'p' flag) =========================================== diff --git a/ceph/doc/dev/index.rst b/ceph/doc/dev/index.rst index 59813b656..b76f2f2fb 100644 --- a/ceph/doc/dev/index.rst +++ b/ceph/doc/dev/index.rst @@ -216,6 +216,12 @@ The rest (including the actual backporting) will be taken care of by the .. _`tracker issue`: http://tracker.ceph.com/ .. _`Stable Releases and Backports`: http://tracker.ceph.com/projects/ceph-releases/wiki +Guidance for use of cluster log +------------------------------- + +If your patches emit messages to the Ceph cluster log, please consult +this guidance: :doc:`/dev/logging`. + What is merged where and when ? =============================== diff --git a/ceph/doc/dev/logging.rst b/ceph/doc/dev/logging.rst new file mode 100644 index 000000000..9c2a6f3e0 --- /dev/null +++ b/ceph/doc/dev/logging.rst @@ -0,0 +1,106 @@ + +Use of the cluster log +====================== + +(Note: none of this applies to the local "dout" logging. This is about +the cluster log that we send through the mon daemons) + +Severity +-------- + +Use ERR for situations where the cluster cannot do its job for some reason. +For example: we tried to do a write, but it returned an error, or we tried +to read something, but it's corrupt so we can't, or we scrubbed a PG but +the data was inconsistent so we can't recover. + +Use WRN for incidents that the cluster can handle, but have some abnormal/negative +aspect, such as a temporary degredation of service, or an unexpected internal +value. For example, a metadata error that can be auto-fixed, or a slow operation. + +Use INFO for ordinary cluster operations that do not indicate a fault in +Ceph. It is especially important that INFO level messages are clearly +worded and do not cause confusion or alarm. + +Frequency +--------- + +It is important that messages of all severities are not excessively +frequent. Consumers may be using a rotating log buffer that contains +messages of all severities, so even DEBUG messages could interfere +with proper display of the latest INFO messages if the DEBUG messages +are too frequent. + +Remember that if you have a bad state (as opposed to event), that is +what health checks are for -- do not spam the cluster log to indicate +a continuing unhealthy state. + +Do not emit cluster log messages for events that scale with +the number of clients or level of activity on the system, or for +events that occur regularly in normal operation. For example, it +would be inappropriate to emit a INFO message about every +new client that connects (scales with #clients), or to emit and INFO +message about every CephFS subtree migration (occurs regularly). + +Language and formatting +----------------------- + +(Note: these guidelines matter much less for DEBUG-level messages than + for INFO and above. Concentrate your efforts on making INFO/WRN/ERR + messages as readable as possible.) + +Use the passive voice. For example, use "Object xyz could not be read", rather +than "I could not read the object xyz". + +Print long/big identifiers, such as inode numbers, as hex, prefixed +with an 0x so that the user can tell it is hex. We do this because +the 0x makes it unambiguous (no equivalent for decimal), and because +the hex form is more likely to fit on the screen. + +Print size quantities as a human readable MB/GB/etc, including the unit +at the end of the number. Exception: if you are specifying an offset, +where precision is essential to the meaning, then you can specify +the value in bytes (but print it as hex). + +Make a good faith effort to fit your message on a single line. It does +not have to be guaranteed, but it should at least usually be +the case. That means, generally, no printing of lists unless there +are only a few items in the list. + +Use nouns that are meaningful to the user, and defined in the +documentation. Common acronyms are OK -- don't waste screen space +typing "Rados Object Gateway" instead of RGW. Do not use internal +class names like "MDCache" or "Objecter". It is okay to mention +internal structures if they are the direct subject of the message, +for example in a corruption, but use plain english. +Example: instead of "Objecter requests" say "OSD client requests" +Example: it is okay to mention internal structure in the context + of "Corrupt session table" (but don't say "Corrupt SessionTable") + +Where possible, describe the consequence for system availability, rather +than only describing the underlying state. For example, rather than +saying "MDS myfs.0 is replaying", say that "myfs is degraded, waiting +for myfs.0 to finish starting". + +While common acronyms are fine, don't randomly truncate words. It's not +"dir ino", it's "directory inode". + +If you're logging something that "should never happen", i.e. a situation +where it would be an assertion, but we're helpfully not crashing, then +make that clear in the language -- this is probably not a situation +that the user can remediate themselves. + +Avoid UNIX/programmer jargon. Instead of "errno", just say "error" (or +preferably give something more descriptive than the number!) + +Do not mention cluster map epochs unless they are essential to +the meaning of the message. For example, "OSDMap epoch 123 is corrupt" +would be okay (the epoch is the point of the message), but saying "OSD +123 is down in OSDMap epoch 456" would not be (the osdmap and epoch +concepts are an implementation detail, the down-ness of the OSD +is the real message). Feel free to send additional detail to +the daemon's local log (via `dout`/`derr`). + +If you log a problem that may go away in the future, make sure you +also log when it goes away. Whatever priority you logged the original +message at, log the "going away" message at INFO. + diff --git a/ceph/doc/index.rst b/ceph/doc/index.rst index d070c4726..253e2a4f5 100644 --- a/ceph/doc/index.rst +++ b/ceph/doc/index.rst @@ -82,7 +82,7 @@ about Ceph, see our `Architecture`_ section. .. _Ceph Object Store: radosgw -.. _Ceph Block Device: rbd/rbd +.. _Ceph Block Device: rbd .. _Ceph Filesystem: cephfs .. _Getting Started: start .. _Architecture: architecture @@ -96,7 +96,7 @@ about Ceph, see our `Architecture`_ section. install/index rados/index cephfs/index - rbd/rbd + rbd/index radosgw/index mgr/index api/index diff --git a/ceph/doc/install/manual-deployment.rst b/ceph/doc/install/manual-deployment.rst index bf5b77f58..2e8bb8672 100644 --- a/ceph/doc/install/manual-deployment.rst +++ b/ceph/doc/install/manual-deployment.rst @@ -162,7 +162,7 @@ The procedure is as follows: #. Generate an administrator keyring, generate a ``client.admin`` user and add the user to the keyring. :: - sudo ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --set-uid=0 --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow' --cap mgr 'allow *' + sudo ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --set-uid=0 --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *' #. Add the ``client.admin`` key to the ``ceph.mon.keyring``. :: diff --git a/ceph/doc/install/manual-freebsd-deployment.rst b/ceph/doc/install/manual-freebsd-deployment.rst index bb323e23a..99386aef5 100644 --- a/ceph/doc/install/manual-freebsd-deployment.rst +++ b/ceph/doc/install/manual-freebsd-deployment.rst @@ -211,7 +211,7 @@ The procedure is as follows: #. Generate an administrator keyring, generate a ``client.admin`` user and add the user to the keyring. :: - sudo ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --set-uid=0 --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow' --cap mgr 'allow *' + sudo ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --set-uid=0 --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *' #. Add the ``client.admin`` key to the ``ceph.mon.keyring``. :: diff --git a/ceph/doc/man/8/CMakeLists.txt b/ceph/doc/man/8/CMakeLists.txt index 76bab3a9b..8a2204c71 100644 --- a/ceph/doc/man/8/CMakeLists.txt +++ b/ceph/doc/man/8/CMakeLists.txt @@ -54,12 +54,17 @@ if(WITH_RBD) list(APPEND man_srcs ceph-rbdnamer.rst rbd-mirror.rst - rbd-nbd.rst rbd-replay-many.rst rbd-replay-prep.rst rbd-replay.rst rbdmap.rst rbd.rst) + if(LINUX) + list(APPEND man_srcs rbd-nbd.rst) + endif() + if(FREEBSD) + list(APPEND man_srcs rbd-ggate.rst) + endif() endif() foreach(man ${man_srcs}) diff --git a/ceph/doc/man/8/rados.rst b/ceph/doc/man/8/rados.rst index 07004ec1e..949010537 100644 --- a/ceph/doc/man/8/rados.rst +++ b/ceph/doc/man/8/rados.rst @@ -136,7 +136,9 @@ Pool specific commands Note: *write* and *seq* must be run on the same host otherwise the objects created by *write* will have names that will fail *seq*. -:command:`cleanup` +:command:`cleanup` [ --run-name *run_name* ] [ --prefix *prefix* ] + Clean up a previous benchmark operation. + Note: the default run-name is "benchmark_last_metadata" :command:`listxattr` *name* List all extended attributes of an object. diff --git a/ceph/doc/man/8/radosgw-admin.rst b/ceph/doc/man/8/radosgw-admin.rst index 0a34df80b..ab33f7e8c 100644 --- a/ceph/doc/man/8/radosgw-admin.rst +++ b/ceph/doc/man/8/radosgw-admin.rst @@ -382,6 +382,10 @@ Options List of caps (e.g., "usage=read, write; user=read". +.. option:: --compression= + + Placement target compression algorithm (lz4|snappy|zlib|zstd) + .. option:: --yes-i-really-mean-it Required for certain operations. diff --git a/ceph/doc/man/8/rbd-ggate.rst b/ceph/doc/man/8/rbd-ggate.rst new file mode 100644 index 000000000..67d0c81e8 --- /dev/null +++ b/ceph/doc/man/8/rbd-ggate.rst @@ -0,0 +1,79 @@ +:orphan: + +================================================== + rbd-ggate -- map rbd images via FreeBSD GEOM Gate +================================================== + +.. program:: rbd-ggate + +Synopsis +======== + +| **rbd-ggate** [--read-only] [--exclusive] [--device *ggate device*] map *image-spec* | *snap-spec* +| **rbd-ggate** unmap *ggate device* +| **rbd-ggate** list + +Description +=========== + +**rbd-ggate** is a client for RADOS block device (rbd) images. It will +map a rbd image to a ggate (FreeBSD GEOM Gate class) device, allowing +access it as regular local block device. + +Commands +======== + +map +--- + +Spawn a process responsible for the creation of ggate device and +forwarding I/O requests between the GEOM Gate kernel subsystem and +RADOS. + +unmap +----- + +Destroy ggate device and terminate the process responsible for it. + +list +---- + +List mapped ggate devices. + +Options +======= + +.. option:: --device *ggate device* + + Specify ggate device path. + +.. option:: --read-only + + Map read-only. + +.. option:: --exclusive + + Forbid writes by other clients. + +Image and snap specs +==================== + +| *image-spec* is [*pool-name*]/*image-name* +| *snap-spec* is [*pool-name*]/*image-name*\ @\ *snap-name* + +The default for *pool-name* is "rbd". If an image name contains a slash +character ('/'), *pool-name* is required. + +Availability +============ + +**rbd-ggate** is part of Ceph, a massively scalable, open-source, +distributed storage system. Please refer to the Ceph documentation at +http://ceph.com/docs for more information. + + +See also +======== + +:doc:`rbd `\(8) +:doc:`ceph `\(8) diff --git a/ceph/doc/rados/configuration/bluestore-config-ref.rst b/ceph/doc/rados/configuration/bluestore-config-ref.rst new file mode 100644 index 000000000..8d8ace653 --- /dev/null +++ b/ceph/doc/rados/configuration/bluestore-config-ref.rst @@ -0,0 +1,297 @@ +========================== +BlueStore Config Reference +========================== + +Devices +======= + +BlueStore manages either one, two, or (in certain cases) three storage +devices. + +In the simplest case, BlueStore consumes a single (primary) storage +device. The storage device is normally partitioned into two parts: + +#. A small partition is formatted with XFS and contains basic metadata + for the OSD. This *data directory* includes information about the + OSD (its identifier, which cluster it belongs to, and its private + keyring. + +#. The rest of the device is normally a large partition occupying the + rest of the device that is managed directly by BlueStore contains + all of the actual data. This *primary device* is normally identifed + by a ``block`` symlink in data directory. + +It is also possible to deploy BlueStore across two additional devices: + +* A *WAL device* can be used for BlueStore's internal journal or + write-ahead log. It is identified by the ``block.wal`` symlink in + the data directory. It is only useful to use a WAL device if the + device is faster than the primary device (e.g., when it is on an SSD + and the primary device is an HDD). +* A *DB device* can be used for storing BlueStore's internal metadata. + BlueStore (or rather, the embedded RocksDB) will put as much + metadata as it can on the DB device to improve performance. If the + DB device fills up, metadata will spill back onto the primary device + (where it would have been otherwise). Again, it is only helpful to + provision a DB device if it is faster than the primary device. + +If there is only a small amount of fast storage available (e.g., less +than a gigabyte), we recommend using it as a WAL device. If there is +more, provisioning a DB device makes more sense. The BlueStore +journal will always be placed on the fastest device available, so +using a DB device will provide the same benefit that the WAL device +would while *also* allowing additional metadata to be stored there (if +it will fix). + +A single-device BlueStore OSD can be provisioned with:: + + ceph-disk prepare --bluestore + +To specify a WAL device and/or DB device, :: + + ceph-disk prepare --bluestore --block.wal --block-db + +Cache size +========== + +The amount of memory consumed by each OSD for BlueStore's cache is +determined by the ``bluestore_cache_size`` configuration option. If +that config option is not set (i.e., remains at 0), there is a +different default value that is used depending on whether an HDD or +SSD is used for the primary device (set by the +``bluestore_cache_size_ssd`` and ``bluestore_cache_size_hdd`` config +options). + +BlueStore and the rest of the Ceph OSD does the best it can currently +to stick to the budgeted memory. Note that on top of the configured +cache size, there is also memory consumed by the OSD itself, and +generally some overhead due to memory fragmentation and other +allocator overhead. + +The configured cache memory budget can be used in a few different ways: + +* Key/Value metadata (i.e., RocksDB's internal cache) +* BlueStore metadata +* BlueStore data (i.e., recently read or written object data) + +Cache memory usage is governed by the following options: +``bluestore_cache_meta_ratio``, ``bluestore_cache_kv_ratio``, and +``bluestore_cache_kv_max``. The fraction of the cache devoted to data +is 1.0 minus the meta and kv ratios. The memory devoted to kv +metadata (the RocksDB cache) is capped by ``bluestore_cache_kv_max`` +since our testing indicates there are diminishing returns beyond a +certain point. + +``bluestore_cache_size`` + +:Description: The amount of memory BlueStore will use for its cache. If zero, ``bluestore_cache_size_hdd`` or ``bluestore_cache_size_ssd`` will be used instead. +:Type: Integer +:Required: Yes +:Default: ``0`` + +``bluestore_cache_size_hdd`` + +:Description: The default amount of memory BlueStore will use for its cache when backed by an HDD. +:Type: Integer +:Required: Yes +:Default: ``1 * 1024 * 1024 * 1024`` (1 GB) + +``bluestore_cache_size_ssd`` + +:Description: The default amount of memory BlueStore will use for its cache when backed by an SSD. +:Type: Integer +:Required: Yes +:Default: ``3 * 1024 * 1024 * 1024`` (3 GB) + +``bluestore_cache_meta_ratio`` + +:Description: The ratio of cache devoted to metadata. +:Type: Floating point +:Required: Yes +:Default: ``.01`` + +``bluestore_cache_kv_ratio`` + +:Description: The ratio of cache devoted to key/value data (rocksdb). +:Type: Floating point +:Required: Yes +:Default: ``.99`` + +``bluestore_cache_kv_max`` + +:Description: The maximum amount of cache devoted to key/value data (rocksdb). +:Type: Floating point +:Required: Yes +:Default: ``512 * 1024*1024`` (512 MB) + + +Checksums +========= + +BlueStore checksums all metadata and data written to disk. Metadata +checksumming is handled by RocksDB and uses `crc32c`. Data +checksumming is done by BlueStore and can make use of `crc32c`, +`xxhash32`, or `xxhash64`. The default is `crc32c` and should be +suitable for most purposes. + +Full data checksumming does increase the amount of metadata that +BlueStore must store and manage. When possible, e.g., when clients +hint that data is written and read sequentially, BlueStore will +checksum larger blocks, but in many cases it must store a checksum +value (usually 4 bytes) for every 4 kilobyte block of data. + +It is possible to use a smaller checksum value by truncating the +checksum to two or one byte, reducing the metadata overhead. The +trade-off is that the probability that a random error will not be +detected is higher with a smaller checksum, going from about one if +four billion with a 32-bit (4 byte) checksum to one is 65,536 for a +16-bit (2 byte) checksum or one in 256 for an 8-bit (1 byte) checksum. +The smaller checksum values can be used by selecting `crc32c_16` or +`crc32c_8` as the checksum algorithm. + +The *checksum algorithm* can be set either via a per-pool +``csum_type`` property or the global config option. For example, :: + + ceph osd pool set csum_type + +``bluestore_csum_type`` + +:Description: The default checksum algorithm to use. +:Type: String +:Required: Yes +:Valid Settings: ``none``, ``crc32c``, ``crc32c_16``, ``crc32c_8``, ``xxhash32``, ``xxhash64`` +:Default: ``crc32c`` + + +Inline Compression +================== + +BlueStore supports inline compression using `snappy`, `zlib`, or +`lz4`. Please note that the `lz4` compression plugin is not +distributed in the official release. + +Whether data in BlueStore is compressed is determined by a combination +of the *compression mode* and any hints associated with a write +operation. The modes are: + +* **none**: Never compress data. +* **passive**: Do not compress data unless the write operation as a + *compressible* hint set. +* **aggressive**: Compress data unless the write operation as an + *incompressible* hint set. +* **force**: Try to compress data no matter what. + +For more information about the *compressible* and *incompressible* IO +hints, see :doc:`/api/librados/#rados_set_alloc_hint`. + +Note that regardless of the mode, if the size of the data chunk is not +reduced sufficiently it will not be used and the original +(uncompressed) data will be stored. For example, if the ``bluestore +compression required ratio`` is set to ``.7`` then the compressed data +must be 70% of the size of the original (or smaller). + +The *compression mode*, *compression algorithm*, *compression required +ratio*, *min blob size*, and *max blob size* can be set either via a +per-pool property or a global config option. Pool properties can be +set with:: + + ceph osd pool set compression_algorithm + ceph osd pool set compression_mode + ceph osd pool set compression_required_ratio + ceph osd pool set compression_min_blob_size + ceph osd pool set compression_max_blob_size + +``bluestore compression algorithm`` + +:Description: The default compressor to use (if any) if the per-pool property + ``compression_algorithm`` is not set. Note that zstd is *not* + recommended for bluestore due to high CPU overhead when + compressing small amounts of data. +:Type: String +:Required: No +:Valid Settings: ``lz4``, ``snappy``, ``zlib``, ``zstd`` +:Default: ``snappy`` + +``bluestore compression mode`` + +:Description: The default policy for using compression if the per-pool property + ``compression_mode`` is not set. ``none`` means never use + compression. ``passive`` means use compression when + `clients hint`_ that data is compressible. ``aggressive`` means + use compression unless clients hint that data is not compressible. + ``force`` means use compression under all circumstances even if + the clients hint that the data is not compressible. +:Type: String +:Required: No +:Valid Settings: ``none``, ``passive``, ``aggressive``, ``force`` +:Default: ``none`` + +``bluestore compression required ratio`` + +:Description: The ratio of the size of the data chunk after + compression relative to the original size must be at + least this small in order to store the compressed + version. + +:Type: Floating point +:Required: No +:Default: .875 + +``bluestore compression min blob size`` + +:Description: Chunks smaller than this are never compressed. + The per-pool property ``compression_min_blob_size`` overrides + this setting. + +:Type: Unsigned Integer +:Required: No +:Default: 0 + +``bluestore compression min blob size hdd`` + +:Description: Default value of ``bluestore compression min blob size`` + for rotational media. + +:Type: Unsigned Integer +:Required: No +:Default: 128K + +``bluestore compression min blob size ssd`` + +:Description: Default value of ``bluestore compression min blob size`` + for non-rotational (solid state) media. + +:Type: Unsigned Integer +:Required: No +:Default: 8K + +``bluestore compression max blob size`` + +:Description: Chunks larger than this are broken into smaller blobs sizing + ``bluestore compression max blob size`` before being compressed. + The per-pool property ``compression_max_blob_size`` overrides + this setting. + +:Type: Unsigned Integer +:Required: No +:Default: 0 + +``bluestore compression max blob size hdd`` + +:Description: Default value of ``bluestore compression max blob size`` + for rotational media. + +:Type: Unsigned Integer +:Required: No +:Default: 512K + +``bluestore compression max blob size ssd`` + +:Description: Default value of ``bluestore compression max blob size`` + for non-rotational (solid state) media. + +:Type: Unsigned Integer +:Required: No +:Default: 64K + +.. _clients hint: ../../api/librados/#rados_set_alloc_hint diff --git a/ceph/doc/rados/configuration/filesystem-recommendations.rst b/ceph/doc/rados/configuration/filesystem-recommendations.rst deleted file mode 100644 index c967d60ce..000000000 --- a/ceph/doc/rados/configuration/filesystem-recommendations.rst +++ /dev/null @@ -1,62 +0,0 @@ -=========================================== - Hard Disk and File System Recommendations -=========================================== - -.. index:: hard drive preparation - -Hard Drive Prep -=============== - -Ceph aims for data safety, which means that when the :term:`Ceph Client` -receives notice that data was written to a storage drive, that data was actually -written to the storage drive. For old kernels (<2.6.33), disable the write cache -if the journal is on a raw drive. Newer kernels should work fine. - -Use ``hdparm`` to disable write caching on the hard disk:: - - sudo hdparm -W 0 /dev/hda 0 - -In production environments, we recommend running a :term:`Ceph OSD Daemon` with -separate drives for the operating system and the data. If you run data and an -operating system on a single disk, we recommend creating a separate partition -for your data. - -.. index:: filesystems - -Filesystems -=========== - -Ceph OSD Daemons rely heavily upon the stability and performance of the -underlying filesystem. - -Recommended ------------ - -We currently recommend ``XFS`` for production deployments. - -Not recommended ---------------- - -We recommand *against* using ``btrfs`` due to the lack of a stable -version to test against and frequent bugs in the ENOSPC handling. - -We recommend *against* using ``ext4`` due to limitations in the size -of xattrs it can store, and the problems this causes with the way Ceph -handles long RADOS object names. Although these issues will generally -not surface with Ceph clusters using only short object names (e.g., an -RBD workload that does not include long RBD image names), other users -like RGW make extensive use of long object names and can break. - -Starting with the Jewel release, the ``ceph-osd`` daemon will refuse -to start if the configured max object name cannot be safely stored on -``ext4``. If the cluster is only being used with short object names -(e.g., RBD only), you can continue using ``ext4`` by setting the -following configuration option:: - - osd max object name len = 256 - osd max object namespace len = 64 - -.. note:: This may result in difficult-to-diagnose errors if you try - to use RGW or other librados clients that do not properly - handle or politely surface any resulting ENAMETOOLONG - errors. diff --git a/ceph/doc/rados/configuration/index.rst b/ceph/doc/rados/configuration/index.rst index b609b155e..48b58efb7 100644 --- a/ceph/doc/rados/configuration/index.rst +++ b/ceph/doc/rados/configuration/index.rst @@ -32,7 +32,7 @@ For general object store configuration, refer to the following: .. toctree:: :maxdepth: 1 - Disks and Filesystems + Storage devices ceph-conf @@ -51,7 +51,8 @@ To optimize the performance of your cluster, refer to the following: mon-lookup-dns Heartbeat Settings OSD Settings - Filestore Settings + BlueStore Settings + FileStore Settings Journal Settings Pool, PG & CRUSH Settings Messaging Settings diff --git a/ceph/doc/rados/configuration/osd-config-ref.rst b/ceph/doc/rados/configuration/osd-config-ref.rst index 30e679fd2..fae707893 100644 --- a/ceph/doc/rados/configuration/osd-config-ref.rst +++ b/ceph/doc/rados/configuration/osd-config-ref.rst @@ -988,6 +988,15 @@ perform well in a degraded state. :Type: Float :Default: ``0`` + +``osd recovery sleep hybrid`` + +:Description: Time in seconds to sleep before next recovery or backfill op + when osd data is on HDD and osd journal is on SSD. + +:Type: Float +:Default: ``0.025`` + Tiering ======= diff --git a/ceph/doc/rados/configuration/storage-devices.rst b/ceph/doc/rados/configuration/storage-devices.rst new file mode 100644 index 000000000..83c0c9b9f --- /dev/null +++ b/ceph/doc/rados/configuration/storage-devices.rst @@ -0,0 +1,83 @@ +================= + Storage Devices +================= + +There are two Ceph daemons that store data on disk: + +* **Ceph OSDs** (or Object Storage Daemons) are where most of the + data is stored in Ceph. Generally speaking, each OSD is backed by + a single storage device, like a traditional hard disk (HDD) or + solid state disk (SSD). OSDs can also be backed by a combination + of devices, like a HDD for most data and an SSD (or partition of an + SSD) for some metadata. The number of OSDs in a cluster is + generally a function of how much data will be stored, how big each + storage device will be, and the level and type of redundancy + (replication or erasure coding). +* **Ceph Monitor** daemons manage critical cluster state like cluster + membership and authentication information. For smaller clusters a + few gigabytes is all that is needed, although for larger clusters + the monitor database can reach tens or possibly hundreds of + gigabytes. + + +OSD Backends +============ + +There are two ways that OSDs can manage the data they store. Starting +with the Luminous 12.2.z release, the new default (and recommended) backend is +*BlueStore*. Prior to Luminous, the default (and only option) was +*FileStore*. + +BlueStore +--------- + +BlueStore is a special-purpose storage backend designed specifically +for managing data on disk for Ceph OSD workloads. It is motivated by +experience supporting and managing OSDs using FileStore over the +last ten years. Key BlueStore features include: + +* Direct management of storage devices. BlueStore consumes raw block + devices or partitions. This avoids any intervening layers of + abstraction (such as local file systems like XFS) that may limit + performance or add complexity. +* Metadata management with RocksDB. We embed RocksDB's key/value database + in order to manage internal metadata, such as the mapping from object + names to block locations on disk. +* Full data and metadata checksumming. By default all data and + metadata written to BlueStore is protected by one or more + checksums. No data or metadata will be read from disk or returned + to the user without being verified. +* Inline compression. Data written may be optionally compressed + before being written to disk. +* Multi-device metadata tiering. BlueStore allows its internal + journal (write-ahead log) to be written to a separate, high-speed + device (like an SSD, NVMe, or NVDIMM) to increased performance. If + a significant amount of faster storage is available, internal + metadata can also be stored on the faster device. +* Efficient copy-on-write. RBD and CephFS snapshots rely on a + copy-on-write *clone* mechanism that is implemented efficiently in + BlueStore. This results in efficient IO both for regular snapshots + and for erasure coded pools (which rely on cloning to implement + efficient two-phase commits). + +For more information, see :doc:`bluestore-config-ref`. + +FileStore +--------- + +FileStore is the legacy approach to storing objects in Ceph. It +relies on a standard file system (normally XFS) in combination with a +key/value database (traditionally LevelDB, now RocksDB) for some +metadata. + +FileStore is well-tested and widely used in production but suffers +from many performance deficiencies due to its overall design and +reliance on a traditional file system for storing object data. + +Although FileStore is generally capable of functioning on most +POSIX-compatible file systems (including btrfs and ext4), we only +recommend that XFS be used. Both btrfs and ext4 have known bugs and +deficiencies and their use may lead to data loss. By default all Ceph +provisioning tools will use XFS. + +For more information, see :doc:`filestore-config-ref`. diff --git a/ceph/doc/rados/index.rst b/ceph/doc/rados/index.rst index 9ff756c97..929bb7efa 100644 --- a/ceph/doc/rados/index.rst +++ b/ceph/doc/rados/index.rst @@ -70,7 +70,7 @@ the Ceph Storage Cluster. -.. _Ceph Block Devices: ../rbd/rbd +.. _Ceph Block Devices: ../rbd/ .. _Ceph Filesystem: ../cephfs/ .. _Ceph Object Storage: ../radosgw/ .. _Deployment: ../rados/deployment/ diff --git a/ceph/doc/rados/operations/crush-map.rst b/ceph/doc/rados/operations/crush-map.rst index d07844c35..05fa4ff69 100644 --- a/ceph/doc/rados/operations/crush-map.rst +++ b/ceph/doc/rados/operations/crush-map.rst @@ -206,6 +206,43 @@ You can view the contents of the rules with:: ceph osd crush rule dump +Device classes +-------------- + +Each device can optionally have a *class* associated with it. By +default, OSDs automatically set their class on startup to either +`hdd`, `ssd`, or `nvme` based on the type of device they are backed +by. + +The device class for one or more OSDs can be explicitly set with:: + + ceph osd crush set-device-class [...] + +Once a device class is set, it cannot be changed to another class +until the old class is unset with:: + + ceph osd crush rm-device-class [...] + +This allows administrators to set device classes without the class +being changed on OSD restart or by some other script. + +A placement rule that targets a specific device class can be created with:: + + ceph osd crush rule create-replicated + +A pool can then be changed to use the new rule with:: + + ceph osd pool set crush_rule + +Device classes are implemented by creating a "shadow" CRUSH hierarchy +for each device class in use that contains only devices of that class. +Rules can then distribute data over the shadow hierarchy. One nice +thing about this approach is that it is fully backward compatible with +old Ceph clients. You can view the CRUSH hierarchy with shadow items +with:: + + ceph osd crush tree --show-shadow + Weights sets ------------ diff --git a/ceph/doc/rados/operations/health-checks.rst b/ceph/doc/rados/operations/health-checks.rst index 68106352e..616435579 100644 --- a/ceph/doc/rados/operations/health-checks.rst +++ b/ceph/doc/rados/operations/health-checks.rst @@ -220,7 +220,7 @@ or delete some existing data to reduce utilization. Data health (pools & placement groups) ------------------------------- +-------------------------------------- PG_AVAILABILITY _______________ @@ -523,23 +523,3 @@ happen if they are misplaced or degraded (see *PG_AVAILABILITY* and You can manually initiate a scrub of a clean PG with:: ceph pg deep-scrub - -CephFS ------- - -FS_WITH_FAILED_MDS -__________________ - - -FS_DEGRADED -___________ - - -MDS_INSUFFICIENT_STANDBY -________________________ - - -MDS_DAMAGED -___________ - - diff --git a/ceph/doc/rados/operations/pools.rst b/ceph/doc/rados/operations/pools.rst index ce0ae9095..70155937c 100644 --- a/ceph/doc/rados/operations/pools.rst +++ b/ceph/doc/rados/operations/pools.rst @@ -275,6 +275,37 @@ To set a value to a pool, execute the following:: You may set values for the following keys: +.. _compression_algorithm: + +``compression_algorithm`` +:Description: Sets inline compression algorithm to use for underlying BlueStore. + This setting overrides the `global setting `_ of ``bluestore compression algorithm``. + +:Type: String +:Valid Settings: ``lz4``, ``snappy``, ``zlib``, ``zstd`` + +``compression_mode`` + +:Description: Sets the policy for the inline compression algorithm for underlying BlueStore. + This setting overrides the `global setting `_ of ``bluestore compression mode``. + +:Type: String +:Valid Settings: ``none``, ``passive``, ``aggressive``, ``force`` + +``compression_min_blob_size`` + +:Description: Chunks smaller than this are never compressed. + This setting overrides the `global setting `_ of ``bluestore compression min blob *``. + +:Type: Unsigned Integer + +``compression_max_blob_size`` + +:Description: Chunks larger than this are broken into smaller blobs sizing + ``compression_max_blob_size`` before being compressed. + +:Type: Unsigned Integer + .. _size: ``size`` diff --git a/ceph/doc/rados/operations/user-management.rst b/ceph/doc/rados/operations/user-management.rst index a4c588400..8a35a501a 100644 --- a/ceph/doc/rados/operations/user-management.rst +++ b/ceph/doc/rados/operations/user-management.rst @@ -113,10 +113,8 @@ Capability syntax follows the form:: osd 'allow {access} [pool={pool-name} [namespace={namespace-name}]]' osd 'profile {name} [pool={pool-name} [namespace={namespace-name}]]' -- **Metadata Server Caps:** Metadata server capability simply requires ``allow``, - or blank and does not parse anything further. :: - - mds 'allow' +- **Metadata Server Caps:** For administrators, use ``allow *``. For all + other users, such as CephFS clients, consult :doc:`/cephfs/client-auth` .. note:: The Ceph Object Gateway daemon (``radosgw``) is a client of the diff --git a/ceph/doc/radosgw/adminops.rst b/ceph/doc/radosgw/adminops.rst index 28c02164b..422dd1652 100644 --- a/ceph/doc/radosgw/adminops.rst +++ b/ceph/doc/radosgw/adminops.rst @@ -321,6 +321,11 @@ generated key is added to the keyring without replacing an existing key pair. If ``access-key`` is specified and refers to an existing key owned by the user then it will be modified. +.. versionadded:: Luminous + +A ``tenant`` may either be specified as a part of uid or as an additional +request param. + :caps: users=write Syntax @@ -342,6 +347,7 @@ Request Parameters :Type: String :Example: ``foo_user`` :Required: Yes +A tenant name may also specified as a part of ``uid``, by following the syntax ``tenant$user``, refer to `Multitenancy`_ for more details. ``display-name`` @@ -408,6 +414,14 @@ Request Parameters :Example: False [False] :Required: No +.. versionadded:: Jewel +``tenant`` + +:Description: the Tenant under which a user is a part of. +:Type: string +:Example: tenant1 +:Required: No + Response Entities ~~~~~~~~~~~~~~~~~ @@ -418,6 +432,11 @@ If successful, the response contains the user information. :Description: A container for the user data information. :Type: Container +``tenant`` +:Description: The tenant which user is a part of +:Type: String +:Parent: ``user`` + ``user_id`` :Description: The user id. @@ -1924,3 +1943,4 @@ Standard Error Responses .. _Admin Guide: ../admin .. _Quota Management: ../admin#quota-management +.. _Multitenancy: ./multitenancy diff --git a/ceph/doc/rbd/api/index.rst b/ceph/doc/rbd/api/index.rst new file mode 100644 index 000000000..71f680933 --- /dev/null +++ b/ceph/doc/rbd/api/index.rst @@ -0,0 +1,8 @@ +======================== + Ceph Block Device APIs +======================== + +.. toctree:: + :maxdepth: 2 + + librados (Python) diff --git a/ceph/doc/rbd/api/librbdpy.rst b/ceph/doc/rbd/api/librbdpy.rst new file mode 100644 index 000000000..fa9033125 --- /dev/null +++ b/ceph/doc/rbd/api/librbdpy.rst @@ -0,0 +1,82 @@ +================ + Librbd (Python) +================ + +.. highlight:: python + +The `rbd` python module provides file-like access to RBD images. + + +Example: Creating and writing to an image +========================================= + +To use `rbd`, you must first connect to RADOS and open an IO +context:: + + cluster = rados.Rados(conffile='my_ceph.conf') + cluster.connect() + ioctx = cluster.open_ioctx('mypool') + +Then you instantiate an :class:rbd.RBD object, which you use to create the +image:: + + rbd_inst = rbd.RBD() + size = 4 * 1024**3 # 4 GiB + rbd_inst.create(ioctx, 'myimage', size) + +To perform I/O on the image, you instantiate an :class:rbd.Image object:: + + image = rbd.Image(ioctx, 'myimage') + data = 'foo' * 200 + image.write(data, 0) + +This writes 'foo' to the first 600 bytes of the image. Note that data +cannot be :type:unicode - `Librbd` does not know how to deal with +characters wider than a :c:type:char. + +In the end, you will want to close the image, the IO context and the connection to RADOS:: + + image.close() + ioctx.close() + cluster.shutdown() + +To be safe, each of these calls would need to be in a separate :finally +block:: + + cluster = rados.Rados(conffile='my_ceph_conf') + try: + ioctx = cluster.open_ioctx('my_pool') + try: + rbd_inst = rbd.RBD() + size = 4 * 1024**3 # 4 GiB + rbd_inst.create(ioctx, 'myimage', size) + image = rbd.Image(ioctx, 'myimage') + try: + data = 'foo' * 200 + image.write(data, 0) + finally: + image.close() + finally: + ioctx.close() + finally: + cluster.shutdown() + +This can be cumbersome, so the :class:`Rados`, :class:`Ioctx`, and +:class:`Image` classes can be used as context managers that close/shutdown +automatically (see :pep:`343`). Using them as context managers, the +above example becomes:: + + with rados.Rados(conffile='my_ceph.conf') as cluster: + with cluster.open_ioctx('mypool') as ioctx: + rbd_inst = rbd.RBD() + size = 4 * 1024**3 # 4 GiB + rbd_inst.create(ioctx, 'myimage', size) + with rbd.Image(ioctx, 'myimage') as image: + data = 'foo' * 200 + image.write(data, 0) + +API Reference +============= + +.. automodule:: rbd + :members: RBD, Image, SnapIterator diff --git a/ceph/doc/rbd/index.rst b/ceph/doc/rbd/index.rst new file mode 100644 index 000000000..5d9d433ce --- /dev/null +++ b/ceph/doc/rbd/index.rst @@ -0,0 +1,74 @@ +=================== + Ceph Block Device +=================== + +.. index:: Ceph Block Device; introduction + +A block is a sequence of bytes (for example, a 512-byte block of data). +Block-based storage interfaces are the most common way to store data with +rotating media such as hard disks, CDs, floppy disks, and even traditional +9-track tape. The ubiquity of block device interfaces makes a virtual block +device an ideal candidate to interact with a mass data storage system like Ceph. + +Ceph block devices are thin-provisioned, resizable and store data striped over +multiple OSDs in a Ceph cluster. Ceph block devices leverage +:abbr:`RADOS (Reliable Autonomic Distributed Object Store)` capabilities +such as snapshotting, replication and consistency. Ceph's +:abbr:`RADOS (Reliable Autonomic Distributed Object Store)` Block Devices (RBD) +interact with OSDs using kernel modules or the ``librbd`` library. + +.. ditaa:: +------------------------+ +------------------------+ + | Kernel Module | | librbd | + +------------------------+-+------------------------+ + | RADOS Protocol | + +------------------------+-+------------------------+ + | OSDs | | Monitors | + +------------------------+ +------------------------+ + +.. note:: Kernel modules can use Linux page caching. For ``librbd``-based + applications, Ceph supports `RBD Caching`_. + +Ceph's block devices deliver high performance with infinite scalability to +`kernel modules`_, or to :abbr:`KVMs (kernel virtual machines)` such as `QEMU`_, and +cloud-based computing systems like `OpenStack`_ and `CloudStack`_ that rely on +libvirt and QEMU to integrate with Ceph block devices. You can use the same cluster +to operate the `Ceph RADOS Gateway`_, the `Ceph FS filesystem`_, and Ceph block +devices simultaneously. + +.. important:: To use Ceph Block Devices, you must have access to a running + Ceph cluster. + +.. toctree:: + :maxdepth: 1 + + Commands + Kernel Modules + Snapshots + Mirroring + QEMU + libvirt + Cache Settings + OpenStack + CloudStack + RBD Replay + +.. toctree:: + :maxdepth: 2 + + Manpages + +.. toctree:: + :maxdepth: 2 + + APIs + + + + +.. _RBD Caching: ../rbd-config-ref/ +.. _kernel modules: ../rbd-ko/ +.. _QEMU: ../qemu-rbd/ +.. _OpenStack: ../rbd-openstack +.. _CloudStack: ../rbd-cloudstack +.. _Ceph RADOS Gateway: ../../radosgw/ +.. _Ceph FS filesystem: ../../cephfs/ diff --git a/ceph/doc/rbd/librbdpy.rst b/ceph/doc/rbd/librbdpy.rst deleted file mode 100644 index fa9033125..000000000 --- a/ceph/doc/rbd/librbdpy.rst +++ /dev/null @@ -1,82 +0,0 @@ -================ - Librbd (Python) -================ - -.. highlight:: python - -The `rbd` python module provides file-like access to RBD images. - - -Example: Creating and writing to an image -========================================= - -To use `rbd`, you must first connect to RADOS and open an IO -context:: - - cluster = rados.Rados(conffile='my_ceph.conf') - cluster.connect() - ioctx = cluster.open_ioctx('mypool') - -Then you instantiate an :class:rbd.RBD object, which you use to create the -image:: - - rbd_inst = rbd.RBD() - size = 4 * 1024**3 # 4 GiB - rbd_inst.create(ioctx, 'myimage', size) - -To perform I/O on the image, you instantiate an :class:rbd.Image object:: - - image = rbd.Image(ioctx, 'myimage') - data = 'foo' * 200 - image.write(data, 0) - -This writes 'foo' to the first 600 bytes of the image. Note that data -cannot be :type:unicode - `Librbd` does not know how to deal with -characters wider than a :c:type:char. - -In the end, you will want to close the image, the IO context and the connection to RADOS:: - - image.close() - ioctx.close() - cluster.shutdown() - -To be safe, each of these calls would need to be in a separate :finally -block:: - - cluster = rados.Rados(conffile='my_ceph_conf') - try: - ioctx = cluster.open_ioctx('my_pool') - try: - rbd_inst = rbd.RBD() - size = 4 * 1024**3 # 4 GiB - rbd_inst.create(ioctx, 'myimage', size) - image = rbd.Image(ioctx, 'myimage') - try: - data = 'foo' * 200 - image.write(data, 0) - finally: - image.close() - finally: - ioctx.close() - finally: - cluster.shutdown() - -This can be cumbersome, so the :class:`Rados`, :class:`Ioctx`, and -:class:`Image` classes can be used as context managers that close/shutdown -automatically (see :pep:`343`). Using them as context managers, the -above example becomes:: - - with rados.Rados(conffile='my_ceph.conf') as cluster: - with cluster.open_ioctx('mypool') as ioctx: - rbd_inst = rbd.RBD() - size = 4 * 1024**3 # 4 GiB - rbd_inst.create(ioctx, 'myimage', size) - with rbd.Image(ioctx, 'myimage') as image: - data = 'foo' * 200 - image.write(data, 0) - -API Reference -============= - -.. automodule:: rbd - :members: RBD, Image, SnapIterator diff --git a/ceph/doc/rbd/man/index.rst b/ceph/doc/rbd/man/index.rst new file mode 100644 index 000000000..33a192a77 --- /dev/null +++ b/ceph/doc/rbd/man/index.rst @@ -0,0 +1,16 @@ +============================ + Ceph Block Device Manpages +============================ + +.. toctree:: + :maxdepth: 1 + + rbd <../../man/8/rbd> + rbd-fuse <../../man/8/rbd-fuse> + rbd-nbd <../../man/8/rbd-nbd> + rbd-ggate <../../man/8/rbd-ggate> + ceph-rbdnamer <../../man/8/ceph-rbdnamer> + rbd-replay-prep <../../man/8/rbd-replay-prep> + rbd-replay <../../man/8/rbd-replay> + rbd-replay-many <../../man/8/rbd-replay-many> + rbd-map <../../man/8/rbdmap> diff --git a/ceph/doc/rbd/rbd-config-ref.rst b/ceph/doc/rbd/rbd-config-ref.rst index 6ce2fdc2c..db942f88c 100644 --- a/ceph/doc/rbd/rbd-config-ref.rst +++ b/ceph/doc/rbd/rbd-config-ref.rst @@ -98,7 +98,7 @@ section of your configuration file. The settings include: :Required: No :Default: ``true`` -.. _Block Device: ../../rbd/rbd/ +.. _Block Device: ../../rbd Read-ahead Settings diff --git a/ceph/doc/rbd/rbd-mirroring.rst b/ceph/doc/rbd/rbd-mirroring.rst index 5f1c11489..e4db92832 100644 --- a/ceph/doc/rbd/rbd-mirroring.rst +++ b/ceph/doc/rbd/rbd-mirroring.rst @@ -288,13 +288,24 @@ distribution package. .. important:: Each ``rbd-mirror`` daemon requires the ability to connect to both clusters simultaneously. -.. warning:: Only run a single ``rbd-mirror`` daemon per Ceph cluster. A - future Ceph release will add support for horizontal scale-out of the - ``rbd-mirror`` daemon. +.. warning:: Pre-Luminous releases: only run a single ``rbd-mirror`` daemon per + Ceph cluster. + +Each ``rbd-mirror`` daemon should use a unique Ceph user ID. To +`create a Ceph user`_, with ``ceph`` specify the ``auth get-or-create`` +command, user name, monitor caps, and OSD caps:: + + ceph auth get-or-create client.rbd-mirror.{unique id} mon 'profile rbd' osd 'profile rbd' + +The ``rbd-mirror`` daemon can be managed by ``systemd`` by specifying the user +ID as the daemon instance:: + + systemctl enable ceph-rbd-mirror@rbd-mirror.{unique id} .. _rbd: ../../man/8/rbd .. _ceph-conf: ../../rados/configuration/ceph-conf/#running-multiple-clusters .. _explicitly enabled: #enable-image-mirroring .. _force resync command: #force-image-resync .. _demote the image: #image-promotion-and-demotion +.. _create a Ceph user: ../../rados/operations/user-management#add-a-user diff --git a/ceph/doc/rbd/rbd.rst b/ceph/doc/rbd/rbd.rst deleted file mode 100644 index e27e8c647..000000000 --- a/ceph/doc/rbd/rbd.rst +++ /dev/null @@ -1,72 +0,0 @@ -=================== - Ceph Block Device -=================== - -.. index:: Ceph Block Device; introduction - -A block is a sequence of bytes (for example, a 512-byte block of data). -Block-based storage interfaces are the most common way to store data with -rotating media such as hard disks, CDs, floppy disks, and even traditional -9-track tape. The ubiquity of block device interfaces makes a virtual block -device an ideal candidate to interact with a mass data storage system like Ceph. - -Ceph block devices are thin-provisioned, resizable and store data striped over -multiple OSDs in a Ceph cluster. Ceph block devices leverage -:abbr:`RADOS (Reliable Autonomic Distributed Object Store)` capabilities -such as snapshotting, replication and consistency. Ceph's -:abbr:`RADOS (Reliable Autonomic Distributed Object Store)` Block Devices (RBD) -interact with OSDs using kernel modules or the ``librbd`` library. - -.. ditaa:: +------------------------+ +------------------------+ - | Kernel Module | | librbd | - +------------------------+-+------------------------+ - | RADOS Protocol | - +------------------------+-+------------------------+ - | OSDs | | Monitors | - +------------------------+ +------------------------+ - -.. note:: Kernel modules can use Linux page caching. For ``librbd``-based - applications, Ceph supports `RBD Caching`_. - -Ceph's block devices deliver high performance with infinite scalability to -`kernel modules`_, or to :abbr:`KVMs (kernel virtual machines)` such as `QEMU`_, and -cloud-based computing systems like `OpenStack`_ and `CloudStack`_ that rely on -libvirt and QEMU to integrate with Ceph block devices. You can use the same cluster -to operate the `Ceph RADOS Gateway`_, the `Ceph FS filesystem`_, and Ceph block -devices simultaneously. - -.. important:: To use Ceph Block Devices, you must have access to a running - Ceph cluster. - -.. toctree:: - :maxdepth: 1 - - Commands - Kernel Modules - Snapshots - Mirroring - QEMU - libvirt - Cache Settings - OpenStack - CloudStack - Manpage rbd <../../man/8/rbd> - Manpage rbd-fuse <../../man/8/rbd-fuse> - Manpage rbd-nbd <../../man/8/rbd-nbd> - Manpage ceph-rbdnamer <../../man/8/ceph-rbdnamer> - RBD Replay - Manpage rbd-replay-prep <../../man/8/rbd-replay-prep> - Manpage rbd-replay <../../man/8/rbd-replay> - Manpage rbd-replay-many <../../man/8/rbd-replay-many> - Manpage rbdmap <../../man/8/rbdmap> - librbd - - - -.. _RBD Caching: ../rbd-config-ref/ -.. _kernel modules: ../rbd-ko/ -.. _QEMU: ../qemu-rbd/ -.. _OpenStack: ../rbd-openstack -.. _CloudStack: ../rbd-cloudstack -.. _Ceph RADOS Gateway: ../../radosgw/ -.. _Ceph FS filesystem: ../../cephfs/ diff --git a/ceph/doc/release-notes.rst b/ceph/doc/release-notes.rst index 299b0a3d8..db0dbbc8b 100644 --- a/ceph/doc/release-notes.rst +++ b/ceph/doc/release-notes.rst @@ -2,11 +2,11 @@ Release Notes =============== -v12.1.0 Luminous (RC) +v12.1.2 Luminous (RC) ===================== -This is the first release candidate for Luminous, the next long term -stable release. +This is the third release candidate for Luminous, the next long term stable +release. Ceph Luminous (v12.2.0) will be the foundation for the next long-term stable release series. There have been major changes since Kraken @@ -18,26 +18,32 @@ Major Changes from Kraken - *General*: - * Ceph now has a simple, built-in web-based dashboard for monitoring - cluster status. See :doc:`/mgr/dashboard/`. + * Ceph now has a simple, `built-in web-based dashboard + <../mgr/dashboard>`_ for monitoring cluster status. - *RADOS*: * *BlueStore*: - - The new *BlueStore* backend for *ceph-osd* is now stable and the new - default for newly created OSDs. BlueStore manages data stored by each OSD - by directly managing the physical HDDs or SSDs without the use of an - intervening file system like XFS. This provides greater performance - and features. FIXME DOCS - - BlueStore supports *full data and metadata checksums* of all + - The new *BlueStore* backend for *ceph-osd* is now stable and the + new default for newly created OSDs. BlueStore manages data + stored by each OSD by directly managing the physical HDDs or + SSDs without the use of an intervening file system like XFS. + This provides greater performance and features. See + :doc:`/rados/configuration/storage-devices` and + :doc:`/rados/configuration/bluestore-config-ref`. + - BlueStore supports `full data and metadata checksums + <../rados/configuration/bluestore-config-ref/#checksums`_ of all data stored by Ceph. - - BlueStore supports inline compression using zlib, snappy, or LZ4. (Ceph - also supports zstd for RGW compression but zstd is not recommended for - BlueStore for performance reasons.) FIXME DOCS + - BlueStore supports `inline compression + <../rados/configuration/bluestore-config-ref/#inline-compression>`_ using + zlib, snappy, or LZ4. (Ceph also supports zstd for `RGW compression + <../man/8/radosgw-admin/#options>`_ but zstd is not recommended for + BlueStore for performance reasons.) - * *Erasure coded* pools now have full support for *overwrites*, - allowing them to be used with RBD and CephFS. See :doc:`/rados/operations/erasure-code/#erasure-coding-with-overwrites`. + * *Erasure coded* pools now have `full support for overwrites + <../rados/operations/erasure-code/#erasure-coding-with-overwrites>`_, + allowing them to be used with RBD and CephFS. * *ceph-mgr*: @@ -46,34 +52,38 @@ Major Changes from Kraken down, metrics will not refresh and some metrics-related calls (e.g., ``ceph df``) may block. We recommend deploying several instances of *ceph-mgr* for reliability. See the notes on `Upgrading`_ below. - - The *ceph-mgr* daemon includes a REST-based management API. The - API is still experimental and somewhat limited but will form the basis - for API-based management of Ceph going forward. See :doc:`/mgr/restful`. - - *ceph-mgr* also includes a Prometheus exporter plugin, which can - provide Ceph perfcounters to Prometheus. See :doc:`/mgr/prometheus`. + - The *ceph-mgr* daemon includes a `REST-based management API + <../mgr/restful>`_. The API is still experimental and somewhat limited but + will form the basis for API-based management of Ceph going forward. + - *ceph-mgr* also includes a `Prometheus exporter <../mgr/prometheus>`_ + plugin, which can provide Ceph perfcounters to Prometheus. * The overall *scalability* of the cluster has improved. We have successfully tested clusters with up to 10,000 OSDs. - * Each OSD can now have a *device class* associated with it (e.g., - `hdd` or `ssd`), allowing CRUSH rules to trivially map data to a - subset of devices in the system. Manually writing CRUSH rules or - manual editing of the CRUSH is normally not required. See - :doc:`/rados/operations/crush-map/#crush-structure`. + * Each OSD can now have a `device class + <../rados/operations/crush-map/#device-classes>`_ associated with + it (e.g., `hdd` or `ssd`), allowing CRUSH rules to trivially map + data to a subset of devices in the system. Manually writing CRUSH + rules or manual editing of the CRUSH is normally not required. * You can now *optimize CRUSH weights* to maintain a *near-perfect distribution of data* across OSDs. FIXME DOCS - * There is also a new `upmap` exception mechanism that allows - individual PGs to be moved around to achieve a *perfect - distribution* (this requires luminous clients). See - :doc:`/rados/operations/upmap`. + * There is also a new `upmap <../rados/operations/upmap>`_ exception + mechanism that allows individual PGs to be moved around to achieve + a *perfect distribution* (this requires luminous clients). * Each OSD now adjusts its default configuration based on whether the backing device is an HDD or SSD. Manual tuning generally not required. - * The prototype `mClock QoS queueing algorithm ` is now available. + * The prototype `mClock QoS queueing algorithm + <../rados/configuration/osd-config-ref/#qos-based-on-mclock>`_ is now + available. * There is now a *backoff* mechanism that prevents OSDs from being overloaded by requests to objects or PGs that are not currently able to process IO. - * There is a simplified OSD replacement process that is more robust (see :doc:`/rados/operations/add-or-rm-osds/#replacing-an-osd`). + * There is a simplified `OSD replacement process + <../rados/operations/add-or-rm-osds/#replacing-an-osd>`_ that is more + robust. * You can query the supported features and (apparent) releases of - all connected daemons and clients with `ceph features `_. + all connected daemons and clients with `ceph features + <../man/8/ceph#features>`_. * You can configure the oldest Ceph client version you wish to allow to connect to the cluster via ``ceph osd set-require-min-compat-client`` and Ceph will prevent you from enabling features that will break compatibility @@ -115,6 +125,8 @@ Major Changes from Kraken * RBD mirroring's rbd-mirror daemon is now highly available. We recommend deploying several instances of rbd-mirror for reliability. + * RBD mirroring's rbd-mirror daemon should utilize unique Ceph user + IDs per instance to support the new mirroring dashboard. * The default 'rbd' pool is no longer created automatically during cluster creation. Additionally, the name of the default pool used by the rbd CLI when no pool is specified can be overridden via a @@ -148,7 +160,8 @@ Major Changes from Kraken - *Miscellaneous*: - * Release packages are now being built for *Debian Stretch*. The + * Release packages are now being built for *Debian Stretch*. Note + that QA is limited to CentOS and Ubuntu (xenial and trusty). The distributions we build for now includes: - CentOS 7 (x86_64 and aarch64) @@ -157,8 +170,6 @@ Major Changes from Kraken - Ubuntu 16.04 Xenial (x86_64 and aarch64) - Ubuntu 14.04 Trusty (x86_64) - Note that QA is limited to CentOS and Ubuntu (xenial and trusty). - * *CLI changes*: - The ``ceph -s`` or ``ceph status`` command has a fresh look. @@ -208,6 +219,8 @@ Major Changes from Kraken disable the named mgr module. The module must be present in the configured `mgr_module_path` on the host(s) where `ceph-mgr` is running. + - ``ceph osd crush ls `` will list items (OSDs or other CRUSH nodes) + directly beneath a given CRUSH node. - ``ceph osd crush swap-bucket `` will swap the contents of two CRUSH buckets in the hierarchy while preserving the buckets' ids. This allows an entire subtree of devices to @@ -234,14 +247,12 @@ Major Changes from Kraken - ``ceph osd reweightn`` will specify the `reweight` values for multiple OSDs in a single command. This is equivalent to a series of ``ceph osd reweight`` commands. - - ``ceph osd crush class {rm,ls,ls-osd}`` manage the new - CRUSH *device class* feature. ``ceph crush set-device-class - [...]`` will set the class for particular devices. - Note that if you specify a non-existent class, it will be created - automatically. ``ceph crush rm-device-class [...]`` - will instead remove the class for particular devices. - And if a class contains no more devices, it will be automatically - destoryed. + - ``ceph osd crush {set,rm}-device-class`` manage the new + CRUSH *device class* feature. Note that manually creating or deleting + a device class name is generally not necessary as it will be smart + enough to be self-managed. ``ceph osd crush class ls`` and + ``ceph osd crush class ls-osd`` will output all existing device classes + and a list of OSD ids under the given device class respectively. - ``ceph osd crush rule create-replicated`` replaces the old ``ceph osd crush rule create-simple`` command to create a CRUSH rule for a replicated pool. Notably it takes a `class` argument @@ -418,8 +429,64 @@ upgrade to Luminous. Upgrade compatibility notes, Kraken to Luminous ----------------------------------------------- +* The configuration option ``osd pool erasure code stripe width`` has + been replaced by ``osd pool erasure code stripe unit``, and given + the ability to be overridden by the erasure code profile setting + ``stripe_unit``. For more details see + :doc:`/rados/operations/erasure-code/#erasure-code-profiles`. + +* rbd and cephfs can use erasure coding with bluestore. This may be + enabled by setting ``allow_ec_overwrites`` to ``true`` for a pool. Since + this relies on bluestore's checksumming to do deep scrubbing, + enabling this on a pool stored on filestore is not allowed. + +* The ``rados df`` JSON output now prints numeric values as numbers instead of + strings. + +* The ``mon_osd_max_op_age`` option has been renamed to + ``mon_osd_warn_op_age`` (default: 32 seconds), to indicate we + generate a warning at this age. There is also a new + ``mon_osd_err_op_age_ratio`` that is a expressed as a multitple of + ``mon_osd_warn_op_age`` (default: 128, for roughly 60 minutes) to + control when an error is generated. + +* The default maximum size for a single RADOS object has been reduced from + 100GB to 128MB. The 100GB limit was completely impractical in practice + while the 128MB limit is a bit high but not unreasonable. If you have an + application written directly to librados that is using objects larger than + 128MB you may need to adjust ``osd_max_object_size``. + +* The semantics of the ``rados ls`` and librados object listing + operations have always been a bit confusing in that "whiteout" + objects (which logically don't exist and will return ENOENT if you + try to access them) are included in the results. Previously + whiteouts only occurred in cache tier pools. In luminous, logically + deleted but snapshotted objects now result in a whiteout object, and + as a result they will appear in ``rados ls`` results, even though + trying to read such an object will result in ENOENT. The ``rados + listsnaps`` operation can be used in such a case to enumerate which + snapshots are present. + + This may seem a bit strange, but is less strange than having a + deleted-but-snapshotted object not appear at all and be completely + hidden from librados's ability to enumerate objects. Future + versions of Ceph will likely include an alternative object + enumeration interface that makes it more natural and efficient to + enumerate all objects along with their snapshot and clone metadata. + +* The deprecated ``crush_ruleset`` property has finally been removed; + please use ``crush_rule`` instead for the ``osd pool get ...`` and ``osd + pool set ...`` commands. + +* The ``osd pool default crush replicated ruleset`` option has been + removed and replaced by the ``psd pool default crush rule`` option. + By default it is -1, which means the mon will pick the first type + replicated rule in the CRUSH map for replicated pools. Erasure + coded pools have rules that are automatically created for them if + they are not specified at pool creation time. + * We no longer test the FileStore ceph-osd backend in combination with - ``btrfs``. We recommend against using btrfs. If you are using + btrfs. We recommend against using btrfs. If you are using btrfs-based OSDs and want to upgrade to luminous you will need to add the follwing to your ceph.conf:: @@ -488,6 +555,7 @@ Upgrade compatibility notes, Kraken to Luminous either the rados_nobjects_list_open (C) and nobjects_begin (C++) API or the new rados_object_list_begin (C) and object_list_begin (C++) API before updating the client-side librados library to Luminous. + Object enumeration (via any API) with the latest librados version and pre-Hammer OSDs is no longer supported. Note that no in-tree Ceph services rely on object enumeration via the deprecated APIs, so @@ -519,6 +587,678 @@ Upgrade compatibility notes, Kraken to Luminous by "ceph tell mds. ..." +Notable Changes since v12.1.1 (RC1) +----------------------------------- + +* choose_args encoding has been changed to make it architecture-independent. + If you deployed Luminous dev releases or 12.1.0 rc release and made use of + the CRUSH choose_args feature, you need to remove all choose_args mappings + from your CRUSH map before starting the upgrade. + +* The 'ceph health' structured output (JSON or XML) no longer contains + a 'timechecks' section describing the time sync status. This + information is now available via the 'ceph time-sync-status' + command. + +* Certain extra fields in the 'ceph health' structured output that + used to appear if the mons were low on disk space (which duplicated + the information in the normal health warning messages) are now gone. + +* The "ceph -w" output no longer contains audit log entries by default. + Add a "--watch-channel=audit" or "--watch-channel=*" to see them. + +* The 'apply' mode of cephfs-journal-tool has been removed + +* Added new configuration "public bind addr" to support dynamic environments + like Kubernetes. When set the Ceph MON daemon could bind locally to an IP + address and advertise a different IP address "public addr" on the network. + +* New "ceph -w" behavior - the "ceph -w" output no longer contains I/O rates, + available space, pg info, etc. because these are no longer logged to the + central log (which is what "ceph -w" shows). The same information can be + obtained by running "ceph pg stat"; alternatively, I/O rates per pool can + be determined using "ceph osd pool stats". Although these commands do not + self-update like "ceph -w" did, they do have the ability to return formatted + output by providing a "--format=" option. + +* Pools are now expected to be associated with the application using them. + Upon completing the upgrade to Luminous, the cluster will attempt to associate + existing pools to known applications (i.e. CephFS, RBD, and RGW). In-use pools + that are not associated to an application will generate a health warning. Any + unassociated pools can be manually associated using the new + "ceph osd pool application enable" command. For more details see + "Associate Pool to Application" in the documentation. + +* ceph-mgr now has a Zabbix plugin. Using zabbix_sender it sends trapper + events to a Zabbix server containing high-level information of the Ceph + cluster. This makes it easy to monitor a Ceph cluster's status and send + out notifications in case of a malfunction. + +* The 'mon_warn_osd_usage_min_max_delta' config option has been + removed and the associated health warning has been disabled because + it does not address clusters undergoing recovery or CRUSH rules that do + not target all devices in the cluster. + +* Specifying user authorization capabilities for RBD clients has been + simplified. The general syntax for using RBD capability profiles is + "mon 'profile rbd' osd 'profile rbd[-read-only][ pool={pool-name}[, ...]]'". + For more details see "User Management" in the documentation. + +* ``ceph config-key put`` has been deprecated in favor of ``ceph config-key set``. + + +Notable Changes since v12.1.1 (RC2) +----------------------------------- + +* New "ceph -w" behavior - the "ceph -w" output no longer contains I/O rates, + available space, pg info, etc. because these are no longer logged to the + central log (which is what "ceph -w" shows). The same information can be + obtained by running "ceph pg stat"; alternatively, I/O rates per pool can + be determined using "ceph osd pool stats". Although these commands do not + self-update like "ceph -w" did, they do have the ability to return formatted + output by providing a "--format=" option. + +* Pools are now expected to be associated with the application using them. + Upon completing the upgrade to Luminous, the cluster will attempt to associate + existing pools to known applications (i.e. CephFS, RBD, and RGW). In-use pools + that are not associated to an application will generate a health warning. Any + unassociated pools can be manually associated using the new + "ceph osd pool application enable" command. For more details see + "Associate Pool to Application" in the documentation. + +* ceph-mgr now has a Zabbix plugin. Using zabbix_sender it sends trapper + events to a Zabbix server containing high-level information of the Ceph + cluster. This makes it easy to monitor a Ceph cluster's status and send + out notifications in case of a malfunction. + +* The 'mon_warn_osd_usage_min_max_delta' config option has been + removed and the associated health warning has been disabled because + it does not address clusters undergoing recovery or CRUSH rules that do + not target all devices in the cluster. + +* Specifying user authorization capabilities for RBD clients has been + simplified. The general syntax for using RBD capability profiles is + "mon 'profile rbd' osd 'profile rbd[-read-only][ pool={pool-name}[, ...]]'". + For more details see "User Management" in the documentation. + +* RGW: bucket index resharding now uses the reshard namespace in log pool + upgrade scenarios as well this is a changed behaviour from RC1 where a + new pool for reshard was created + +* RGW multisite now supports for enabling or disabling sync at a bucket level. + +Other Notable Changes +--------------------- +* bluestore: bluestore/BlueFS: pass string as const ref (`pr#16600 `_, dingdangzhang) +* bluestore: common/options: make "blue{fs,store}_allocator" LEVEL_DEV (`issue#20660 `_, `pr#16645 `_, Kefu Chai) +* bluestore: os/bluestore/BlueStore: Avoid double counting state_kv_queued_lat (`pr#16374 `_, Jianpeng Ma) +* bluestore: os/bluestore/BlueStore: remove unused code (`pr#16522 `_, Jianpeng Ma) +* bluestore: os/bluestore: move aio.h/cc from fs dir to bluestore dir (`pr#16409 `_, Pan Liu) +* bluestore: os/bluestore/StupidAllocator: rounded down len to an align boundary (`issue#20660 `_, `pr#16593 `_, Zhu Shangzhong) +* bluestore: os/bluestore: use reference to avoid string copy (`pr#16364 `_, Pan Liu) +* build/ops: ceph-disk: don't activate suppressed journal devices (`issue#19489 `_, `pr#16123 `_, David Disseldorp) +* build/ops: do_cmake.sh: fix syntax for /bin/sh (doesn't have +=) (`pr#16433 `_, Dan Mick) +* build/ops: include/assert: test c++ before using static_cast<> (`pr#16424 `_, Kefu Chai) +* build/ops: install-deps.sh: add missing dependencies for FreeBSD (`pr#16545 `_, Alan Somers) +* build/ops,rbd,rgw: CMakeLists: trim rbd/rgw forced dependencies (`pr#16574 `_, Patrick Donnelly) +* build/ops: rpm: Drop legacy libxio support (`pr#16449 `_, Nathan Cutler) +* build/ops: rpm: fix typo WTIH_BABELTRACE (`pr#16366 `_, Nathan Cutler) +* build/ops: rpm: put mgr python build dependencies in make_check bcond (`issue#20425 `_, `pr#15940 `_, Nathan Cutler, Tim Serong) +* build/ops,tests: qa: make run-standalone work on FreeBSD (`pr#16595 `_, Willem Jan Withagen) +* cmake: disable -fvar-tracking-assignments for config.cc (`pr#16695 `_, Kefu Chai) +* cmake: use CMAKE_INSTALL_INCLUDEDIR (`pr#16483 `_, David Disseldorp) +* common: buffer: silence unused var warning on FreeBSD (`pr#16452 `_, Willem Jan Withagen) +* common: common/common_init: disable default dout logging for UTILITY_NODOUT too (`issue#20771 `_, `pr#16578 `_, Sage Weil) +* common: common/options: refactors to set the properties in a more structured way (`pr#16482 `_, Kefu Chai) +* common: common/WorkQueue: use threadpoolname + threadaddr for heartbeat_han… (`pr#16563 `_, huangjun) +* common,core: osd,mds,mgr: do not dereference null rotating_keys (`issue#20667 `_, `pr#16455 `_, Sage Weil) +* common: fix Option set_long_description (`pr#16668 `_, Yan Jun) +* common: follow up to new options infrastructure (`pr#16527 `_, John Spray) +* common: HashIndex.cc: add compat.h for ENODATA (`pr#16697 `_, Willem Jan Withagen) +* common: libradosstriper: fix format injection vulnerability (`issue#20240 `_, `pr#15674 `_, Stan K) +* common,mon: crush,mon: add weight-set introspection and manipulation commands (`pr#16326 `_, Sage Weil) +* common: mon/MonClient: scale backoff interval down when we have a healthy mon session (`issue#20371 `_, `pr#16576 `_, Kefu Chai, Sage Weil) +* common: prevent unset_dumpable from generating warnings (`pr#16462 `_, Willem Jan Withagen) +* common,rbd: osdc/Objecter: unify disparate EAGAIN handling paths into one (`pr#16627 `_, Sage Weil) +* common: remove config opt conversion utility (`pr#16480 `_, John Spray) +* common: Revamp config option definitions (`issue#20627 `_, `pr#16211 `_, John Spray, Kefu Chai, Sage Weil) +* common,rgw: cls/refcount: store and use list of retired tags (`issue#20107 `_, `pr#15673 `_, Yehuda Sadeh) +* common: the latency dumped by "ceph osd perf" is not real (`issue#20749 `_, `pr#16512 `_, Pan Liu) +* common: use std::move() for better performance (`pr#16620 `_, Xinying Song) +* core: auth: Remove unused function in AuthSessionHandler (`pr#16666 `_, Luo Kexue) +* core: ceph: allow '-' with -i and -o for stdin/stdout (`pr#16359 `_, Sage Weil) +* core: ceph-disk: support osd new (`pr#15432 `_, Loic Dachary, Sage Weil) +* core: common/options: remove mon_warn_osd_usage_min_max_delta from options.cc too (`pr#16488 `_, Sage Weil) +* core: kv: resolve a crash issue in ~LevelDBStore() (`pr#16553 `_, wumingqiao) +* core: kv/RocksDBStore: use vector instead of VLA for holding slices (`pr#16615 `_, Kefu Chai) +* core: messages: default-initialize MOSDPGRecoveryDelete[Reply] members (`pr#16584 `_, Greg Farnum) +* core: mgr/MgrClient: do not attempt to access a global variable for config (`pr#16544 `_, Jason Dillaman) +* core,mgr,tests: qa: flush out monc's dropped msgs on msgr failure injection (`issue#20371 `_, `pr#16484 `_, Joao Eduardo Luis) +* core,mon: crush, mon: simplify device class manipulation commands (`pr#16388 `_, xie xingguo) +* core: mon, osd: misc fixes (`pr#16283 `_, xie xingguo) +* core,mon,rbd: mon,osd: new rbd-based cephx cap profiles (`pr#15991 `_, Jason Dillaman) +* core: msg/async: fix the bug of inaccurate calculation of l_msgr_send_bytes (`pr#16526 `_, Jin Cai) +* core: objclass: modify omap_get_{keys,vals} api (`pr#16667 `_, Yehuda Sadeh, Casey Bodley) +* core: osd/PG: fix warning so we discard_event() on a no-op state change (`pr#16655 `_, Sage Weil) +* core: osd/PG: ignore CancelRecovery in NotRecovering (`issue#20804 `_, `pr#16638 `_, Sage Weil) +* core: osd/PGLog: fix inaccurate missing assert (`issue#20753 `_, `pr#16539 `_, Josh Durgin) +* core: osd/PrimaryLogPG: fix recovering hang when have unfound objects (`pr#16558 `_, huangjun) +* core: osd/PrimaryLogPG: skip deleted missing objects in pg[n]ls (`issue#20739 `_, `pr#16490 `_, Josh Durgin) +* core,performance: kv/RocksDBStore: Table options for indexing and filtering (`pr#16450 `_, Mark Nelson) +* core,performance: osd/PG: make prioritized recovery possible (`pr#13723 `_, Piotr Dałek) +* core: PGLog: store extra duplicate ops beyond the normal log entries (`pr#16172 `_, Josh Durgin, J. Eric Ivancich) +* core,rgw,tests: qa/suits/rados/basic/tasks/rgw_snaps: wait for pools to be created (`pr#16509 `_, Sage Weil) +* core,tests: ceph_test_rados_api_watch_notify: flush after unwatch (`issue#20105 `_, `pr#16402 `_, Sage Weil) +* core,tests: ceph_test_rados: max_stride_size must be more than min_stride_size (`issue#20775 `_, `pr#16590 `_, Lianne Wang) +* core,tests: qa: move ceph-helpers-based make check tests to qa/standalone; run via teuthology (`pr#16513 `_, Sage Weil) +* core,tests: qa/suites/rados: at-end: ignore PG_{AVAILABILITY,DEGRADED} (`issue#20693 `_, `pr#16575 `_, Sage Weil) +* core,tests: qa/tasks/ceph_manager: wait for osd to start after objectstore-tool sequence (`issue#20705 `_, `pr#16454 `_, Sage Weil) +* core,tests: qa/tasks/ceph: wait for mgr to activate and pg stats to flush in health() (`issue#20744 `_, `pr#16514 `_, Sage Weil) +* core,tests: qa/tasks/dump_stuck: fix dump_stuck test bug (`pr#16559 `_, huangjun) +* core,tests: qa/workunits/cephtool/test.sh: add sudo for daemon compact (`pr#16500 `_, Sage Weil) +* core,tests: test: add separate ceph-helpers-based smoke test (`pr#16572 `_, Sage Weil) +* core: throttle: Minimal destructor fix for Luminous (`pr#16661 `_, Adam C. Emerson) +* core: vstart.sh: start mgr after mon, before osds (`pr#16613 `_, Sage Weil) +* crush: a couple of weight-set fixes (`pr#16623 `_, xie xingguo) +* crush: enforce buckets-before-rules rule (`pr#16453 `_, Sage Weil) +* crush: s/ruleset/id/ in decompiled output; prevent compilation when ruleset != id (`pr#16400 `_, Sage Weil) +* doc: Add amitkumar50 affiliation to .organizationmap (`pr#16475 `_, Amit Kumar) +* doc: add doc requirements on PR submitters (`pr#16394 `_, John Spray) +* doc: added mgr caps to manual deployment documentation (`pr#16660 `_, Nick Erdmann) +* doc: add instructions for replacing an OSD (`pr#16314 `_, Kefu Chai) +* doc: add rbd new trash cli and cleanups in release-notes.rst (`issue#20702 `_, `pr#16498 `_, songweibin) +* doc: Add Zabbix ceph-mgr plugin to PendingReleaseNotes (`pr#16412 `_, Wido den Hollander) +* doc: AUTHORS: update CephFS PTL (`pr#16399 `_, Patrick Donnelly) +* doc: ceph-disk: use '-' for feeding ceph cli with stdin (`pr#16362 `_, Kefu Chai) +* doc: common/options.cc: document bluestore config options (`pr#16489 `_, Sage Weil) +* doc: Describe mClock's use within Ceph in great detail (`pr#16707 `_, J. Eric Ivancich) +* doc: doc/install/manual-deployment: update osd creation steps (`pr#16573 `_, Sage Weil) +* doc: doc/mon: fix ceph-authtool command in rebuild mon's sample (`pr#16503 `_, huanwen ren) +* doc: doc/qa: cover `config help` command (`pr#16727 `_, John Spray) +* doc: doc/rados: add page for health checks and update monitoring.rst (`pr#16566 `_, John Spray) +* doc: doc/rados/operations/health-checks: osd section (`pr#16611 `_, Sage Weil) +* doc: doc/release-notes: fix upmap and osd replacement links; add fixme (`pr#16730 `_, Sage Weil) +* doc: [docs/quick-start]: update quick start to add a note for mgr create command for luminous+ builds (`pr#16350 `_, Vasu Kulkarni) +* doc: Documentation updates for July 2017 releases (`pr#16401 `_, Bryan Stillwell) +* doc: document mClock related options (`pr#16552 `_, Kefu Chai) +* doc: Fixed a typo in yum repo filename script (`pr#16431 `_, Jeff Green) +* doc: fix typo in config.rst (`pr#16721 `_, Jos Collin) +* doc: fix typos in config.rst (`pr#16681 `_, Song Shun) +* doc: mailmap: add affiliation for Zhu Shangzhong (`pr#16537 `_, Zhu Shangzhong) +* doc: .mailmap, .organizationmap: Update ztczll affiliation (`pr#16038 `_, zhanglei) +* doc: PendingReleaseNotes: "ceph -w" behavior has changed drastically (`pr#16425 `_, Joao Eduardo Luis, Nathan Cutler) +* doc: Remove contractions from the documentation (`pr#16629 `_, John Wilkins) +* doc: remove docs on non-existant command (`pr#16616 `_, Luo Kexue, Kefu Chai) +* doc: reword mds deactivate docs; add optional fs_name argument (`issue#20607 `_, `pr#16471 `_, Jan Fajerski) +* doc: rgw clarify limitations when creating tenant names (`pr#16418 `_, Abhishek Lekshmanan) +* doc: update ceph(8) man page with new sub-commands (`pr#16437 `_, Kefu Chai) +* doc: Update .organizationmap (`pr#16507 `_, luokexue) +* doc: update the pool names created by vstart.sh by default (`pr#16652 `_, Zhu Shangzhong) +* doc: update the rados namespace docs (`pr#15838 `_, Abhishek Lekshmanan) +* doc: upmap docs; various missing links for release notes (`pr#16637 `_, Sage Weil) +* doc: various fixes (`pr#16723 `_, Kefu Chai) +* librados: add missing implementations for C service daemon API methods (`pr#16543 `_, Jason Dillaman) +* librbd: add compare and write API (`pr#14868 `_, Zhengyong Wang, Jason Dillaman) +* librbd: add LIBRBD_SUPPORTS_WRITESAME support (`pr#16583 `_, Xiubo Li) +* mgr: add per-DaemonState lock (`pr#16432 `_, Sage Weil) +* mgr: fix lock cycle (`pr#16508 `_, Sage Weil) +* mgr: mgr/dashboard: add OSD list view (`pr#16373 `_, John Spray) +* mgr: mgr_module interface to report health alerts (`pr#16487 `_, Sage Weil) +* mgr: mgr/PyState: shut up about get_config on nonexistent keys (`pr#16641 `_, Sage Weil) +* mgr: mon/MgrMonitor: fix standby addition to mgrmap (`issue#20647 `_, `pr#16397 `_, Sage Weil) +* mgr,mon: mon/AuthMonitor: generate bootstrap-mgr key on upgrade (`issue#20666 `_, `pr#16395 `_, Joao Eduardo Luis) +* mgr,mon: mon/MgrMonitor: reset mgrdigest timer with new subscription (`issue#20633 `_, `pr#16582 `_, Sage Weil) +* mgr: perf schema fns/change notification and Prometheus plugin (`pr#16406 `_, Dan Mick) +* mgr: pybind/mgr/zabbix: fix health in non-compat mode (`issue#20767 `_, `pr#16580 `_, Sage Weil) +* mgr,pybind,rbd: mgr/dashboard: show rbd image features (`pr#16468 `_, Yanhu Cao) +* mgr,rbd: mgr/dashboard: RBD iSCSI daemon status page (`pr#16547 `_, Jason Dillaman) +* mgr,rbd: mgr/dashboard: rbd mirroring status page (`pr#16360 `_, Jason Dillaman) +* mgr: vstart.sh: fix mgr vs restful command startup race (`pr#16564 `_, Sage Weil) +* mon: add force-create-pg back (`issue#20605 `_, `pr#16353 `_, Kefu Chai) +* mon: add mgr metdata commands, and overall 'versions' command for all daemon versions (`pr#16460 `_, Sage Weil) +* mon: a few health fixes (`pr#16415 `_, xie xingguo) +* mon: 'config-key put' -> 'config-key set' (`pr#16569 `_, Sage Weil) +* mon: do not dereference empty mgr_commands (`pr#16501 `_, Sage Weil) +* mon: Fix deep_age copy paste error (`pr#16434 `_, Brad Hubbard) +* mon: Fix output text and doc (`pr#16367 `_, Yan Jun) +* mon: '\* list' -> '\* ls' (`pr#16423 `_, Sage Weil) +* mon: load mgr commands at runtime (`pr#16028 `_, John Spray, Sage Weil) +* mon: mon/HealthMonitor: avoid sending unnecessary MMonHealthChecks to leader (`pr#16478 `_, xie xingguo) +* mon: mon/HealthMonitor: trigger a proposal if stat updated (`pr#16477 `_, Kefu Chai) +* mon: mon/LogMonitor: don't read list's end() for log last (`pr#16376 `_, Joao Eduardo Luis) +* mon: mon/MDSMonitor: close object section of formatter (`pr#16516 `_, Chang Liu) +* mon: mon/MgrMonitor: only induce mgr epoch shortly after mkfs (`pr#16356 `_, Sage Weil) +* mon: mon/OSDMonitor: ensure UP is not set for newly-created OSDs (`issue#20751 `_, `pr#16534 `_, Sage Weil) +* mon: mon/OSDMonitor: issue pool application related warning (`pr#16520 `_, xie xingguo) +* mon: mon/OSDMonitor: remove zeroed new_state updates (`issue#20751 `_, `pr#16518 `_, Sage Weil) +* mon: mon/PGMap: remove skewed utilizatoin warning (`issue#20730 `_, `pr#16461 `_, Sage Weil) +* mon: OSDMonitor: check mon_max_pool_pg_num when set pool pg_num (`pr#16511 `_, chenhg) +* mon: prime pg_temp and a few health warning fixes (`pr#16530 `_, xie xingguo) +* mon: show destroyed status in tree view; do not auto-out destroyed osds (`pr#16446 `_, xie xingguo) +* mon: stop issuing not-[deep]-scrubbed warnings if disabled (`pr#16465 `_, xie xingguo) +* mon: support pool application metadata key/values (`pr#15763 `_, Jason Dillaman) +* msg: messages/: always set header.version in encode_payload() (`issue#19939 `_, `pr#16421 `_, Kefu Chai) +* msg: mgr/status: row has incorrect number of values (`issue#20750 `_, `pr#16529 `_, liuchang0812) +* msg: msg/async: use auto iterator having more simple code and good performance (`pr#16524 `_, dingdangzhang) +* osd: add default_device_class to metadata (`pr#16634 `_, Neha Ojha) +* osd: add dump filter for tracked ops (`pr#16561 `_, Yan Jun) +* osd: Add recovery sleep configuration option for HDDs and SSDs (`pr#16328 `_, Neha Ojha) +* osd: cmpext operator should ignore -ENOENT on read (`pr#16622 `_, Jason Dillaman) +* osd: combine conditional statements (`pr#16391 `_, Yan Jun) +* osd: do not send pg_created unless luminous (`issue#20785 `_, `pr#16677 `_, Kefu Chai) +* osd: EC read handling: don't grab an objectstore error to use as the read error (`pr#16663 `_, David Zafman) +* osd: fix a couple bugs with persisting the missing set when it contains deletes (`issue#20704 `_, `pr#16459 `_, Josh Durgin) +* osd: fix OpRequest and tracked op dump information (`pr#16504 `_, Yan Jun) +* osd: fix pg ref leaks when osd shutdown (`issue#20684 `_, `pr#16408 `_, Yang Honggang) +* osd: Log audit (`pr#16281 `_, Brad Hubbard) +* osd: moved OpFinisher logic from OSDOp to OpContext (`issue#20783 `_, `pr#16617 `_, Jason Dillaman) +* osd: populate last_epoch_split during build_initial_pg_history (`issue#20754 `_, `pr#16519 `_, Sage Weil) +* osd: PrimaryLogPG, PGBackend: complete callback even if interval changes (`issue#20747 `_, `pr#16536 `_, Josh Durgin) +* osd: process deletes during recovery instead of peering (`issue#19971 `_, `pr#15952 `_, Josh Durgin) +* osd: rephrase "wrongly marked me down" clog message (`pr#16365 `_, John Spray) +* osd: scrub_to specifies clone ver, but transaction include head write… (`issue#20041 `_, `pr#16404 `_, David Zafman) +* osd: support cmpext operation on EC-backed pools (`pr#15693 `_, Zhengyong Wang, Jason Dillaman) +* performance,rgw: rgw_file: permit dirent offset computation (`pr#16275 `_, Matt Benjamin) +* pybind: pybind/mgr/restful: fix typo (`pr#16560 `_, Nick Erdmann) +* rbd: cls/rbd: silence warning from -Wunused-variable (`pr#16670 `_, Yan Jun) +* rbd: cls/rbd: trash_list should be iterable (`issue#20643 `_, `pr#16372 `_, Jason Dillaman) +* rbd: fixed coverity 'Argument cannot be negative' warning (`pr#16686 `_, amitkuma) +* rbd: make it more understandable when adding peer returns error (`pr#16313 `_, songweibin) +* rbd-mirror: guard the deletion of non-primary images (`pr#16398 `_, Jason Dillaman) +* rbd-mirror: initialize timer context pointer to null (`pr#16603 `_, Jason Dillaman) +* rbd: modified some commands' description into imperative sentence (`pr#16694 `_, songweibin) +* rbd,tests: qa/tasks/rbd_fio: bump default fio version to 2.21 (`pr#16656 `_, Ilya Dryomov) +* rbd,tests: qa: thrash tests for backoff and upmap (`pr#16428 `_, Ilya Dryomov) +* rbd,tests: qa/workunits: adjust path to ceph-helpers.sh (`pr#16599 `_, Sage Weil) +* rgw: acl grants num limit (`pr#16291 `_, Enming Zhang) +* rgw: check placement existence when create bucket (`pr#16385 `_, Jiaying Ren) +* rgw: check placement target existence during bucket creation (`pr#16384 `_, Jiaying Ren) +* rgw: delete object in error path (`issue#20620 `_, `pr#16324 `_, Yehuda Sadeh) +* rgw: Do not decrement stats cache when the cache values are zero (`issue#20661 `_, `pr#16389 `_, Pavan Rallabhandi) +* rgw: Drop dump_usage_bucket_info() to silence warning from -Wunused-function (`pr#16497 `_, Wei Qiaomiao) +* rgw: drop unused find_replacement() and some function docs (`pr#16386 `_, Jiaying Ren) +* rgw: fix asctime when logging in rgw_lc (`pr#16422 `_, Abhishek Lekshmanan) +* rgw: fix error message in removing bucket with --bypass-gc flag (`issue#20688 `_, `pr#16419 `_, Abhishek Varshney) +* rgw: fix err when copy object in bucket with specified placement rule (`issue#20378 `_, `pr#15837 `_, fang yuxiang) +* rgw: Fix for Policy Parse exception in case of multiple statements (`pr#16689 `_, Pritha Srivastava) +* rgw: fix memory leaks during Swift Static Website's error handling (`issue#20757 `_, `pr#16531 `_, Radoslaw Zarzynski) +* rgw: fix parse/eval of policy conditions with IfExists (`issue#20708 `_, `pr#16463 `_, Casey Bodley) +* rgw: fix radosgw will crash when service is restarted during lifecycl… (`issue#20756 `_, `pr#16495 `_, Wei Qiaomiao) +* rgw: fix rgw hang when do RGWRealmReloader::reload after go SIGHUP (`issue#20686 `_, `pr#16417 `_, fang.yuxiang) +* rgw: fix segfault in RevokeThread during its shutdown procedure (`issue#19831 `_, `pr#15033 `_, Radoslaw Zarzynski) +* rgw: fix the UTF8 check on bucket entry name in rgw_log_op() (`issue#20779 `_, `pr#16604 `_, Radoslaw Zarzynski) +* rgw: modify email to empty by admin RESTful api doesn't work (`pr#16309 `_, fang.yuxiang) +* rgw: never let http_redirect_code of RGWRedirectInfo to stay uninitialized (`issue#20774 `_, `pr#16601 `_, Radoslaw Zarzynski) +* rgw: raise debug level of RGWPostObj_ObjStore_S3::get_policy (`pr#16203 `_, Shasha Lu) +* rgw: req xml params size limitation error msg (`pr#16310 `_, Enming Zhang) +* rgw: restore admin socket path in mrgw.sh (`pr#16540 `_, Casey Bodley) +* rgw: rgw_file: properly & |'d flags (`issue#20663 `_, `pr#16448 `_, Matt Benjamin) +* rgw: rgw multisite: feature of bucket sync enable/disable (`pr#15801 `_, Zhang Shaowen, Casey Bodley, Zengran Zhang) +* rgw: should unlock when reshard_log->update() reture non-zero in RGWB… (`pr#16502 `_, Wei Qiaomiao) +* rgw: test,rgw: fix rgw placement rule pool config option (`pr#16380 `_, Jiaying Ren) +* rgw: usage (`issue#16191 `_, `pr#14287 `_, Ji Chen, Orit Wasserman) +* rgw: use a namespace for rgw reshard pool for upgrades as well (`issue#20289 `_, `pr#16368 `_, Karol Mroz, Abhishek Lekshmanan) +* rgw: Use comparison instead of assignment (`pr#16653 `_, amitkuma) +* tests: add setup/teardown for asok dir (`pr#16523 `_, Kefu Chai) +* tests: cephtool/test.sh: Only delete a test pool when no longer needed (`pr#16443 `_, Willem Jan Withagen) +* tests: qa: Added luminous to the mix in schedule_subset.sh (`pr#16430 `_, Yuri Weinstein) +* tests: qa,doc: document and fix tests for pool application warnings (`pr#16568 `_, Sage Weil) +* tests: qa/run-standalone.sh: fix the find option to be compatible with GNU find (`pr#16646 `_, Kefu Chai) +* tests: qa/suites/rados/singleton/all/erasure-code-nonregression: fix typo (`pr#16579 `_, Sage Weil) +* tests: qa/suites/upgrade/jewel-x: misc fixes for new health checks (`pr#16429 `_, Sage Weil) +* tests: qa/tasks/ceph-deploy: Fix bluestore options for ceph-deploy (`pr#16571 `_, Vasu Kulkarni) +* tests: qa/tasks/reg11184: use literal 'foo' instead pool_name (`pr#16451 `_, Kefu Chai) +* tests: qa/workunits/cephtool/test.sh: "ceph osd stat" output changed, update accordingly (`pr#16444 `_, Willem Jan Withagen, Kefu Chai) +* tests: qa/workunits/cephtool/test.sh: disable 'fs status' until bug is fixed (`issue#20761 `_, `pr#16541 `_, Sage Weil) +* tests: qa/workunits/cephtool/test.sh: fix test to watch audit channel (`pr#16470 `_, Sage Weil) +* tests: test: ceph osd stat out has changed, fix tests for that (`pr#16403 `_, Willem Jan Withagen) +* tests: test: create asok files in a temp directory under $TMPDIR (`issue#16895 `_, `pr#16445 `_, Kefu Chai) +* tests: test: Fixes for test_pidfile (`issue#20770 `_, `pr#16587 `_, David Zafman) +* tests: test/osd: kill compile warning (`pr#16669 `_, Yan Jun) +* tests: test/rados: fix wrong parameter order of RETURN1_IF_NOT_VAL (`pr#16589 `_, Yan Jun) +* tests: test: reg11184 might not always find pg 2.0 prior to import (`pr#16610 `_, David Zafman) +* tests: test: s/osd_objectstore_type/osd_objectstore (`pr#16469 `_, xie xingguo) +* tests: test: test_pidfile running 2nd mon has unreliable log output (`pr#16635 `_, David Zafman) +* tools: ceph-disk: change the lockbox partition number to 5 (`issue#20556 `_, `pr#16247 `_, Shangzhong Zhu) +* tools: ceph-disk: Fix for missing 'not' in \*_is_diskdevice checks (`issue#20706 `_, `pr#16481 `_, Nikita Gerasimov) +* tools: ceph_disk/main.py: FreeBSD root has wheel for group (`pr#16609 `_, Willem Jan Withagen) +* tools: ceph-disk: s/ceph_osd_mkfs/command_check_call/ (`issue#20685 `_, `pr#16427 `_, Zhu Shangzhong) +* tools: ceph-release-notes: escape _ for unintended links (`issue#17499 `_, `pr#16528 `_, Kefu Chai) +* tools: ceph-release-notes: port it to py3 (`pr#16261 `_, Kefu Chai) +* tools: ceph-release-notes: refactor and fix regressions (`pr#16411 `_, Nathan Cutler) +* tools: os/bluestore/bluestore_tool: add sanity check to get rid of occasionally crash (`pr#16013 `_, xie xingguo) +* tools: script: add docker core dump debugger (`pr#16375 `_, Patrick Donnelly) + + +v12.1.2 Luminous (RC) +===================== + +This is the second release candidate for Luminous, the next long term +stable release. + + +Other Notable Changes +--------------------- + +* bluestore,common,performance: isa-l: update isa-l to v2.18 (`pr#15895 `_, Ganesh Mahalingam, Tushar Gohad) +* bluestore: os/bluestore/BlueFS: clean up log_writer aios from compaction (`issue#20454 `_, `pr#16017 `_, Sage Weil) +* bluestore: os/bluestore/BlueFS: clear current log entrys before dump all fnode (`pr#15973 `_, Jianpeng Ma) +* bluestore: os/bluestore: cleanup min_alloc_size; some formatting nits (`pr#15826 `_, xie xingguo) +* bluestore: os/bluestore: clear up redundant size assignment in KerenelDevice (`pr#16121 `_, Shasha Lu) +* bluestore: os/blueStore: Failure retry for opening file (`pr#16237 `_, Yankun Li) +* bluestore: os/bluestore: fix deferred_aio deadlock (`pr#16051 `_, Sage Weil) +* bluestore: os/bluestore: Make BitmapFreelistManager kv itereator short lived (`pr#16243 `_, Mark Nelson) +* bluestore: os/bluestore: misc fix and cleanups (`pr#16315 `_, Jianpeng Ma) +* bluestore: os/bluestore: move object exist in assign nid (`pr#16117 `_, Jianpeng Ma) +* bluestore: os/bluestore: narrow cache lock range; make sure min_alloc_size p2 aligned (`pr#15911 `_, xie xingguo) +* bluestore: os/bluestore: only submit deferred if there is any (`pr#16269 `_, Sage Weil) +* bluestore: os/bluestore: reduce some overhead for _do_clone_range() and _do_remove() (`pr#15944 `_, xie xingguo) +* bluestore: os/bluestore: slightly refactor Blob::try_reuse_blob (`pr#15836 `_, xie xingguo) +* bluestore: os/bluestore: use bufferlist functions whenever possible (`pr#16158 `_, Jianpeng Ma) +* bluestore,performance: os/bluestore: cap rocksdb cache size (`pr#15786 `_, Mark Nelson) +* bluestore,performance: os/bluestore: default cache size of 3gb (`pr#15976 `_, Sage Weil) +* bluestore,performance: os/bluestore: differ default cache size for hdd/ssd backends (`pr#16157 `_, xie xingguo) +* bluestore,performance: os/bluestore/KernelDevice: batch aio submit (`pr#16032 `_, Haodong Tang) +* bluestore,performance: os/bluestore: optimized (encode|decode)_escaped (`pr#15759 `_, Piotr Dałek) +* build/ops: build: build erasure-code isa lib without versions (`pr#16205 `_, James Page) +* build/ops: build: execute dh_systemd_{enable,start} after dh_install (`issue#19585 `_, `pr#16218 `_, James Page) +* build/ops: ceph.in: allow developer mode from outside build tree (`issue#20472 `_, `pr#16055 `_, Dan Mick) +* build/ops: ceph_release: we are in the 'rc' phase (12.1.z) (`pr#15957 `_, Sage Weil) +* build/ops,core: osd/OSD: auto class on osd start up (`pr#16014 `_, xie xingguo) +* build/ops: debian: workaround the bug in dpkg-maintscript-helper (`issue#20453 `_, `pr#16072 `_, Kefu Chai) +* build/ops: debian: wrap-and-sort all files (`pr#16110 `_, James Page) +* build/ops: os/bluestore: fix build errors when spdk is on (`pr#16118 `_, Ilsoo Byun) +* build/ops,rbd,tests: test/librbd: re-enable internal tests in ceph_test_librbd (`pr#16255 `_, Mykola Golub) +* build/ops,rgw,tests,tools: vstart: allow to start multiple radosgw when RGW=x (`pr#15632 `_, Adam Kupczyk) +* build/ops,rgw,tools: vstart: add --rgw_compression to set rgw compression plugin (`pr#15929 `_, Casey Bodley) +* build/ops: rpm: bump epoch ahead of RHEL base (`issue#20508 `_, `pr#16126 `_, Ken Dreyer) +* build/ops: rpm: Fix undefined FIRST_ARG (`issue#20077 `_, `pr#16208 `_, Boris Ranto) +* build/ops: rpm: obsolete libcephfs1 (`pr#16074 `_, Nathan Cutler) +* build/ops: rpm: sane packaging of %{_docdir}/ceph directory (`pr#15900 `_, Nathan Cutler) +* build/ops: systemd: Add explicit Before=ceph.target (`pr#15835 `_, Tim Serong) +* build/ops: systemd/ceph-mgr: remove automagic mgr creation hack (`issue#19994 `_, `pr#16023 `_, Sage Weil) +* build/ops,tests,tools: vstart.sh: Work around mgr restfull not available (`pr#15877 `_, Willem Jan Withagen) +* cephfs: Remove "experimental" warnings from multimds (`pr#15154 `_, John Spray, "Yan, Zheng") +* cleanup: test,mon,msg: kill clang analyzer warnings (`pr#16320 `_, Kefu Chai) +* cmake: fix the build with -DWITH_ZFS=ON (`pr#15907 `_, Kefu Chai) +* cmake: Rewrite HAVE_BABELTRACE option to WITH_ (`pr#15305 `_, Willem Jan Withagen) +* common: auth/RotatingKeyRing: use std::move() to set secrets (`pr#15866 `_, Kefu Chai) +* common: ceph.in, mgr: misc cleanups (`pr#16229 `_, liuchang0812) +* common: common,config: OPT_FLOAT and OPT_DOUBLE output format in config show (`issue#20104 `_, `pr#15647 `_, Yanhu Cao) +* common: common/config_opt: remove unused config (`pr#15874 `_, alex.wu) +* common: common/config_opts: drop unused opt (`pr#15876 `_, Yanhu Cao) +* common: common/Mutex.cc: fixed the error in comment (`pr#16214 `_, Pan Liu) +* common: common/Timer: do not add event if already shutdown (`issue#20432 `_, `pr#16201 `_, Kefu Chai) +* common: compressor/zlib: remove g_ceph_context/g_conf from compressor plugin (`pr#16245 `_, Casey Bodley) +* common,core: osd/osd_types: add flag name (IGNORE_REDIRECT) (`pr#15795 `_, Myoungwon Oh) +* common: fix log warnings (`pr#16056 `_, xie xingguo) +* common: initialize array in struct BackTrace (`pr#15864 `_, Jos Collin) +* common: libradosstriper: fix format injection vulnerability (`issue#20240 `_, `pr#15674 `_, Stan K) +* common: misc cleanups in common, global, os, osd submodules (`pr#16321 `_, Yan Jun) +* common: msg/async: make recv_stamp more precise (`pr#15810 `_, Pan Liu) +* common: osdc/Objecter: release message if it's not handled (`issue#19741 `_, `pr#15890 `_, Kefu Chai) +* common: osd/OSDMap: print require_osd_release (`pr#15974 `_, Sage Weil) +* common: Passing null pointer option_name to operator << in md_config_t::parse_option() (`pr#15881 `_, Jos Collin) +* common,rdma: msg/async/rdma: use lists properly (`pr#15908 `_, Adir lev, Adir Lev) +* common,tests: ceph_test_rados_api_c_read_operations: do not assert per-op rval is correct (`issue#19518 `_, `pr#16196 `_, Sage Weil) +* common: Update the error string when res_nsearch() or res_search() fails (`pr#15878 `_, huanwen ren) +* core: ceph-disk/ceph_disk/main.py: Replace ST_ISBLK() test by is_diskdevice() (`pr#15587 `_, Willem Jan Withagen) +* core: ceph_disk/main.py: Allow FreeBSD zap a OSD disk (`pr#15642 `_, Willem Jan Withagen) +* core: ceph-disk: set the default systemd unit timeout to 3h (`issue#20229 `_, `pr#15585 `_, Loic Dachary) +* core: Context: C_ContextsBase: delete enclosed contexts in dtor (`issue#20432 `_, `pr#16159 `_, Kefu Chai) +* core: crush/CrushWrapper: chooseargs encoding fix (`pr#15984 `_, Ilya Dryomov) +* core: crush/CrushWrapper: make get_immediate_parent[_id] ignore per-class shadow hierarchy (`issue#20546 `_, `pr#16221 `_, Sage Weil) +* core: kv/RocksDBStore: abort if rocksdb EIO, don't return incorrect result (`pr#15862 `_, Haomai Wang) +* core: make the conversion from wire error to host OS work (`pr#15780 `_, Willem Jan Withagen) +* core: messages/MOSDPing.h: drop unused fields (`pr#15843 `_, Piotr Dałek) +* core,mgr: mgr,librados: service map (`pr#15858 `_, Yehuda Sadeh, John Spray, Sage Weil) +* core,mgr,mon: mgr,mon: enable/disable mgr modules via 'ceph mgr module ...' commands (`pr#15958 `_, Sage Weil) +* core,mgr: mon/PGMap: slightly better debugging around pgmap updates (`pr#15820 `_, Sage Weil) +* core: mon/MonClient: respect the priority in SRV RR (`issue#5249 `_, `pr#15964 `_, Kefu Chai) +* core: mon/MonmapMonitor: use __func__ instead of hard code function name (`pr#16037 `_, Yanhu Cao) +* core,mon: mon/MDSMonitor: fix segv when multiple MDSs raise same alert (`pr#16302 `_, Sage Weil) +* core,mon: mon/MgrStatMonitor: avoid dup health warnings during luminous upgrade (`issue#20435 `_, `pr#15986 `_, Sage Weil) +* core,mon: mon, osd: misc fixes (`pr#16078 `_, xie xingguo) +* core: mon, osd: misc fixes and cleanups (`pr#16160 `_, xie xingguo) +* core: mon/OSDMonitor: _apply_remap -> _apply_upmap; less code redundancy (`pr#15846 `_, xie xingguo) +* core: mon/OSDMonitor: do not allow crush device classes until luminous (`pr#16188 `_, Sage Weil) +* core: osd/ECTransaction: cleanup the redundant check which works in overwrite IO context (`pr#15765 `_, tang.jin) +* core: osd/filestore: Revert "os/filestore: move ondisk in front (`issue#20524 `_, `pr#16156 `_, Kefu Chai) +* core: osd/PG: Add two new mClock implementations of the PG sharded operator queue (`pr#14997 `_, J. Eric Ivancich) +* core: osd/PG: set clean when last_epoch_clean is updated (`issue#19023 `_, `pr#15555 `_, Samuel Just) +* core: osd/PrimaryLogPG solve cache tier osd high memory consumption (`issue#20464 `_, `pr#16011 `_, Peng Xie) +* core: osd/ReplicatedBackend: reset thread heartbeat after every omap entry … (`issue#20375 `_, `pr#15823 `_, Josh Durgin) +* core: os/filestore: call committed_thru when no journal entries are replayed (`pr#15781 `_, Kuan-Kai Chiu) +* core: os/filestore: do not free event if not added (`pr#16235 `_, Kefu Chai) +* core: os/filestore: Exclude BTRFS on FreeBSD (`pr#16171 `_, Willem Jan Withagen) +* core: os/filestore/FileJournal: FileJournal::open() close journal file before return error (`issue#20504 `_, `pr#16120 `_, Yang Honggang) +* core: os/filestore/FileStore.cc: remove a redundant judgement when get max latency (`pr#15961 `_, Jianpeng Ma) +* core: os/filestore: require experimental flag for btrfs (`pr#16086 `_, Sage Weil) +* core,performance: os/filestore/HashIndex: randomize split threshold by a configurable amount (`issue#15835 `_, `pr#15689 `_, Josh Durgin) +* core,performance: os/filestore: queue ondisk completion before apply work (`pr#13918 `_, Pan Liu) +* core,performance: src/OSD: add more useful perf counters for performance tuning (`pr#15915 `_, Pan Liu) +* core,rbd: mon,osd: do not create rbd pool by default (`pr#15894 `_, Greg Farnum, Sage Weil, David Zafman) +* core: src/vstart.sh: kill dead upmap option (`pr#15848 `_, xie xingguo) +* core:" Stringify needs access to << before reference" src/include/stringify.h (`pr#16334 `_, Willem Jan Withagen) +* core,tests: do all valgrind runs on centos (`issue#20360 `_, `issue#18126 `_, `pr#16046 `_, Sage Weil) +* core,tests: qa/objectstore/filestore-btrfs: test btrfs on trusty only (`issue#20169 `_, `pr#15814 `_, Sage Weil) +* core,tests: qa: stop testing btrfs (`issue#20169 `_, `pr#16044 `_, Sage Weil) +* core,tests: qa/suites/powercycle/osd/tasks/radosbench: consume less space (`issue#20302 `_, `pr#15821 `_, Sage Weil) +* core,tests: qa/suites/rados/singleton/all/reg11184: whitelist health warnings (`pr#16306 `_, Sage Weil) +* core,tests: qa/suites/rados/thrash/workload/\*: enable rados.py cache tiering ops (`issue#11793 `_, `pr#16244 `_, Sage Weil) +* core,tests: qa/tasks/ceph_manager: wait longer for pg stats to flush (`pr#16322 `_, Sage Weil) +* core,tests: qa/tasks/ceph.py: no osd id to 'osd create' command (`issue#20548 `_, `pr#16233 `_, Sage Weil) +* core,tests: qa/tasks/ceph: simplify ceph deployment slightly (`pr#15853 `_, Sage Weil) +* core,tests: qa/tasks/dump_stuck: fix for active+clean+remapped (`issue#20431 `_, `pr#15955 `_, Sage Weil) +* core,tests: qa/tasks/radosbench: longer timeout (`pr#16213 `_, Sage Weil) +* crush: silence warning from -Woverflow (`pr#16329 `_, Jos Collin) +* doc: dev: add notes on PR make check validation test (`pr#16079 `_, Nathan Cutler) +* doc: doc/mgr/dashboard: update dashboard docs to reflect new defaults (`pr#16241 `_, Sage Weil) +* doc: doc/rados.8: add offset option for put command (`pr#16155 `_, Jianpeng Ma) +* doc: doc/release-notes: add Images creation timestamp note (`pr#15963 `_, clove) +* doc: doc/release-notes: fix ceph-deploy command (`pr#15987 `_, Sage Weil) +* doc: doc/release-notes: Luminous release notes typo fixes "ceph config-key ls"->"ceph config-key list" (`pr#16330 `_, scienceluo) +* doc: doc/release-notes: Luminous release notes typo fixes (`pr#16338 `_, Luo Kexue) +* doc: doc/release-notes: update luminous notes (`pr#15851 `_, Sage Weil) +* doc: doc/releases: Update releases from Feb 2017 to July 2017 (`pr#16303 `_, Bryan Stillwell) +* doc: docs: mgr dashboard (`pr#15920 `_, Wido den Hollander) +* doc: fix link for ceph-mgr cephx authorization (`pr#16246 `_, Greg Farnum) +* doc: Jewel v10.2.8 release notes (`pr#16274 `_, Nathan Cutler) +* doc: Jewel v10.2.9 release notes (`pr#16318 `_, Nathan Cutler) +* doc: kill sphinx warnings (`pr#16198 `_, Kefu Chai) +* doc: Luminous release notes typo fixes (`pr#15899 `_, Abhishek Lekshmanan) +* doc: mailmap: add Myoungwon Oh's mailmap and affiliation (`pr#15934 `_, Myoungwon Oh) +* doc: mailmap, organizationmap: add affiliation for Tushar Gohad (`pr#16081 `_, Tushar Gohad) +* doc: .mailmap, .organizationmap: Update Fan Yang information and affiliation (`pr#16067 `_, Fan Yang) +* doc: .mailmap, .organizationmap: Update Song Weibin information and affiliation (`pr#16311 `_, songweibin) +* doc: mgr/restful: bind to :: and update docs (`pr#16267 `_, Sage Weil) +* doc: update intro, quick start docs (`pr#16224 `_, Sage Weil) +* doc: v12.1.0 release notes notable changes addition again (`pr#15857 `_, Abhishek Lekshmanan) +* librados: add log channel to rados_monitor_log2 callback (`pr#15926 `_, Sage Weil) +* librados: redirect balanced reads to acting primary when targeting object isn't recovered (`issue#17968 `_, `pr#15489 `_, Xuehan Xu) +* librbd: fail IO request when exclusive lock cannot be obtained (`pr#15860 `_, Jason Dillaman) +* mgr: clean up daemon start process (`issue#20383 `_, `pr#16020 `_, John Spray) +* mgr: clean up fsstatus module (`pr#15925 `_, John Spray) +* mgr: cluster log message on plugin load error (`pr#15927 `_, John Spray) +* mgr: dashboard improvements (`pr#16043 `_, John Spray) +* mgr: drop repeated log info. and unnecessary write permission (`pr#15896 `_, Yan Jun) +* mgr: enable ceph_send_command() to send pg command (`pr#15865 `_, Kefu Chai) +* mgr: increase debug level for ticks 0 -> 10 (`pr#16301 `_, Dan Mick) +* mgr: mgr/ClusterState: do not mangle PGMap outside of Incremental (`issue#20208 `_, `pr#16262 `_, Sage Weil) +* mgr: mgr/dashboard: add OSD list view (`pr#16373 `_, John Spray) +* mgr: mon/mgr: add detail error infomation (`pr#16048 `_, Yan Jun) +* mgr,mon: mgr,mon: debug init and mgrdigest subscriptions (`issue#20633 `_, `pr#16351 `_, Sage Weil) +* mgr: pybind/mgr/dashboard: bind to :: by default (`pr#16223 `_, Sage Weil) +* mgr,rbd: pybind/mgr/dashboard: initial block integration (`pr#15521 `_, Jason Dillaman) +* mgr: Zabbix monitoring module (`pr#16019 `_, Wido den Hollander) +* mon: add support public_bind_addr option (`pr#16189 `_, Bassam Tabbara) +* mon: a few more upmap (and other) fixes (`pr#16239 `_, xie xingguo) +* mon: clean up in ceph_mon.cc (`pr#14102 `_, huanwen ren) +* mon: collect mon metdata as part of the election (`issue#20434 `_, `pr#16148 `_, Sage Weil) +* mon: debug session feature tracking (`issue#20475 `_, `pr#16128 `_, Sage Weil) +* mon: Division by zero in PGMapDigest::dump_pool_stats_full() (`pr#15901 `_, Jos Collin) +* mon: do crushtool test with fork and timeout, but w/o exec of crushtool (`issue#19964 `_, `pr#16025 `_, Sage Weil) +* mon: Filter `log last` output by severity and channel (`pr#15924 `_, John Spray) +* mon: fix hang on deprecated/removed 'pg set_\*full_ratio' commands (`issue#20600 `_, `pr#16300 `_, Sage Weil) +* mon: fix kvstore type in mon compact command (`pr#15954 `_, liuchang0812) +* mon: Fix status output warning for mon_warn_osd_usage_min_max_delta (`issue#20544 `_, `pr#16220 `_, David Zafman) +* mon: handle cases where store->get() may return error (`issue#19601 `_, `pr#14678 `_, Jos Collin) +* mon: include device class in tree view; hide shadow hierarchy (`pr#16016 `_, Sage Weil) +* mon: maintain the "cluster" PerfCounters when using ceph-mgr (`issue#20562 `_, `pr#16249 `_, Greg Farnum) +* mon: mon,crush: create crush rules using device classes for replicated and ec pools via cli (`pr#16027 `_, Sage Weil) +* mon: mon/MgrStatMonitor: do not crash on luminous dev version upgrades (`pr#16287 `_, Sage Weil) +* mon: mon/Monitor: recreate mon session if features changed (`issue#20433 `_, `pr#16230 `_, Joao Eduardo Luis) +* mon: mon/OSDMonitor: a couple of upmap and other fixes (`pr#15917 `_, xie xingguo) +* mon: mon/OSDMonitor: guard 'osd crush set-device-class' (`pr#16217 `_, Sage Weil) +* mon: mon/OSDMonitor: "osd crush class rename" support (`pr#15875 `_, xie xingguo) +* mon: mon/OSDMonitor: two pool opts related fix (`pr#15968 `_, xie xingguo) +* mon: mon/PaxosService: use __func__ instead of hard code function name (`pr#15863 `_, Yanhu Cao) +* mon: revamp health check/warning system (`pr#15643 `_, John Spray, Sage Weil) +* mon: show the leader info on mon stat command (`pr#14178 `_, song baisen) +* mon: skip crush smoke test when running under valgrind (`issue#20602 `_, `pr#16346 `_, Sage Weil) +* mon,tests: qa/suites: add test exercising workunits/mon/auth_caps.sh (`pr#15754 `_, Kefu Chai) +* msg: make listen backlog an option, increase from 128 to 512 (`issue#20330 `_, `pr#15743 `_, Haomai Wang) +* msg: msg/async: increase worker reference with local listen table enabled backend (`issue#20390 `_, `pr#15897 `_, Haomai Wang) +* msg: msg/async/rdma: Data path fixes (`pr#15903 `_, Adir lev) +* msg: msg/async/rdma: register buffer as continuous (`pr#15967 `_, Adir Lev) +* msg: msg/async/rdma: remove assert from ibv_dealloc_pd in ProtectionDomain (`pr#15832 `_, DanielBar-On) +* msg: msg/MOSDOpReply: fix missing trace decode (`pr#15999 `_, Yan Jun) +* msg: QueueStrategy::wait() joins all threads (`issue#20534 `_, `pr#16194 `_, Casey Bodley) +* msg: Revert "msg/async: increase worker reference with local listen table enabled backend" (`issue#20603 `_, `pr#16323 `_, Haomai Wang) +* osd: Check for and automatically repair object info soid during scrub (`issue#20471 `_, `pr#16052 `_, David Zafman) +* osd: check queue_transaction return value (`pr#15873 `_, zhanglei) +* osd: clear_queued_recovery() in on_shutdown() (`issue#20432 `_, `pr#16093 `_, Kefu Chai) +* osd: compact osd feature (`issue#19592 `_, `pr#16045 `_, liuchang0812) +* osd: Corrupt objects stop snaptrim and mark pg snaptrim_error (`issue#13837 `_, `pr#15635 `_, David Zafman) +* osd: dump the field name of object watchers and cleanups (`pr#15946 `_, Yan Jun) +* osd: Execute crush_location_hook when configured in ceph.conf (`pr#15951 `_, Wido den Hollander) +* osd: On EIO from read recover the primary replica from another copy (`issue#18165 `_, `pr#14760 `_, David Zafman) +* osd: osd does not using MPing Messages,do not include unused include (`pr#15833 `_, linbing) +* osd: Preserve OSDOp information for historic ops (`pr#15265 `_, Guo-Fu Tseng) +* osd: restart boot process if waiting for luminous mons (`issue#20631 `_, `pr#16341 `_, Sage Weil) +* osd: unlock sdata_op_ordering_lock with sdata_lock hold to avoid miss… (`pr#15891 `_, Ming Lin) +* pybind: ceph.in: Check return value when connecting (`pr#16130 `_, Douglas Fuller) +* pybind: ceph-rest-api: Various REST API fixes (`pr#15910 `_, Wido den Hollander) +* pybind: pybind/mgr/dashboard: fix get kernel_version error (`pr#16094 `_, Peng Zhang) +* pybind: restore original API for backwards compatibility (`issue#20421 `_, `pr#15932 `_, Jason Dillaman) +* rbd: do not attempt to load key if auth is disabled (`issue#19035 `_, `pr#16024 `_, Jason Dillaman) +* rbd-mirror: ignore permission errors on rbd_mirroring object (`issue#20571 `_, `pr#16264 `_, Jason Dillaman) +* rbd,tests: qa/suites/rbd: restrict python memcheck validation to CentOS (`pr#15923 `_, Jason Dillaman) +* rbd,tests: qa/tasks: rbd-mirror daemon not properly run in foreground mode (`issue#20630 `_, `pr#16340 `_, Jason Dillaman) +* rbd,tests: test: fix compile warning in ceph_test_cls_rbd (`pr#15919 `_, Jason Dillaman) +* rbd,tests: test: fix failing rbd devstack teuthology test (`pr#15956 `_, Jason Dillaman) +* rbd,tools: tools/rbd_mirror: initialize non-static class member m_do_resync in ImageReplayer (`pr#15889 `_, Jos Collin) +* rbd,tools: tools/rbd_nbd: add --version show support (`pr#16254 `_, Jin Cai) +* rgw: add a new error code for non-existed subuser (`pr#16095 `_, Zhao Chao) +* rgw: add a new error code for non-existed user (`issue#20468 `_, `pr#16033 `_, Zhao Chao) +* rgw: add missing RGWPeriod::reflect() based on new atomic update_latest_epoch() (`issue#19816 `_, `issue#19817 `_, `pr#14915 `_, Casey Bodley) +* rgw: auto reshard old buckets (`pr#15665 `_, Orit Wasserman) +* rgw: cleanup rgw-admin duplicated judge during OLH GET/READLOG (`pr#15700 `_, Jiaying Ren) +* rgw: cls: ceph::timespan tag_timeout wrong units (`issue#20380 `_, `pr#16026 `_, Matt Benjamin) +* rgw: Compress crash bug refactor (`issue#20098 `_, `pr#15569 `_, Adam Kupczyk) +* rgw: Correcting the condition in ceph_assert while parsing an AWS Principal (`pr#15997 `_, Pritha Srivastava) +* rgw: Do not fetch bucket stats by default upon bucket listing (`issue#20377 `_, `pr#15834 `_, Pavan Rallabhandi) +* rgw: drop unused function RGWRemoteDataLog::get_shard_info() (`pr#16236 `_, Shasha Lu) +* rgw: drop unused rgw_pool parameter, local variables and member variable (`pr#16154 `_, Jiaying Ren) +* rgw: external auth engines of S3 honor rgw_keystone_implicit_tenants (`issue#17779 `_, `pr#15572 `_, Radoslaw Zarzynski) +* rgw: Fix a bug that multipart upload may exceed the quota (`issue#19602 `_, `pr#12010 `_, Zhang Shaowen) +* rgw: Fix duplicate tag removal during GC (`issue#20107 `_, `pr#15912 `_, Jens Rosenboom) +* rgw: fix error handling in get_params() of RGWPostObj_ObjStore_S3 (`pr#15670 `_, Radoslaw Zarzynski) +* rgw: fix error handling in the link() method of RGWBucket (`issue#20279 `_, `pr#15669 `_, Radoslaw Zarzynski) +* rgw: fixes for AWSBrowserUploadAbstractor auth (`issue#20372 `_, `pr#15882 `_, Radoslaw Zarzynski, Casey Bodley) +* rgw: fix infinite loop in rest api for log list (`issue#20386 `_, `pr#15983 `_, xierui, Casey Bodley) +* rgw: fix leaks with incomplete multiparts (`issue#17164 `_, `pr#15630 `_, Abhishek Varshney) +* rgw: fix marker encoding problem (`issue#20463 `_, `pr#15998 `_, Marcus Watts) +* rgw: fix memory leak in copy_obj_to_remote_dest (`pr#9974 `_, weiqiaomiao) +* rgw: fix not initialized vars which cause rgw crash with ec data pool (`issue#20542 `_, `pr#16177 `_, Aleksei Gutikov) +* rgw: fix potential null pointer dereference in rgw_admin (`pr#15667 `_, Radoslaw Zarzynski) +* rgw: fix radosgw-admin data sync run crash (`issue#20423 `_, `pr#15938 `_, Shasha Lu) +* rgw: fix s3 object uploads with chunked transfers and v4 signatures (`issue#20447 `_, `pr#15965 `_, Marcus Watts) +* rgw: fix wrong error code for expired Swift TempURL's links (`issue#20384 `_, `pr#15850 `_, Radoslaw Zarzynski) +* rgw: fix zone did't update realm_id when added to zonegroup (`issue#17995 `_, `pr#12139 `_, Tianshan Qu) +* rgw: implement get/put object tags for S3 (`pr#13753 `_, Abhishek Lekshmanan) +* rgw: /info claims we do support Swift's accounts ACLs (`issue#20394 `_, `pr#15887 `_, Radoslaw Zarzynski) +* rgw: initialize non-static class members in ESQueryCompiler (`pr#15884 `_, Jos Collin) +* rgw: initialize Non-static class member val in ESQueryNodeLeafVal_Int (`pr#15888 `_, Jos Collin) +* rgw: initialize Non-static class member worker in RGWReshard (`pr#15886 `_, Jos Collin) +* rgw: Initialize pointer fields (`pr#16021 `_, Jos Collin) +* rgw: lease_stack: use reset method instead of assignment (`pr#16185 `_, Nathan Cutler) +* rgw: lock is not released when set sync marker is failed (`issue#18077 `_, `pr#12197 `_, Zhang Shaowen) +* rgw: log_meta only for more than one zone (`issue#20357 `_, `pr#15777 `_, Orit Wasserman, Leo Zhang) +* rgw: multipart copy-part remove '/' for s3 java sdk request header (`issue#20075 `_, `pr#15283 `_, root) +* rgw:multisite: fix RGWRadosRemoveOmapKeysCR and change cn to intrusive_ptr (`issue#20539 `_, `pr#16197 `_, Shasha Lu) +* rgw: omit X-Account-Access-Control if there is no grant to serialize (`issue#20395 `_, `pr#15883 `_, Radoslaw Zarzynski) +* rgw: radosgw: fix compilation with cryptopp (`pr#15960 `_, Adam Kupczyk) +* rgw: reject request if decoded URI contains \0 in the middle (`issue#20418 `_, `pr#15953 `_, Radoslaw Zarzynski) +* rgw: remove a redundant judgement in rgw_rados.cc:delete_obj (`pr#11124 `_, Zhang Shaowen) +* rgw: remove the useless output when listing zonegroups (`pr#16331 `_, Zhang Shaowen) +* rgw: Replace get_zonegroup().is_master_zonegroup() with is_meta_master() in RGWBulkDelete::Deleter::delete_single() (`pr#16062 `_, Fan Yang) +* rgw: rgw_file: add compression interop to RGW NFS (`issue#20462 `_, `pr#15989 `_, Matt Benjamin) +* rgw: rgw_file: add service map registration (`pr#16251 `_, Matt Benjamin) +* rgw: rgw_file: avoid a recursive lane lock in LRU drain (`issue#20374 `_, `pr#15819 `_, Matt Benjamin) +* rgw: rgw_file: fix misuse of make_key_name before make_fhk (`pr#15108 `_, Gui Hecheng) +* rgw: rgw_file skip policy read for virtual components (`pr#16034 `_, Gui Hecheng) +* rgw: rgw:fix s3 aws v2 signature priority between header['X-Amz-Date'] and header['Date'] (`issue#20176 `_, `pr#15467 `_, yuliyang) +* rgw: rgw: fix the subdir without slash of s3 website url (`issue#20307 `_, `pr#15703 `_, liuhong) +* rgw: rgw/rgw_frontend.h: Return negative value for empty uid in RGWLoadGenFrontend::init() (`pr#16204 `_, jimifm) +* rgw: rgw/rgw_op: fix whitespace and indentation warning (`pr#15928 `_, Sage Weil) +* rgw: rgw/rgw_rados: Remove duplicate calls in RGWRados::finalize() (`pr#15281 `_, jimifm) +* rgw: rgw,test: fix rgw placement rule pool config option (`pr#16084 `_, Jiaying Ren) +* rgw: S3 lifecycle now supports expiration date (`pr#15807 `_, Zhang Shaowen) +* rgw: silence compile warning from -Wmaybe-uninitialized (`pr#15996 `_, Jiaying Ren) +* rgw: silence warning from -Wmaybe-uninitialized (`pr#15949 `_, Jos Collin) +* rgw,tests: qa/tasks: S3A hadoop task to test s3a with Ceph (`pr#14624 `_, Vasu Kulkarni) +* rgw,tests: vstart: remove rgw_enable_static_website (`pr#15856 `_, Casey Bodley) +* rgw: Uninitialized member in LCRule (`pr#15827 `_, Jos Collin) +* rgw: use 64-bit offsets for compression (`issue#20231 `_, `pr#15656 `_, Adam Kupczyk, fang yuxiang) +* rgw: use uncompressed size for range_to_ofs() in slo/dlo (`pr#15931 `_, Casey Bodley) +* rgw: using RGW_OBJ_NS_MULTIPART in check_bad_index_multipart (`pr#15774 `_, Shasha Lu) +* rgw: verify md5 in post obj (`issue#19739 `_, `pr#14961 `_, Yehuda Sadeh) +* rgw: Wip rgw fix prefix list (`issue#19432 `_, `pr#15916 `_, Giovani Rinaldi, Orit Wasserman) +* tests: ceph-disk: use communicate() instead of wait() for output (`pr#16347 `_, Kefu Chai) +* tests: cls_lock: move lock_info_t definition to cls_lock_types.h (`pr#16091 `_, runsisi) +* tests: fix rados/upgrade/jewel-x-singleton and make workunit task handle repo URLs not ending in ".git" (`issue#20554 `_, `issue#20368 `_, `pr#16228 `_, Nathan Cutler, Sage Weil) +* tests: mgr,os,test: kill clang analyzer warnings (`pr#16227 `_, Kefu Chai) +* tests: move swift.py task from teuthology to ceph, phase one (master) (`issue#20392 `_, `pr#15859 `_, Nathan Cutler, Sage Weil, Warren Usui, Greg Farnum, Ali Maredia, Tommi Virtanen, Zack Cerza, Sam Lang, Yehuda Sadeh, Joe Buck, Josh Durgin) +* tests: [qa/ceph-deploy]: run create mgr nodes as well (`pr#16216 `_, Vasu Kulkarni) +* tests: qa: do not restrict valgrind runs to centos (`issue#18126 `_, `pr#15893 `_, Greg Farnum) +* tests: qa/suites/rados/singleton/all/mon-auth-caps: more osds so we can go clean (`pr#16225 `_, Sage Weil) +* tests: qa/suites/upgrade/hammer-jewel-x: add luminous.yaml (`issue#20342 `_, `pr#15764 `_, Kefu Chai) +* tests: qa/tasks/ceph: don't hard-code cluster name when copying fsid (`pr#16212 `_, Jason Dillaman) +* tests: qa/tasks/ceph: should be "Waiting for all PGs", not "all osds" (`pr#16122 `_, Kefu Chai) +* tests: qa/tasks/radosbench: increase timeout (`pr#15885 `_, Sage Weil) +* tests: qa/workunits/ceph-helpers: enable experimental features for osd (`pr#16319 `_, Kefu Chai) +* tests: qa/workunits/ceph-helpers: test wait_for_health_ok differently (`pr#16317 `_, Kefu Chai) +* tests: rgw.py: put client roles in a separate list (`issue#20417 `_, `pr#15913 `_, Nathan Cutler) +* tests: rgw/singleton: drop duplicate filestore-xfs.yaml (`pr#15959 `_, Nathan Cutler) +* tests: test: Division by zero in Legacy::encode_n() (`pr#15902 `_, Jos Collin) +* tests: test/fio: print all perfcounters rather than objectstore itself (`pr#16339 `_, Jianpeng Ma) +* tests: test/fio: remove experimental option for bluestore & rocksdb (`pr#16263 `_, Pan Liu) +* tests: test: Fix reg11184 test to remove extraneous pg (`pr#16265 `_, David Zafman) +* tests: test/msgr: fixed the hang issue for perf_msg_client (`pr#16358 `_, Pan Liu) +* tests: test/osd/osd-scrub-repair.sh: disable ec_overwrite tests on FreeBSD (`pr#15445 `_, Willem Jan Withagen) +* tests: test/osd/osd-scrub-repair.sh: Fix diff options on FreeBSD (`pr#15914 `_, Willem Jan Withagen) +* tests,tools: test, ceph-osdomap-tool: kill clang warnings (`pr#15905 `_, Kefu Chai) +* tools: ceph-conf: fix typo in usage: 'mon add' should be 'mon addr' (`pr#15935 `_, Peng Zhang) +* tools: ceph-create-keys: add an argument to override default 10-minute timeout (`pr#16049 `_, Douglas Fuller) +* tools: ceph.in: filter out audit from ceph -w (`pr#16345 `_, John Spray) +* tools: ceph-release-notes: escape asterisks not for inline emphasis (`pr#16199 `_, Kefu Chai) +* tools: ceph-release-notes: handle an edge case (`pr#16277 `_, Nathan Cutler) +* tools: Cleanup dead code in ceph-objectstore-tool (`pr#15812 `_, David Zafman) +* tools: libradosstriper: fix MultiAioCompletion leaks on failure (`pr#15471 `_, Kefu Chai) +* tools: tools/rados: some cleanups (`pr#16147 `_, Yan Jun) +* tools: vstart.sh: bind restful, dashboard to ::, not 127.0.0.1 (`pr#16349 `_, Sage Weil) + + +v12.1.0 Luminous (RC) +===================== + +This is the first release candidate for Luminous, the next long term +stable release. + + + + Notable Changes since Kraken ---------------------------- diff --git a/ceph/doc/start/quick-ceph-deploy.rst b/ceph/doc/start/quick-ceph-deploy.rst index f86d75674..50b7f307f 100644 --- a/ceph/doc/start/quick-ceph-deploy.rst +++ b/ceph/doc/start/quick-ceph-deploy.rst @@ -101,6 +101,7 @@ configuration details, perform the following steps using ``ceph-deploy``. - ``ceph.bootstrap-osd.keyring`` - ``ceph.bootstrap-mds.keyring`` - ``ceph.bootstrap-rgw.keyring`` + - ``ceph.bootstrap-rbd.keyring`` .. note:: If this process fails with a message similar to "Unable to find /etc/ceph/ceph.client.admin.keyring", please ensure that the diff --git a/ceph/doc/start/quick-rbd.rst b/ceph/doc/start/quick-rbd.rst index debc0fc20..5534fa9e5 100644 --- a/ceph/doc/start/quick-rbd.rst +++ b/ceph/doc/start/quick-rbd.rst @@ -89,7 +89,7 @@ See `block devices`_ for additional details. .. _Storage Cluster Quick Start: ../quick-ceph-deploy .. _create a pool: ../../rados/operations/pools/#create-a-pool -.. _block devices: ../../rbd/rbd +.. _block devices: ../../rbd .. _FAQ: http://wiki.ceph.com/How_Can_I_Give_Ceph_a_Try .. _OS Recommendations: ../os-recommendations .. _rbdmap manpage: ../../man/8/rbdmap diff --git a/ceph/qa/cephfs/overrides/whitelist_health.yaml b/ceph/qa/cephfs/overrides/whitelist_health.yaml new file mode 100644 index 000000000..ddd8eab69 --- /dev/null +++ b/ceph/qa/cephfs/overrides/whitelist_health.yaml @@ -0,0 +1,9 @@ +overrides: + ceph: + log-whitelist: + - overall HEALTH_ + - \(FS_DEGRADED\) + - \(MDS_FAILED\) + - \(MDS_DEGRADED\) + - \(FS_WITH_FAILED_MDS\) + - \(MDS_DAMAGE\) diff --git a/ceph/qa/cephfs/overrides/whitelist_wrongly_marked_down.yaml b/ceph/qa/cephfs/overrides/whitelist_wrongly_marked_down.yaml index a41bd3498..9e090d7de 100644 --- a/ceph/qa/cephfs/overrides/whitelist_wrongly_marked_down.yaml +++ b/ceph/qa/cephfs/overrides/whitelist_wrongly_marked_down.yaml @@ -2,8 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (OSD_DOWN) - - (OSD_ + - \(OSD_DOWN\) + - \(OSD_ - but it is still running # MDS daemon 'b' is not responding, replacing it as rank 0 with standby 'a' - is not responding diff --git a/ceph/qa/clusters/fixed-2.yaml b/ceph/qa/clusters/fixed-2.yaml index 3b08e287d..5d5fcca9c 100644 --- a/ceph/qa/clusters/fixed-2.yaml +++ b/ceph/qa/clusters/fixed-2.yaml @@ -1,12 +1,12 @@ roles: -- [mon.a, mon.c, mgr.y, osd.0, osd.1, osd.2, client.0] -- [mon.b, mgr.x, osd.3, osd.4, osd.5, client.1] +- [mon.a, mon.c, mgr.y, osd.0, osd.1, osd.2, osd.3, client.0] +- [mon.b, mgr.x, osd.4, osd.5, osd.6, osd.7, client.1] openstack: - volumes: # attached to each instance - count: 3 + count: 4 size: 10 # GB overrides: ceph: conf: osd: - osd shutdown pgref assert: true \ No newline at end of file + osd shutdown pgref assert: true diff --git a/ceph/qa/clusters/fixed-3.yaml b/ceph/qa/clusters/fixed-3.yaml index cd4f4e8ec..ddc79a84b 100644 --- a/ceph/qa/clusters/fixed-3.yaml +++ b/ceph/qa/clusters/fixed-3.yaml @@ -1,13 +1,13 @@ roles: -- [mon.a, mon.c, mgr.x, osd.0, osd.1, osd.2] -- [mon.b, mgr.y, osd.3, osd.4, osd.5] +- [mon.a, mon.c, mgr.x, osd.0, osd.1, osd.2, osd.3] +- [mon.b, mgr.y, osd.4, osd.5, osd.6, osd.7] - [client.0] openstack: - volumes: # attached to each instance - count: 3 + count: 4 size: 10 # GB overrides: ceph: conf: osd: - osd shutdown pgref assert: true \ No newline at end of file + osd shutdown pgref assert: true diff --git a/ceph/qa/erasure-code/ec-rados-plugin=jerasure-k=4-m=2.yaml b/ceph/qa/erasure-code/ec-rados-plugin=jerasure-k=4-m=2.yaml new file mode 100644 index 000000000..dfcc61607 --- /dev/null +++ b/ceph/qa/erasure-code/ec-rados-plugin=jerasure-k=4-m=2.yaml @@ -0,0 +1,25 @@ +tasks: +- rados: + clients: [client.0] + ops: 4000 + objects: 50 + ec_pool: true + write_append_excl: false + erasure_code_profile: + name: jerasure21profile + plugin: jerasure + k: 4 + m: 2 + technique: reed_sol_van + crush-failure-domain: osd + op_weights: + read: 100 + write: 0 + append: 100 + delete: 50 + snap_create: 50 + snap_remove: 50 + rollback: 50 + copy_from: 50 + setattr: 25 + rmattr: 25 diff --git a/ceph/qa/standalone/crush/crush-classes.sh b/ceph/qa/standalone/crush/crush-classes.sh index ee9c9092e..24696fcd3 100755 --- a/ceph/qa/standalone/crush/crush-classes.sh +++ b/ceph/qa/standalone/crush/crush-classes.sh @@ -162,39 +162,21 @@ function TEST_mon_classes() { ceph osd crush tree --show-shadow | grep -q '~ccc' || return 1 ceph osd crush rm-device-class 0 || return 1 ceph osd tree | grep -q 'aaa' && return 1 - ceph osd crush dump | grep -q '~aaa' && return 1 - ceph osd crush tree --show-shadow | grep -q '~aaa' && return 1 - ceph osd crush class ls | grep -q 'aaa' && return 1 + ceph osd crush class ls | grep -q 'aaa' && return 1 # class 'aaa' should gone ceph osd crush rm-device-class 1 || return 1 ceph osd tree | grep -q 'bbb' && return 1 - ceph osd crush dump | grep -q '~bbb' && return 1 - ceph osd crush tree --show-shadow | grep -q '~bbb' && return 1 - ceph osd crush class ls | grep -q 'bbb' && return 1 + ceph osd crush class ls | grep -q 'bbb' && return 1 # class 'bbb' should gone ceph osd crush rm-device-class 2 || return 1 ceph osd tree | grep -q 'ccc' && return 1 - ceph osd crush dump | grep -q '~ccc' && return 1 - ceph osd crush tree --show-shadow | grep -q '~ccc' && return 1 - ceph osd crush class ls | grep -q 'ccc' && return 1 + ceph osd crush class ls | grep -q 'ccc' && return 1 # class 'ccc' should gone ceph osd crush set-device-class asdf all || return 1 ceph osd tree | grep -q 'asdf' || return 1 ceph osd crush dump | grep -q '~asdf' || return 1 ceph osd crush tree --show-shadow | grep -q '~asdf' || return 1 + ceph osd crush rule create-replicated asdf-rule default host asdf || return 1 ceph osd crush rm-device-class all || return 1 ceph osd tree | grep -q 'asdf' && return 1 - ceph osd crush dump | grep -q '~asdf' && return 1 - ceph osd crush tree --show-shadow | grep -q '~asdf' && return 1 - - # test 'class rm' automatically recycles shadow trees - ceph osd crush set-device-class asdf 0 1 2 || return 1 - ceph osd tree | grep -q 'asdf' || return 1 - ceph osd crush dump | grep -q '~asdf' || return 1 - ceph osd crush tree --show-shadow | grep -q '~asdf' || return 1 - ceph osd crush class ls | grep -q 'asdf' || return 1 - ceph osd crush class rm asdf || return 1 - ceph osd tree | grep -q 'asdf' && return 1 - ceph osd crush dump | grep -q '~asdf' && return 1 - ceph osd crush tree --show-shadow | grep -q '~asdf' && return 1 - ceph osd crush class ls | grep -q 'asdf' && return 1 + ceph osd crush class ls | grep -q 'asdf' || return 1 # still referenced by asdf-rule ceph osd crush set-device-class abc osd.2 || return 1 ceph osd crush move osd.2 root=foo rack=foo-rack host=foo-host || return 1 @@ -211,35 +193,11 @@ function TEST_mon_classes() { ceph osd crush dump | grep -q 'foo-host~abc' || return 1 ceph osd crush tree --show-shadow | grep -q 'foo-host~abc' || return 1 ceph osd crush rm-device-class osd.2 || return 1 - ceph osd crush dump | grep -q 'foo~abc' && return 1 - ceph osd crush tree --show-shadow | grep -q 'foo~abc' && return 1 - ceph osd crush dump | grep -q 'foo-rack~abc' && return 1 - ceph osd crush tree --show-shadow | grep -q 'foo-rack~abc' && return 1 - ceph osd crush dump | grep -q 'foo-host~abc' && return 1 - ceph osd crush tree --show-shadow | grep -q 'foo-host~abc' && return 1 # restore class, so we can continue to test create-replicated ceph osd crush set-device-class abc osd.2 || return 1 ceph osd crush rule create-replicated foo-rule foo host abc || return 1 - # test class_is_in_use - ceph osd crush set-device-class hdd osd.0 || return 1 - ceph osd crush set-device-class ssd osd.1 || return 1 - ceph osd crush rule create-replicated foo-hdd1 default host hdd || return 1 - ceph osd crush rule create-replicated foo-hdd2 default host hdd || return 1 - ceph osd crush rule create-replicated foo-ssd default host ssd || return 1 - expect_failure $dir EBUSY ceph osd crush class rm hdd || return 1 - expect_failure $dir EBUSY ceph osd crush class rm ssd || return 1 - ceph osd crush rule rm foo-hdd1 || return 1 - expect_failure $dir EBUSY ceph osd crush class rm hdd || return 1 # still referenced by foo-hdd2 - ceph osd crush rule rm foo-hdd2 || return 1 - ceph osd crush rule rm foo-ssd || return 1 - ceph osd crush class rm hdd || return 1 - ceph osd crush class rm ssd || return 1 - expect_failure $dir EBUSY ceph osd crush class rm abc || return 1 # still referenced by foo-rule - ceph osd crush rule rm foo-rule || return 1 - ceph osd crush class rm abc || return 1 - # test set-device-class implicitly change class ceph osd crush set-device-class hdd osd.0 || return 1 expect_failure $dir EBUSY ceph osd crush set-device-class nvme osd.0 || return 1 diff --git a/ceph/qa/standalone/osd/osd-fast-mark-down.sh b/ceph/qa/standalone/osd/osd-fast-mark-down.sh index 3b8e5a31b..9f413d080 100755 --- a/ceph/qa/standalone/osd/osd-fast-mark-down.sh +++ b/ceph/qa/standalone/osd/osd-fast-mark-down.sh @@ -27,25 +27,6 @@ function run() { export CEPH_ARGS CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " CEPH_ARGS+="--mon-host=$CEPH_MON " - # - # Disable device auto class feature for this testing, - # as it will automatically make root clones based on new class types - # and hence affect the down osd counting. - # E.g., - # - # ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY - # -4 3.00000 root default~hdd - # -3 3.00000 host gitbuilder-ceph-rpm-centos7-amd64-basic~hdd - # 0 1.00000 osd.0 down 1.00000 1.00000 - # 1 1.00000 osd.1 up 1.00000 1.00000 - # 2 1.00000 osd.2 up 1.00000 1.00000 - # -1 3.00000 root default - # -2 3.00000 host gitbuilder-ceph-rpm-centos7-amd64-basic - # 0 1.00000 osd.0 down 1.00000 1.00000 - # 1 1.00000 osd.1 up 1.00000 1.00000 - # 2 1.00000 osd.2 up 1.00000 1.00000 - # - CEPH_ARGS+="--osd-class-update-on-start=false " OLD_ARGS=$CEPH_ARGS CEPH_ARGS+="--osd-fast-fail-on-connection-refused=false " diff --git a/ceph/qa/suites/big/rados-thrash/openstack.yaml b/ceph/qa/suites/big/rados-thrash/openstack.yaml new file mode 100644 index 000000000..4d6edcd07 --- /dev/null +++ b/ceph/qa/suites/big/rados-thrash/openstack.yaml @@ -0,0 +1,8 @@ +openstack: + - machine: + disk: 40 # GB + ram: 8000 # MB + cpus: 1 + volumes: # attached to each instance + count: 3 + size: 10 # GB diff --git a/ceph/qa/suites/ceph-disk/basic/tasks/ceph-disk.yaml b/ceph/qa/suites/ceph-disk/basic/tasks/ceph-disk.yaml index b79ce8dc0..c61c376aa 100644 --- a/ceph/qa/suites/ceph-disk/basic/tasks/ceph-disk.yaml +++ b/ceph/qa/suites/ceph-disk/basic/tasks/ceph-disk.yaml @@ -18,8 +18,8 @@ tasks: fs: xfs # this implicitly means /dev/vd? are used instead of directories wait-for-scrub: false log-whitelist: - - (OSD_ - - (PG_ + - \(OSD_ + - \(PG_ conf: global: mon pg warn min per osd: 2 diff --git a/ceph/qa/suites/fs/32bits/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/32bits/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/32bits/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/basic_functional/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/basic_functional/overrides/whitelist_health.yaml deleted file mode 100644 index b5bf1fa7b..000000000 --- a/ceph/qa/suites/fs/basic_functional/overrides/whitelist_health.yaml +++ /dev/null @@ -1,9 +0,0 @@ -overrides: - ceph: - log-whitelist: - - overall HEALTH_ - - (FS_DEGRADED) - - (MDS_FAILED) - - (MDS_DEGRADED) - - (FS_WITH_FAILED_MDS) - - (MDS_DAMAGE) diff --git a/ceph/qa/suites/fs/basic_functional/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/basic_functional/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/basic_functional/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/basic_functional/tasks/auto-repair.yaml b/ceph/qa/suites/fs/basic_functional/tasks/auto-repair.yaml index 629804ec7..90d0e7bcb 100644 --- a/ceph/qa/suites/fs/basic_functional/tasks/auto-repair.yaml +++ b/ceph/qa/suites/fs/basic_functional/tasks/auto-repair.yaml @@ -4,6 +4,7 @@ overrides: - force file system read-only - bad backtrace - MDS in read-only mode + - \(MDS_READ_ONLY\) tasks: diff --git a/ceph/qa/suites/fs/basic_functional/tasks/client-limits.yaml b/ceph/qa/suites/fs/basic_functional/tasks/client-limits.yaml index 4483dbb6f..d22bc353c 100644 --- a/ceph/qa/suites/fs/basic_functional/tasks/client-limits.yaml +++ b/ceph/qa/suites/fs/basic_functional/tasks/client-limits.yaml @@ -9,6 +9,7 @@ overrides: - failing to respond to cache pressure - slow requests are blocked - failing to respond to capability release + - \(MDS_CLIENT_OLDEST_TID\) tasks: - cephfs_test_runner: diff --git a/ceph/qa/suites/fs/basic_functional/tasks/journal-repair.yaml b/ceph/qa/suites/fs/basic_functional/tasks/journal-repair.yaml index 324ff75df..66f819d06 100644 --- a/ceph/qa/suites/fs/basic_functional/tasks/journal-repair.yaml +++ b/ceph/qa/suites/fs/basic_functional/tasks/journal-repair.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - - bad backtrace on dir ino + - bad backtrace on directory inode - error reading table object - Metadata damage detected - slow requests are blocked diff --git a/ceph/qa/suites/fs/basic_workload/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/basic_workload/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/basic_workload/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/multiclient/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/multiclient/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/multiclient/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/multifs/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/multifs/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/multifs/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/multifs/tasks/failover.yaml b/ceph/qa/suites/fs/multifs/tasks/failover.yaml index 3358b664e..8833fd63b 100644 --- a/ceph/qa/suites/fs/multifs/tasks/failover.yaml +++ b/ceph/qa/suites/fs/multifs/tasks/failover.yaml @@ -2,6 +2,7 @@ overrides: ceph: log-whitelist: - not responding, replacing + - \(MDS_INSUFFICIENT_STANDBY\) ceph-fuse: disabled: true tasks: diff --git a/ceph/qa/suites/fs/permission/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/permission/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/permission/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/snaps/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/snaps/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/snaps/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/thrash/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/thrash/overrides/whitelist_health.yaml deleted file mode 100644 index fc8119dac..000000000 --- a/ceph/qa/suites/fs/thrash/overrides/whitelist_health.yaml +++ /dev/null @@ -1,8 +0,0 @@ -overrides: - ceph: - log-whitelist: - - overall HEALTH_ - - (FS_DEGRADED) - - (MDS_FAILED) - - (MDS_DEGRADED) - - (FS_WITH_FAILED_MDS) diff --git a/ceph/qa/suites/fs/thrash/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/thrash/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/thrash/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/traceless/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/traceless/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/traceless/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/fs/verify/overrides/whitelist_health.yaml b/ceph/qa/suites/fs/verify/overrides/whitelist_health.yaml new file mode 120000 index 000000000..440e747fb --- /dev/null +++ b/ceph/qa/suites/fs/verify/overrides/whitelist_health.yaml @@ -0,0 +1 @@ +../../../../cephfs/overrides/whitelist_health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/kcephfs/recovery/tasks/journal-repair.yaml b/ceph/qa/suites/kcephfs/recovery/tasks/journal-repair.yaml index 324ff75df..66f819d06 100644 --- a/ceph/qa/suites/kcephfs/recovery/tasks/journal-repair.yaml +++ b/ceph/qa/suites/kcephfs/recovery/tasks/journal-repair.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - - bad backtrace on dir ino + - bad backtrace on directory inode - error reading table object - Metadata damage detected - slow requests are blocked diff --git a/ceph/qa/suites/powercycle/osd/tasks/rados_api_tests.yaml b/ceph/qa/suites/powercycle/osd/tasks/rados_api_tests.yaml index c893a4604..06f3f5738 100644 --- a/ceph/qa/suites/powercycle/osd/tasks/rados_api_tests.yaml +++ b/ceph/qa/suites/powercycle/osd/tasks/rados_api_tests.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - reached quota - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) tasks: - ceph-fuse: - workunit: diff --git a/ceph/qa/suites/powercycle/osd/thrashosds-health.yaml b/ceph/qa/suites/powercycle/osd/thrashosds-health.yaml new file mode 120000 index 000000000..ebf7f34f3 --- /dev/null +++ b/ceph/qa/suites/powercycle/osd/thrashosds-health.yaml @@ -0,0 +1 @@ +../../../tasks/thrashosds-health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/powercycle/osd/whitelist_health.yaml b/ceph/qa/suites/powercycle/osd/whitelist_health.yaml index 1c333a0f3..740908301 100644 --- a/ceph/qa/suites/powercycle/osd/whitelist_health.yaml +++ b/ceph/qa/suites/powercycle/osd/whitelist_health.yaml @@ -1,4 +1,4 @@ overrides: ceph: log-whitelist: - - (MDS_TRIM) + - \(MDS_TRIM\) diff --git a/ceph/qa/suites/rados/basic/clusters/openstack.yaml b/ceph/qa/suites/rados/basic/clusters/openstack.yaml index e4d84236a..e559d9126 100644 --- a/ceph/qa/suites/rados/basic/clusters/openstack.yaml +++ b/ceph/qa/suites/rados/basic/clusters/openstack.yaml @@ -1,4 +1,4 @@ openstack: - volumes: # attached to each instance - count: 3 + count: 4 size: 10 # GB diff --git a/ceph/qa/suites/rados/basic/tasks/rados_python.yaml b/ceph/qa/suites/rados/basic/tasks/rados_python.yaml index e633ae2d4..8c70304d0 100644 --- a/ceph/qa/suites/rados/basic/tasks/rados_python.yaml +++ b/ceph/qa/suites/rados/basic/tasks/rados_python.yaml @@ -3,10 +3,11 @@ overrides: log-whitelist: - but it is still running - overall HEALTH_ - - (OSDMAP_FLAGS) - - (PG_ - - (OSD_ - - (OBJECT_ + - \(OSDMAP_FLAGS\) + - \(PG_ + - \(OSD_ + - \(OBJECT_ + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rados/basic/tasks/rados_stress_watch.yaml b/ceph/qa/suites/rados/basic/tasks/rados_stress_watch.yaml index ded794c17..bee513eb9 100644 --- a/ceph/qa/suites/rados/basic/tasks/rados_stress_watch.yaml +++ b/ceph/qa/suites/rados/basic/tasks/rados_stress_watch.yaml @@ -2,8 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) - - (TOO_FEW_PGS) + - \(CACHE_POOL_NO_HIT_SET\) + - \(TOO_FEW_PGS\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_big.yaml b/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_big.yaml index 545e50fed..2dade6dee 100644 --- a/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_big.yaml +++ b/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_big.yaml @@ -3,7 +3,7 @@ overrides: log-whitelist: - but it is still running - overall HEALTH_ - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_mix.yaml b/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_mix.yaml index 4e826b2b9..6b764a875 100644 --- a/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_mix.yaml +++ b/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_mix.yaml @@ -3,7 +3,7 @@ overrides: log-whitelist: - but it is still running - overall HEALTH_ - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_mostlyread.yaml b/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_mostlyread.yaml index d89ac340b..c82023c2a 100644 --- a/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_mostlyread.yaml +++ b/ceph/qa/suites/rados/basic/tasks/rados_workunit_loadgen_mostlyread.yaml @@ -3,7 +3,7 @@ overrides: log-whitelist: - but it is still running - overall HEALTH_ - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rados/mgr/tasks/failover.yaml b/ceph/qa/suites/rados/mgr/tasks/failover.yaml index fd5eb8515..34be47151 100644 --- a/ceph/qa/suites/rados/mgr/tasks/failover.yaml +++ b/ceph/qa/suites/rados/mgr/tasks/failover.yaml @@ -7,8 +7,10 @@ tasks: wait-for-scrub: false log-whitelist: - overall HEALTH_ - - (MGR_DOWN) - - (PG_ + - \(MGR_DOWN\) + - \(PG_ + - replacing it with standby + - No standby daemons available - cephfs_test_runner: modules: - tasks.mgr.test_failover diff --git a/ceph/qa/suites/rados/monthrash/ceph.yaml b/ceph/qa/suites/rados/monthrash/ceph.yaml index a2c0efc77..9c08e93f3 100644 --- a/ceph/qa/suites/rados/monthrash/ceph.yaml +++ b/ceph/qa/suites/rados/monthrash/ceph.yaml @@ -4,6 +4,11 @@ overrides: mon: mon min osdmap epochs: 25 paxos service trim min: 5 +# thrashing monitors may make mgr have trouble w/ its keepalive + log-whitelist: + - daemon x is unresponsive + - overall HEALTH_ + - \(MGR_DOWN\) tasks: - install: - ceph: diff --git a/ceph/qa/suites/rados/monthrash/thrashers/force-sync-many.yaml b/ceph/qa/suites/rados/monthrash/thrashers/force-sync-many.yaml index 38570fcf6..2d1ba8824 100644 --- a/ceph/qa/suites/rados/monthrash/thrashers/force-sync-many.yaml +++ b/ceph/qa/suites/rados/monthrash/thrashers/force-sync-many.yaml @@ -2,8 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (MON_DOWN) - - (TOO_FEW_PGS) + - \(MON_DOWN\) + - \(TOO_FEW_PGS\) tasks: - mon_thrash: revive_delay: 90 diff --git a/ceph/qa/suites/rados/monthrash/thrashers/many.yaml b/ceph/qa/suites/rados/monthrash/thrashers/many.yaml index e940c42ad..fa829b34b 100644 --- a/ceph/qa/suites/rados/monthrash/thrashers/many.yaml +++ b/ceph/qa/suites/rados/monthrash/thrashers/many.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (MON_DOWN) + - \(MON_DOWN\) conf: osd: mon client ping interval: 4 diff --git a/ceph/qa/suites/rados/monthrash/thrashers/one.yaml b/ceph/qa/suites/rados/monthrash/thrashers/one.yaml index 92c9eb3a8..041cee0b3 100644 --- a/ceph/qa/suites/rados/monthrash/thrashers/one.yaml +++ b/ceph/qa/suites/rados/monthrash/thrashers/one.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (MON_DOWN) + - \(MON_DOWN\) tasks: - mon_thrash: revive_delay: 20 diff --git a/ceph/qa/suites/rados/monthrash/thrashers/sync-many.yaml b/ceph/qa/suites/rados/monthrash/thrashers/sync-many.yaml index 68020cd66..14f41f7fb 100644 --- a/ceph/qa/suites/rados/monthrash/thrashers/sync-many.yaml +++ b/ceph/qa/suites/rados/monthrash/thrashers/sync-many.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (MON_DOWN) + - \(MON_DOWN\) conf: mon: paxos min: 10 diff --git a/ceph/qa/suites/rados/monthrash/thrashers/sync.yaml b/ceph/qa/suites/rados/monthrash/thrashers/sync.yaml index b07f8b511..08b1522c7 100644 --- a/ceph/qa/suites/rados/monthrash/thrashers/sync.yaml +++ b/ceph/qa/suites/rados/monthrash/thrashers/sync.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (MON_DOWN) + - \(MON_DOWN\) conf: mon: paxos min: 10 diff --git a/ceph/qa/suites/rados/monthrash/workloads/pool-create-delete.yaml b/ceph/qa/suites/rados/monthrash/workloads/pool-create-delete.yaml index abe8b6cb8..c6b00b486 100644 --- a/ceph/qa/suites/rados/monthrash/workloads/pool-create-delete.yaml +++ b/ceph/qa/suites/rados/monthrash/workloads/pool-create-delete.yaml @@ -3,7 +3,7 @@ overrides: log-whitelist: - slow request - overall HEALTH_ - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) tasks: - exec: client.0: diff --git a/ceph/qa/suites/rados/monthrash/workloads/rados_5925.yaml b/ceph/qa/suites/rados/monthrash/workloads/rados_5925.yaml index 00b951907..940d3a8e4 100644 --- a/ceph/qa/suites/rados/monthrash/workloads/rados_5925.yaml +++ b/ceph/qa/suites/rados/monthrash/workloads/rados_5925.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) tasks: - exec: client.0: diff --git a/ceph/qa/suites/rados/monthrash/workloads/rados_api_tests.yaml b/ceph/qa/suites/rados/monthrash/workloads/rados_api_tests.yaml index b2994181f..3b821bc0c 100644 --- a/ceph/qa/suites/rados/monthrash/workloads/rados_api_tests.yaml +++ b/ceph/qa/suites/rados/monthrash/workloads/rados_api_tests.yaml @@ -3,12 +3,14 @@ overrides: log-whitelist: - reached quota - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) - - (POOL_FULL) - - (REQUEST_SLOW) - - (MON_DOWN) - - (PG_ - - (POOL_APP_NOT_ENABLED) + - \(CACHE_POOL_NO_HIT_SET\) + - \(CACHE_POOL_NEAR_FULL\) + - \(POOL_FULL\) + - \(REQUEST_SLOW\) + - \(MON_DOWN\) + - \(PG_ + - \(POOL_APP_NOT_ENABLED\) + - \(SMALLER_PGP_NUM\) conf: global: debug objecter: 20 diff --git a/ceph/qa/suites/rados/monthrash/workloads/rados_mon_workunits.yaml b/ceph/qa/suites/rados/monthrash/workloads/rados_mon_workunits.yaml index fc5e7f25e..b05eb38be 100644 --- a/ceph/qa/suites/rados/monthrash/workloads/rados_mon_workunits.yaml +++ b/ceph/qa/suites/rados/monthrash/workloads/rados_mon_workunits.yaml @@ -3,8 +3,8 @@ overrides: log-whitelist: - but it is still running - overall HEALTH_ - - (PG_ - - (MON_DOWN) + - \(PG_ + - \(MON_DOWN\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rados/multimon/tasks/mon_recovery.yaml b/ceph/qa/suites/rados/multimon/tasks/mon_recovery.yaml index 4234bf73e..137f58dc7 100644 --- a/ceph/qa/suites/rados/multimon/tasks/mon_recovery.yaml +++ b/ceph/qa/suites/rados/multimon/tasks/mon_recovery.yaml @@ -3,5 +3,5 @@ tasks: - ceph: log-whitelist: - overall HEALTH_ - - (MON_DOWN) + - \(MON_DOWN\) - mon_recovery: diff --git a/ceph/qa/suites/rados/objectstore/ceph_objectstore_tool.yaml b/ceph/qa/suites/rados/objectstore/ceph_objectstore_tool.yaml index 2001faa3f..f3163c96b 100644 --- a/ceph/qa/suites/rados/objectstore/ceph_objectstore_tool.yaml +++ b/ceph/qa/suites/rados/objectstore/ceph_objectstore_tool.yaml @@ -14,9 +14,10 @@ tasks: osd max object namespace len: 64 log-whitelist: - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (TOO_FEW_PGS) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(TOO_FEW_PGS\) + - \(POOL_APP_NOT_ENABLED\) - ceph_objectstore_tool: objects: 20 diff --git a/ceph/qa/suites/rados/rest/mgr-restful.yaml b/ceph/qa/suites/rados/rest/mgr-restful.yaml index e62dd068f..90906d66e 100644 --- a/ceph/qa/suites/rados/rest/mgr-restful.yaml +++ b/ceph/qa/suites/rados/rest/mgr-restful.yaml @@ -5,13 +5,18 @@ tasks: - ceph: log-whitelist: - overall HEALTH_ - - (MGR_DOWN) + - \(MGR_DOWN\) - exec: mon.a: - ceph restful create-key admin - ceph restful create-self-signed-cert -- ceph.restart: [mgr.x] + - ceph restful restart - workunit: clients: client.a: - rest/test-restful.sh +- exec: + mon.a: + - ceph restful delete-key admin + - ceph restful list-keys | jq ".admin" | grep null + diff --git a/ceph/qa/suites/rados/singleton-nomsgr/all/cache-fs-trunc.yaml b/ceph/qa/suites/rados/singleton-nomsgr/all/cache-fs-trunc.yaml index ac64165aa..586480315 100644 --- a/ceph/qa/suites/rados/singleton-nomsgr/all/cache-fs-trunc.yaml +++ b/ceph/qa/suites/rados/singleton-nomsgr/all/cache-fs-trunc.yaml @@ -5,7 +5,7 @@ tasks: - ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) conf: global: osd max object name len: 460 diff --git a/ceph/qa/suites/rados/singleton-nomsgr/all/export-after-evict.yaml b/ceph/qa/suites/rados/singleton-nomsgr/all/export-after-evict.yaml index e7fafe9ac..e766bdc57 100644 --- a/ceph/qa/suites/rados/singleton-nomsgr/all/export-after-evict.yaml +++ b/ceph/qa/suites/rados/singleton-nomsgr/all/export-after-evict.yaml @@ -10,7 +10,7 @@ tasks: - ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) conf: global: osd max object name len: 460 diff --git a/ceph/qa/suites/rados/singleton-nomsgr/all/full-tiering.yaml b/ceph/qa/suites/rados/singleton-nomsgr/all/full-tiering.yaml index b811199d1..b24586608 100644 --- a/ceph/qa/suites/rados/singleton-nomsgr/all/full-tiering.yaml +++ b/ceph/qa/suites/rados/singleton-nomsgr/all/full-tiering.yaml @@ -6,9 +6,10 @@ overrides: log-whitelist: - is full - overall HEALTH_ - - (POOL_FULL) - - (POOL_NEAR_FULL) - - (CACHE_POOL_NO_HIT_SET) + - \(POOL_FULL\) + - \(POOL_NEAR_FULL\) + - \(CACHE_POOL_NO_HIT_SET\) + - \(CACHE_POOL_NEAR_FULL\) tasks: - install: - ceph: diff --git a/ceph/qa/suites/rados/singleton-nomsgr/all/health-warnings.yaml b/ceph/qa/suites/rados/singleton-nomsgr/all/health-warnings.yaml index 00157dfaf..a28582fd6 100644 --- a/ceph/qa/suites/rados/singleton-nomsgr/all/health-warnings.yaml +++ b/ceph/qa/suites/rados/singleton-nomsgr/all/health-warnings.yaml @@ -11,9 +11,9 @@ tasks: log-whitelist: - but it is still running - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ - workunit: clients: all: diff --git a/ceph/qa/suites/rados/singleton-nomsgr/all/multi-backfill-reject.yaml b/ceph/qa/suites/rados/singleton-nomsgr/all/multi-backfill-reject.yaml index 3a9dbde31..f480dbbf9 100644 --- a/ceph/qa/suites/rados/singleton-nomsgr/all/multi-backfill-reject.yaml +++ b/ceph/qa/suites/rados/singleton-nomsgr/all/multi-backfill-reject.yaml @@ -13,9 +13,9 @@ tasks: - ceph: log-whitelist: - overall HEALTH_ - - (PG_ - - (OSD_ - - (OBJECT_ + - \(PG_ + - \(OSD_ + - \(OBJECT_ conf: osd: osd debug reject backfill probability: .3 @@ -40,3 +40,5 @@ tasks: - exec: client.0: - sudo ceph osd pool set foo size 2 +- sleep: + duration: 300 diff --git a/ceph/qa/suites/rados/singleton-nomsgr/all/valgrind-leaks.yaml b/ceph/qa/suites/rados/singleton-nomsgr/all/valgrind-leaks.yaml index 347c49952..b0d5de305 100644 --- a/ceph/qa/suites/rados/singleton-nomsgr/all/valgrind-leaks.yaml +++ b/ceph/qa/suites/rados/singleton-nomsgr/all/valgrind-leaks.yaml @@ -9,7 +9,7 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (PG_ + - \(PG_ conf: global: osd heartbeat grace: 40 diff --git a/ceph/qa/suites/rados/singleton/all/divergent_priors.yaml b/ceph/qa/suites/rados/singleton/all/divergent_priors.yaml index f15fb8896..604a9e452 100644 --- a/ceph/qa/suites/rados/singleton/all/divergent_priors.yaml +++ b/ceph/qa/suites/rados/singleton/all/divergent_priors.yaml @@ -14,10 +14,11 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_DEGRADED) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_DEGRADED\) + - \(POOL_APP_NOT_ENABLED\) conf: osd: debug osd: 5 diff --git a/ceph/qa/suites/rados/singleton/all/divergent_priors2.yaml b/ceph/qa/suites/rados/singleton/all/divergent_priors2.yaml index 90d8b1838..e2f0245df 100644 --- a/ceph/qa/suites/rados/singleton/all/divergent_priors2.yaml +++ b/ceph/qa/suites/rados/singleton/all/divergent_priors2.yaml @@ -14,10 +14,11 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_DEGRADED) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_DEGRADED\) + - \(POOL_APP_NOT_ENABLED\) conf: osd: debug osd: 5 diff --git a/ceph/qa/suites/rados/singleton/all/dump-stuck.yaml b/ceph/qa/suites/rados/singleton/all/dump-stuck.yaml index 67546062c..59085ffae 100644 --- a/ceph/qa/suites/rados/singleton/all/dump-stuck.yaml +++ b/ceph/qa/suites/rados/singleton/all/dump-stuck.yaml @@ -13,7 +13,7 @@ tasks: log-whitelist: - but it is still running - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ - dump_stuck: diff --git a/ceph/qa/suites/rados/singleton/all/ec-lost-unfound.yaml b/ceph/qa/suites/rados/singleton/all/ec-lost-unfound.yaml index e095fd0d5..68644c860 100644 --- a/ceph/qa/suites/rados/singleton/all/ec-lost-unfound.yaml +++ b/ceph/qa/suites/rados/singleton/all/ec-lost-unfound.yaml @@ -17,8 +17,8 @@ tasks: log-whitelist: - objects unfound and apparently lost - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_ - ec_lost_unfound: diff --git a/ceph/qa/suites/rados/singleton/all/lost-unfound-delete.yaml b/ceph/qa/suites/rados/singleton/all/lost-unfound-delete.yaml index 5502b5c9b..bcaef784f 100644 --- a/ceph/qa/suites/rados/singleton/all/lost-unfound-delete.yaml +++ b/ceph/qa/suites/rados/singleton/all/lost-unfound-delete.yaml @@ -16,8 +16,8 @@ tasks: log-whitelist: - objects unfound and apparently lost - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_ - rep_lost_unfound_delete: diff --git a/ceph/qa/suites/rados/singleton/all/lost-unfound.yaml b/ceph/qa/suites/rados/singleton/all/lost-unfound.yaml index bb0bb2c0a..a4a309dee 100644 --- a/ceph/qa/suites/rados/singleton/all/lost-unfound.yaml +++ b/ceph/qa/suites/rados/singleton/all/lost-unfound.yaml @@ -16,8 +16,8 @@ tasks: log-whitelist: - objects unfound and apparently lost - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_ - lost_unfound: diff --git a/ceph/qa/suites/rados/singleton/all/osd-backfill.yaml b/ceph/qa/suites/rados/singleton/all/osd-backfill.yaml index 9b3a1f56e..5b3740715 100644 --- a/ceph/qa/suites/rados/singleton/all/osd-backfill.yaml +++ b/ceph/qa/suites/rados/singleton/all/osd-backfill.yaml @@ -16,10 +16,10 @@ tasks: log-whitelist: - but it is still running - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_ conf: osd: osd min pg log entries: 5 diff --git a/ceph/qa/suites/rados/singleton/all/osd-recovery-incomplete.yaml b/ceph/qa/suites/rados/singleton/all/osd-recovery-incomplete.yaml index a779f06af..ed5b216b2 100644 --- a/ceph/qa/suites/rados/singleton/all/osd-recovery-incomplete.yaml +++ b/ceph/qa/suites/rados/singleton/all/osd-recovery-incomplete.yaml @@ -17,10 +17,10 @@ tasks: log-whitelist: - but it is still running - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_ conf: osd: osd min pg log entries: 5 diff --git a/ceph/qa/suites/rados/singleton/all/osd-recovery.yaml b/ceph/qa/suites/rados/singleton/all/osd-recovery.yaml index eb0f6c337..a887ac5e3 100644 --- a/ceph/qa/suites/rados/singleton/all/osd-recovery.yaml +++ b/ceph/qa/suites/rados/singleton/all/osd-recovery.yaml @@ -16,10 +16,10 @@ tasks: log-whitelist: - but it is still running - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_DEGRADED) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_DEGRADED\) conf: osd: osd min pg log entries: 5 diff --git a/ceph/qa/suites/rados/singleton/all/peer.yaml b/ceph/qa/suites/rados/singleton/all/peer.yaml index e87cd543c..645034a40 100644 --- a/ceph/qa/suites/rados/singleton/all/peer.yaml +++ b/ceph/qa/suites/rados/singleton/all/peer.yaml @@ -19,7 +19,7 @@ tasks: log-whitelist: - objects unfound and apparently lost - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ - peer: diff --git a/ceph/qa/suites/rados/singleton/all/radostool.yaml b/ceph/qa/suites/rados/singleton/all/radostool.yaml index bf4813a1f..182779531 100644 --- a/ceph/qa/suites/rados/singleton/all/radostool.yaml +++ b/ceph/qa/suites/rados/singleton/all/radostool.yaml @@ -18,8 +18,8 @@ tasks: - had wrong cluster addr - reached quota - overall HEALTH_ - - (POOL_FULL) - - (POOL_APP_NOT_ENABLED) + - \(POOL_FULL\) + - \(POOL_APP_NOT_ENABLED\) - workunit: clients: all: diff --git a/ceph/qa/suites/rados/singleton/all/rebuild-mondb.yaml b/ceph/qa/suites/rados/singleton/all/rebuild-mondb.yaml index 6847cef8d..78d77c881 100644 --- a/ceph/qa/suites/rados/singleton/all/rebuild-mondb.yaml +++ b/ceph/qa/suites/rados/singleton/all/rebuild-mondb.yaml @@ -17,10 +17,10 @@ tasks: log-whitelist: - no reply from - overall HEALTH_ - - (MON_DOWN) - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ + - \(MON_DOWN\) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ - full_sequential: - radosbench: clients: [client.0] diff --git a/ceph/qa/suites/rados/singleton/all/reg11184.yaml b/ceph/qa/suites/rados/singleton/all/reg11184.yaml index 1abf5739f..f3c8575f1 100644 --- a/ceph/qa/suites/rados/singleton/all/reg11184.yaml +++ b/ceph/qa/suites/rados/singleton/all/reg11184.yaml @@ -17,11 +17,11 @@ overrides: debug osd: 5 log-whitelist: - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (SMALLER_PGP_NUM) - - (OBJECT_ + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(SMALLER_PGP_NUM\) + - \(OBJECT_ tasks: - install: - ceph: diff --git a/ceph/qa/suites/rados/singleton/all/resolve_stuck_peering.yaml b/ceph/qa/suites/rados/singleton/all/resolve_stuck_peering.yaml index 97da13790..3eddce821 100644 --- a/ceph/qa/suites/rados/singleton/all/resolve_stuck_peering.yaml +++ b/ceph/qa/suites/rados/singleton/all/resolve_stuck_peering.yaml @@ -8,9 +8,10 @@ tasks: fs: xfs log-whitelist: - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_DEGRADED) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_DEGRADED\) + - \(POOL_APP_NOT_ENABLED\) - resolve_stuck_peering: diff --git a/ceph/qa/suites/rados/singleton/all/rest-api.yaml b/ceph/qa/suites/rados/singleton/all/rest-api.yaml index fbcec1117..d988d1ad1 100644 --- a/ceph/qa/suites/rados/singleton/all/rest-api.yaml +++ b/ceph/qa/suites/rados/singleton/all/rest-api.yaml @@ -19,10 +19,10 @@ tasks: - but it is still running - had wrong client addr - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_DEGRADED) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_DEGRADED\) conf: client.rest0: debug ms: 1 diff --git a/ceph/qa/suites/rados/singleton/all/test_envlibrados_for_rocksdb.yaml b/ceph/qa/suites/rados/singleton/all/test_envlibrados_for_rocksdb.yaml index 8273b2ef6..42c8ae394 100644 --- a/ceph/qa/suites/rados/singleton/all/test_envlibrados_for_rocksdb.yaml +++ b/ceph/qa/suites/rados/singleton/all/test_envlibrados_for_rocksdb.yaml @@ -12,7 +12,7 @@ tasks: - ceph: log-whitelist: - overall HEALTH_ - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) - workunit: clients: all: diff --git a/ceph/qa/suites/rados/singleton/all/watch-notify-same-primary.yaml b/ceph/qa/suites/rados/singleton/all/watch-notify-same-primary.yaml index 3efdb955f..48ef78ff9 100644 --- a/ceph/qa/suites/rados/singleton/all/watch-notify-same-primary.yaml +++ b/ceph/qa/suites/rados/singleton/all/watch-notify-same-primary.yaml @@ -24,9 +24,9 @@ tasks: log-whitelist: - objects unfound and apparently lost - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (OBJECT_DEGRADED) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(OBJECT_DEGRADED\) - watch_notify_same_primary: clients: [client.0] diff --git a/ceph/qa/suites/rados/thrash-erasure-code-big/cluster/12-osds.yaml b/ceph/qa/suites/rados/thrash-erasure-code-big/cluster/12-osds.yaml index db86583f2..1c45ee352 100644 --- a/ceph/qa/suites/rados/thrash-erasure-code-big/cluster/12-osds.yaml +++ b/ceph/qa/suites/rados/thrash-erasure-code-big/cluster/12-osds.yaml @@ -1,5 +1,4 @@ roles: -- [osd.0, osd.1, osd.2, client.0, mon.a] -- [osd.3, osd.4, osd.5, mon.b] -- [osd.6, osd.7, osd.8, mon.c] -- [osd.9, osd.10, osd.11, mgr.x] +- [osd.0, osd.1, osd.2, osd.3, client.0, mon.a] +- [osd.4, osd.5, osd.6, osd.7, mon.b, mgr.x] +- [osd.8, osd.9, osd.10, osd.11, mon.c] diff --git a/ceph/qa/suites/rados/thrash-erasure-code-big/cluster/openstack.yaml b/ceph/qa/suites/rados/thrash-erasure-code-big/cluster/openstack.yaml index e4d84236a..e559d9126 100644 --- a/ceph/qa/suites/rados/thrash-erasure-code-big/cluster/openstack.yaml +++ b/ceph/qa/suites/rados/thrash-erasure-code-big/cluster/openstack.yaml @@ -1,4 +1,4 @@ openstack: - volumes: # attached to each instance - count: 3 + count: 4 size: 10 # GB diff --git a/ceph/qa/suites/rados/thrash-erasure-code-big/workloads/ec-rados-plugin=jerasure-k=4-m=2.yaml b/ceph/qa/suites/rados/thrash-erasure-code-big/workloads/ec-rados-plugin=jerasure-k=4-m=2.yaml new file mode 120000 index 000000000..a4d836c45 --- /dev/null +++ b/ceph/qa/suites/rados/thrash-erasure-code-big/workloads/ec-rados-plugin=jerasure-k=4-m=2.yaml @@ -0,0 +1 @@ +../../../../erasure-code/ec-rados-plugin=jerasure-k=4-m=2.yaml \ No newline at end of file diff --git a/ceph/qa/suites/rados/thrash-erasure-code/thrashers/mapgap.yaml b/ceph/qa/suites/rados/thrash-erasure-code/thrashers/mapgap.yaml deleted file mode 100644 index fc2bd4359..000000000 --- a/ceph/qa/suites/rados/thrash-erasure-code/thrashers/mapgap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -overrides: - ceph: - conf: - mon: - mon min osdmap epochs: 2 - osd: - osd map cache size: 1 - osd scrub min interval: 60 - osd scrub max interval: 120 - osd max backfills: 5 - log-whitelist: - - but it is still running - - objects unfound and apparently lost - - osd_map_cache_size -tasks: -- thrashosds: - timeout: 1800 - chance_pgnum_grow: 1 - chance_pgpnum_fix: 1 - chance_test_map_discontinuity: 0.5 - min_in: 4 diff --git a/ceph/qa/suites/rados/thrash/clusters/openstack.yaml b/ceph/qa/suites/rados/thrash/clusters/openstack.yaml index f4d1349b4..b0f3b9b4d 100644 --- a/ceph/qa/suites/rados/thrash/clusters/openstack.yaml +++ b/ceph/qa/suites/rados/thrash/clusters/openstack.yaml @@ -1,4 +1,4 @@ openstack: - volumes: # attached to each instance - count: 3 + count: 4 size: 30 # GB diff --git a/ceph/qa/suites/rados/thrash/d-require-luminous/at-end.yaml b/ceph/qa/suites/rados/thrash/d-require-luminous/at-end.yaml index a18aa3342..4e60cd656 100644 --- a/ceph/qa/suites/rados/thrash/d-require-luminous/at-end.yaml +++ b/ceph/qa/suites/rados/thrash/d-require-luminous/at-end.yaml @@ -25,7 +25,7 @@ overrides: # setting luminous triggers peering, which *might* trigger health alerts log-whitelist: - overall HEALTH_ - - (PG_AVAILABILITY) - - (PG_DEGRADED) + - \(PG_AVAILABILITY\) + - \(PG_DEGRADED\) thrashosds: chance_thrash_cluster_full: 0 diff --git a/ceph/qa/suites/rados/thrash/workloads/cache-agent-big.yaml b/ceph/qa/suites/rados/thrash/workloads/cache-agent-big.yaml index bbfe7bf50..0cef20773 100644 --- a/ceph/qa/suites/rados/thrash/workloads/cache-agent-big.yaml +++ b/ceph/qa/suites/rados/thrash/workloads/cache-agent-big.yaml @@ -5,8 +5,8 @@ overrides: tasks: - exec: client.0: - - sudo ceph osd erasure-code-profile set teuthologyprofile crush-failure-domain=osd m=1 k=2 - - sudo ceph osd pool create base 4 4 erasure teuthologyprofile + - sudo ceph osd erasure-code-profile set myprofile crush-failure-domain=osd m=2 k=2 + - sudo ceph osd pool create base 4 4 erasure myprofile - sudo ceph osd pool application enable base rados - sudo ceph osd pool set base min_size 2 - sudo ceph osd pool create cache 4 diff --git a/ceph/qa/suites/rados/thrash/workloads/rados_api_tests.yaml b/ceph/qa/suites/rados/thrash/workloads/rados_api_tests.yaml index e096e4e56..23c705d1e 100644 --- a/ceph/qa/suites/rados/thrash/workloads/rados_api_tests.yaml +++ b/ceph/qa/suites/rados/thrash/workloads/rados_api_tests.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - reached quota - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) crush_tunables: hammer conf: client: diff --git a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/6-finish-upgrade.yaml b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/6-finish-upgrade.yaml index d4c69463c..a1108158c 100644 --- a/ceph/qa/suites/rados/upgrade/jewel-x-singleton/6-finish-upgrade.yaml +++ b/ceph/qa/suites/rados/upgrade/jewel-x-singleton/6-finish-upgrade.yaml @@ -2,6 +2,12 @@ meta: - desc: | install upgrade on remaining node restartin remaining osds +overrides: + ceph: + log-whitelist: + - overall HEALTH_ + - \(FS_DEGRADED\) + - \(MDS_ tasks: - install.upgrade: osd.3: diff --git a/ceph/qa/suites/rados/verify/clusters/openstack.yaml b/ceph/qa/suites/rados/verify/clusters/openstack.yaml index e4d84236a..e559d9126 100644 --- a/ceph/qa/suites/rados/verify/clusters/openstack.yaml +++ b/ceph/qa/suites/rados/verify/clusters/openstack.yaml @@ -1,4 +1,4 @@ openstack: - volumes: # attached to each instance - count: 3 + count: 4 size: 10 # GB diff --git a/ceph/qa/suites/rados/verify/tasks/mon_recovery.yaml b/ceph/qa/suites/rados/verify/tasks/mon_recovery.yaml index 4063f4e6e..266a4e479 100644 --- a/ceph/qa/suites/rados/verify/tasks/mon_recovery.yaml +++ b/ceph/qa/suites/rados/verify/tasks/mon_recovery.yaml @@ -2,9 +2,9 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (MON_DOWN) - - (OSDMAP_FLAGS) - - (SMALLER_PGP_NUM) - - (POOL_APP_NOT_ENABLED) + - \(MON_DOWN\) + - \(OSDMAP_FLAGS\) + - \(SMALLER_PGP_NUM\) + - \(POOL_APP_NOT_ENABLED\) tasks: - mon_recovery: diff --git a/ceph/qa/suites/rados/verify/tasks/rados_api_tests.yaml b/ceph/qa/suites/rados/verify/tasks/rados_api_tests.yaml index ea81ad1ff..05b843ebd 100644 --- a/ceph/qa/suites/rados/verify/tasks/rados_api_tests.yaml +++ b/ceph/qa/suites/rados/verify/tasks/rados_api_tests.yaml @@ -3,12 +3,12 @@ overrides: log-whitelist: - reached quota - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) - - (POOL_FULL) - - (SMALLER_PGP_NUM) - - (REQUEST_SLOW) - - (CACHE_POOL_NEAR_FULL) - - (POOL_APP_NOT_ENABLED) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_FULL\) + - \(SMALLER_PGP_NUM\) + - \(REQUEST_SLOW\) + - \(CACHE_POOL_NEAR_FULL\) + - \(POOL_APP_NOT_ENABLED\) conf: client: debug ms: 1 diff --git a/ceph/qa/suites/rbd/basic/cachepool/small.yaml b/ceph/qa/suites/rbd/basic/cachepool/small.yaml index 5c8f924ab..1b5056573 100644 --- a/ceph/qa/suites/rbd/basic/cachepool/small.yaml +++ b/ceph/qa/suites/rbd/basic/cachepool/small.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NEAR_FULL\) + - \(CACHE_POOL_NO_HIT_SET\) tasks: - exec: client.0: diff --git a/ceph/qa/suites/rbd/basic/tasks/rbd_api_tests_old_format.yaml b/ceph/qa/suites/rbd/basic/tasks/rbd_api_tests_old_format.yaml index 9d34002a1..fe1e26d53 100644 --- a/ceph/qa/suites/rbd/basic/tasks/rbd_api_tests_old_format.yaml +++ b/ceph/qa/suites/rbd/basic/tasks/rbd_api_tests_old_format.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/basic/tasks/rbd_python_api_tests_old_format.yaml b/ceph/qa/suites/rbd/basic/tasks/rbd_python_api_tests_old_format.yaml index f60a5ffa7..7ab3185ec 100644 --- a/ceph/qa/suites/rbd/basic/tasks/rbd_python_api_tests_old_format.yaml +++ b/ceph/qa/suites/rbd/basic/tasks/rbd_python_api_tests_old_format.yaml @@ -1,7 +1,7 @@ overrides: ceph: log-whitelist: - - (REQUEST_SLOW) + - \(REQUEST_SLOW\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/cli/pool/ec-data-pool.yaml b/ceph/qa/suites/rbd/cli/pool/ec-data-pool.yaml index 9e90369ef..7fdb1f1a4 100644 --- a/ceph/qa/suites/rbd/cli/pool/ec-data-pool.yaml +++ b/ceph/qa/suites/rbd/cli/pool/ec-data-pool.yaml @@ -14,7 +14,7 @@ overrides: fs: xfs log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) conf: client: rbd default data pool: datapool diff --git a/ceph/qa/suites/rbd/cli/pool/small-cache-pool.yaml b/ceph/qa/suites/rbd/cli/pool/small-cache-pool.yaml index 5c8f924ab..1b5056573 100644 --- a/ceph/qa/suites/rbd/cli/pool/small-cache-pool.yaml +++ b/ceph/qa/suites/rbd/cli/pool/small-cache-pool.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NEAR_FULL\) + - \(CACHE_POOL_NO_HIT_SET\) tasks: - exec: client.0: diff --git a/ceph/qa/suites/rbd/librbd/clusters/openstack.yaml b/ceph/qa/suites/rbd/librbd/clusters/openstack.yaml index f4d1349b4..b0f3b9b4d 100644 --- a/ceph/qa/suites/rbd/librbd/clusters/openstack.yaml +++ b/ceph/qa/suites/rbd/librbd/clusters/openstack.yaml @@ -1,4 +1,4 @@ openstack: - volumes: # attached to each instance - count: 3 + count: 4 size: 30 # GB diff --git a/ceph/qa/suites/rbd/librbd/pool/ec-data-pool.yaml b/ceph/qa/suites/rbd/librbd/pool/ec-data-pool.yaml index 75dfc6a45..a63ab2703 100644 --- a/ceph/qa/suites/rbd/librbd/pool/ec-data-pool.yaml +++ b/ceph/qa/suites/rbd/librbd/pool/ec-data-pool.yaml @@ -4,6 +4,7 @@ tasks: - sudo ceph osd erasure-code-profile set teuthologyprofile crush-failure-domain=osd m=1 k=2 - sudo ceph osd pool create datapool 4 4 erasure teuthologyprofile - sudo ceph osd pool set datapool allow_ec_overwrites true + - rbd pool init datapool overrides: thrashosds: diff --git a/ceph/qa/suites/rbd/librbd/pool/small-cache-pool.yaml b/ceph/qa/suites/rbd/librbd/pool/small-cache-pool.yaml index 5c8f924ab..1b5056573 100644 --- a/ceph/qa/suites/rbd/librbd/pool/small-cache-pool.yaml +++ b/ceph/qa/suites/rbd/librbd/pool/small-cache-pool.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NEAR_FULL\) + - \(CACHE_POOL_NO_HIT_SET\) tasks: - exec: client.0: diff --git a/ceph/qa/suites/rbd/librbd/workloads/c_api_tests.yaml b/ceph/qa/suites/rbd/librbd/workloads/c_api_tests.yaml index b70e8d52b..04af9c85b 100644 --- a/ceph/qa/suites/rbd/librbd/workloads/c_api_tests.yaml +++ b/ceph/qa/suites/rbd/librbd/workloads/c_api_tests.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/librbd/workloads/c_api_tests_with_defaults.yaml b/ceph/qa/suites/rbd/librbd/workloads/c_api_tests_with_defaults.yaml index c2af3573d..6ae7f4627 100644 --- a/ceph/qa/suites/rbd/librbd/workloads/c_api_tests_with_defaults.yaml +++ b/ceph/qa/suites/rbd/librbd/workloads/c_api_tests_with_defaults.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/librbd/workloads/c_api_tests_with_journaling.yaml b/ceph/qa/suites/rbd/librbd/workloads/c_api_tests_with_journaling.yaml index f1121a403..578115ee6 100644 --- a/ceph/qa/suites/rbd/librbd/workloads/c_api_tests_with_journaling.yaml +++ b/ceph/qa/suites/rbd/librbd/workloads/c_api_tests_with_journaling.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/openstack/base/install.yaml b/ceph/qa/suites/rbd/openstack/base/install.yaml index 2030acb90..90f80dcf2 100644 --- a/ceph/qa/suites/rbd/openstack/base/install.yaml +++ b/ceph/qa/suites/rbd/openstack/base/install.yaml @@ -1,3 +1,7 @@ tasks: - install: - ceph: +overrides: + ceph: + log-whitelist: + - (POOL_APP_NOT_ENABLED) diff --git a/ceph/qa/suites/rbd/qemu/clusters/openstack.yaml b/ceph/qa/suites/rbd/qemu/clusters/openstack.yaml index f87995808..9c39c7e5f 100644 --- a/ceph/qa/suites/rbd/qemu/clusters/openstack.yaml +++ b/ceph/qa/suites/rbd/qemu/clusters/openstack.yaml @@ -4,5 +4,5 @@ openstack: ram: 30000 # MB cpus: 1 volumes: # attached to each instance - count: 3 + count: 4 size: 30 # GB diff --git a/ceph/qa/suites/rbd/qemu/pool/ec-cache-pool.yaml b/ceph/qa/suites/rbd/qemu/pool/ec-cache-pool.yaml index cfa0fcd70..c75e6fd47 100644 --- a/ceph/qa/suites/rbd/qemu/pool/ec-cache-pool.yaml +++ b/ceph/qa/suites/rbd/qemu/pool/ec-cache-pool.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NEAR_FULL\) + - \(CACHE_POOL_NO_HIT_SET\) tasks: - exec: client.0: diff --git a/ceph/qa/suites/rbd/qemu/pool/small-cache-pool.yaml b/ceph/qa/suites/rbd/qemu/pool/small-cache-pool.yaml index 5c8f924ab..1b5056573 100644 --- a/ceph/qa/suites/rbd/qemu/pool/small-cache-pool.yaml +++ b/ceph/qa/suites/rbd/qemu/pool/small-cache-pool.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NEAR_FULL\) + - \(CACHE_POOL_NO_HIT_SET\) tasks: - exec: client.0: diff --git a/ceph/qa/suites/rbd/singleton-bluestore/% b/ceph/qa/suites/rbd/singleton-bluestore/% new file mode 100644 index 000000000..e69de29bb diff --git a/ceph/qa/suites/rbd/singleton-bluestore/all/issue-20295.yaml b/ceph/qa/suites/rbd/singleton-bluestore/all/issue-20295.yaml new file mode 100644 index 000000000..9af52e0ed --- /dev/null +++ b/ceph/qa/suites/rbd/singleton-bluestore/all/issue-20295.yaml @@ -0,0 +1,14 @@ +roles: +- [mon.a, mgr.x, osd.0, osd.1, osd.2, client.0] +- [mon.b, mgr.y, osd.3, osd.4, osd.5] +- [mon.c, mgr.z, osd.6, osd.7, osd.8] +- [osd.9, osd.10, osd.11] +tasks: +- install: +- ceph: + log-whitelist: + - 'application not enabled' +- workunit: + timeout: 30m + clients: + all: [rbd/issue-20295.sh] diff --git a/ceph/qa/suites/rbd/singleton-bluestore/objectstore/bluestore-comp.yaml b/ceph/qa/suites/rbd/singleton-bluestore/objectstore/bluestore-comp.yaml new file mode 120000 index 000000000..b23b2a792 --- /dev/null +++ b/ceph/qa/suites/rbd/singleton-bluestore/objectstore/bluestore-comp.yaml @@ -0,0 +1 @@ +../../../../objectstore/bluestore-comp.yaml \ No newline at end of file diff --git a/ceph/qa/suites/rbd/singleton-bluestore/objectstore/bluestore.yaml b/ceph/qa/suites/rbd/singleton-bluestore/objectstore/bluestore.yaml new file mode 120000 index 000000000..bd7d7e004 --- /dev/null +++ b/ceph/qa/suites/rbd/singleton-bluestore/objectstore/bluestore.yaml @@ -0,0 +1 @@ +../../../../objectstore/bluestore.yaml \ No newline at end of file diff --git a/ceph/qa/suites/rbd/singleton-bluestore/openstack.yaml b/ceph/qa/suites/rbd/singleton-bluestore/openstack.yaml new file mode 100644 index 000000000..f4d1349b4 --- /dev/null +++ b/ceph/qa/suites/rbd/singleton-bluestore/openstack.yaml @@ -0,0 +1,4 @@ +openstack: + - volumes: # attached to each instance + count: 3 + size: 30 # GB diff --git a/ceph/qa/suites/rbd/singleton/all/rbd_mirror.yaml b/ceph/qa/suites/rbd/singleton/all/rbd_mirror.yaml index 5006dd801..0800cbfce 100644 --- a/ceph/qa/suites/rbd/singleton/all/rbd_mirror.yaml +++ b/ceph/qa/suites/rbd/singleton/all/rbd_mirror.yaml @@ -6,7 +6,8 @@ tasks: fs: xfs log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) - workunit: clients: all: [rbd/test_rbd_mirror.sh] diff --git a/ceph/qa/suites/rbd/thrash/clusters/openstack.yaml b/ceph/qa/suites/rbd/thrash/clusters/openstack.yaml index 39e43d021..40fef4770 100644 --- a/ceph/qa/suites/rbd/thrash/clusters/openstack.yaml +++ b/ceph/qa/suites/rbd/thrash/clusters/openstack.yaml @@ -4,5 +4,5 @@ openstack: ram: 8000 # MB cpus: 1 volumes: # attached to each instance - count: 3 + count: 4 size: 30 # GB diff --git a/ceph/qa/suites/rbd/thrash/thrashers/cache.yaml b/ceph/qa/suites/rbd/thrash/thrashers/cache.yaml index 7ed2c709b..e723e0929 100644 --- a/ceph/qa/suites/rbd/thrash/thrashers/cache.yaml +++ b/ceph/qa/suites/rbd/thrash/thrashers/cache.yaml @@ -1,8 +1,11 @@ overrides: ceph: log-whitelist: - - but it is still running - - objects unfound and apparently lost + - but it is still running + - objects unfound and apparently lost + - overall HEALTH_ + - (CACHE_POOL_NEAR_FULL) + - (CACHE_POOL_NO_HIT_SET) tasks: - exec: client.0: diff --git a/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests.yaml b/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests.yaml index c2af3573d..6ae7f4627 100644 --- a/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests.yaml +++ b/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_copy_on_read.yaml b/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_copy_on_read.yaml index 7f64ef3f1..a9021548d 100644 --- a/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_copy_on_read.yaml +++ b/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_copy_on_read.yaml @@ -9,7 +9,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) conf: client: rbd clone copy on read: true diff --git a/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_journaling.yaml b/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_journaling.yaml index f1121a403..578115ee6 100644 --- a/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_journaling.yaml +++ b/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_journaling.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_no_locking.yaml b/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_no_locking.yaml index b70e8d52b..04af9c85b 100644 --- a/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_no_locking.yaml +++ b/ceph/qa/suites/rbd/thrash/workloads/rbd_api_tests_no_locking.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests.yaml b/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests.yaml index b70e8d52b..04af9c85b 100644 --- a/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests.yaml +++ b/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests_with_defaults.yaml b/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests_with_defaults.yaml index c2af3573d..6ae7f4627 100644 --- a/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests_with_defaults.yaml +++ b/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests_with_defaults.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests_with_journaling.yaml b/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests_with_journaling.yaml index f1121a403..578115ee6 100644 --- a/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests_with_journaling.yaml +++ b/ceph/qa/suites/rbd/valgrind/workloads/c_api_tests_with_journaling.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/rbd/valgrind/workloads/rbd_mirror.yaml b/ceph/qa/suites/rbd/valgrind/workloads/rbd_mirror.yaml index 8adc7209a..e0943439a 100644 --- a/ceph/qa/suites/rbd/valgrind/workloads/rbd_mirror.yaml +++ b/ceph/qa/suites/rbd/valgrind/workloads/rbd_mirror.yaml @@ -2,7 +2,8 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (CACHE_POOL_NO_HIT_SET) + - \(CACHE_POOL_NO_HIT_SET\) + - \(POOL_APP_NOT_ENABLED\) tasks: - workunit: clients: diff --git a/ceph/qa/suites/smoke/basic/clusters/openstack.yaml b/ceph/qa/suites/smoke/basic/clusters/openstack.yaml index 4d6edcd07..7d652b491 100644 --- a/ceph/qa/suites/smoke/basic/clusters/openstack.yaml +++ b/ceph/qa/suites/smoke/basic/clusters/openstack.yaml @@ -4,5 +4,5 @@ openstack: ram: 8000 # MB cpus: 1 volumes: # attached to each instance - count: 3 + count: 4 size: 10 # GB diff --git a/ceph/qa/suites/smoke/basic/tasks/mon_thrash.yaml b/ceph/qa/suites/smoke/basic/tasks/mon_thrash.yaml index 2c0ab2d8a..591931d9f 100644 --- a/ceph/qa/suites/smoke/basic/tasks/mon_thrash.yaml +++ b/ceph/qa/suites/smoke/basic/tasks/mon_thrash.yaml @@ -2,7 +2,7 @@ overrides: ceph: log-whitelist: - reached quota - - (POOL_APP_NOT_ENABLED) + - \(POOL_APP_NOT_ENABLED\) conf: global: ms inject delay max: 1 diff --git a/ceph/qa/suites/upgrade/jewel-x/parallel/0-cluster/start.yaml b/ceph/qa/suites/upgrade/jewel-x/parallel/0-cluster/start.yaml index a8934deed..20e81be24 100644 --- a/ceph/qa/suites/upgrade/jewel-x/parallel/0-cluster/start.yaml +++ b/ceph/qa/suites/upgrade/jewel-x/parallel/0-cluster/start.yaml @@ -24,5 +24,6 @@ overrides: - scrub mismatch - ScrubResult - wrongly marked + - (MDS_FAILED) conf: fs: xfs diff --git a/ceph/qa/suites/upgrade/jewel-x/parallel/1-jewel-install/jewel.yaml b/ceph/qa/suites/upgrade/jewel-x/parallel/1-jewel-install/jewel.yaml index d90dc18b5..a7ff9f485 100644 --- a/ceph/qa/suites/upgrade/jewel-x/parallel/1-jewel-install/jewel.yaml +++ b/ceph/qa/suites/upgrade/jewel-x/parallel/1-jewel-install/jewel.yaml @@ -13,8 +13,19 @@ tasks: add_osds_to_crush: true log-whitelist: - overall HEALTH_ - - (FS_ - - (MDS_ + - \(FS_ + - \(MDS_ + - \(OSD_ + - \(MON_DOWN\) + - \(CACHE_POOL_ + - \(POOL_ + - \(MGR_DOWN\) + - \(PG_ + - Monitor daemon marked osd + - Behind on trimming + conf: + global: + mon warn on pool no app: false - print: "**** done ceph" - install.upgrade: mon.a: diff --git a/ceph/qa/suites/upgrade/jewel-x/point-to-point-x/point-to-point-upgrade.yaml b/ceph/qa/suites/upgrade/jewel-x/point-to-point-x/point-to-point-upgrade.yaml index d69068293..3033f14be 100644 --- a/ceph/qa/suites/upgrade/jewel-x/point-to-point-x/point-to-point-upgrade.yaml +++ b/ceph/qa/suites/upgrade/jewel-x/point-to-point-x/point-to-point-upgrade.yaml @@ -20,6 +20,7 @@ overrides: conf: mon: mon debug unsafe allow tier with nonempty snaps: true + mon warn on pool no app: false osd: osd map max advance: 1000 roles: diff --git a/ceph/qa/suites/upgrade/kraken-x/parallel/1-kraken-install/kraken.yaml b/ceph/qa/suites/upgrade/kraken-x/parallel/1-kraken-install/kraken.yaml index 882f2a7d2..de0893c1d 100644 --- a/ceph/qa/suites/upgrade/kraken-x/parallel/1-kraken-install/kraken.yaml +++ b/ceph/qa/suites/upgrade/kraken-x/parallel/1-kraken-install/kraken.yaml @@ -8,6 +8,23 @@ tasks: branch: kraken - print: "**** done installing kraken" - ceph: + log-whitelist: + - overall HEALTH_ + - \(FS_ + - \(MDS_ + - \(OSD_ + - \(MON_DOWN\) + - \(CACHE_POOL_ + - \(POOL_ + - \(MGR_DOWN\) + - \(PG_ + - \(SMALLER_PGP_NUM\) + - Monitor daemon marked osd + - Behind on trimming + - Manager daemon + conf: + global: + mon warn on pool no app: false - print: "**** done ceph" - install.upgrade: mon.a: diff --git a/ceph/qa/suites/upgrade/kraken-x/stress-split-erasure-code/thrashosds-health.yaml b/ceph/qa/suites/upgrade/kraken-x/stress-split-erasure-code/thrashosds-health.yaml new file mode 120000 index 000000000..e0426dbe4 --- /dev/null +++ b/ceph/qa/suites/upgrade/kraken-x/stress-split-erasure-code/thrashosds-health.yaml @@ -0,0 +1 @@ +../../../../tasks/thrashosds-health.yaml \ No newline at end of file diff --git a/ceph/qa/suites/upgrade/kraken-x/stress-split/0-cluster/start.yaml b/ceph/qa/suites/upgrade/kraken-x/stress-split/0-cluster/start.yaml index dbb03ec82..b8a28f986 100644 --- a/ceph/qa/suites/upgrade/kraken-x/stress-split/0-cluster/start.yaml +++ b/ceph/qa/suites/upgrade/kraken-x/stress-split/0-cluster/start.yaml @@ -6,6 +6,10 @@ meta: overrides: ceph: fs: xfs + log-whitelist: + - overall HEALTH_ + - \(MON_DOWN\) + - \(MGR_DOWN\) conf: global: enable experimental unrecoverable data corrupting features: "*" diff --git a/ceph/qa/suites/upgrade/kraken-x/stress-split/thrashosds-health.yaml b/ceph/qa/suites/upgrade/kraken-x/stress-split/thrashosds-health.yaml new file mode 120000 index 000000000..e0426dbe4 --- /dev/null +++ b/ceph/qa/suites/upgrade/kraken-x/stress-split/thrashosds-health.yaml @@ -0,0 +1 @@ +../../../../tasks/thrashosds-health.yaml \ No newline at end of file diff --git a/ceph/qa/tasks/ceph.py b/ceph/qa/tasks/ceph.py index 05c4c7d90..358ec8d64 100644 --- a/ceph/qa/tasks/ceph.py +++ b/ceph/qa/tasks/ceph.py @@ -342,6 +342,13 @@ def create_rbd_pool(ctx, config): mon_remote.run( args=['sudo', 'ceph', '--cluster', cluster_name, 'osd', 'pool', 'create', 'rbd', '8']) + mon_remote.run( + args=[ + 'sudo', 'ceph', '--cluster', cluster_name, + 'osd', 'pool', 'application', 'enable', + 'rbd', 'rbd', '--yes-i-really-mean-it' + ], + check_status=False) yield @contextlib.contextmanager @@ -686,6 +693,7 @@ def cluster(ctx, config): '-p', mnt_point, ]) + log.info(str(roles_to_devs)) log.info(str(roles_to_journals)) log.info(role) if roles_to_devs.get(role): @@ -1022,8 +1030,8 @@ def osd_scrub_pgs(ctx, config): indicate the last scrub completed. Time out if no progess is made here after two minutes. """ - retries = 20 - delays = 10 + retries = 40 + delays = 20 cluster_name = config['cluster'] manager = ctx.managers[cluster_name] all_clean = False @@ -1225,9 +1233,9 @@ def healthy(ctx, config): log.info('Waiting until %s daemons up and pgs clean...', cluster_name) manager = ctx.managers[cluster_name] try: - manager.wait_for_mgr_available() - except run.CommandFailedError: - log.info('ignoring mgr wait error, probably testing upgrade') + manager.wait_for_mgr_available(timeout=30) + except (run.CommandFailedError, AssertionError) as e: + log.info('ignoring mgr wait error, probably testing upgrade: %s', e) firstmon = teuthology.get_first_mon(ctx, config, cluster_name) (mon0_remote,) = ctx.cluster.only(firstmon).remotes.keys() @@ -1240,8 +1248,8 @@ def healthy(ctx, config): try: manager.flush_all_pg_stats() - except run.CommandFailedError: - log.info('ignoring flush pg stats error, probably testing upgrade') + except (run.CommandFailedError, Exception) as e: + log.info('ignoring flush pg stats error, probably testing upgrade: %s', e) manager.wait_for_clean() log.info('Waiting until ceph cluster %s is healthy...', cluster_name) diff --git a/ceph/qa/tasks/ceph_test_case.py b/ceph/qa/tasks/ceph_test_case.py index 47f392134..0f66106c9 100644 --- a/ceph/qa/tasks/ceph_test_case.py +++ b/ceph/qa/tasks/ceph_test_case.py @@ -84,7 +84,7 @@ class CephTestCase(unittest.TestCase): def seen_health_warning(): health = self.ceph_cluster.mon_manager.get_mon_health() codes = [s for s in health['checks']] - summary_strings = [s[1]['message'] for s in health['checks'].iteritems()] + summary_strings = [s[1]['summary']['message'] for s in health['checks'].iteritems()] if len(summary_strings) == 0: log.debug("Not expected number of summary strings ({0})".format(summary_strings)) return False diff --git a/ceph/qa/tasks/cephfs/test_exports.py b/ceph/qa/tasks/cephfs/test_exports.py index 774dd8ffe..913999db7 100644 --- a/ceph/qa/tasks/cephfs/test_exports.py +++ b/ceph/qa/tasks/cephfs/test_exports.py @@ -18,6 +18,9 @@ class TestExports(CephFSTestCase): filtered = sorted([(s['dir']['path'], s['auth_first']) for s in subtrees]) log.info("%s =?= %s", filtered, test) if filtered == test: + # Confirm export_pin in output is correct: + for s in subtrees: + self.assertTrue(s['export_pin'] == s['auth_first']) return subtrees time.sleep(pause) raise RuntimeError("rank {0} failed to reach desired subtree state", rank) diff --git a/ceph/qa/tasks/cephfs/test_fragment.py b/ceph/qa/tasks/cephfs/test_fragment.py index f2486a063..a62ef7432 100644 --- a/ceph/qa/tasks/cephfs/test_fragment.py +++ b/ceph/qa/tasks/cephfs/test_fragment.py @@ -68,8 +68,8 @@ class TestFragmentation(CephFSTestCase): frags = self.get_dir_ino("/splitdir")['dirfrags'] self.assertEqual(len(frags), 2) - self.assertEqual(frags[0]['dirfrag'], "10000000000.0*") - self.assertEqual(frags[1]['dirfrag'], "10000000000.1*") + self.assertEqual(frags[0]['dirfrag'], "0x10000000000.0*") + self.assertEqual(frags[1]['dirfrag'], "0x10000000000.1*") self.assertEqual( sum([len(f['dentries']) for f in frags]), split_size + 1 diff --git a/ceph/qa/tasks/cephfs/test_misc.py b/ceph/qa/tasks/cephfs/test_misc.py index 2774423da..77ca07a19 100644 --- a/ceph/qa/tasks/cephfs/test_misc.py +++ b/ceph/qa/tasks/cephfs/test_misc.py @@ -5,6 +5,7 @@ from tasks.cephfs.cephfs_test_case import CephFSTestCase from teuthology.orchestra.run import CommandFailedError import errno import time +import json class TestMisc(CephFSTestCase): @@ -130,3 +131,21 @@ class TestMisc(CephFSTestCase): time.sleep(self.mds_session_autoclose * 1.5) ls_data = self.fs.mds_asok(['session', 'ls']) self.assert_session_count(1, ls_data) + + def test_filtered_df(self): + pool_name = self.fs.get_data_pool_name() + raw_df = self.fs.get_pool_df(pool_name) + raw_avail = float(raw_df["max_avail"]) + out = self.fs.mon_manager.raw_cluster_cmd('osd', 'pool', 'get', + pool_name, 'size', + '-f', 'json-pretty') + j = json.loads(out) + pool_size = int(j['size']) + + proc = self.mount_a.run_shell(['df', '.']) + output = proc.stdout.getvalue() + fs_avail = output.split('\n')[1].split()[3] + fs_avail = float(fs_avail) * 1024 + + ratio = (raw_avail / pool_size) / fs_avail + assert 0.9 < ratio < 1.1 diff --git a/ceph/qa/tasks/cephfs/test_volume_client.py b/ceph/qa/tasks/cephfs/test_volume_client.py index 3c639bbfc..65dc9a9eb 100644 --- a/ceph/qa/tasks/cephfs/test_volume_client.py +++ b/ceph/qa/tasks/cephfs/test_volume_client.py @@ -230,13 +230,16 @@ vc.disconnect() # Write something outside volume to check this space usage is # not reported in the volume's DF. - other_bin_mb = 6 + other_bin_mb = 8 self.mount_a.write_n_mb("other.bin", other_bin_mb) # global: df should see all the writes (data + other). This is a > # rather than a == because the global spaced used includes all pools - self.assertGreater(self.mount_a.df()['used'], - (data_bin_mb + other_bin_mb) * 1024 * 1024) + def check_df(): + used = self.mount_a.df()['used'] + return used >= (other_bin_mb * 1024 * 1024) + + self.wait_until_true(check_df, timeout=30) # Hack: do a metadata IO to kick rstats self.mounts[2].run_shell(["touch", "foo"]) diff --git a/ceph/qa/tasks/s3tests.py b/ceph/qa/tasks/s3tests.py index ee16381d1..ef5680d01 100644 --- a/ceph/qa/tasks/s3tests.py +++ b/ceph/qa/tasks/s3tests.py @@ -228,7 +228,7 @@ def run_tests(ctx, config): """ assert isinstance(config, dict) testdir = teuthology.get_testdir(ctx) - attrs = ["!fails_on_rgw"] + attrs = ["!fails_on_rgw", "!lifecycle"] for client, client_config in config.iteritems(): args = [ 'S3TEST_CONF={tdir}/archive/s3-tests.{client}.conf'.format(tdir=testdir, client=client), diff --git a/ceph/qa/tasks/thrashosds-health.yaml b/ceph/qa/tasks/thrashosds-health.yaml index 7113e5948..3c9c4d226 100644 --- a/ceph/qa/tasks/thrashosds-health.yaml +++ b/ceph/qa/tasks/thrashosds-health.yaml @@ -2,12 +2,12 @@ overrides: ceph: log-whitelist: - overall HEALTH_ - - (OSDMAP_FLAGS) - - (OSD_ - - (PG_ - - (POOL_ - - (CACHE_POOL_ - - (SMALLER_PGP_NUM) - - (OBJECT_ - - (REQUEST_SLOW) - - (TOO_FEW_PGS) + - \(OSDMAP_FLAGS\) + - \(OSD_ + - \(PG_ + - \(POOL_ + - \(CACHE_POOL_ + - \(SMALLER_PGP_NUM\) + - \(OBJECT_ + - \(REQUEST_SLOW\) + - \(TOO_FEW_PGS\) diff --git a/ceph/qa/workunits/ceph-disk/ceph-disk.sh b/ceph/qa/workunits/ceph-disk/ceph-disk.sh index bbb93f078..7a795b925 100755 --- a/ceph/qa/workunits/ceph-disk/ceph-disk.sh +++ b/ceph/qa/workunits/ceph-disk/ceph-disk.sh @@ -1,8 +1,8 @@ #!/bin/bash -if [ -f $(dirname $0)/../../standalone/ceph-helpers-root.sh ]; then - source $(dirname $0)/../../standalone/ceph-helpers-root.sh +if [ -f $(dirname $0)/../ceph-helpers-root.sh ]; then + source $(dirname $0)/../ceph-helpers-root.sh else - echo "$(dirname $0)/../../standalone/ceph-helpers-root.sh does not exist." + echo "$(dirname $0)/../ceph-helpers-root.sh does not exist." exit 1 fi diff --git a/ceph/qa/workunits/cephtool/test.sh b/ceph/qa/workunits/cephtool/test.sh index 9d8482df6..7c43ada28 100755 --- a/ceph/qa/workunits/cephtool/test.sh +++ b/ceph/qa/workunits/cephtool/test.sh @@ -1327,9 +1327,10 @@ function test_mon_osd_create_destroy() expect_false ceph auth get-key client.osd-lockbox.$uuid3 expect_false ceph config-key exists dm-crypt/osd/$uuid3/luks ceph osd purge osd.$id3 --yes-i-really-mean-it - ceph osd purge osd.$id3 --yes-i-really-mean-it + ceph osd purge osd.$id3 --yes-i-really-mean-it # idempotent ceph osd purge osd.$id --yes-i-really-mean-it + ceph osd purge 123456 --yes-i-really-mean-it expect_false ceph osd find $id expect_false ceph auth get-key osd.$id expect_false ceph auth get-key client.osd-lockbox.$uuid diff --git a/ceph/qa/workunits/mon/crush_ops.sh b/ceph/qa/workunits/mon/crush_ops.sh index 5e6f69611..a9f1512c5 100755 --- a/ceph/qa/workunits/mon/crush_ops.sh +++ b/ceph/qa/workunits/mon/crush_ops.sh @@ -21,6 +21,7 @@ ceph osd crush rule create-simple bar default host # make sure we're at luminous+ before using crush device classes ceph osd require-osd-release luminous +ceph osd crush rm-device-class all ceph osd crush set-device-class ssd osd.0 ceph osd crush set-device-class hdd osd.1 ceph osd crush rule create-replicated foo-ssd default host ssd diff --git a/ceph/qa/workunits/mon/rbd_snaps_ops.sh b/ceph/qa/workunits/mon/rbd_snaps_ops.sh index 3ff7e7603..2bff335c6 100755 --- a/ceph/qa/workunits/mon/rbd_snaps_ops.sh +++ b/ceph/qa/workunits/mon/rbd_snaps_ops.sh @@ -20,10 +20,10 @@ expect() ceph osd pool delete test test --yes-i-really-really-mean-it || true expect 'ceph osd pool create test 256 256' 0 +expect 'rbd --pool=test pool init' 0 expect 'ceph osd pool mksnap test snapshot' 0 expect 'ceph osd pool rmsnap test snapshot' 0 -expect 'rbd --pool=test pool init' 0 expect 'rbd --pool=test --rbd_validate_pool=false create --size=102400 image' 0 expect 'rbd --pool=test snap create image@snapshot' 22 @@ -45,11 +45,13 @@ expect 'ceph osd pool delete test test --yes-i-really-really-mean-it' 0 ceph osd pool delete test-foo test-foo --yes-i-really-really-mean-it || true expect 'rados mkpool test-foo' 0 +expect 'rbd pool init test-foo' expect 'rbd --pool test-foo create --size 1024 image' 0 expect 'rbd --pool test-foo snap create image@snapshot' 0 ceph osd pool delete test-bar test-bar --yes-i-really-really-mean-it || true expect 'rados mkpool test-bar' 0 +expect 'rbd pool init test-bar' expect 'rados cppool test-foo test-bar --yes-i-really-mean-it' 0 expect 'rbd --pool test-bar snap rm image@snapshot' 95 expect 'ceph osd pool delete test-foo test-foo --yes-i-really-really-mean-it' 0 diff --git a/ceph/qa/workunits/rbd/cli_generic.sh b/ceph/qa/workunits/rbd/cli_generic.sh index 1c839d234..f95852084 100755 --- a/ceph/qa/workunits/rbd/cli_generic.sh +++ b/ceph/qa/workunits/rbd/cli_generic.sh @@ -123,6 +123,7 @@ test_rename() { rbd rename bar2 foo2 2>&1 | grep exists rados mkpool rbd2 + rbd pool init rbd2 rbd create -p rbd2 -s 1 foo rbd rename rbd2/foo rbd2/bar rbd -p rbd2 ls | grep bar @@ -359,6 +360,7 @@ test_clone() { rbd snap protect test1@s1 rados mkpool rbd2 + rbd pool init rbd2 rbd clone test1@s1 rbd2/clone rbd -p rbd2 ls | grep clone rbd -p rbd2 ls -l | grep clone | grep test1@s1 diff --git a/ceph/qa/workunits/rbd/issue-20295.sh b/ceph/qa/workunits/rbd/issue-20295.sh new file mode 100755 index 000000000..3d617a066 --- /dev/null +++ b/ceph/qa/workunits/rbd/issue-20295.sh @@ -0,0 +1,18 @@ +#!/bin/sh -ex + +TEST_POOL=ecpool +TEST_IMAGE=test1 +PGS=12 + +ceph osd pool create $TEST_POOL $PGS $PGS erasure +ceph osd pool application enable $TEST_POOL rbd +ceph osd pool set $TEST_POOL allow_ec_overwrites true +rbd --data-pool $TEST_POOL create --size 1024G $TEST_IMAGE +rbd bench \ + --io-type write \ + --io-size 4096 \ + --io-pattern=rand \ + --io-total 100M \ + $TEST_IMAGE + +echo "OK" diff --git a/ceph/qa/workunits/rbd/rbd-ggate.sh b/ceph/qa/workunits/rbd/rbd-ggate.sh new file mode 100755 index 000000000..536070a2f --- /dev/null +++ b/ceph/qa/workunits/rbd/rbd-ggate.sh @@ -0,0 +1,182 @@ +#!/bin/sh -ex + +POOL=testrbdggate$$ +IMAGE=test +SIZE=64 +DATA= +DEV= + +if which xmlstarlet > /dev/null 2>&1; then + XMLSTARLET=xmlstarlet +elif which xml > /dev/null 2>&1; then + XMLSTARLET=xml +else + echo "Missing xmlstarlet binary!" + exit 1 +fi + +_sudo() +{ + local cmd + + if [ `id -u` -eq 0 ] + then + "$@" + return $? + fi + + # Look for the command in the user path. If it fails run it as is, + # supposing it is in sudo path. + cmd=`which $1 2>/dev/null` || cmd=$1 + shift + sudo -nE "${cmd}" "$@" +} + +setup() +{ + if [ -e CMakeCache.txt ]; then + # running under cmake build dir + + CEPH_SRC=$(readlink -f $(dirname $0)/../../../src) + CEPH_ROOT=${PWD} + CEPH_BIN=${CEPH_ROOT}/bin + + export LD_LIBRARY_PATH=${CEPH_ROOT}/lib:${LD_LIBRARY_PATH} + export PYTHONPATH=${PYTHONPATH}:${CEPH_SRC}/pybind + for x in ${CEPH_ROOT}/lib/cython_modules/lib* ; do + PYTHONPATH="${PYTHONPATH}:${x}" + done + PATH=${CEPH_BIN}:${PATH} + fi + + _sudo echo test sudo + + trap cleanup INT TERM EXIT + TEMPDIR=`mktemp -d` + DATA=${TEMPDIR}/data + dd if=/dev/urandom of=${DATA} bs=1M count=${SIZE} + ceph osd pool create ${POOL} 64 64 + rbd --dest-pool ${POOL} --no-progress import ${DATA} ${IMAGE} +} + +cleanup() +{ + set +e + rm -Rf ${TEMPDIR} + if [ -n "${DEV}" ] + then + _sudo rbd-ggate unmap ${DEV} + fi + ceph osd pool delete ${POOL} ${POOL} --yes-i-really-really-mean-it +} + +expect_false() +{ + if "$@"; then return 1; else return 0; fi +} + +# +# main +# + +setup + +# exit status test +expect_false rbd-ggate +expect_false rbd-ggate INVALIDCMD +if [ `id -u` -ne 0 ] +then + expect_false rbd-ggate map ${IMAGE} +fi +expect_false _sudo rbd-ggate map INVALIDIMAGE + +# map test using the first unused device +DEV=`_sudo rbd-ggate map ${POOL}/${IMAGE}` +_sudo rbd-ggate list | grep "^${DEV}$" + +# map test specifying the device +expect_false _sudo rbd-ggate --device ${DEV} map ${POOL}/${IMAGE} +dev1=${DEV} +_sudo rbd-ggate unmap ${DEV} +_sudo rbd-ggate list | expect_false grep "^${DEV}$" +DEV= +# XXX: race possible when the device is reused by other process +DEV=`_sudo rbd-ggate --device ${dev1} map ${POOL}/${IMAGE}` +[ "${DEV}" = "${dev1}" ] +_sudo rbd-ggate list | grep "^${DEV}$" + +# read test +[ "`dd if=${DATA} bs=1M | md5`" = "`_sudo dd if=${DEV} bs=1M | md5`" ] + +# write test +dd if=/dev/urandom of=${DATA} bs=1M count=${SIZE} +_sudo dd if=${DATA} of=${DEV} bs=1M +_sudo sync +[ "`dd if=${DATA} bs=1M | md5`" = "`rbd -p ${POOL} --no-progress export ${IMAGE} - | md5`" ] + +# trim test +provisioned=`rbd -p ${POOL} --format xml du ${IMAGE} | + $XMLSTARLET sel -t -m "//stats/images/image/provisioned_size" -v .` +used=`rbd -p ${POOL} --format xml du ${IMAGE} | + $XMLSTARLET sel -t -m "//stats/images/image/used_size" -v .` +[ "${used}" -eq "${provisioned}" ] +_sudo newfs -E ${DEV} +_sudo sync +provisioned=`rbd -p ${POOL} --format xml du ${IMAGE} | + $XMLSTARLET sel -t -m "//stats/images/image/provisioned_size" -v .` +used=`rbd -p ${POOL} --format xml du ${IMAGE} | + $XMLSTARLET sel -t -m "//stats/images/image/used_size" -v .` +[ "${used}" -lt "${provisioned}" ] + +# resize test +devname=$(basename ${DEV}) +size=$(geom gate list ${devname} | awk '$1 ~ /Mediasize:/ {print $2}') +test -n "${size}" +rbd resize ${POOL}/${IMAGE} --size $((SIZE * 2))M +rbd info ${POOL}/${IMAGE} +if [ -z "$RBD_GGATE_RESIZE_SUPPORTED" ]; then + # XXX: ggate device resize is not supported by vanila kernel. + # rbd-ggate should terminate when detecting resize. + _sudo rbd-ggate list | expect_false grep "^${DEV}$" +else + _sudo rbd-ggate list | grep "^${DEV}$" + size2=$(geom gate list ${devname} | awk '$1 ~ /Mediasize:/ {print $2}') + test -n "${size2}" + test ${size2} -eq $((size * 2)) + dd if=/dev/urandom of=${DATA} bs=1M count=$((SIZE * 2)) + _sudo dd if=${DATA} of=${DEV} bs=1M + _sudo sync + [ "`dd if=${DATA} bs=1M | md5`" = "`rbd -p ${POOL} --no-progress export ${IMAGE} - | md5`" ] + rbd resize ${POOL}/${IMAGE} --allow-shrink --size ${SIZE}M + rbd info ${POOL}/${IMAGE} + size2=$(geom gate list ${devname} | awk '$1 ~ /Mediasize:/ {print $2}') + test -n "${size2}" + test ${size2} -eq ${size} + truncate -s ${SIZE}M ${DATA} + [ "`dd if=${DATA} bs=1M | md5`" = "`rbd -p ${POOL} --no-progress export ${IMAGE} - | md5`" ] + _sudo rbd-ggate unmap ${DEV} +fi +DEV= + +# read-only option test +DEV=`_sudo rbd-ggate map --read-only ${POOL}/${IMAGE}` +devname=$(basename ${DEV}) +_sudo rbd-ggate list | grep "^${DEV}$" +access=$(geom gate list ${devname} | awk '$1 == "access:" {print $2}') +test "${access}" = "read-only" +_sudo dd if=${DEV} of=/dev/null bs=1M +expect_false _sudo dd if=${DATA} of=${DEV} bs=1M +_sudo rbd-ggate unmap ${DEV} + +# exclusive option test +DEV=`_sudo rbd-ggate map --exclusive ${POOL}/${IMAGE}` +_sudo rbd-ggate list | grep "^${DEV}$" +_sudo dd if=${DATA} of=${DEV} bs=1M +_sudo sync +expect_false timeout 10 \ + rbd -p ${POOL} bench ${IMAGE} --io-type=write --io-size=1024 --io-total=1024 +_sudo rbd-ggate unmap ${DEV} +DEV= +rbd bench -p ${POOL} ${IMAGE} --io-type=write --io-size=1024 --io-total=1024 + +echo OK diff --git a/ceph/qa/workunits/rbd/rbd_mirror.sh b/ceph/qa/workunits/rbd/rbd_mirror.sh index 7d59200c1..021cbaf03 100755 --- a/ceph/qa/workunits/rbd/rbd_mirror.sh +++ b/ceph/qa/workunits/rbd/rbd_mirror.sh @@ -286,6 +286,7 @@ wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} testlog "TEST: simple image resync" request_resync_image ${CLUSTER1} ${POOL} ${image} image_id wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id} +wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present' wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+replaying' 'master_position' compare_images ${POOL} ${image} @@ -297,6 +298,7 @@ request_resync_image ${CLUSTER1} ${POOL} ${image} image_id admin_daemon ${CLUSTER1} rbd mirror start ${POOL}/${image} wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id} admin_daemon ${CLUSTER1} rbd mirror start ${POOL}/${image} +wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present' wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+replaying' 'master_position' compare_images ${POOL} ${image} @@ -306,6 +308,7 @@ stop_mirror ${CLUSTER1} request_resync_image ${CLUSTER1} ${POOL} ${image} image_id start_mirror ${CLUSTER1} wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id} +wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present' wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+replaying' 'master_position' compare_images ${POOL} ${image} @@ -327,6 +330,7 @@ wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+error' 'disconnecte testlog " - replay started after resync requested" request_resync_image ${CLUSTER1} ${POOL} ${image} image_id wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id} +wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present' wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image} test -n "$(get_mirror_position ${CLUSTER2} ${POOL} ${image})" @@ -352,6 +356,7 @@ wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+error' 'disconnecte testlog " - replay started after resync requested" request_resync_image ${CLUSTER1} ${POOL} ${image} image_id wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id} +wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present' wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image} test -n "$(get_mirror_position ${CLUSTER2} ${POOL} ${image})" @@ -361,8 +366,10 @@ testlog " - rbd_mirroring_resync_after_disconnect config option" set_image_meta ${CLUSTER2} ${POOL} ${image} \ conf_rbd_mirroring_resync_after_disconnect true wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image} +image_id=$(get_image_id ${CLUSTER1} ${pool} ${image}) disconnect_image ${CLUSTER2} ${POOL} ${image} -wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' +wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id} +wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present' wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image} wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image} test -n "$(get_mirror_position ${CLUSTER2} ${POOL} ${image})" diff --git a/ceph/qa/workunits/rbd/rbd_mirror_helpers.sh b/ceph/qa/workunits/rbd/rbd_mirror_helpers.sh index b3cf017f6..f825bec85 100755 --- a/ceph/qa/workunits/rbd/rbd_mirror_helpers.sh +++ b/ceph/qa/workunits/rbd/rbd_mirror_helpers.sh @@ -217,6 +217,11 @@ setup() CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd pool create ${PARENT_POOL} 64 64 CEPH_ARGS='' ceph --cluster ${CLUSTER2} osd pool create ${POOL} 64 64 + CEPH_ARGS='' rbd --cluster ${CLUSTER1} pool init ${POOL} + CEPH_ARGS='' rbd --cluster ${CLUSTER2} pool init ${POOL} + CEPH_ARGS='' rbd --cluster ${CLUSTER1} pool init ${PARENT_POOL} + CEPH_ARGS='' rbd --cluster ${CLUSTER2} pool init ${PARENT_POOL} + rbd --cluster ${CLUSTER1} mirror pool enable ${POOL} pool rbd --cluster ${CLUSTER2} mirror pool enable ${POOL} pool rbd --cluster ${CLUSTER1} mirror pool enable ${PARENT_POOL} image diff --git a/ceph/qa/workunits/rbd/test_admin_socket.sh b/ceph/qa/workunits/rbd/test_admin_socket.sh index 9135c2ece..a7ecd839c 100755 --- a/ceph/qa/workunits/rbd/test_admin_socket.sh +++ b/ceph/qa/workunits/rbd/test_admin_socket.sh @@ -62,15 +62,17 @@ function rbd_check_perfcounter() function rbd_watch_start() { local image=$1 + local asok=$(rbd_watch_asok ${image}) mkfifo $(rbd_watch_fifo ${image}) (cat $(rbd_watch_fifo ${image}) | - rbd watch ${image} > $(rbd_watch_out_file ${image}) 2>&1)& + rbd --admin-socket ${asok} watch ${image} \ + > $(rbd_watch_out_file ${image}) 2>&1)& # find pid of the started rbd watch process local pid for i in `seq 10`; do - pid=$(ps auxww | awk "/[r]bd watch ${image}/ {print \$2}") + pid=$(ps auxww | awk "/[r]bd --admin.* watch ${image}/ {print \$2}") test -n "${pid}" && break sleep 0.1 done @@ -78,14 +80,12 @@ function rbd_watch_start() echo ${pid} > $(rbd_watch_pid_file ${image}) # find watcher admin socket - local asok=$(ceph-conf admin_socket | sed -E "s/[0-9]+/${pid}/") test -n "${asok}" for i in `seq 10`; do test -S "${asok}" && break sleep 0.1 done test -S "${asok}" - ln -s "${asok}" $(rbd_watch_asok ${image}) # configure debug level ceph --admin-daemon "${asok}" config set debug_rbd 20 diff --git a/ceph/run-make-check.sh b/ceph/run-make-check.sh index b23672c4f..aa8f8ed28 100755 --- a/ceph/run-make-check.sh +++ b/ceph/run-make-check.sh @@ -71,6 +71,8 @@ function run() { $DRY_RUN ./do_cmake.sh $@ || return 1 $DRY_RUN cd build $DRY_RUN make $BUILD_MAKEOPTS tests || return 1 + # prevent OSD EMFILE death on tests + $DRY_RUN sudo ulimit -n 32768 if ! $DRY_RUN ctest $CHECK_MAKEOPTS --output-on-failure; then rm -f ${TMPDIR:-/tmp}/ceph-asok.* return 1 diff --git a/ceph/src/.git_version b/ceph/src/.git_version index 6c097ab5b..5d44bb535 100644 --- a/ceph/src/.git_version +++ b/ceph/src/.git_version @@ -1,2 +1,2 @@ -b661348f156f148d764b998b65b90451f096cb27 -v12.1.2 +c56d9c07b342c08419bbc18dcf2a4c5fae62b9cf +v12.1.3 diff --git a/ceph/src/CMakeLists.txt b/ceph/src/CMakeLists.txt index 5060b41bc..915e10aa6 100644 --- a/ceph/src/CMakeLists.txt +++ b/ceph/src/CMakeLists.txt @@ -56,7 +56,7 @@ endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU) set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}") if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Default BUILD_TYPE is RelWithDebInfo, other options are: Debug, Release, and MinSizeRel." FORCE) + set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Default BUILD_TYPE is RelWithDebInfo, other options are: Debug, Release, and MinSizeRel." FORCE) endif() if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) @@ -722,6 +722,7 @@ endif() add_subdirectory(pybind) add_subdirectory(ceph-disk) +add_subdirectory(ceph-volume) add_subdirectory(ceph-detect-init) ## dencoder diff --git a/ceph/src/ceph-create-keys b/ceph/src/ceph-create-keys index 75005f587..c14c02f28 100755 --- a/ceph/src/ceph-create-keys +++ b/ceph/src/ceph-create-keys @@ -305,7 +305,11 @@ def main(): type_='mds', wait_count=args.timeout, ) - + bootstrap_key( + cluster=args.cluster, + type_='rbd', + wait_count=args.timeout, + ) if __name__ == '__main__': main() diff --git a/ceph/src/ceph-disk/ceph_disk/main.py b/ceph/src/ceph-disk/ceph_disk/main.py index 5ae5840b6..8b0c5dbc3 100755 --- a/ceph/src/ceph-disk/ceph_disk/main.py +++ b/ceph/src/ceph-disk/ceph_disk/main.py @@ -1279,11 +1279,14 @@ def get_dmcrypt_key( osd_uuid = get_oneliner(path, 'osd-uuid') ceph_fsid = read_one_line(path, 'ceph_fsid') if ceph_fsid is None: - raise Error('No cluster uuid assigned.') - cluster = find_cluster_by_uuid(ceph_fsid) - if cluster is None: - raise Error('No cluster conf found in ' + SYSCONFDIR + - ' with fsid %s' % ceph_fsid) + LOG.warning("no `ceph_fsid` found falling back to 'ceph' " + "for cluster name") + cluster = 'ceph' + else: + cluster = find_cluster_by_uuid(ceph_fsid) + if cluster is None: + raise Error('No cluster conf found in ' + SYSCONFDIR + + ' with fsid %s' % ceph_fsid) if mode == KEY_MANAGEMENT_MODE_V1: key, stderr, ret = command( @@ -1450,6 +1453,7 @@ def mount( def unmount( path, + do_rm=True, ): """ Unmount and removes the given mount point. @@ -1473,7 +1477,8 @@ def unmount( else: time.sleep(0.5 + retries * 1.0) retries += 1 - + if not do_rm: + return os.rmdir(path) @@ -3942,7 +3947,7 @@ def main_deactivate_locked(args): with open(os.path.join(mounted_path, 'deactive'), 'w'): path_set_context(os.path.join(mounted_path, 'deactive')) - unmount(mounted_path) + unmount(mounted_path, do_rm=not args.once) LOG.info("Umount `%s` successfully.", mounted_path) if dmcrypt: diff --git a/ceph/src/ceph-disk/tests/test_main.py b/ceph/src/ceph-disk/tests/test_main.py index ef6d7d445..57e4af23b 100644 --- a/ceph/src/ceph-disk/tests/test_main.py +++ b/ceph/src/ceph-disk/tests/test_main.py @@ -812,7 +812,7 @@ class TestCephDiskDeactivateAndDestroy(unittest.TestCase): stop_daemon=lambda cluster, osd_id: True, _remove_osd_directory_files=lambda path, cluster: True, path_set_context=lambda path: True, - unmount=lambda path: True, + unmount=lambda path, do_rm: True, dmcrypt_unmap=lambda part_uuid: True, ): main.main_deactivate(args) @@ -846,7 +846,7 @@ class TestCephDiskDeactivateAndDestroy(unittest.TestCase): stop_daemon=lambda cluster, osd_id: True, _remove_osd_directory_files=lambda path, cluster: True, path_set_context=lambda path: True, - unmount=lambda path: True, + unmount=lambda path, do_rm: True, dmcrypt_unmap=lambda part_uuid: True, ): main.main_deactivate(args) diff --git a/ceph/src/ceph-volume/CMakeLists.txt b/ceph/src/ceph-volume/CMakeLists.txt new file mode 100644 index 000000000..20841ff2e --- /dev/null +++ b/ceph/src/ceph-volume/CMakeLists.txt @@ -0,0 +1,4 @@ + +include(Distutils) +distutils_install_module(ceph_volume + INSTALL_SCRIPT ${CMAKE_INSTALL_FULL_SBINDIR}) diff --git a/ceph/src/ceph-volume/MANIFEST.in b/ceph/src/ceph-volume/MANIFEST.in new file mode 100644 index 000000000..5b4a149c7 --- /dev/null +++ b/ceph/src/ceph-volume/MANIFEST.in @@ -0,0 +1,2 @@ +include bin/ceph-volume +include tox.ini diff --git a/ceph/src/ceph-volume/bin/ceph-volume b/ceph/src/ceph-volume/bin/ceph-volume new file mode 100755 index 000000000..5905cfccc --- /dev/null +++ b/ceph/src/ceph-volume/bin/ceph-volume @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +from ceph_volume import main + +if __name__ == '__main__': + main.Volume() diff --git a/ceph/src/ceph-volume/bin/ceph-volume-systemd b/ceph/src/ceph-volume/bin/ceph-volume-systemd new file mode 100755 index 000000000..7da8ec6b1 --- /dev/null +++ b/ceph/src/ceph-volume/bin/ceph-volume-systemd @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +from ceph_volume.systemd import main + +if __name__ == '__main__': + main.main() diff --git a/ceph/src/ceph-volume/ceph_volume/__init__.py b/ceph/src/ceph-volume/ceph_volume/__init__.py new file mode 100644 index 000000000..f5500015c --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/__init__.py @@ -0,0 +1,5 @@ +from collections import namedtuple + +conf = namedtuple('config', ['ceph', 'cluster', 'verbosity', 'path', 'log_path']) + +__version__ = "1.0.0" diff --git a/ceph/src/ceph-volume/ceph_volume/configuration.py b/ceph/src/ceph-volume/ceph_volume/configuration.py new file mode 100644 index 000000000..eda58f09b --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/configuration.py @@ -0,0 +1,99 @@ +try: + import configparser +except ImportError: + import ConfigParser as configparser +import logging +import os +import re +from ceph_volume import terminal +from ceph_volume import exceptions + + +logger = logging.getLogger(__name__) + + +class _TrimIndentFile(object): + """ + This is used to take a file-like object and removes any + leading tabs from each line when it's read. This is important + because some ceph configuration files include tabs which break + ConfigParser. + """ + def __init__(self, fp): + self.fp = fp + + def readline(self): + line = self.fp.readline() + return line.lstrip(' \t') + + def __iter__(self): + return iter(self.readline, '') + + +def load(abspath=None): + parser = Conf() + try: + parser.read_path(abspath) + return parser + except configparser.ParsingError as error: + terminal.error('Unable to read configuration file: %s' % abspath) + terminal.error(str(error)) + logger.exception('Unable to parse INI-style file: %s' % abspath) + + +class Conf(configparser.SafeConfigParser): + """ + Subclasses from SafeConfigParser to give a few helpers for Ceph + configuration. + """ + + def read_path(self, path): + self.path = path + return self.read(path) + + def is_valid(self): + if not os.path.exists(self.path): + raise exceptions.ConfigurationError(abspath=self.path) + + try: + self.get('global', 'fsid') + except (configparser.NoSectionError, configparser.NoOptionError): + raise exceptions.ConfigurationKeyError('global', 'fsid') + + def get_safe(self, section, key, default=None): + """ + Attempt to get a configuration value from a certain section + in a ``cfg`` object but returning None if not found. Avoids the need + to be doing try/except {ConfigParser Exceptions} every time. + """ + self.is_valid() + try: + return self.get(section, key) + except (configparser.NoSectionError, configparser.NoOptionError): + return default + + def get_list(self, section, key, default=None, split=','): + """ + Assumes that the value for a given key is going to be a list separated + by commas. It gets rid of trailing comments. If just one item is + present it returns a list with a single item, if no key is found an + empty list is returned. + + Optionally split on other characters besides ',' and return a fallback + value if no items are found. + """ + self.is_valid() + value = self.get_safe(section, key, []) + if value == []: + if default is not None: + return default + return value + + # strip comments + value = re.split(r'\s+#', value)[0] + + # split on commas + value = value.split(split) + + # strip spaces + return [x.strip() for x in value] diff --git a/ceph/src/ceph-volume/ceph_volume/decorators.py b/ceph/src/ceph-volume/ceph_volume/decorators.py new file mode 100644 index 000000000..c1e14bc79 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/decorators.py @@ -0,0 +1,87 @@ +import os +import sys +from ceph_volume import terminal, exceptions +from functools import wraps + + +def needs_root(func): + """ + Check for super user privileges on functions/methods. Raise + ``SuperUserError`` with a nice message. + """ + @wraps(func) + def is_root(*a, **kw): + if not os.getuid() == 0: + raise exceptions.SuperUserError() + return func(*a, **kw) + return is_root + + +def catches(catch=None, handler=None, exit=True): + """ + Very simple decorator that tries any of the exception(s) passed in as + a single exception class or tuple (containing multiple ones) returning the + exception message and optionally handling the problem if it rises with the + handler if it is provided. + + So instead of douing something like this:: + + def bar(): + try: + some_call() + print "Success!" + except TypeError, exc: + print "Error while handling some call: %s" % exc + sys.exit(1) + + You would need to decorate it like this to have the same effect:: + + @catches(TypeError) + def bar(): + some_call() + print "Success!" + + If multiple exceptions need to be catched they need to be provided as a + tuple:: + + @catches((TypeError, AttributeError)) + def bar(): + some_call() + print "Success!" + """ + catch = catch or Exception + + def decorate(f): + + @wraps(f) + def newfunc(*a, **kw): + try: + return f(*a, **kw) + except catch as e: + if os.environ.get('CEPH_VOLUME_DEBUG'): + raise + if handler: + return handler(e) + else: + sys.stderr.write(make_exception_message(e)) + if exit: + sys.exit(1) + return newfunc + + return decorate + +# +# Decorator helpers +# + + +def make_exception_message(exc): + """ + An exception is passed in and this function + returns the proper string depending on the result + so it is readable enough. + """ + if str(exc): + return '%s %s: %s\n' % (terminal.red_arrow, exc.__class__.__name__, exc) + else: + return '%s %s\n' % (terminal.red_arrow, exc.__class__.__name__) diff --git a/ceph/src/ceph-volume/ceph_volume/devices/__init__.py b/ceph/src/ceph-volume/ceph_volume/devices/__init__.py new file mode 100644 index 000000000..c77c344d6 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/__init__.py @@ -0,0 +1 @@ +from . import lvm # noqa diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/__init__.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/__init__.py new file mode 100644 index 000000000..3c147123e --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/__init__.py @@ -0,0 +1 @@ +from .main import LVM # noqa diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py new file mode 100644 index 000000000..7787aabd1 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py @@ -0,0 +1,114 @@ +from __future__ import print_function +import argparse +import os +from textwrap import dedent +from ceph_volume import process, conf, decorators +from ceph_volume.util import system +from ceph_volume.systemd import systemctl +from . import api + + +def activate_filestore(lvs): + # find the osd + osd_lv = lvs.get(lv_tags={'ceph.type': 'data'}) + osd_id = osd_lv.tags['ceph.osd_id'] + # it may have a volume with a journal + osd_journal_lv = lvs.get(lv_tags={'ceph.type': 'journal'}) + # TODO: add sensible error reporting if this is ever the case + # blow up with a KeyError if this doesn't exist + osd_fsid = osd_lv.tags['ceph.osd_fsid'] + if not osd_journal_lv: + osd_journal = osd_lv.tags.get('ceph.journal_device') + else: + osd_journal = osd_journal.lv_path + + if not osd_journal: + raise RuntimeError('unable to detect an lv or device journal for OSD %s' % osd_id) + + # mount the osd + source = osd_lv.lv_path + destination = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id) + if not system.is_mounted(source, destination=destination): + process.run(['sudo', 'mount', '-v', source, destination]) + + # ensure that the symlink for the journal is there + if not os.path.exists(osd_journal): + source = osd_journal + destination = '/var/lib/ceph/osd/%s-%s/journal' % (conf.cluster, osd_id) + process.run(['sudo', 'ln', '-s', source, destination]) + + # make sure that the journal has proper permissions + system.chown(osd_journal) + + # enable the ceph-volume unit for this OSD + systemctl.enable_volume(osd_id, osd_fsid, 'lvm') + + # start the OSD + systemctl.start_osd(osd_id) + + +def activate_bluestore(lvs): + # TODO + pass + + +class Activate(object): + + help = 'Discover and mount the LVM device associated with an OSD ID and start the Ceph OSD' + + def __init__(self, argv): + self.argv = argv + + @decorators.needs_root + def activate(self, args): + lvs = api.Volumes() + # filter them down for the OSD ID and FSID we need to activate + lvs.filter(lv_tags={'ceph.osd_id': args.osd_id, 'ceph.osd_fsid': args.osd_fsid}) + if not lvs: + raise RuntimeError('could not find osd.%s with fsid %s' % (args.osd_id, args.osd_fsid)) + activate_filestore(lvs) + + def main(self): + sub_command_help = dedent(""" + Activate OSDs by discovering them with LVM and mounting them in their + appropriate destination: + + ceph-volume lvm activate {ID} {FSID} + + The lvs associated with the OSD need to have been prepared previously, + so that all needed tags and metadata exist. + + """) + parser = argparse.ArgumentParser( + prog='ceph-volume lvm activate', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=sub_command_help, + ) + + parser.add_argument( + 'osd_id', + metavar='ID', + nargs='?', + help='The ID of the OSD, usually an integer, like 0' + ) + parser.add_argument( + 'osd_fsid', + metavar='FSID', + nargs='?', + help='The FSID of the OSD, similar to a SHA1' + ) + parser.add_argument( + '--bluestore', + action='store_true', default=False, + help='filestore objectstore (not yet implemented)', + ) + parser.add_argument( + '--filestore', + action='store_true', default=True, + help='filestore objectstore (current default)', + ) + if len(self.argv) == 0: + print(sub_command_help) + return + args = parser.parse_args(self.argv) + self.activate(args) diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/api.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/api.py new file mode 100644 index 000000000..8ff2faf4d --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/api.py @@ -0,0 +1,484 @@ +""" +API for CRUD lvm tag operations. Follows the Ceph LVM tag naming convention +that prefixes tags with ``ceph.`` and uses ``=`` for assignment, and provides +set of utilities for interacting with LVM. +""" +import json +from ceph_volume import process +from ceph_volume.exceptions import MultipleLVsError, MultipleVGsError + + +def parse_tags(lv_tags): + """ + Return a dictionary mapping of all the tags associated with + a Volume from the comma-separated tags coming from the LVM API + + Input look like:: + + "ceph.osd_fsid=aaa-fff-bbbb,ceph.osd_id=0" + + For the above example, the expected return value would be:: + + { + "ceph.osd_fsid": "aaa-fff-bbbb", + "ceph.osd_id": "0" + } + """ + if not lv_tags: + return {} + tag_mapping = {} + tags = lv_tags.split(',') + for tag_assignment in tags: + key, value = tag_assignment.split('=', 1) + tag_mapping[key] = value + + return tag_mapping + + +def get_api_vgs(): + """ + Return the list of group volumes available in the system using flags to include common + metadata associated with them + + Command and sample JSON output, should look like:: + + $ sudo vgs --reportformat=json + { + "report": [ + { + "vg": [ + { + "vg_name":"VolGroup00", + "pv_count":"1", + "lv_count":"2", + "snap_count":"0", + "vg_attr":"wz--n-", + "vg_size":"38.97g", + "vg_free":"0 "}, + { + "vg_name":"osd_vg", + "pv_count":"3", + "lv_count":"1", + "snap_count":"0", + "vg_attr":"wz--n-", + "vg_size":"32.21g", + "vg_free":"9.21g" + } + ] + } + ] + } + + """ + stdout, stderr, returncode = process.call( + [ + 'sudo', 'vgs', '--reportformat=json' + ] + ) + report = json.loads(''.join(stdout)) + for report_item in report.get('report', []): + # is it possible to get more than one item in "report" ? + return report_item['vg'] + return [] + + +def get_api_lvs(): + """ + Return the list of logical volumes available in the system using flags to include common + metadata associated with them + + Command and sample JSON output, should look like:: + + $ sudo lvs -o lv_tags,lv_path,lv_name,vg_name --reportformat=json + { + "report": [ + { + "lv": [ + { + "lv_tags":"", + "lv_path":"/dev/VolGroup00/LogVol00", + "lv_name":"LogVol00", + "vg_name":"VolGroup00"}, + { + "lv_tags":"ceph.osd_fsid=aaa-fff-0000,ceph.osd_fsid=aaa-fff-bbbb,ceph.osd_id=0", + "lv_path":"/dev/osd_vg/OriginLV", + "lv_name":"OriginLV", + "vg_name":"osd_vg" + } + ] + } + ] + } + + """ + stdout, stderr, returncode = process.call( + ['sudo', 'lvs', '-o', 'lv_tags,lv_path,lv_name,vg_name', '--reportformat=json']) + report = json.loads(''.join(stdout)) + for report_item in report.get('report', []): + # is it possible to get more than one item in "report" ? + return report_item['lv'] + return [] + + +def get_lv(lv_name=None, vg_name=None, lv_path=None, lv_tags=None): + """ + Return a matching lv for the current system, requiring ``lv_name``, + ``vg_name``, ``lv_path`` or ``tags``. Raises an error if more than one lv + is found. + + It is useful to use ``tags`` when trying to find a specific logical volume, + but it can also lead to multiple lvs being found, since a lot of metadata + is shared between lvs of a distinct OSD. + """ + if not any([lv_name, vg_name, lv_path, lv_tags]): + return None + lvs = Volumes() + return lvs.get(lv_name=lv_name, vg_name=vg_name, lv_path=lv_path, lv_tags=lv_tags) + + +def create_lv(name, group, size=None, **tags): + """ + Create a Logical Volume in a Volume Group. Command looks like:: + + lvcreate -L 50G -n gfslv vg0 + + ``name``, ``group``, and ``size`` are required. Tags are optional and are "translated" to include + the prefixes for the Ceph LVM tag API. + + """ + # XXX add CEPH_VOLUME_LVM_DEBUG to enable -vvvv on lv operations + type_path_tag = { + 'journal': 'ceph.journal_device', + 'data': 'ceph.data_device', + 'block': 'ceph.block', + 'wal': 'ceph.wal', + 'db': 'ceph.db', + 'lockbox': 'ceph.lockbox_device', + } + if size: + process.run([ + 'sudo', + 'lvcreate', + '--yes', + '-L', + '%sG' % size, + '-n', name, group + ]) + # create the lv with all the space available, this is needed because the + # system call is different for LVM + else: + process.run([ + 'sudo', + 'lvcreate', + '--yes', + '-l', + '100%FREE', + '-n', name, group + ]) + + lv = get_lv(lv_name=name, vg_name=group) + ceph_tags = {} + for k, v in tags.items(): + ceph_tags['ceph.%s' % k] = v + lv.set_tags(ceph_tags) + + # when creating a distinct type, the caller doesn't know what the path will + # be so this function will set it after creation using the mapping + path_tag = type_path_tag[tags['type']] + lv.set_tags( + {path_tag: lv.lv_path} + ) + return lv + + +def get_vg(vg_name=None, vg_tags=None): + """ + Return a matching vg for the current system, requires ``vg_name`` or + ``tags``. Raises an error if more than one vg is found. + + It is useful to use ``tags`` when trying to find a specific volume group, + but it can also lead to multiple vgs being found. + """ + if not any([vg_name, vg_tags]): + return None + vgs = VolumeGroups() + return vgs.get(vg_name=vg_name, vg_tags=vg_tags) + + +class VolumeGroups(list): + """ + A list of all known volume groups for the current system, with the ability + to filter them via keyword arguments. + """ + + def __init__(self): + self._populate() + + def _populate(self): + # get all the vgs in the current system + for vg_item in get_api_vgs(): + self.append(VolumeGroup(**vg_item)) + + def _purge(self): + """ + Deplete all the items in the list, used internally only so that we can + dynamically allocate the items when filtering without the concern of + messing up the contents + """ + self[:] = [] + + def _filter(self, vg_name=None, vg_tags=None): + """ + The actual method that filters using a new list. Useful so that other + methods that do not want to alter the contents of the list (e.g. + ``self.find``) can operate safely. + + .. note:: ``vg_tags`` is not yet implemented + """ + filtered = [i for i in self] + if vg_name: + filtered = [i for i in filtered if i.vg_name == vg_name] + + # at this point, `filtered` has either all the volumes in self or is an + # actual filtered list if any filters were applied + if vg_tags: + tag_filtered = [] + for k, v in vg_tags.items(): + for volume in filtered: + if volume.tags.get(k) == str(v): + if volume not in tag_filtered: + tag_filtered.append(volume) + # return the tag_filtered volumes here, the `filtered` list is no + # longer useable + return tag_filtered + + return filtered + + def filter(self, vg_name=None, vg_tags=None): + """ + Filter out groups on top level attributes like ``vg_name`` or by + ``vg_tags`` where a dict is required. For example, to find a Ceph group + with dmcache as the type, the filter would look like:: + + vg_tags={'ceph.type': 'dmcache'} + + .. warning:: These tags are not documented because they are currently + unused, but are here to maintain API consistency + """ + if not any([vg_name, vg_tags]): + raise TypeError('.filter() requires vg_name or vg_tags (none given)') + # first find the filtered volumes with the values in self + filtered_groups = self._filter( + vg_name=vg_name, + vg_tags=vg_tags + ) + # then purge everything + self._purge() + # and add the filtered items + self.extend(filtered_groups) + + def get(self, vg_name=None, vg_tags=None): + """ + This is a bit expensive, since it will try to filter out all the + matching items in the list, filter them out applying anything that was + added and return the matching item. + + This method does *not* alter the list, and it will raise an error if + multiple VGs are matched + + It is useful to use ``tags`` when trying to find a specific volume group, + but it can also lead to multiple vgs being found (although unlikely) + """ + if not any([vg_name, vg_tags]): + return None + vgs = self._filter( + vg_name=vg_name, + vg_tags=vg_tags + ) + if not vgs: + return None + if len(vgs) > 1: + # this is probably never going to happen, but it is here to keep + # the API code consistent + raise MultipleVGsError(vg_name) + return vgs[0] + + +class Volumes(list): + """ + A list of all known (logical) volumes for the current system, with the ability + to filter them via keyword arguments. + """ + + def __init__(self): + self._populate() + + def _populate(self): + # get all the lvs in the current system + for lv_item in get_api_lvs(): + self.append(Volume(**lv_item)) + + def _purge(self): + """ + Deplete all the items in the list, used internally only so that we can + dynamically allocate the items when filtering without the concern of + messing up the contents + """ + self[:] = [] + + def _filter(self, lv_name=None, vg_name=None, lv_path=None, lv_tags=None): + """ + The actual method that filters using a new list. Useful so that other + methods that do not want to alter the contents of the list (e.g. + ``self.find``) can operate safely. + """ + filtered = [i for i in self] + if lv_name: + filtered = [i for i in filtered if i.lv_name == lv_name] + + if vg_name: + filtered = [i for i in filtered if i.vg_name == vg_name] + + if lv_path: + filtered = [i for i in filtered if i.lv_path == lv_path] + + # at this point, `filtered` has either all the volumes in self or is an + # actual filtered list if any filters were applied + if lv_tags: + tag_filtered = [] + for k, v in lv_tags.items(): + for volume in filtered: + if volume.tags.get(k) == str(v): + if volume not in tag_filtered: + tag_filtered.append(volume) + # return the tag_filtered volumes here, the `filtered` list is no + # longer useable + return tag_filtered + + return filtered + + def filter(self, lv_name=None, vg_name=None, lv_path=None, lv_tags=None): + """ + Filter out volumes on top level attributes like ``lv_name`` or by + ``lv_tags`` where a dict is required. For example, to find a volume + that has an OSD ID of 0, the filter would look like:: + + lv_tags={'ceph.osd_id': '0'} + + """ + if not any([lv_name, vg_name, lv_path, lv_tags]): + raise TypeError('.filter() requires lv_name, vg_name, lv_path, or tags (none given)') + # first find the filtered volumes with the values in self + filtered_volumes = self._filter( + lv_name=lv_name, + vg_name=vg_name, + lv_path=lv_path, + lv_tags=lv_tags + ) + # then purge everything + self._purge() + # and add the filtered items + self.extend(filtered_volumes) + + def get(self, lv_name=None, vg_name=None, lv_path=None, lv_tags=None): + """ + This is a bit expensive, since it will try to filter out all the + matching items in the list, filter them out applying anything that was + added and return the matching item. + + This method does *not* alter the list, and it will raise an error if + multiple LVs are matched + + It is useful to use ``tags`` when trying to find a specific logical volume, + but it can also lead to multiple lvs being found, since a lot of metadata + is shared between lvs of a distinct OSD. + """ + if not any([lv_name, vg_name, lv_path, lv_tags]): + return None + lvs = self._filter( + lv_name=lv_name, + vg_name=vg_name, + lv_path=lv_path, + lv_tags=lv_tags + ) + if not lvs: + return None + if len(lvs) > 1: + raise MultipleLVsError(lv_name, lv_path) + return lvs[0] + + +class VolumeGroup(object): + """ + Represents an LVM group, with some top-level attributes like ``vg_name`` + """ + + def __init__(self, **kw): + for k, v in kw.items(): + setattr(self, k, v) + self.name = kw['vg_name'] + self.tags = parse_tags(kw.get('vg_tags', '')) + + def __str__(self): + return '<%s>' % self.name + + def __repr__(self): + return self.__str__() + + +class Volume(object): + """ + Represents a Logical Volume from LVM, with some top-level attributes like + ``lv_name`` and parsed tags as a dictionary of key/value pairs. + """ + + def __init__(self, **kw): + for k, v in kw.items(): + setattr(self, k, v) + self.lv_api = kw + self.name = kw['lv_name'] + self.tags = parse_tags(kw['lv_tags']) + + def __str__(self): + return '<%s>' % self.lv_api['lv_path'] + + def __repr__(self): + return self.__str__() + + def set_tags(self, tags): + """ + :param tags: A dictionary of tag names and values, like:: + + { + "ceph.osd_fsid": "aaa-fff-bbbb", + "ceph.osd_id": "0" + } + + At the end of all modifications, the tags are refreshed to reflect + LVM's most current view. + """ + for k, v in tags.items(): + self.set_tag(k, v) + # after setting all the tags, refresh them for the current object, use the + # lv_* identifiers to filter because those shouldn't change + lv_object = get_lv(lv_name=self.lv_name, lv_path=self.lv_path) + self.tags = lv_object.tags + + def set_tag(self, key, value): + """ + Set the key/value pair as an LVM tag. Does not "refresh" the values of + the current object for its tags. Meant to be a "fire and forget" type + of modification. + """ + # remove it first if it exists + if self.tags.get(key): + current_value = self.tags[key] + tag = "%s=%s" % (key, current_value) + process.call(['sudo', 'lvchange', '--deltag', tag, self.lv_api['lv_path']]) + + process.call( + [ + 'sudo', 'lvchange', + '--addtag', '%s=%s' % (key, value), self.lv_path + ] + ) diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/common.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/common.py new file mode 100644 index 000000000..599bbe6e0 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/common.py @@ -0,0 +1,55 @@ +import argparse + + +def common_parser(prog, description): + """ + Both prepare and create share the same parser, those are defined here to + avoid duplication + """ + parser = argparse.ArgumentParser( + prog=prog, + formatter_class=argparse.RawDescriptionHelpFormatter, + description=description, + ) + required_args = parser.add_argument_group('required arguments') + parser.add_argument( + '--journal', + help='A logical group name, path to a logical volume, or path to a device', + ) + required_args.add_argument( + '--data', + required=True, + help='A logical group name or a path to a logical volume', + ) + parser.add_argument( + '--journal-size', + default=5, + metavar='GB', + type=int, + help='Size (in GB) A logical group name or a path to a logical volume', + ) + parser.add_argument( + '--bluestore', + action='store_true', default=False, + help='Use the bluestore objectstore (not currently supported)', + ) + parser.add_argument( + '--filestore', + action='store_true', default=True, + help='Use the filestore objectstore (currently the only supported object store)', + ) + parser.add_argument( + '--osd-id', + help='Reuse an existing OSD id', + ) + parser.add_argument( + '--osd-fsid', + help='Reuse an existing OSD fsid', + ) + # Do not parse args, so that consumers can do something before the args get + # parsed triggering argparse behavior + return parser + + +create_parser = common_parser # noqa +prepare_parser = common_parser # noqa diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/create.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/create.py new file mode 100644 index 000000000..1d3f6a3b6 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/create.py @@ -0,0 +1,63 @@ +from __future__ import print_function +from textwrap import dedent +from ceph_volume.util import system +from ceph_volume import decorators +from .common import create_parser +from .prepare import Prepare +from .activate import Activate + + +class Create(object): + + help = 'Create a new OSD from an LVM device' + + def __init__(self, argv): + self.argv = argv + + @decorators.needs_root + def create(self, args): + if not args.osd_fsid: + args.osd_fsid = system.generate_uuid() + Prepare([]).prepare(args) + Activate([]).activate(args) + + def main(self): + sub_command_help = dedent(""" + Create an OSD by assigning an ID and FSID, registering them with the + cluster with an ID and FSID, formatting and mounting the volume, adding + all the metadata to the logical volumes using LVM tags, and starting + the OSD daemon. + + Most basic Usage looks like (journal will be collocated from the same volume group): + + ceph-volume lvm create --data {volume group name} + + + Example calls for supported scenarios: + + Dedicated volume group for Journal(s) + ------------------------------------- + + Existing logical volume (lv) or device: + + ceph-volume lvm create --data {logical volume} --journal /path/to/{lv}|{device} + + Or: + + ceph-volume lvm create --data {data volume group} --journal {journal volume group} + + Collocated (same group) for data and journal + -------------------------------------------- + + ceph-volume lvm create --data {volume group} + + """) + parser = create_parser( + prog='ceph-volume lvm create', + description=sub_command_help, + ) + if len(self.argv) == 0: + print(sub_command_help) + return + args = parser.parse_args(self.argv) + self.create(args) diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/main.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/main.py new file mode 100644 index 000000000..59e69329b --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/main.py @@ -0,0 +1,42 @@ +import argparse +from textwrap import dedent +from ceph_volume import terminal +from . import activate +from . import prepare +from . import create +from . import trigger + + +class LVM(object): + + help = 'Use LVM and LVM-based technologies like dmcache to deploy OSDs' + + _help = dedent(""" + Use LVM and LVM-based technologies like dmcache to deploy OSDs + + {sub_help} + """) + + mapper = { + 'activate': activate.Activate, + 'prepare': prepare.Prepare, + 'create': create.Create, + 'trigger': trigger.Trigger, + } + + def __init__(self, argv): + self.argv = argv + + def print_help(self, sub_help): + return self._help.format(sub_help=sub_help) + + def main(self): + terminal.dispatch(self.mapper, self.argv) + parser = argparse.ArgumentParser( + prog='ceph-volume lvm', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=self.print_help(terminal.subhelp(self.mapper)), + ) + parser.parse_args(self.argv) + if len(self.argv) <= 1: + return parser.print_help() diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/prepare.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/prepare.py new file mode 100644 index 000000000..bd84aab18 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/prepare.py @@ -0,0 +1,202 @@ +from __future__ import print_function +import json +import os +from textwrap import dedent +from ceph_volume.util import prepare as prepare_utils +from ceph_volume.util import system +from ceph_volume import conf, decorators +from . import api +from .common import prepare_parser + + +def canonical_device_path(device): + """ + Ensure that a device is canonical (full path) and that it exists so that + it can be used throughout the prepare/activate process + """ + # FIXME: this is obviously super naive + inferred = os.path.join('/dev', device) + if os.path.exists(os.path.abspath(device)): + return device + elif os.path.exists(inferred): + return inferred + raise RuntimeError('Selected device does not exist: %s' % device) + + +def prepare_filestore(device, journal, secrets, id_=None, fsid=None): + """ + :param device: The name of the volume group or lvm to work with + :param journal: similar to device but can also be a regular/plain disk + :param secrets: A dict with the secrets needed to create the osd (e.g. cephx) + :param id_: The OSD id + :param fsid: The OSD fsid, also known as the OSD UUID + """ + cephx_secret = secrets.get('cephx_secret', prepare_utils.create_key()) + json_secrets = json.dumps(secrets) + + # allow re-using an existing fsid, in case prepare failed + fsid = fsid or system.generate_uuid() + # allow re-using an id, in case a prepare failed + osd_id = id_ or prepare_utils.create_id(fsid, json_secrets) + # create the directory + prepare_utils.create_path(osd_id) + # format the device + prepare_utils.format_device(device) + # mount the data device + prepare_utils.mount_osd(device, osd_id) + # symlink the journal + prepare_utils.link_journal(journal, osd_id) + # get the latest monmap + prepare_utils.get_monmap(osd_id) + # prepare the osd filesystem + prepare_utils.osd_mkfs(osd_id, fsid) + # write the OSD keyring if it doesn't exist already + prepare_utils.write_keyring(osd_id, cephx_secret) + + +def prepare_bluestore(): + raise NotImplemented() + + +class Prepare(object): + + help = 'Format an LVM device and associate it with an OSD' + + def __init__(self, argv): + self.argv = argv + + @decorators.needs_root + def prepare(self, args): + # FIXME we don't allow re-using a keyring, we always generate one for the + # OSD, this needs to be fixed. This could either be a file (!) or a string + # (!!) or some flags that we would need to compound into a dict so that we + # can convert to JSON (!!!) + secrets = {'cephx_secret': prepare_utils.create_key()} + + cluster_fsid = conf.ceph.get('global', 'fsid') + fsid = args.osd_fsid or system.generate_uuid() + #osd_id = args.osd_id or prepare_utils.create_id(fsid) + # allow re-using an id, in case a prepare failed + osd_id = args.osd_id or prepare_utils.create_id(fsid, json.dumps(secrets)) + journal_name = "journal_%s" % fsid + osd_name = "osd_%s" % fsid + + if args.filestore: + data_vg = api.get_vg(vg_name=args.data) + data_lv = api.get_lv(lv_name=args.data) + journal_vg = api.get_vg(vg_name=args.journal) + journal_lv = api.get_lv(lv_name=args.journal) + journal_device = None + # it is possible to pass a device as a journal that is not + # an actual logical volume (or group) + if not args.journal: + if data_lv: + raise RuntimeError('--journal is required when not using a vg for OSD data') + # collocated: carve out the journal from the data vg + if data_vg: + journal_lv = api.create_lv( + name=journal_name, + group=data_vg.name, + size=args.journal_size, + osd_fsid=fsid, + osd_id=osd_id, + type='journal', + cluster_fsid=cluster_fsid + ) + + # if a volume group was defined for the journal create that first + if journal_vg: + journal_lv = api.create_lv( + name=journal_name, + group=args.journal, + size=args.journal_size, + osd_fsid=fsid, + osd_id=osd_id, + type='journal', + cluster_fsid=cluster_fsid + ) + if journal_lv: + journal_device = journal_lv.lv_path + # The journal is probably a device, not in LVM + elif args.journal: + journal_device = canonical_device_path(args.journal) + # At this point we must have a journal_lv or a journal device + # now create the osd from the group if that was found + if data_vg: + # XXX make sure that a there aren't more OSDs than physical + # devices from this volume group + data_lv = api.create_lv( + name=osd_name, + group=args.data, + osd_fsid=fsid, + osd_id=osd_id, + type='data', + journal_device=journal_device, + cluster_fsid=cluster_fsid + ) + # we must have either an existing data_lv or a newly created, so lets make + # sure that the tags are correct + if not data_lv: + raise RuntimeError('no data logical volume found with: %s' % args.data) + data_lv.set_tags({ + 'ceph.type': 'data', + 'ceph.osd_fsid': fsid, + 'ceph.osd_id': osd_id, + 'ceph.cluster_fsid': cluster_fsid, + 'ceph.journal_device': journal_device, + 'ceph.data_device': data_lv.lv_path, + }) + + prepare_filestore( + data_lv.lv_path, + journal_device, + secrets, + id_=osd_id, + fsid=fsid, + ) + elif args.bluestore: + prepare_bluestore(args) + + def main(self): + sub_command_help = dedent(""" + Prepare an OSD by assigning an ID and FSID, registering them with the + cluster with an ID and FSID, formatting and mounting the volume, and + finally by adding all the metadata to the logical volumes using LVM + tags, so that it can later be discovered. + + Once the OSD is ready, an ad-hoc systemd unit will be enabled so that + it can later get activated and the OSD daemon can get started. + + Most basic Usage looks like (journal will be collocated from the same volume group): + + ceph-volume lvm prepare --data {volume group name} + + + Example calls for supported scenarios: + + Dedicated volume group for Journal(s) + ------------------------------------- + + Existing logical volume (lv) or device: + + ceph-volume lvm prepare --data {logical volume} --journal /path/to/{lv}|{device} + + Or: + + ceph-volume lvm prepare --data {data volume group} --journal {journal volume group} + + Collocated (same group) for data and journal + -------------------------------------------- + + ceph-volume lvm prepare --data {volume group} + + """) + parser = prepare_parser( + prog='ceph-volume lvm prepare', + description=sub_command_help, + ) + if len(self.argv) == 0: + print(sub_command_help) + return + args = parser.parse_args(self.argv) + self.prepare(args) diff --git a/ceph/src/ceph-volume/ceph_volume/devices/lvm/trigger.py b/ceph/src/ceph-volume/ceph_volume/devices/lvm/trigger.py new file mode 100644 index 000000000..7486bfaa9 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/devices/lvm/trigger.py @@ -0,0 +1,70 @@ +from __future__ import print_function +import argparse +from textwrap import dedent +from ceph_volume.exceptions import SuffixParsingError +from ceph_volume import decorators +from .activate import Activate + + +def parse_osd_id(string): + osd_id = string.split('-', 1)[0] + if not osd_id: + raise SuffixParsingError('OSD id', string) + if osd_id.isdigit(): + return osd_id + raise SuffixParsingError('OSD id', string) + + +def parse_osd_uuid(string): + osd_id = '%s-' % parse_osd_id(string) + # remove the id first + osd_uuid = string.split(osd_id)[-1] + if not osd_uuid: + raise SuffixParsingError('OSD uuid', string) + return osd_uuid + + +class Trigger(object): + + help = 'systemd helper to activate an OSD' + + def __init__(self, argv): + self.argv = argv + + @decorators.needs_root + def main(self): + sub_command_help = dedent(""" + ** DO NOT USE DIRECTLY ** + This tool is meant to help the systemd unit that knows about OSDs. + + Proxy OSD activation to ``ceph-volume lvm activate`` by parsing the + input from systemd, detecting the UUID and ID associated with an OSD:: + + ceph-volume lvm trigger {SYSTEMD-DATA} + + The systemd "data" is expected to be in the format of:: + + {OSD ID}-{OSD UUID} + + The lvs associated with the OSD need to have been prepared previously, + so that all needed tags and metadata exist. + """) + parser = argparse.ArgumentParser( + prog='ceph-volume lvm trigger', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=sub_command_help, + ) + + parser.add_argument( + 'systemd_data', + metavar='SYSTEMD_DATA', + nargs='?', + help='Data from a systemd unit containing ID and UUID of the OSD, like asdf-lkjh-0' + ) + if len(self.argv) == 0: + print(sub_command_help) + return + args = parser.parse_args(self.argv) + osd_id = parse_osd_id(args.systemd_data) + osd_uuid = parse_osd_uuid(args.systemd_data) + Activate([osd_id, osd_uuid]).main() diff --git a/ceph/src/ceph-volume/ceph_volume/exceptions.py b/ceph/src/ceph-volume/ceph_volume/exceptions.py new file mode 100644 index 000000000..75c6b6c64 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/exceptions.py @@ -0,0 +1,71 @@ +import os + + +class ConfigurationError(Exception): + + def __init__(self, cluster_name='ceph', path='/etc/ceph', abspath=None): + self.cluster_name = cluster_name + self.path = path + self.abspath = abspath or "%s.conf" % os.path.join(self.path, self.cluster_name) + + def __str__(self): + return 'Unable to load expected Ceph config at: %s' % self.abspath + + +class ConfigurationSectionError(Exception): + + def __init__(self, section): + self.section = section + + def __str__(self): + return 'Unable to find expected configuration section: "%s"' % self.section + + +class ConfigurationKeyError(Exception): + + def __init__(self, section, key): + self.section = section + self.key = key + + def __str__(self): + return 'Unable to find expected configuration key: "%s" from section "%s"' % ( + self.key, + self.section + ) + + +class SuffixParsingError(Exception): + + def __init__(self, suffix, part=None): + self.suffix = suffix + self.part = part + + def __str__(self): + return 'Unable to parse the %s from systemd suffix: %s' % (self.part, self.suffix) + + +class SuperUserError(Exception): + + def __str__(self): + return 'This command needs to be executed with sudo or as root' + + +class MultipleLVsError(Exception): + + def __init__(self, lv_name, lv_path): + self.lv_name = lv_name + self.lv_path = lv_path + + def __str__(self): + msg = "Got more than 1 result looking for %s with path: %s" % (self.lv_name, self.lv_path) + return msg + + +class MultipleVGsError(Exception): + + def __init__(self, vg_name): + self.vg_name = vg_name + + def __str__(self): + msg = "Got more than 1 result looking for volume group: %s" % self.vg_name + return msg diff --git a/ceph/src/ceph-volume/ceph_volume/log.py b/ceph/src/ceph-volume/ceph_volume/log.py new file mode 100644 index 000000000..890b6da1b --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/log.py @@ -0,0 +1,33 @@ +import logging +import os +from ceph_volume import terminal +from ceph_volume import conf + +BASE_FORMAT = "[%(name)s][%(levelname)-6s] %(message)s" +FILE_FORMAT = "[%(asctime)s]" + BASE_FORMAT + + +def setup(name='ceph-volume.log', log_path=None): + log_path = log_path or conf.log_path + # if a non-root user calls help or other no-sudo-required command the + # logger will fail to write to /var/lib/ceph/ so this /tmp/ path is used as + # a fallback + tmp_log_file = os.path.join('/tmp/', name) + root_logger = logging.getLogger() + # The default path is where all ceph log files are, and will get rotated by + # Ceph's logrotate rules. + + root_logger.setLevel(logging.DEBUG) + + try: + fh = logging.FileHandler(log_path) + except (OSError, IOError) as err: + terminal.warning("Falling back to /tmp/ for logging. Can't use %s" % log_path) + terminal.warning(str(err)) + conf.log_path = tmp_log_file + fh = logging.FileHandler(tmp_log_file) + + fh.setLevel(logging.DEBUG) + fh.setFormatter(logging.Formatter(FILE_FORMAT)) + + root_logger.addHandler(fh) diff --git a/ceph/src/ceph-volume/ceph_volume/main.py b/ceph/src/ceph-volume/ceph_volume/main.py new file mode 100644 index 000000000..d4bee154d --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/main.py @@ -0,0 +1,174 @@ +from __future__ import print_function +import argparse +import os +import pkg_resources +import sys +import logging + +import ceph_volume +from ceph_volume.decorators import catches +from ceph_volume import log, devices, configuration, conf, exceptions, terminal + + +class Volume(object): + _help = """ +ceph-volume: Deploy Ceph OSDs using different device technologies like lvm or +physical disks. + +Version: {version} + +Log Path: {log_path} +Ceph Conf: {ceph_path} + +{sub_help} +{plugins} +{environ_vars} +{warning} + """ + + def __init__(self, argv=None, parse=True): + self.mapper = {'lvm': devices.lvm.LVM} + self.plugin_help = "No plugins found/loaded" + if argv is None: + self.argv = sys.argv + else: + self.argv = argv + if parse: + self.main(self.argv) + + def help(self, warning=False): + warning = 'See "ceph-volume --help" for full list of options.' if warning else '' + return self._help.format( + warning=warning, + version=ceph_volume.__version__, + log_path=conf.log_path, + ceph_path=self.stat_ceph_conf(), + plugins=self.plugin_help, + sub_help=terminal.subhelp(self.mapper), + environ_vars=self.get_environ_vars() + ) + + def get_environ_vars(self): + environ_vars = [] + for key, value in os.environ.items(): + if key.startswith('CEPH_'): + environ_vars.append("%s=%s" % (key, value)) + if not environ_vars: + return '' + else: + environ_vars.insert(0, '\nEnviron Variables:') + return '\n'.join(environ_vars) + + def enable_plugins(self): + """ + Load all plugins available, add them to the mapper and extend the help + string with the information from each one + """ + plugins = _load_library_extensions() + for plugin in plugins: + self.mapper[plugin._ceph_volume_name_] = plugin + self.plugin_help = '\n'.join(['%-19s %s\n' % ( + plugin.name, getattr(plugin, 'help_menu', '')) + for plugin in plugins]) + if self.plugin_help: + self.plugin_help = '\nPlugins:\n' + self.plugin_help + + def load_ceph_conf_path(self, cluster_name='ceph'): + abspath = '/etc/ceph/%s.conf' % cluster_name + conf.path = os.getenv('CEPH_CONF', abspath) + conf.cluster = cluster_name + + def load_log_path(self): + conf.log_path = os.getenv('CEPH_VOLUME_LOG_PATH', '/var/log/ceph') + + def stat_ceph_conf(self): + try: + configuration.load(conf.path) + return terminal.green(conf.path) + except exceptions.ConfigurationError as error: + return terminal.red(error) + + def _get_split_args(self): + subcommands = self.mapper.keys() + slice_on_index = len(self.argv) + 1 + pruned_args = self.argv[1:] + for count, arg in enumerate(pruned_args): + if arg in subcommands: + slice_on_index = count + break + return pruned_args[:slice_on_index], pruned_args[slice_on_index:] + + @catches() + def main(self, argv): + # these need to be available for the help, which gets parsed super + # early + self.load_ceph_conf_path() + self.load_log_path() + self.enable_plugins() + main_args, subcommand_args = self._get_split_args() + # no flags where passed in, return the help menu instead of waiting for + # argparse which will end up complaning that there are no args + if len(argv) <= 1: + print(self.help(warning=True)) + return + parser = argparse.ArgumentParser( + prog='ceph-volume', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=self.help(), + ) + parser.add_argument( + '--cluster', + default='ceph', + help='Cluster name (defaults to "ceph")', + ) + parser.add_argument( + '--log-level', + default='debug', + help='Change the file log level (defaults to debug)', + ) + parser.add_argument( + '--log-path', + default='/var/log/ceph/', + help='Change the log path (defaults to /var/log/ceph)', + ) + args = parser.parse_args(main_args) + conf.log_path = args.log_path + if os.path.isdir(conf.log_path): + conf.log_path = os.path.join(args.log_path, 'ceph-volume.log') + log.setup() + # set all variables from args and load everything needed according to + # them + self.load_ceph_conf_path(cluster_name=args.cluster) + conf.ceph = configuration.load(conf.path) + # dispatch to sub-commands + terminal.dispatch(self.mapper, subcommand_args) + + +def _load_library_extensions(): + """ + Locate all setuptools entry points by the name 'ceph_volume_handlers' + and initialize them. + Any third-party library may register an entry point by adding the + following to their setup.py:: + + entry_points = { + 'ceph_volume_handlers': [ + 'plugin_name = mylib.mymodule:Handler_Class', + ], + }, + + `plugin_name` will be used to load it as a sub command. + """ + logger = logging.getLogger('ceph_volume.plugins') + group = 'ceph_volume_handlers' + entry_points = pkg_resources.iter_entry_points(group=group) + plugins = [] + for ep in entry_points: + try: + logger.debug('loading %s' % ep.name) + plugin = ep.load() + plugin._ceph_volume_name_ = ep.name + plugins.append(plugin) + except Exception as error: + logger.exception("Error initializing plugin %s: %s" % (ep, error)) + return plugins diff --git a/ceph/src/ceph-volume/ceph_volume/process.py b/ceph/src/ceph-volume/ceph_volume/process.py new file mode 100644 index 000000000..bc5047a17 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/process.py @@ -0,0 +1,156 @@ +from fcntl import fcntl, F_GETFL, F_SETFL +from os import O_NONBLOCK, read +import subprocess +from select import select +from ceph_volume import terminal + +import logging + +logger = logging.getLogger(__name__) + + +def log_output(descriptor, message, terminal_logging): + """ + log output to both the logger and the terminal if terminal_logging is + enabled + """ + if not message: + return + message = message.strip() + line = '%s %s' % (descriptor, message) + if terminal_logging: + getattr(terminal, descriptor)(message) + logger.info(line) + + +def log_descriptors(reads, process, terminal_logging): + """ + Helper to send output to the terminal while polling the subprocess + """ + # these fcntl are set to O_NONBLOCK for the filedescriptors coming from + # subprocess so that the logging does not block. Without these a prompt in + # a subprocess output would hang and nothing would get printed. Note how + # these are just set when logging subprocess, not globally. + stdout_flags = fcntl(process.stdout, F_GETFL) # get current p.stdout flags + stderr_flags = fcntl(process.stderr, F_GETFL) # get current p.stderr flags + fcntl(process.stdout, F_SETFL, stdout_flags | O_NONBLOCK) + fcntl(process.stderr, F_SETFL, stderr_flags | O_NONBLOCK) + descriptor_names = { + process.stdout.fileno(): 'stdout', + process.stderr.fileno(): 'stderr' + } + for descriptor in reads: + descriptor_name = descriptor_names[descriptor] + try: + log_output(descriptor_name, read(descriptor, 1024), terminal_logging) + except (IOError, OSError): + # nothing else to log + pass + + +def run(command, **kw): + """ + A real-time-logging implementation of a remote subprocess.Popen call where + a command is just executed on the remote end and no other handling is done. + + :param command: The command to pass in to the remote subprocess.Popen as a list + :param stop_on_error: If a nonzero exit status is return, it raises a ``RuntimeError`` + """ + stop_on_error = kw.pop('stop_on_error', True) + command_msg = "Running command: %s" % ' '.join(command) + stdin = kw.pop('stdin', None) + logger.info(command_msg) + terminal.write(command_msg) + terminal_logging = kw.pop('terminal_logging', True) + + process = subprocess.Popen( + command, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True, + **kw + ) + + if stdin: + process.communicate(stdin) + while True: + reads, _, _ = select( + [process.stdout.fileno(), process.stderr.fileno()], + [], [] + ) + log_descriptors(reads, process, terminal_logging) + + if process.poll() is not None: + # ensure we do not have anything pending in stdout or stderr + log_descriptors(reads, process, terminal_logging) + + break + + returncode = process.wait() + if returncode != 0: + msg = "command returned non-zero exit status: %s" % returncode + if stop_on_error: + raise RuntimeError(msg) + else: + if terminal_logging: + terminal.warning(msg) + logger.warning(msg) + + +def call(command, **kw): + """ + Similar to ``subprocess.Popen`` with the following changes: + + * returns stdout, stderr, and exit code (vs. just the exit code) + * logs the full contents of stderr and stdout (separately) to the file log + + By default, no terminal output is given, not even the command that is going + to run. + + Useful when system calls are needed to act on output, and that same output + shouldn't get displayed on the terminal. + + :param terminal_verbose: Log command output to terminal, defaults to False, and + it is forcefully set to True if a return code is non-zero + """ + terminal_verbose = kw.pop('terminal_verbose', False) + command_msg = "Running command: %s" % ' '.join(command) + stdin = kw.pop('stdin', None) + logger.info(command_msg) + terminal.write(command_msg) + + process = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + close_fds=True, + **kw + ) + if stdin: + stdout_stream, stderr_stream = process.communicate(stdin) + else: + stdout_stream = process.stdout.read() + stderr_stream = process.stderr.read() + returncode = process.wait() + if not isinstance(stdout_stream, str): + stdout_stream = stdout_stream.decode('utf-8') + if not isinstance(stderr_stream, str): + stderr_stream = stderr_stream.decode('utf-8') + stdout = stdout_stream.splitlines() + stderr = stderr_stream.splitlines() + + if returncode != 0: + # set to true so that we can log the stderr/stdout that callers would + # do anyway + terminal_verbose = True + + # the following can get a messed up order in the log if the system call + # returns output with both stderr and stdout intermingled. This separates + # that. + for line in stdout: + log_output('stdout', line, terminal_verbose) + for line in stderr: + log_output('stderr', line, terminal_verbose) + return stdout, stderr, returncode diff --git a/ceph/src/ceph-volume/ceph_volume/systemd/__init__.py b/ceph/src/ceph-volume/ceph_volume/systemd/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ceph/src/ceph-volume/ceph_volume/systemd/main.py b/ceph/src/ceph-volume/ceph_volume/systemd/main.py new file mode 100644 index 000000000..69c0f38a2 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/systemd/main.py @@ -0,0 +1,109 @@ +""" +This file is used only by systemd units that are passing their instance suffix +as arguments to this script so that it can parse the suffix into arguments that +``ceph-volume `` can consume +""" +import os +import sys +import time +import logging +from ceph_volume import log, process +from ceph_volume.exceptions import SuffixParsingError + + +def parse_subcommand(string): + subcommand = string.split('-', 1)[0] + if not subcommand: + raise SuffixParsingError('subcommand', string) + return subcommand + + +def parse_extra_data(string): + # get the subcommand to split on that + sub_command = parse_subcommand(string) + + # the split will leave data with a dash, so remove that + data = string.split(sub_command)[-1] + if not data: + raise SuffixParsingError('data', string) + return data.lstrip('-') + + +def parse_osd_id(string): + osd_id = string.split('-', 1)[0] + if not osd_id: + raise SuffixParsingError('OSD id', string) + if osd_id.isdigit(): + return osd_id + raise SuffixParsingError('OSD id', string) + + +def parse_osd_uuid(string): + osd_id = '%s-' % parse_osd_id(string) + osd_subcommand = '-%s' % parse_subcommand(string) + # remove the id first + trimmed_suffix = string.split(osd_id)[-1] + # now remove the sub command + osd_uuid = trimmed_suffix.split(osd_subcommand)[0] + if not osd_uuid: + raise SuffixParsingError('OSD uuid', string) + return osd_uuid + + +def main(args=None): + """ + Main entry point for the ``ceph-volume-systemd`` executable. ``args`` are + optional for easier testing of arguments. + + Expected input is similar to:: + + ['/path/to/ceph-volume-systemd', '--'] + ['/path/to/ceph-volume-systemd', '-'] + + For example:: + + [ + '/usr/bin/ceph-volume-systemd', + 'lvm-0-8715BEB4-15C5-49DE-BA6F-401086EC7B41' + ] + + The first part of the argument is the only interesting bit, which contains + the metadata needed to proxy the call to ``ceph-volume`` itself. + + Reusing the example, the proxy call to ``ceph-volume`` would look like:: + + ceph-volume lvm trigger 0-8715BEB4-15C5-49DE-BA6F-401086EC7B41 + + That means that ``lvm`` is used as the subcommand and it is **expected** + that a ``trigger`` sub-commmand will be present to make sense of the extra + piece of the string. + + """ + log.setup(name='ceph-volume-systemd.log', log_path='/var/log/ceph/ceph-volume-systemd.log') + logger = logging.getLogger('systemd') + + args = args if args is not None else sys.argv + try: + suffix = args[-1] + except IndexError: + raise RuntimeError('no arguments supplied') + sub_command = parse_subcommand(suffix) + extra_data = parse_extra_data(suffix) + logger.info('raw systemd input received: %s', suffix) + logger.info('parsed sub-command: %s, extra data: %s', sub_command, extra_data) + command = ['ceph-volume', sub_command, 'trigger', extra_data] + + tries = os.environ.get('CEPH_VOLUME_SYSTEMD_TRIES', 30) + interval = os.environ.get('CEPH_VOLUME_SYSTEMD_INTERVAL', 5) + while tries > 0: + try: + # don't log any output to the terminal, just rely on stderr/stdout + # going to logging + process.run(command, terminal_logging=False) + logger.info('successfully trggered activation for: %s', extra_data) + break + except RuntimeError as error: + logger.warning(error) + logger.warning('failed activating OSD, retries left: %s', tries) + tries -= 1 + time.sleep(interval) diff --git a/ceph/src/ceph-volume/ceph_volume/systemd/systemctl.py b/ceph/src/ceph-volume/ceph_volume/systemd/systemctl.py new file mode 100644 index 000000000..9bb4d7d3a --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/systemd/systemctl.py @@ -0,0 +1,48 @@ +""" +Utilities to control systemd units +""" +from ceph_volume import process + + +def start(unit): + process.run(['sudo', 'systemctl', 'start', unit]) + + +def stop(unit): + process.run(['sudo', 'systemctl', 'stop', unit]) + + +def enable(unit): + process.run(['sudo', 'systemctl', 'enable', unit]) + + +def disable(unit): + process.run(['sudo', 'systemctl', 'disable', unit]) + + +def start_osd(id_): + return start(osd_unit % id_) + + +def stop_osd(id_): + return stop(osd_unit % id_) + + +def enable_osd(id_): + return enable(osd_unit % id_) + + +def disable_osd(id_): + return disable(osd_unit % id_) + + +def enable_volume(id_, fsid, device_type='lvm'): + return enable(volume_unit % (device_type, id_, fsid)) + + +# +# templates +# + +osd_unit = "ceph-osd@%s" +volume_unit = "ceph-volume@%s-%s-%s" diff --git a/ceph/src/ceph-volume/ceph_volume/terminal.py b/ceph/src/ceph-volume/ceph_volume/terminal.py new file mode 100644 index 000000000..55ce2d4ca --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/terminal.py @@ -0,0 +1,151 @@ +import sys + + +class colorize(str): + """ + Pretty simple to use:: + + colorize.make('foo').bold + colorize.make('foo').green + colorize.make('foo').yellow + colorize.make('foo').red + colorize.make('foo').blue + + Otherwise you could go the long way (for example if you are + testing this class):: + + string = colorize('foo') + string._set_attributes() + string.red + + """ + + def __init__(self, string): + self.stdout = sys.__stdout__ + self.appends = '' + self.prepends = '' + self.isatty = self.stdout.isatty() + + def _set_attributes(self): + """ + Sets the attributes here because the str class does not + allow to pass in anything other than a string to the constructor + so we can't really mess with the other attributes. + """ + for k, v in self.__colors__.items(): + setattr(self, k, self.make_color(v)) + + def make_color(self, color): + if not self.isatty: + return self + return color + self + '\033[0m' + self.appends + + @property + def __colors__(self): + return dict( + blue='\033[34m', + green='\033[92m', + yellow='\033[33m', + red='\033[91m', + bold='\033[1m', + ends='\033[0m' + ) + + @classmethod + def make(cls, string): + """ + A helper method to return itself and workaround the fact that + the str object doesn't allow extra arguments passed in to the + constructor + """ + obj = cls(string) + obj._set_attributes() + return obj + +# +# Common string manipulations +# +yellow = lambda x: colorize.make(x).yellow # noqa +blue = lambda x: colorize.make(x).blue # noqa +green = lambda x: colorize.make(x).green # noqa +red = lambda x: colorize.make(x).red # noqa +bold = lambda x: colorize.make(x).bold # noqa +red_arrow = red('--> ') +blue_arrow = blue('--> ') +green_arrow = green('--> ') +yellow_arrow = yellow('--> ') + + +class _Write(object): + + def __init__(self, _writer=None, prefix='', suffix='', flush=False): + self._writer = _writer or sys.stdout + self.suffix = suffix + self.prefix = prefix + self.flush = flush + + def bold(self, string): + self.write(bold(string)) + + def raw(self, string): + if not string.endswith('\n'): + string = '%s\n' % string + self.write(string) + + def write(self, line): + self._writer.write(self.prefix + line + self.suffix) + if self.flush: + self._writer.flush() + + +def stdout(msg): + return _Write(prefix=blue(' stdout: ')).raw(msg) + + +def stderr(msg): + return _Write(prefix=yellow(' stderr: ')).raw(msg) + + +def write(msg): + return _Write().raw(msg) + + +def error(msg): + return _Write(prefix=red_arrow).raw(msg) + + +def warning(msg): + return _Write(prefix=yellow_arrow).raw(msg) + + +def success(msg): + return _Write(prefix=green_arrow).raw(msg) + + +def dispatch(mapper, argv=None): + argv = argv or sys.argv + for count, arg in enumerate(argv, 1): + if arg in mapper.keys(): + instance = mapper.get(arg)(argv[count:]) + if hasattr(instance, 'main'): + instance.main() + raise SystemExit(0) + + +def subhelp(mapper): + """ + Look at every value of every key in the mapper and will output any + ``class.help`` possible to return it as a string that will be sent to + stdout. + """ + help_text_lines = [] + for key, value in mapper.items(): + try: + help_text = value.help + except AttributeError: + continue + help_text_lines.append("%-24s %s" % (key, help_text)) + + if help_text_lines: + return "Available subcommands:\n\n%s" % '\n'.join(help_text_lines) + return '' diff --git a/ceph/src/ceph-volume/ceph_volume/tests/__init__.py b/ceph/src/ceph-volume/ceph_volume/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ceph/src/ceph-volume/ceph_volume/tests/conftest.py b/ceph/src/ceph-volume/ceph_volume/tests/conftest.py new file mode 100644 index 000000000..869979ebf --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/conftest.py @@ -0,0 +1,16 @@ +import pytest + +class Capture(object): + + def __init__(self, *a, **kw): + self.a = a + self.kw = kw + self.calls = [] + + def __call__(self, *a, **kw): + self.calls.append({'args': a, 'kwargs': kw}) + + +@pytest.fixture +def capture(): + return Capture() diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/__init__.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/__init__.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_api.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_api.py new file mode 100644 index 000000000..c849fac99 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_api.py @@ -0,0 +1,240 @@ +import pytest +from ceph_volume import process, exceptions +from ceph_volume.devices.lvm import api + + +class TestParseTags(object): + + def test_no_tags_means_empty_dict(self): + result = api.parse_tags('') + assert result == {} + + def test_single_tag_gets_parsed(self): + result = api.parse_tags('ceph.osd_something=1') + assert result == {'ceph.osd_something': '1'} + + def test_multiple_csv_expands_in_dict(self): + result = api.parse_tags('ceph.osd_something=1,ceph.foo=2,ceph.fsid=0000') + # assert them piecemeal to avoid the un-ordered dict nature + assert result['ceph.osd_something'] == '1' + assert result['ceph.foo'] == '2' + assert result['ceph.fsid'] == '0000' + + +class TestGetAPIVgs(object): + + def test_report_is_emtpy(self, monkeypatch): + monkeypatch.setattr(api.process, 'call', lambda x: ('{}', '', 0)) + assert api.get_api_vgs() == [] + + def test_report_has_stuff(self, monkeypatch): + report = '{"report":[{"vg":[{"vg_name":"VolGroup00"}]}]}' + monkeypatch.setattr(api.process, 'call', lambda x: (report, '', 0)) + assert api.get_api_vgs() == [{'vg_name': 'VolGroup00'}] + + def test_report_has_multiple_items(self, monkeypatch): + report = '{"report":[{"vg":[{"vg_name":"VolGroup00"},{"vg_name":"ceph_vg"}]}]}' + monkeypatch.setattr(api.process, 'call', lambda x: (report, '', 0)) + assert api.get_api_vgs() == [{'vg_name': 'VolGroup00'}, {'vg_name': 'ceph_vg'}] + + def test_does_not_get_poluted_with_non_vg_items(self, monkeypatch): + report = '{"report":[{"vg":[{"vg_name":"VolGroup00"}],"lv":[{"lv":"1"}]}]}' + monkeypatch.setattr(api.process, 'call', lambda x: (report, '', 0)) + assert api.get_api_vgs() == [{'vg_name': 'VolGroup00'}] + + +class TestGetAPILvs(object): + + def test_report_is_emtpy(self, monkeypatch): + monkeypatch.setattr(api.process, 'call', lambda x: ('{}', '', 0)) + assert api.get_api_lvs() == [] + + def test_report_has_stuff(self, monkeypatch): + report = '{"report":[{"lv":[{"lv_name":"VolGroup00"}]}]}' + monkeypatch.setattr(api.process, 'call', lambda x: (report, '', 0)) + assert api.get_api_lvs() == [{'lv_name': 'VolGroup00'}] + + def test_report_has_multiple_items(self, monkeypatch): + report = '{"report":[{"lv":[{"lv_name":"VolName"},{"lv_name":"ceph_lv"}]}]}' + monkeypatch.setattr(api.process, 'call', lambda x: (report, '', 0)) + assert api.get_api_lvs() == [{'lv_name': 'VolName'}, {'lv_name': 'ceph_lv'}] + + def test_does_not_get_poluted_with_non_lv_items(self, monkeypatch): + report = '{"report":[{"lv":[{"lv_name":"VolName"}],"vg":[{"vg":"1"}]}]}' + monkeypatch.setattr(api.process, 'call', lambda x: (report, '', 0)) + assert api.get_api_lvs() == [{'lv_name': 'VolName'}] + + +@pytest.fixture +def volumes(monkeypatch): + monkeypatch.setattr(process, 'call', lambda x: ('{}', '', 0)) + volumes = api.Volumes() + volumes._purge() + return volumes + + +@pytest.fixture +def volume_groups(monkeypatch): + monkeypatch.setattr(process, 'call', lambda x: ('{}', '', 0)) + vgs = api.VolumeGroups() + vgs._purge() + return vgs + + +class TestGetLV(object): + + def test_nothing_is_passed_in(self): + # so we return a None + assert api.get_lv() is None + + def test_single_lv_is_matched(self, volumes, monkeypatch): + FooVolume = api.Volume(lv_name='foo', lv_path='/dev/vg/foo', lv_tags="ceph.type=data") + volumes.append(FooVolume) + monkeypatch.setattr(api, 'Volumes', lambda: volumes) + assert api.get_lv(lv_name='foo') == FooVolume + + +class TestGetVG(object): + + def test_nothing_is_passed_in(self): + # so we return a None + assert api.get_vg() is None + + def test_single_vg_is_matched(self, volume_groups, monkeypatch): + FooVG = api.VolumeGroup(vg_name='foo') + volume_groups.append(FooVG) + monkeypatch.setattr(api, 'VolumeGroups', lambda: volume_groups) + assert api.get_vg(vg_name='foo') == FooVG + + +class TestVolumes(object): + + def test_volume_get_has_no_volumes(self, volumes): + assert volumes.get() is None + + def test_volume_get_filtered_has_no_volumes(self, volumes): + assert volumes.get(lv_name='ceph') is None + + def test_volume_has_multiple_matches(self, volumes): + volume1 = volume2 = api.Volume(lv_name='foo', lv_path='/dev/vg/lv', lv_tags='') + volumes.append(volume1) + volumes.append(volume2) + with pytest.raises(exceptions.MultipleLVsError): + volumes.get(lv_name='foo') + + def test_find_the_correct_one(self, volumes): + volume1 = api.Volume(lv_name='volume1', lv_path='/dev/vg/lv', lv_tags='') + volume2 = api.Volume(lv_name='volume2', lv_path='/dev/vg/lv', lv_tags='') + volumes.append(volume1) + volumes.append(volume2) + assert volumes.get(lv_name='volume1') == volume1 + + def test_filter_by_tag(self, volumes): + lv_tags = "ceph.type=data,ceph.fsid=000-aaa" + osd = api.Volume(lv_name='volume1', lv_path='/dev/vg/lv', lv_tags=lv_tags) + journal = api.Volume(lv_name='volume2', lv_path='/dev/vg/lv', lv_tags='ceph.type=journal') + volumes.append(osd) + volumes.append(journal) + volumes.filter(lv_tags={'ceph.type': 'data'}) + assert len(volumes) == 1 + assert volumes[0].lv_name == 'volume1' + + def test_filter_by_vg_name(self, volumes): + lv_tags = "ceph.type=data,ceph.fsid=000-aaa" + osd = api.Volume(lv_name='volume1', vg_name='ceph_vg', lv_tags=lv_tags) + journal = api.Volume(lv_name='volume2', vg_name='system_vg', lv_tags='ceph.type=journal') + volumes.append(osd) + volumes.append(journal) + volumes.filter(vg_name='ceph_vg') + assert len(volumes) == 1 + assert volumes[0].lv_name == 'volume1' + + def test_filter_by_lv_path(self, volumes): + osd = api.Volume(lv_name='volume1', lv_path='/dev/volume1', lv_tags='') + journal = api.Volume(lv_name='volume2', lv_path='/dev/volume2', lv_tags='') + volumes.append(osd) + volumes.append(journal) + volumes.filter(lv_path='/dev/volume1') + assert len(volumes) == 1 + assert volumes[0].lv_name == 'volume1' + + def test_filter_requires_params(self, volumes): + with pytest.raises(TypeError): + volumes.filter() + + +class TestVolumeGroups(object): + + def test_volume_get_has_no_volume_groups(self, volume_groups): + assert volume_groups.get() is None + + def test_volume_get_filtered_has_no_volumes(self, volume_groups): + assert volume_groups.get(vg_name='ceph') is None + + def test_volume_has_multiple_matches(self, volume_groups): + volume1 = volume2 = api.VolumeGroup(vg_name='foo', lv_path='/dev/vg/lv', lv_tags='') + volume_groups.append(volume1) + volume_groups.append(volume2) + with pytest.raises(exceptions.MultipleVGsError): + volume_groups.get(vg_name='foo') + + def test_find_the_correct_one(self, volume_groups): + volume1 = api.VolumeGroup(vg_name='volume1', lv_tags='') + volume2 = api.VolumeGroup(vg_name='volume2', lv_tags='') + volume_groups.append(volume1) + volume_groups.append(volume2) + assert volume_groups.get(vg_name='volume1') == volume1 + + def test_filter_by_tag(self, volume_groups): + vg_tags = "ceph.group=dmcache" + osd = api.VolumeGroup(vg_name='volume1', vg_tags=vg_tags) + journal = api.VolumeGroup(vg_name='volume2', vg_tags='ceph.group=plain') + volume_groups.append(osd) + volume_groups.append(journal) + volume_groups.filter(vg_tags={'ceph.group': 'dmcache'}) + assert len(volume_groups) == 1 + assert volume_groups[0].vg_name == 'volume1' + + def test_filter_by_vg_name(self, volume_groups): + vg_tags = "ceph.type=data,ceph.fsid=000-aaa" + osd = api.VolumeGroup(vg_name='ceph_vg', vg_tags=vg_tags) + journal = api.VolumeGroup(vg_name='volume2', vg_tags='ceph.type=journal') + volume_groups.append(osd) + volume_groups.append(journal) + volume_groups.filter(vg_name='ceph_vg') + assert len(volume_groups) == 1 + assert volume_groups[0].vg_name == 'ceph_vg' + + def test_filter_requires_params(self, volume_groups): + with pytest.raises(TypeError): + volume_groups.filter() + + +class TestCreateLV(object): + + def setup(self): + self.foo_volume = api.Volume(lv_name='foo', lv_path='/path', vg_name='foo_group', lv_tags='') + + def test_uses_size(self, monkeypatch, capture): + monkeypatch.setattr(process, 'run', capture) + monkeypatch.setattr(process, 'call', capture) + monkeypatch.setattr(api, 'get_lv', lambda *a, **kw: self.foo_volume) + api.create_lv('foo', 'foo_group', size=5, type='data') + expected = ['sudo', 'lvcreate', '--yes', '-L', '5G', '-n', 'foo', 'foo_group'] + assert capture.calls[0]['args'][0] == expected + + def test_calls_to_set_type_tag(self, monkeypatch, capture): + monkeypatch.setattr(process, 'run', capture) + monkeypatch.setattr(process, 'call', capture) + monkeypatch.setattr(api, 'get_lv', lambda *a, **kw: self.foo_volume) + api.create_lv('foo', 'foo_group', size=5, type='data') + ceph_tag = ['sudo', 'lvchange', '--addtag', 'ceph.type=data', '/path'] + assert capture.calls[1]['args'][0] == ceph_tag + + def test_calls_to_set_data_tag(self, monkeypatch, capture): + monkeypatch.setattr(process, 'run', capture) + monkeypatch.setattr(process, 'call', capture) + monkeypatch.setattr(api, 'get_lv', lambda *a, **kw: self.foo_volume) + api.create_lv('foo', 'foo_group', size=5, type='data') + data_tag = ['sudo', 'lvchange', '--addtag', 'ceph.data_device=/path', '/path'] + assert capture.calls[2]['args'][0] == data_tag diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py new file mode 100644 index 000000000..b8402a767 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py @@ -0,0 +1,53 @@ +import pytest +from ceph_volume.devices import lvm + + +class TestLVM(object): + + def test_main_spits_help_with_no_arguments(self, capsys): + lvm.main.LVM([]).main() + stdout, stderr = capsys.readouterr() + assert 'Use LVM and LVM-based technologies like dmcache to deploy' in stdout + + def test_main_shows_activate_subcommands(self, capsys): + lvm.main.LVM([]).main() + stdout, stderr = capsys.readouterr() + assert 'activate ' in stdout + assert 'Discover and mount' in stdout + + def test_main_shows_prepare_subcommands(self, capsys): + lvm.main.LVM([]).main() + stdout, stderr = capsys.readouterr() + assert 'prepare ' in stdout + assert 'Format an LVM device' in stdout + + +class TestPrepare(object): + + def test_main_spits_help_with_no_arguments(self, capsys): + lvm.prepare.Prepare([]).main() + stdout, stderr = capsys.readouterr() + assert 'Prepare an OSD by assigning an ID and FSID' in stdout + + def test_main_shows_full_help(self, capsys): + with pytest.raises(SystemExit): + lvm.prepare.Prepare(argv=['--help']).main() + stdout, stderr = capsys.readouterr() + assert 'required arguments:' in stdout + assert 'A logical group name or a path' in stdout + + +class TestActivate(object): + + def test_main_spits_help_with_no_arguments(self, capsys): + lvm.activate.Activate([]).main() + stdout, stderr = capsys.readouterr() + assert 'Activate OSDs by discovering them with' in stdout + + def test_main_shows_full_help(self, capsys): + with pytest.raises(SystemExit): + lvm.activate.Activate(argv=['--help']).main() + stdout, stderr = capsys.readouterr() + assert 'optional arguments' in stdout + assert 'positional arguments' in stdout + diff --git a/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_trigger.py b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_trigger.py new file mode 100644 index 000000000..f1dff2d32 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/devices/lvm/test_trigger.py @@ -0,0 +1,39 @@ +import pytest +from ceph_volume import exceptions +from ceph_volume.devices.lvm import trigger + + +class TestParseOSDid(object): + + def test_no_id_found_if_no_digit(self): + with pytest.raises(exceptions.SuffixParsingError): + trigger.parse_osd_id('asdlj-ljahsdfaslkjhdfa') + + def test_no_id_found(self): + with pytest.raises(exceptions.SuffixParsingError): + trigger.parse_osd_id('ljahsdfaslkjhdfa') + + def test_id_found(self): + result = trigger.parse_osd_id('1-ljahsdfaslkjhdfa') + assert result == '1' + + +class TestParseOSDUUID(object): + + def test_uuid_is_parsed(self): + result = trigger.parse_osd_uuid('1-asdf-ljkh-asdf-ljkh-asdf') + assert result == 'asdf-ljkh-asdf-ljkh-asdf' + + def test_uuid_is_parsed_longer_sha1(self): + result = trigger.parse_osd_uuid('1-foo-bar-asdf-ljkh-asdf-ljkh-asdf') + assert result == 'foo-bar-asdf-ljkh-asdf-ljkh-asdf' + + def test_uuid_is_not_found(self): + with pytest.raises(exceptions.SuffixParsingError): + trigger.parse_osd_uuid('ljahsdfaslkjhdfa') + + def test_uuid_is_not_found_missing_id(self): + with pytest.raises(exceptions.SuffixParsingError): + trigger.parse_osd_uuid('ljahs-dfa-slkjhdfa-foo') + + diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/Vagrantfile b/ceph/src/ceph-volume/ceph_volume/tests/functional/Vagrantfile new file mode 100644 index 000000000..4a7949573 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/Vagrantfile @@ -0,0 +1,398 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +require 'yaml' +require 'time' +VAGRANTFILE_API_VERSION = '2' + +DEBUG = false + +config_file=File.expand_path(File.join(File.dirname(__FILE__), 'vagrant_variables.yml')) +settings=YAML.load_file(config_file) + +LABEL_PREFIX = settings['label_prefix'] ? settings['label_prefix'] + "-" : "" +NMONS = settings['mon_vms'] +NOSDS = settings['osd_vms'] +NMDSS = settings['mds_vms'] +NRGWS = settings['rgw_vms'] +NNFSS = settings['nfs_vms'] +RESTAPI = settings['restapi'] +NRBD_MIRRORS = settings['rbd_mirror_vms'] +CLIENTS = settings['client_vms'] +NISCSI_GWS = settings['iscsi_gw_vms'] +PUBLIC_SUBNET = settings['public_subnet'] +CLUSTER_SUBNET = settings['cluster_subnet'] +BOX = settings['vagrant_box'] +CLIENT_BOX = settings['client_vagrant_box'] +BOX_URL = settings['vagrant_box_url'] +SYNC_DIR = settings['vagrant_sync_dir'] +MEMORY = settings['memory'] +ETH = settings['eth'] +USER = settings['ssh_username'] + +ASSIGN_STATIC_IP = settings.fetch('assign_static_ip', true) +DISABLE_SYNCED_FOLDER = settings.fetch('vagrant_disable_synced_folder', false) +DISK_UUID = Time.now.utc.to_i + +def create_vmdk(name, size) + dir = Pathname.new(__FILE__).expand_path.dirname + path = File.join(dir, '.vagrant', name + '.vmdk') + `vmware-vdiskmanager -c -s #{size} -t 0 -a scsi #{path} \ + 2>&1 > /dev/null` unless File.exist?(path) +end + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + config.ssh.insert_key = false # workaround for https://github.com/mitchellh/vagrant/issues/5048 + config.ssh.private_key_path = settings['ssh_private_key_path'] + config.ssh.username = USER + + # When using libvirt, avoid errors like: + # "CPU feature cmt not found" + config.vm.provider :libvirt do |lv| + lv.cpu_mode = 'host-passthrough' + end + + # Faster bootup. Disables mounting the sync folder for libvirt and virtualbox + if DISABLE_SYNCED_FOLDER + config.vm.provider :virtualbox do |v,override| + override.vm.synced_folder '.', SYNC_DIR, disabled: true + end + config.vm.provider :libvirt do |v,override| + override.vm.synced_folder '.', SYNC_DIR, disabled: true + end + end + + (0..CLIENTS - 1).each do |i| + config.vm.define "#{LABEL_PREFIX}client#{i}" do |client| + client.vm.box = CLIENT_BOX + client.vm.hostname = "#{LABEL_PREFIX}ceph-client#{i}" + if ASSIGN_STATIC_IP + client.vm.network :private_network, + ip: "#{PUBLIC_SUBNET}.4#{i}" + end + # Virtualbox + client.vm.provider :virtualbox do |vb| + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + client.vm.provider :vmware_fusion do |v| + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + client.vm.provider :libvirt do |lv| + lv.memory = MEMORY + lv.random_hostname = true + end + + # Parallels + client.vm.provider "parallels" do |prl| + prl.name = "ceph-client#{i}" + prl.memory = "#{MEMORY}" + end + + client.vm.provider :linode do |provider| + provider.label = client.vm.hostname + end + end + end + + (0..NRGWS - 1).each do |i| + config.vm.define "#{LABEL_PREFIX}rgw#{i}" do |rgw| + rgw.vm.box = BOX + rgw.vm.box_url = BOX_URL + rgw.vm.hostname = "#{LABEL_PREFIX}ceph-rgw#{i}" + if ASSIGN_STATIC_IP + rgw.vm.network :private_network, + ip: "#{PUBLIC_SUBNET}.5#{i}" + end + + # Virtualbox + rgw.vm.provider :virtualbox do |vb| + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + rgw.vm.provider :vmware_fusion do |v| + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + rgw.vm.provider :libvirt do |lv| + lv.memory = MEMORY + lv.random_hostname = true + end + + # Parallels + rgw.vm.provider "parallels" do |prl| + prl.name = "ceph-rgw#{i}" + prl.memory = "#{MEMORY}" + end + + rgw.vm.provider :linode do |provider| + provider.label = rgw.vm.hostname + end + end + end + + (0..NNFSS - 1).each do |i| + config.vm.define "nfs#{i}" do |nfs| + nfs.vm.box = BOX + nfs.vm.box_url = BOX_URL + nfs.vm.hostname = "ceph-nfs#{i}" + if ASSIGN_STATIC_IP + nfs.vm.network :private_network, + ip: "#{PUBLIC_SUBNET}.6#{i}" + end + + # Virtualbox + nfs.vm.provider :virtualbox do |vb| + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + nfs.vm.provider :vmware_fusion do |v| + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + nfs.vm.provider :libvirt do |lv| + lv.memory = MEMORY + lv.random_hostname = true + end + + # Parallels + nfs.vm.provider "parallels" do |prl| + prl.name = "ceph-nfs#{i}" + prl.memory = "#{MEMORY}" + end + + nfs.vm.provider :linode do |provider| + provider.label = nfs.vm.hostname + end + end + end + + (0..NMDSS - 1).each do |i| + config.vm.define "#{LABEL_PREFIX}mds#{i}" do |mds| + mds.vm.box = BOX + mds.vm.box_url = BOX_URL + mds.vm.hostname = "#{LABEL_PREFIX}ceph-mds#{i}" + if ASSIGN_STATIC_IP + mds.vm.network :private_network, + ip: "#{PUBLIC_SUBNET}.7#{i}" + end + # Virtualbox + mds.vm.provider :virtualbox do |vb| + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + mds.vm.provider :vmware_fusion do |v| + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + mds.vm.provider :libvirt do |lv| + lv.memory = MEMORY + lv.random_hostname = true + end + # Parallels + mds.vm.provider "parallels" do |prl| + prl.name = "ceph-mds#{i}" + prl.memory = "#{MEMORY}" + end + + mds.vm.provider :linode do |provider| + provider.label = mds.vm.hostname + end + end + end + + (0..NRBD_MIRRORS - 1).each do |i| + config.vm.define "#{LABEL_PREFIX}rbd_mirror#{i}" do |rbd_mirror| + rbd_mirror.vm.box = BOX + rbd_mirror.vm.box_url = BOX_URL + rbd_mirror.vm.hostname = "#{LABEL_PREFIX}ceph-rbd-mirror#{i}" + if ASSIGN_STATIC_IP + rbd_mirror.vm.network :private_network, + ip: "#{PUBLIC_SUBNET}.8#{i}" + end + # Virtualbox + rbd_mirror.vm.provider :virtualbox do |vb| + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + rbd_mirror.vm.provider :vmware_fusion do |v| + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + rbd_mirror.vm.provider :libvirt do |lv| + lv.memory = MEMORY + lv.random_hostname = true + end + # Parallels + rbd_mirror.vm.provider "parallels" do |prl| + prl.name = "ceph-rbd-mirror#{i}" + prl.memory = "#{MEMORY}" + end + + rbd_mirror.vm.provider :linode do |provider| + provider.label = rbd_mirror.vm.hostname + end + end + end + + (0..NISCSI_GWS - 1).each do |i| + config.vm.define "#{LABEL_PREFIX}iscsi_gw#{i}" do |iscsi_gw| + iscsi_gw.vm.box = BOX + iscsi_gw.vm.box_url = BOX_URL + iscsi_gw.vm.hostname = "#{LABEL_PREFIX}ceph-iscsi-gw#{i}" + if ASSIGN_STATIC_IP + iscsi_gw.vm.network :private_network, + ip: "#{PUBLIC_SUBNET}.9#{i}" + end + # Virtualbox + iscsi_gw.vm.provider :virtualbox do |vb| + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + iscsi_gw.vm.provider :vmware_fusion do |v| + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + iscsi_gw.vm.provider :libvirt do |lv| + lv.memory = MEMORY + lv.random_hostname = true + end + # Parallels + iscsi_gw.vm.provider "parallels" do |prl| + prl.name = "ceph-iscsi-gw#{i}" + prl.memory = "#{MEMORY}" + end + + iscsi_gw.vm.provider :linode do |provider| + provider.label = iscsi_gw.vm.hostname + end + end + end + + (0..NMONS - 1).each do |i| + config.vm.define "#{LABEL_PREFIX}mon#{i}" do |mon| + mon.vm.box = BOX + mon.vm.box_url = BOX_URL + mon.vm.hostname = "#{LABEL_PREFIX}ceph-mon#{i}" + if ASSIGN_STATIC_IP + mon.vm.network :private_network, + ip: "#{PUBLIC_SUBNET}.1#{i}" + end + # Virtualbox + mon.vm.provider :virtualbox do |vb| + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + mon.vm.provider :vmware_fusion do |v| + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + mon.vm.provider :libvirt do |lv| + lv.memory = MEMORY + lv.random_hostname = true + end + + # Parallels + mon.vm.provider "parallels" do |prl| + prl.name = "ceph-mon#{i}" + prl.memory = "#{MEMORY}" + end + + mon.vm.provider :linode do |provider| + provider.label = mon.vm.hostname + end + end + end + + (0..NOSDS - 1).each do |i| + config.vm.define "#{LABEL_PREFIX}osd#{i}" do |osd| + osd.vm.box = BOX + osd.vm.box_url = BOX_URL + osd.vm.hostname = "#{LABEL_PREFIX}ceph-osd#{i}" + if ASSIGN_STATIC_IP + osd.vm.network :private_network, + ip: "#{PUBLIC_SUBNET}.10#{i}" + osd.vm.network :private_network, + ip: "#{CLUSTER_SUBNET}.20#{i}" + end + # Virtualbox + osd.vm.provider :virtualbox do |vb| + # Create our own controller for consistency and to remove VM dependency + # but only do it once, otherwise it would fail when rebooting machines. + # We assume this has run if one disk was created before + unless File.exist?("disk-#{i}-0.vdi") + vb.customize ['storagectl', :id, + '--name', 'OSD Controller', + '--add', 'scsi'] + end + (0..2).each do |d| + vb.customize ['createhd', + '--filename', "disk-#{i}-#{d}", + '--size', '11000'] unless File.exist?("disk-#{i}-#{d}.vdi") + vb.customize ['storageattach', :id, + '--storagectl', 'OSD Controller', + '--port', 3 + d, + '--device', 0, + '--type', 'hdd', + '--medium', "disk-#{i}-#{d}.vdi"] + end + vb.customize ['modifyvm', :id, '--memory', "#{MEMORY}"] + end + + # VMware + osd.vm.provider :vmware_fusion do |v| + (0..1).each do |d| + v.vmx["scsi0:#{d + 1}.present"] = 'TRUE' + v.vmx["scsi0:#{d + 1}.fileName"] = + create_vmdk("disk-#{i}-#{d}", '11000MB') + end + v.vmx['memsize'] = "#{MEMORY}" + end + + # Libvirt + driverletters = ('a'..'z').to_a + osd.vm.provider :libvirt do |lv| + # always make /dev/sd{a/b/c/d} so that CI can ensure that + # virtualbox and libvirt will have the same devices to use for OSDs + (0..3).each do |d| + lv.storage :file, :device => "hd#{driverletters[d]}", :path => "disk-#{i}-#{d}-#{DISK_UUID}.disk", :size => '12G', :bus => "ide" + end + lv.memory = MEMORY + lv.random_hostname = true + end + + # Parallels + osd.vm.provider "parallels" do |prl| + prl.name = "ceph-osd#{i}" + prl.memory = "#{MEMORY}" + (0..1).each do |d| + prl.customize ["set", :id, + "--device-add", + "hdd", + "--iface", + "sata"] + end + end + + osd.vm.provider :linode do |provider| + provider.label = osd.vm.hostname + end + + end + end +end diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/Vagrantfile b/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/Vagrantfile new file mode 120000 index 000000000..2572fa2c9 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/Vagrantfile @@ -0,0 +1 @@ +../../Vagrantfile \ No newline at end of file diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/group_vars/all b/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/group_vars/all new file mode 100644 index 000000000..971c63d40 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/group_vars/all @@ -0,0 +1,21 @@ +--- + +ceph_dev: True +cluster: ceph +public_network: "192.168.3.0/24" +cluster_network: "192.168.4.0/24" +monitor_interface: eth1 +journal_size: 100 +osd_objectstore: "filestore" +osd_scenario: lvm +copy_admin_key: true +# test-volume is created by tests/functional/lvm_setup.yml from /dev/sda +lvm_volumes: + test_volume: /dev/sdc +os_tuning_params: + - { name: kernel.pid_max, value: 4194303 } + - { name: fs.file-max, value: 26234859 } +ceph_conf_overrides: + global: + osd_pool_default_pg_num: 8 + osd_pool_default_size: 1 diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/hosts b/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/hosts new file mode 100644 index 000000000..f6a265ab3 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/hosts @@ -0,0 +1,5 @@ +[mons] +mon0 + +[osds] +osd0 diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/vagrant_variables.yml b/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/vagrant_variables.yml new file mode 100644 index 000000000..7d1a4449a --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/centos7/create/vagrant_variables.yml @@ -0,0 +1,56 @@ +--- + +# DEFINE THE NUMBER OF VMS TO RUN +mon_vms: 1 +osd_vms: 1 +mds_vms: 0 +rgw_vms: 0 +nfs_vms: 0 +rbd_mirror_vms: 0 +client_vms: 0 +iscsi_gw_vms: 0 +mgr_vms: 0 + +# SUBNETS TO USE FOR THE VMS +public_subnet: 192.168.3 +cluster_subnet: 192.168.4 + +# MEMORY +# set 1024 for CentOS +memory: 512 + +# Ethernet interface name +# use eth1 for libvirt and ubuntu precise, enp0s8 for CentOS and ubuntu xenial +eth: 'eth1' + + +# VAGRANT BOX +# Ceph boxes are *strongly* suggested. They are under better control and will +# not get updated frequently unless required for build systems. These are (for +# now): +# +# * ceph/ubuntu-xenial +# +# Ubuntu: ceph/ubuntu-xenial bento/ubuntu-16.04 or ubuntu/trusty64 or ubuntu/wily64 +# CentOS: bento/centos-7.1 or puppetlabs/centos-7.0-64-puppet +# libvirt CentOS: centos/7 +# parallels Ubuntu: parallels/ubuntu-14.04 +# Debian: deb/jessie-amd64 - be careful the storage controller is named 'SATA Controller' +# For more boxes have a look at: +# - https://atlas.hashicorp.com/boxes/search?utf8=✓&sort=&provider=virtualbox&q= +# - https://download.gluster.org/pub/gluster/purpleidea/vagrant/ +vagrant_box: centos/7 +#ssh_private_key_path: "~/.ssh/id_rsa" +# The sync directory changes based on vagrant box +# Set to /home/vagrant/sync for Centos/7, /home/{ user }/vagrant for openstack and defaults to /vagrant +#vagrant_sync_dir: /home/vagrant/sync +#vagrant_sync_dir: / +# Disables synced folder creation. Not needed for testing, will skip mounting +# the vagrant directory on the remote box regardless of the provider. +vagrant_disable_synced_folder: true +# VAGRANT URL +# This is a URL to download an image from an alternate location. vagrant_box +# above should be set to the filename of the image. +# Fedora virtualbox: https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Base-Vagrant-22-20150521.x86_64.vagrant-virtualbox.box +# Fedora libvirt: https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Base-Vagrant-22-20150521.x86_64.vagrant-libvirt.box +# vagrant_box_url: https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Base-Vagrant-22-20150521.x86_64.vagrant-virtualbox.box diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/generate_ssh_config.sh b/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/generate_ssh_config.sh new file mode 100644 index 000000000..43e64a654 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/scripts/generate_ssh_config.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Generate a custom ssh config from Vagrant so that it can then be used by +# ansible.cfg + +path=$1 + +if [ $# -eq 0 ] + then + echo "A path to the scenario is required as an argument and it wasn't provided" + exit 1 +fi + +cd "$path" +vagrant ssh-config > vagrant_ssh_config diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/tox.ini b/ceph/src/ceph-volume/ceph_volume/tests/functional/tox.ini new file mode 100644 index 000000000..6fe16a51e --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/tox.ini @@ -0,0 +1,52 @@ +[tox] +envlist = {centos7,xenial}-{create,prepare_activate} +skipsdist = True + +[testenv] +whitelist_externals = + vagrant + bash + git +passenv=* +setenv= + ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config + ANSIBLE_STDOUT_CALLBACK = debug + ANSIBLE_RETRY_FILES_ENABLED = False + VAGRANT_CWD = {changedir} + CEPH_VOLUME_DEBUG = 1 +deps= + ansible==2.2.3 + testinfra==1.6.0 + pytest-xdist +changedir= + centos7-create: {toxinidir}/centos7/create + xenial-create: {toxinidir}/xenial/create + # TODO: these are placeholders for now, eventually we want to + # test the prepare/activate workflow of ceph-volume as well + xenial-prepare_activate: {toxinidir}/xenial/prepare_activate + centos7-prepare_activate: {toxinidir}/xenial/prepare_activate +commands= + git clone -b {env:CEPH_ANSIBLE_BRANCH:master} --single-branch https://github.com/ceph/ceph-ansible.git {envdir}/tmp/ceph-ansible + + vagrant up --no-provision {posargs:--provider=virtualbox} + bash {toxinidir}/scripts/generate_ssh_config.sh {changedir} + + # create logical volumes to test with on the vms + ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/lvm_setup.yml + + # use ceph-ansible to deploy a ceph cluster on the vms + ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/site.yml.sample --extra-vars "fetch_directory={changedir}/fetch ceph_dev_branch={env:CEPH_DEV_BRANCH:master} ceph_dev_sha1={env:CEPH_DEV_SHA1:latest}" + + # prepare nodes for testing with testinfra + ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/setup.yml + + # test cluster state using ceph-ansible tests + testinfra -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/tests + + # reboot all vms + vagrant reload --no-provision + + # retest to ensure cluster came back up correctly after rebooting + testinfra -n 4 --sudo -v --connection=ansible --ansible-inventory={changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/tests + + vagrant destroy --force diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/Vagrantfile b/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/Vagrantfile new file mode 120000 index 000000000..2572fa2c9 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/Vagrantfile @@ -0,0 +1 @@ +../../Vagrantfile \ No newline at end of file diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/group_vars/all b/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/group_vars/all new file mode 100644 index 000000000..971c63d40 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/group_vars/all @@ -0,0 +1,21 @@ +--- + +ceph_dev: True +cluster: ceph +public_network: "192.168.3.0/24" +cluster_network: "192.168.4.0/24" +monitor_interface: eth1 +journal_size: 100 +osd_objectstore: "filestore" +osd_scenario: lvm +copy_admin_key: true +# test-volume is created by tests/functional/lvm_setup.yml from /dev/sda +lvm_volumes: + test_volume: /dev/sdc +os_tuning_params: + - { name: kernel.pid_max, value: 4194303 } + - { name: fs.file-max, value: 26234859 } +ceph_conf_overrides: + global: + osd_pool_default_pg_num: 8 + osd_pool_default_size: 1 diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/hosts b/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/hosts new file mode 100644 index 000000000..f6a265ab3 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/hosts @@ -0,0 +1,5 @@ +[mons] +mon0 + +[osds] +osd0 diff --git a/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/vagrant_variables.yml b/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/vagrant_variables.yml new file mode 100644 index 000000000..82b330ef9 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/functional/xenial/create/vagrant_variables.yml @@ -0,0 +1,54 @@ +--- +# DEFINE THE NUMBER OF VMS TO RUN +mon_vms: 1 +osd_vms: 1 +mds_vms: 0 +rgw_vms: 0 +nfs_vms: 0 +rbd_mirror_vms: 0 +client_vms: 0 +iscsi_gw_vms: 0 +mgr_vms: 0 + +# SUBNETS TO USE FOR THE VMS +public_subnet: 192.168.3 +cluster_subnet: 192.168.4 + +# MEMORY +# set 1024 for CentOS +memory: 512 + +# Ethernet interface name +# use eth1 for libvirt and ubuntu precise, enp0s8 for CentOS and ubuntu xenial +eth: 'eth1' + +# VAGRANT BOX +# Ceph boxes are *strongly* suggested. They are under better control and will +# not get updated frequently unless required for build systems. These are (for +# now): +# +# * ceph/ubuntu-xenial +# +# Ubuntu: ceph/ubuntu-xenial bento/ubuntu-16.04 or ubuntu/trusty64 or ubuntu/wily64 +# CentOS: bento/centos-7.1 or puppetlabs/centos-7.0-64-puppet +# libvirt CentOS: centos/7 +# parallels Ubuntu: parallels/ubuntu-14.04 +# Debian: deb/jessie-amd64 - be careful the storage controller is named 'SATA Controller' +# For more boxes have a look at: +# - https://atlas.hashicorp.com/boxes/search?utf8=✓&sort=&provider=virtualbox&q= +# - https://download.gluster.org/pub/gluster/purpleidea/vagrant/ +vagrant_box: ceph/ubuntu-xenial +#ssh_private_key_path: "~/.ssh/id_rsa" +# The sync directory changes based on vagrant box +# Set to /home/vagrant/sync for Centos/7, /home/{ user }/vagrant for openstack and defaults to /vagrant +#vagrant_sync_dir: /home/vagrant/sync +#vagrant_sync_dir: / +# Disables synced folder creation. Not needed for testing, will skip mounting +# the vagrant directory on the remote box regardless of the provider. +vagrant_disable_synced_folder: true +# VAGRANT URL +# This is a URL to download an image from an alternate location. vagrant_box +# above should be set to the filename of the image. +# Fedora virtualbox: https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Base-Vagrant-22-20150521.x86_64.vagrant-virtualbox.box +# Fedora libvirt: https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Base-Vagrant-22-20150521.x86_64.vagrant-libvirt.box +# vagrant_box_url: https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Base-Vagrant-22-20150521.x86_64.vagrant-virtualbox.box diff --git a/ceph/src/ceph-volume/ceph_volume/tests/systemd/test_main.py b/ceph/src/ceph-volume/ceph_volume/tests/systemd/test_main.py new file mode 100644 index 000000000..86a685ab5 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/systemd/test_main.py @@ -0,0 +1,51 @@ +import pytest +from ceph_volume import exceptions, conf +from ceph_volume.systemd import main + + +class TestParseSubcommand(object): + + def test_no_subcommand_found(self): + with pytest.raises(exceptions.SuffixParsingError): + main.parse_subcommand('') + + def test_sub_command_is_found(self): + result = main.parse_subcommand('lvm-1-sha-1-something-0') + assert result == 'lvm' + + +class Capture(object): + + def __init__(self, *a, **kw): + self.a = a + self.kw = kw + self.calls = [] + + def __call__(self, *a, **kw): + self.calls.append(a) + self.calls.append(kw) + + +class TestMain(object): + + def setup(self): + conf.log_path = '/tmp/' + + def test_no_arguments_parsing_error(self): + with pytest.raises(RuntimeError): + main.main(args=[]) + + def test_parsing_suffix_error(self): + with pytest.raises(exceptions.SuffixParsingError): + main.main(args=['asdf']) + + def test_correct_command(self, monkeypatch): + run = Capture() + monkeypatch.setattr(main.process, 'run', run) + main.main(args=['ceph-volume-systemd', 'lvm-8715BEB4-15C5-49DE-BA6F-401086EC7B41-0' ]) + command = run.calls[0][0] + assert command == [ + 'ceph-volume', + 'lvm', 'trigger', + '8715BEB4-15C5-49DE-BA6F-401086EC7B41-0' + ] diff --git a/ceph/src/ceph-volume/ceph_volume/tests/test_configuration.py b/ceph/src/ceph-volume/ceph_volume/tests/test_configuration.py new file mode 100644 index 000000000..5ef7fae47 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/test_configuration.py @@ -0,0 +1,79 @@ +import os +try: + from cStringIO import StringIO +except ImportError: # pragma: no cover + from io import StringIO # pragma: no cover +from textwrap import dedent +import pytest +from ceph_volume import configuration, exceptions + + +class TestConf(object): + + def setup(self): + self.conf_file = StringIO(dedent(""" + [foo] + default = 0 + """)) + + def test_get_non_existing_list(self): + cfg = configuration.Conf() + cfg.is_valid = lambda: True + cfg.readfp(self.conf_file) + assert cfg.get_list('global', 'key') == [] + + def test_get_non_existing_list_get_default(self): + cfg = configuration.Conf() + cfg.is_valid = lambda: True + cfg.readfp(self.conf_file) + assert cfg.get_list('global', 'key', ['a']) == ['a'] + + def test_get_rid_of_comments(self): + cfg = configuration.Conf() + cfg.is_valid = lambda: True + conf_file = StringIO(dedent(""" + [foo] + default = 0 # this is a comment + """)) + + cfg.readfp(conf_file) + assert cfg.get_list('foo', 'default') == ['0'] + + def test_gets_split_on_commas(self): + cfg = configuration.Conf() + cfg.is_valid = lambda: True + conf_file = StringIO(dedent(""" + [foo] + default = 0,1,2,3 # this is a comment + """)) + + cfg.readfp(conf_file) + assert cfg.get_list('foo', 'default') == ['0', '1', '2', '3'] + + def test_spaces_and_tabs_are_ignored(self): + cfg = configuration.Conf() + cfg.is_valid = lambda: True + conf_file = StringIO(dedent(""" + [foo] + default = 0, 1, 2 ,3 # this is a comment + """)) + + cfg.readfp(conf_file) + assert cfg.get_list('foo', 'default') == ['0', '1', '2', '3'] + + +class TestLoad(object): + + def test_path_does_not_exist(self): + with pytest.raises(exceptions.ConfigurationError): + conf = configuration.load('/path/does/not/exist/ceph.con') + conf.is_valid() + + def test_unable_to_read_configuration(self, tmpdir, capsys): + ceph_conf = os.path.join(str(tmpdir), 'ceph.conf') + with open(ceph_conf, 'w') as config: + config.write(']broken] config\n[[') + configuration.load(ceph_conf) + stdout, stderr = capsys.readouterr() + assert 'Unable to read configuration file' in stdout + assert 'File contains no section headers' in stdout diff --git a/ceph/src/ceph-volume/ceph_volume/tests/test_decorators.py b/ceph/src/ceph-volume/ceph_volume/tests/test_decorators.py new file mode 100644 index 000000000..8df891456 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/test_decorators.py @@ -0,0 +1,71 @@ +import os +import pytest +from ceph_volume import exceptions, decorators, terminal + + +class TestNeedsRoot(object): + + def test_is_root(self, monkeypatch): + def func(): + return True + monkeypatch.setattr(decorators.os, 'getuid', lambda: 0) + assert decorators.needs_root(func)() is True + + def test_is_not_root(self, monkeypatch): + def func(): + return True # pragma: no cover + monkeypatch.setattr(decorators.os, 'getuid', lambda: 20) + with pytest.raises(exceptions.SuperUserError) as error: + decorators.needs_root(func)() + + msg = 'This command needs to be executed with sudo or as root' + assert str(error.value) == msg + + +class TestExceptionMessage(object): + + def test_has_str_method(self): + result = decorators.make_exception_message(RuntimeError('an error')) + expected = "%s %s\n" % (terminal.red_arrow, 'RuntimeError: an error') + assert result == expected + + def test_has_no_str_method(self): + class Error(Exception): + pass + result = decorators.make_exception_message(Error()) + expected = "%s %s\n" % (terminal.red_arrow, 'Error') + assert result == expected + + +class TestCatches(object): + + def teardown(self): + try: + del(os.environ['CEPH_VOLUME_DEBUG']) + except KeyError: + pass + + def test_ceph_volume_debug_enabled(self): + os.environ['CEPH_VOLUME_DEBUG'] = '1' + @decorators.catches() # noqa + def func(): + raise RuntimeError() + with pytest.raises(RuntimeError): + func() + + def test_ceph_volume_debug_disabled_no_exit(self, capsys): + @decorators.catches(exit=False) + def func(): + raise RuntimeError() + func() + stdout, stderr = capsys.readouterr() + assert 'RuntimeError\n' in stderr + + def test_ceph_volume_debug_exits(self, capsys): + @decorators.catches() + def func(): + raise RuntimeError() + with pytest.raises(SystemExit): + func() + stdout, stderr = capsys.readouterr() + assert 'RuntimeError\n' in stderr diff --git a/ceph/src/ceph-volume/ceph_volume/tests/test_main.py b/ceph/src/ceph-volume/ceph_volume/tests/test_main.py new file mode 100644 index 000000000..c61729464 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/test_main.py @@ -0,0 +1,30 @@ +import os +import pytest +from ceph_volume import main + + +class TestVolume(object): + + def test_main_spits_help_with_no_arguments(self, capsys): + main.Volume(argv=[]) + stdout, stderr = capsys.readouterr() + assert 'Log Path' in stdout + + def test_warn_about_using_help_for_full_options(self, capsys): + main.Volume(argv=[]) + stdout, stderr = capsys.readouterr() + assert 'See "ceph-volume --help" for full list' in stdout + + def test_environ_vars_show_up(self, capsys): + os.environ['CEPH_CONF'] = '/opt/ceph.conf' + main.Volume(argv=[]) + stdout, stderr = capsys.readouterr() + assert 'CEPH_CONF' in stdout + assert '/opt/ceph.conf' in stdout + + def test_flags_are_parsed_with_help(self, capsys): + with pytest.raises(SystemExit): + main.Volume(argv=['ceph-volume', '--help']) + stdout, stderr = capsys.readouterr() + assert '--cluster' in stdout + assert '--log-path' in stdout diff --git a/ceph/src/ceph-volume/ceph_volume/tests/test_terminal.py b/ceph/src/ceph-volume/ceph_volume/tests/test_terminal.py new file mode 100644 index 000000000..9435dbb26 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/test_terminal.py @@ -0,0 +1,68 @@ +import pytest +from ceph_volume import terminal + + +class SubCommand(object): + + help = "this is the subcommand help" + + def __init__(self, argv): + self.argv = argv + + def main(self): + pass + + +class BadSubCommand(object): + + def __init__(self, argv): + self.argv = argv + + def main(self): + raise SystemExit(100) + + +class TestSubhelp(object): + + def test_no_sub_command_help(self): + assert terminal.subhelp({}) == '' + + def test_single_level_help(self): + result = terminal.subhelp({'sub': SubCommand}) + + assert 'this is the subcommand help' in result + + def test_has_title_header(self): + result = terminal.subhelp({'sub': SubCommand}) + assert 'Available subcommands:' in result + + def test_command_with_no_help(self): + class SubCommandNoHelp(object): + pass + result = terminal.subhelp({'sub': SubCommandNoHelp}) + assert result == '' + + +class TestDispatch(object): + + def test_no_subcommand_found(self): + result = terminal.dispatch({'sub': SubCommand}, argv=[]) + assert result is None + + def test_no_main_found(self): + class NoMain(object): + + def __init__(self, argv): + pass + result = terminal.dispatch({'sub': NoMain}, argv=['sub']) + assert result is None + + def test_subcommand_found_and_dispatched(self): + with pytest.raises(SystemExit) as error: + terminal.dispatch({'sub': SubCommand}, argv=['sub']) + assert str(error.value) == '0' + + def test_subcommand_found_and_dispatched_with_errors(self): + with pytest.raises(SystemExit) as error: + terminal.dispatch({'sub': BadSubCommand}, argv=['sub']) + assert str(error.value) == '100' diff --git a/ceph/src/ceph-volume/ceph_volume/tests/util/test_system.py b/ceph/src/ceph-volume/ceph_volume/tests/util/test_system.py new file mode 100644 index 000000000..7cb6a1f14 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/tests/util/test_system.py @@ -0,0 +1,89 @@ +import os +import pwd +import getpass +from textwrap import dedent +from ceph_volume.util import system + + +class TestMkdirP(object): + + def test_existing_dir_does_not_raise_w_chown(self, monkeypatch, tmpdir): + user = pwd.getpwnam(getpass.getuser()) + uid, gid = user[2], user[3] + monkeypatch.setattr(system, 'get_ceph_user_ids', lambda: (uid, gid,)) + path = str(tmpdir) + system.mkdir_p(path) + assert os.path.isdir(path) + + def test_new_dir_w_chown(self, monkeypatch, tmpdir): + user = pwd.getpwnam(getpass.getuser()) + uid, gid = user[2], user[3] + monkeypatch.setattr(system, 'get_ceph_user_ids', lambda: (uid, gid,)) + path = os.path.join(str(tmpdir), 'new') + system.mkdir_p(path) + assert os.path.isdir(path) + + def test_existing_dir_does_not_raise_no_chown(self, tmpdir): + path = str(tmpdir) + system.mkdir_p(path, chown=False) + assert os.path.isdir(path) + + def test_new_dir_no_chown(self, tmpdir): + path = os.path.join(str(tmpdir), 'new') + system.mkdir_p(path, chown=False) + assert os.path.isdir(path) + + +class TestIsMounted(object): + + def test_not_mounted(self, tmpdir, monkeypatch): + PROCDIR = str(tmpdir) + proc_path = os.path.join(PROCDIR, 'mounts') + with open(proc_path, 'w') as f: + f.write('') + monkeypatch.setattr(system, 'PROCDIR', PROCDIR) + assert system.is_mounted('sdb') is False + + def test_is_mounted_(self, tmpdir, monkeypatch): + PROCDIR = str(tmpdir) + proc_path = os.path.join(PROCDIR, 'mounts') + with open(proc_path, 'w') as f: + f.write(dedent("""nfsd /proc/fs/nfsd nfsd rw,relatime 0 0 + /dev/sdc2 /boot xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0 + tmpfs /run/user/1000 tmpfs rw,seclabel,mode=700,uid=1000,gid=1000 0 0""")) + monkeypatch.setattr(system, 'PROCDIR', PROCDIR) + monkeypatch.setattr(os.path, 'exists', lambda x: True) + assert system.is_mounted('/dev/sdc2') is True + + def test_ignores_two_fields(self, tmpdir, monkeypatch): + PROCDIR = str(tmpdir) + proc_path = os.path.join(PROCDIR, 'mounts') + with open(proc_path, 'w') as f: + f.write(dedent("""nfsd /proc/fs/nfsd nfsd rw,relatime 0 0 + /dev/sdc2 /boot + tmpfs /run/user/1000 tmpfs rw,seclabel,mode=700,uid=1000,gid=1000 0 0""")) + monkeypatch.setattr(system, 'PROCDIR', PROCDIR) + monkeypatch.setattr(os.path, 'exists', lambda x: True) + assert system.is_mounted('/dev/sdc2') is False + + def test_not_mounted_at_destination(self, tmpdir, monkeypatch): + PROCDIR = str(tmpdir) + proc_path = os.path.join(PROCDIR, 'mounts') + with open(proc_path, 'w') as f: + f.write(dedent("""nfsd /proc/fs/nfsd nfsd rw,relatime 0 0 + /dev/sdc2 /var/lib/ceph/osd/ceph-9 xfs rw,attr2,inode64,noquota 0 0 + tmpfs /run/user/1000 tmpfs rw,seclabel,mode=700,uid=1000,gid=1000 0 0""")) + monkeypatch.setattr(system, 'PROCDIR', PROCDIR) + monkeypatch.setattr(os.path, 'exists', lambda x: True) + assert system.is_mounted('/dev/sdc2', '/var/lib/ceph/osd/ceph-0') is False + + def test_is_mounted_at_destination(self, tmpdir, monkeypatch): + PROCDIR = str(tmpdir) + proc_path = os.path.join(PROCDIR, 'mounts') + with open(proc_path, 'w') as f: + f.write(dedent("""nfsd /proc/fs/nfsd nfsd rw,relatime 0 0 + /dev/sdc2 /var/lib/ceph/osd/ceph-0 xfs rw,attr2,inode64,noquota 0 0 + tmpfs /run/user/1000 tmpfs rw,seclabel,mode=700,uid=1000,gid=1000 0 0""")) + monkeypatch.setattr(system, 'PROCDIR', PROCDIR) + monkeypatch.setattr(os.path, 'exists', lambda x: True) + assert system.is_mounted('/dev/sdc2', '/var/lib/ceph/osd/ceph-0') is True diff --git a/ceph/src/ceph-volume/ceph_volume/util/__init__.py b/ceph/src/ceph-volume/ceph_volume/util/__init__.py new file mode 100644 index 000000000..3b8c30906 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/util/__init__.py @@ -0,0 +1,10 @@ + +def as_string(string): + """ + Ensure that whatever type of string is incoming, it is returned as an + actual string, versus 'bytes' which Python 3 likes to use. + """ + if isinstance(string, bytes): + # we really ignore here if we can't properly decode with utf-8 + return string.decode('utf-8', 'ignore') + return string diff --git a/ceph/src/ceph-volume/ceph_volume/util/constants.py b/ceph/src/ceph-volume/ceph_volume/util/constants.py new file mode 100644 index 000000000..07df5a4f3 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/util/constants.py @@ -0,0 +1,17 @@ + +# mount flags +mount = dict( + xfs='noatime,inode64', +) + + +# format flags +mkfs = dict( + xfs=[ + # force overwriting previous fs + '-f', + # set the inode size to 2kb + '-i', 'size=2048', + ], +) + diff --git a/ceph/src/ceph-volume/ceph_volume/util/prepare.py b/ceph/src/ceph-volume/ceph_volume/util/prepare.py new file mode 100644 index 000000000..eefa0adc2 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/util/prepare.py @@ -0,0 +1,165 @@ +""" +These utilities for prepare provide all the pieces needed to prepare a device +but also a compounded ("single call") helper to do them in order. Some plugins +may want to change some part of the process, while others might want to consume +the single-call helper +""" +import os +import logging +from ceph_volume import process, conf +from ceph_volume.util import system, constants + +logger = logging.getLogger(__name__) + + +def create_key(): + stdout, stderr, returncode = process.call(['ceph-authtool', '--gen-print-key']) + if returncode != 0: + raise RuntimeError('Unable to generate a new auth key') + return ' '.join(stdout).strip() + + +def write_keyring(osd_id, secret): + # FIXME this only works for cephx, but there will be other types of secrets + # later + osd_keyring = '/var/lib/ceph/osd/%s-%s/keyring' % (conf.cluster, osd_id) + process.run( + [ + 'ceph-authtool', osd_keyring, + '--create-keyring', + '--name', 'osd.%s' % str(osd_id), + '--add-key', secret + ]) + system.chown(osd_keyring) + # TODO: do the restorecon dance on the osd_keyring path + + +def create_id(fsid, json_secrets): + """ + :param fsid: The osd fsid to create, always required + :param json_secrets: a json-ready object with whatever secrets are wanted + to be passed to the monitor + """ + bootstrap_keyring = '/var/lib/ceph/bootstrap-osd/%s.keyring' % conf.cluster + stdout, stderr, returncode = process.call( + [ + 'ceph', + '--cluster', conf.cluster, + '--name', 'client.bootstrap-osd', + '--keyring', bootstrap_keyring, + '-i', '-', + 'osd', 'new', fsid + ], + stdin=json_secrets + ) + if returncode != 0: + raise RuntimeError('Unable to create a new OSD id') + return ' '.join(stdout).strip() + + +def create_path(osd_id): + system.mkdir_p('/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id)) + + +def format_device(device): + # only supports xfs + command = ['sudo', 'mkfs', '-t', 'xfs'] + + # get the mkfs options if any for xfs, + # fallback to the default options defined in constants.mkfs + flags = conf.ceph.get_list( + 'osd', + 'osd_mkfs_options_xfs', + default=constants.mkfs.get('xfs'), + split=' ', + ) + + # always force + if '-f' not in flags: + flags.insert(0, '-f') + + command.extend(flags) + command.append(device) + process.run(command) + + +def mount_osd(device, osd_id): + destination = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id) + command = ['sudo', 'mount', '-t', 'xfs', '-o'] + flags = conf.ceph.get_list( + 'osd', + 'osd_mount_options_xfs', + default=constants.mount.get('xfs'), + split=' ', + ) + command.append(flags) + command.append(device) + command.append(destination) + process.run(command) + + +def link_journal(journal_device, osd_id): + journal_path = '/var/lib/ceph/osd/%s-%s/journal' % ( + conf.cluster, + osd_id + ) + command = ['sudo', 'ln', '-s', journal_device, journal_path] + process.run(command) + + +def get_monmap(osd_id): + """ + Before creating the OSD files, a monmap needs to be retrieved so that it + can be used to tell the monitor(s) about the new OSD. A call will look like:: + + ceph --cluster ceph --name client.bootstrap-osd \ + --keyring /var/lib/ceph/bootstrap-osd/ceph.keyring \ + mon getmap -o /var/lib/ceph/osd/ceph-0/activate.monmap + """ + path = '/var/lib/ceph/osd/%s-%s/' % (conf.cluster, osd_id) + bootstrap_keyring = '/var/lib/ceph/bootstrap-osd/%s.keyring' % conf.cluster + monmap_destination = os.path.join(path, 'activate.monmap') + + process.run([ + 'sudo', + 'ceph', + '--cluster', conf.cluster, + '--name', 'client.bootstrap-osd', + '--keyring', bootstrap_keyring, + 'mon', 'getmap', '-o', monmap_destination + ]) + + +def osd_mkfs(osd_id, fsid): + """ + Create the files for the OSD to function. A normal call will look like: + + ceph-osd --cluster ceph --mkfs --mkkey -i 0 \ + --monmap /var/lib/ceph/osd/ceph-0/activate.monmap \ + --osd-data /var/lib/ceph/osd/ceph-0 \ + --osd-journal /var/lib/ceph/osd/ceph-0/journal \ + --osd-uuid 8d208665-89ae-4733-8888-5d3bfbeeec6c \ + --keyring /var/lib/ceph/osd/ceph-0/keyring \ + --setuser ceph --setgroup ceph + + """ + path = '/var/lib/ceph/osd/%s-%s/' % (conf.cluster, osd_id) + monmap = os.path.join(path, 'activate.monmap') + journal = os.path.join(path, 'journal') + + system.chown(journal) + system.chown(path) + + process.run([ + 'sudo', + 'ceph-osd', + '--cluster', conf.cluster, + '--mkfs', + '-i', osd_id, + '--monmap', monmap, + '--osd-data', path, + '--osd-journal', journal, + '--osd-uuid', fsid, + '--setuser', 'ceph', + '--setgroup', 'ceph' + ]) diff --git a/ceph/src/ceph-volume/ceph_volume/util/system.py b/ceph/src/ceph-volume/ceph_volume/util/system.py new file mode 100644 index 000000000..084a0e0d3 --- /dev/null +++ b/ceph/src/ceph-volume/ceph_volume/util/system.py @@ -0,0 +1,104 @@ +import errno +import os +import pwd +import platform +import uuid +from ceph_volume import process +from . import as_string + + +# TODO: get these out of here and into a common area for others to consume +if platform.system() == 'FreeBSD': + FREEBSD = True + DEFAULT_FS_TYPE = 'zfs' + PROCDIR = '/compat/linux/proc' + # FreeBSD does not have blockdevices any more + BLOCKDIR = '/dev' + ROOTGROUP = 'wheel' +else: + FREEBSD = False + DEFAULT_FS_TYPE = 'xfs' + PROCDIR = '/proc' + BLOCKDIR = '/sys/block' + ROOTGROUP = 'root' + + +def generate_uuid(): + return str(uuid.uuid4()) + + +def get_ceph_user_ids(): + """ + Return the id and gid of the ceph user + """ + try: + user = pwd.getpwnam('ceph') + except KeyError: + # is this even possible? + raise RuntimeError('"ceph" user is not available in the current system') + return user[2], user[3] + + +def mkdir_p(path, chown=True): + """ + A `mkdir -p` that defaults to chown the path to the ceph user + """ + try: + os.mkdir(path) + except OSError as e: + if e.errno == errno.EEXIST: + pass + else: + raise + if chown: + uid, gid = get_ceph_user_ids() + os.chown(path, uid, gid) + + +def chown(path, recursive=True): + """ + ``chown`` a path to the ceph user (uid and guid fetched at runtime) + """ + uid, gid = get_ceph_user_ids() + if os.path.islink(path): + path = os.path.realpath(path) + if recursive: + process.run(['chown', '-R', 'ceph:ceph', path]) + else: + os.chown(path, uid, gid) + + +def is_mounted(source, destination=None): + """ + Check if the given device is mounted, optionally validating destination. + This relies on absolute path devices, it will ignore non-absolute + entries like:: + + tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0 + + But will parse paths that are absolute like:: + + /dev/sdc2 /boot xfs rw,attr2,inode64,noquota 0 0 + + When destination is passed in, it will check that the entry where the + source appears is mounted to where destination defines. This is useful so + that an error message can report that a source is not mounted at an + expected destination. + """ + dev = os.path.realpath(source) + with open(PROCDIR + '/mounts', 'rb') as proc_mounts: + for line in proc_mounts: + fields = line.split() + if len(fields) < 3: + continue + mounted_device = fields[0] + mounted_path = fields[1] + if os.path.isabs(mounted_device) and os.path.exists(mounted_device): + mounted_device = os.path.realpath(mounted_device) + if as_string(mounted_device) == dev: + if destination: + destination = os.path.realpath(destination) + return destination == as_string(os.path.realpath(mounted_path)) + else: + return True + return False diff --git a/ceph/src/ceph-volume/setup.py b/ceph/src/ceph-volume/setup.py new file mode 100644 index 000000000..cfdb1e1a9 --- /dev/null +++ b/ceph/src/ceph-volume/setup.py @@ -0,0 +1,33 @@ +from setuptools import setup, find_packages + + +setup( + name='ceph-volume', + version='1.0.0', + packages=find_packages(), + + author='', + author_email='contact@redhat.com', + description='Deploy Ceph OSDs using different device technologies like lvm or physical disks', + license='LGPLv2+', + keywords='ceph volume disk devices lvm', + url="https://github.com/ceph/ceph", + zip_safe = False, + tests_require=[ + 'pytest >=2.1.3', + 'tox', + ], + scripts = ['bin/ceph-volume', 'bin/ceph-volume-systemd'], + classifiers = [ + 'Environment :: Console', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'Operating System :: POSIX :: Linux', + 'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + ] + +) diff --git a/ceph/src/ceph-volume/tox.ini b/ceph/src/ceph-volume/tox.ini new file mode 100644 index 000000000..514d208fa --- /dev/null +++ b/ceph/src/ceph-volume/tox.ini @@ -0,0 +1,14 @@ +[tox] +envlist = py27, py35, py36, flake8 + +[testenv] +deps= + pytest +commands=py.test -v {posargs:ceph_volume/tests} + +[testenv:flake8] +deps=flake8 +commands=flake8 --select=F,E9 {posargs:ceph_volume} + +[tool:pytest] +norecursedirs = .* _* virtualenv diff --git a/ceph/src/ceph.in b/ceph/src/ceph.in index e34c468a7..bb2516c78 100755 --- a/ceph/src/ceph.in +++ b/ceph/src/ceph.in @@ -355,6 +355,9 @@ def do_extended_help(parser, args, target, partial): partial=partial)) def help_for_target(target, partial=None): + # wait for osdmap because we know this is sent after the mgrmap + # and monmap (it's alphabetical). + cluster_handle.wait_for_latest_osdmap() ret, outbuf, outs = json_command(cluster_handle, target=target, prefix='get_command_descriptions', timeout=10) diff --git a/ceph/src/ceph_osd.cc b/ceph/src/ceph_osd.cc index f3d585b47..d7e54a3a3 100644 --- a/ceph/src/ceph_osd.cc +++ b/ceph/src/ceph_osd.cc @@ -246,6 +246,7 @@ int main(int argc, const char **argv) bl.read_fd(fd, 64); if (bl.length()) { store_type = string(bl.c_str(), bl.length() - 1); // drop \n + g_conf->set_val("osd_objectstore", store_type); dout(5) << "object store type is " << store_type << dendl; } ::close(fd); @@ -333,28 +334,28 @@ int main(int argc, const char **argv) } if (check_wants_journal) { if (store->wants_journal()) { - cout << "yes" << std::endl; + cout << "wants journal: yes" << std::endl; exit(0); } else { - cout << "no" << std::endl; + cout << "wants journal: no" << std::endl; exit(1); } } if (check_allows_journal) { if (store->allows_journal()) { - cout << "yes" << std::endl; + cout << "allows journal: yes" << std::endl; exit(0); } else { - cout << "no" << std::endl; + cout << "allows journal: no" << std::endl; exit(1); } } if (check_needs_journal) { if (store->needs_journal()) { - cout << "yes" << std::endl; + cout << "needs journal: yes" << std::endl; exit(0); } else { - cout << "no" << std::endl; + cout << "needs journal: no" << std::endl; exit(1); } } diff --git a/ceph/src/client/Client.cc b/ceph/src/client/Client.cc index 6b34e4a33..e461ab4a5 100644 --- a/ceph/src/client/Client.cc +++ b/ceph/src/client/Client.cc @@ -9430,7 +9430,13 @@ int Client::statfs(const char *path, struct statvfs *stbuf, ceph_statfs stats; C_SaferCond cond; - objecter->get_fs_stats(stats, &cond); + + const vector &data_pools = mdsmap->get_data_pools(); + if (data_pools.size() == 1) { + objecter->get_fs_stats(stats, data_pools[0], &cond); + } else { + objecter->get_fs_stats(stats, boost::optional(), &cond); + } client_lock.Unlock(); int rval = cond.wait(); @@ -9501,7 +9507,7 @@ int Client::statfs(const char *path, struct statvfs *stbuf, stbuf->f_bfree = free; stbuf->f_bavail = free; } else { - // General case: report the overall RADOS cluster's statistics. Because + // General case: report the cluster statistics returned from RADOS. Because // multiple pools may be used without one filesystem namespace via // layouts, this is the most correct thing we can do. stbuf->f_blocks = stats.kb >> (CEPH_BLOCK_SHIFT - 10); @@ -12708,6 +12714,12 @@ int Client::fdescribe_layout(int fd, file_layout_t *lp) return 0; } +int64_t Client::get_default_pool_id() +{ + Mutex::Locker lock(client_lock); + /* first data pool is the default */ + return mdsmap->get_first_data_pool(); +} // expose osdmap @@ -12900,6 +12912,7 @@ void Client::ms_handle_remote_reset(Connection *con) } } if (mds >= 0) { + assert (s != NULL); switch (s->state) { case MetaSession::STATE_CLOSING: ldout(cct, 1) << "reset from mds we were closing; we'll call that closed" << dendl; diff --git a/ceph/src/client/Client.h b/ceph/src/client/Client.h index b6369a293..beefa1eba 100644 --- a/ceph/src/client/Client.h +++ b/ceph/src/client/Client.h @@ -1101,6 +1101,9 @@ public: int get_file_stripe_address(int fd, loff_t offset, vector& address); int get_file_extent_osds(int fd, loff_t off, loff_t *len, vector& osds); int get_osd_addr(int osd, entity_addr_t& addr); + + // expose mdsmap + int64_t get_default_pool_id(); // expose osdmap int get_local_osd(); diff --git a/ceph/src/cls/lua/cls_lua.cc b/ceph/src/cls/lua/cls_lua.cc index 5cb5bc80e..3c84570c5 100644 --- a/ceph/src/cls/lua/cls_lua.cc +++ b/ceph/src/cls/lua/cls_lua.cc @@ -643,7 +643,7 @@ static const luaL_Reg clslua_lib[] = { }; /* - * Set int const in table at top of stack + * Set const int in table at top of stack */ #define SET_INT_CONST(var) do { \ lua_pushinteger(L, var); \ diff --git a/ceph/src/common/backport14.h b/ceph/src/common/backport14.h index d56e24c3e..3e6505d46 100644 --- a/ceph/src/common/backport14.h +++ b/ceph/src/common/backport14.h @@ -27,6 +27,8 @@ template using remove_reference_t = typename std::remove_reference::type; template using result_of_t = typename std::result_of::type; +template +using decay_t = typename std::decay::type; namespace _backport14 { template @@ -75,10 +77,52 @@ template constexpr std::size_t size(const T (&array)[N]) noexcept { return N; } + +/// http://en.cppreference.com/w/cpp/utility/functional/not_fn +// this implementation uses c++14's result_of_t (above) instead of the c++17 +// invoke_result_t, and so may not behave correctly when SFINAE is required +template +class not_fn_result { + using DecayF = decay_t; + DecayF fn; + public: + explicit not_fn_result(F&& f) : fn(std::forward(f)) {} + not_fn_result(not_fn_result&& f) = default; + not_fn_result(const not_fn_result& f) = default; + + template + auto operator()(Args&&... args) & + -> decltype(!std::declval>()) { + return !fn(std::forward(args)...); + } + template + auto operator()(Args&&... args) const& + -> decltype(!std::declval>()) { + return !fn(std::forward(args)...); + } + + template + auto operator()(Args&&... args) && + -> decltype(!std::declval>()) { + return !std::move(fn)(std::forward(args)...); + } + template + auto operator()(Args&&... args) const&& + -> decltype(!std::declval>()) { + return !std::move(fn)(std::forward(args)...); + } +}; + +template +not_fn_result not_fn(F&& fn) { + return not_fn_result(std::forward(fn)); +} + } // namespace _backport17 using _backport14::make_unique; using _backport17::size; using _backport14::max; +using _backport17::not_fn; } // namespace ceph #endif // CEPH_COMMON_BACKPORT14_H diff --git a/ceph/src/common/buffer.cc b/ceph/src/common/buffer.cc index 4b75b9b63..b8e87d1ee 100644 --- a/ceph/src/common/buffer.cc +++ b/ceph/src/common/buffer.cc @@ -2382,7 +2382,7 @@ int buffer::list::write_fd(int fd) const } ++p; - if (iovlen == IOV_MAX-1 || + if (iovlen == IOV_MAX || p == _buffers.end()) { iovec *start = iov; int num = iovlen; diff --git a/ceph/src/common/cmdparse.cc b/ceph/src/common/cmdparse.cc index 592b889b4..9a873f514 100644 --- a/ceph/src/common/cmdparse.cc +++ b/ceph/src/common/cmdparse.cc @@ -55,12 +55,10 @@ dump_cmd_to_json(Formatter *f, const string& cmd) // elements are: "name", meaning "the typeless name that means a literal" // an object {} with key:value pairs representing an argument - int argnum = 0; stringstream ss(cmd); std::string word; while (std::getline(ss, word, ' ')) { - argnum++; // if no , or =, must be a plain word to put out if (word.find_first_of(",=") == string::npos) { f->dump_string("arg", word); diff --git a/ceph/src/common/mClockPriorityQueue.h b/ceph/src/common/mClockPriorityQueue.h index b651cf08f..7f7b7c35b 100644 --- a/ceph/src/common/mClockPriorityQueue.h +++ b/ceph/src/common/mClockPriorityQueue.h @@ -298,7 +298,7 @@ namespace ceph { void enqueue(K cl, unsigned priority, unsigned cost, T item) override final { // priority is ignored - queue.add_request(item, cl, cost); + queue.add_request(std::move(item), cl, cost); } void enqueue_front(K cl, diff --git a/ceph/src/common/options.cc b/ceph/src/common/options.cc index f97d619ed..cfb518d77 100644 --- a/ceph/src/common/options.cc +++ b/ceph/src/common/options.cc @@ -88,7 +88,6 @@ void Option::dump(Formatter *f) const f->dump_string("name", name); f->dump_string("type", type_to_str(type)); - std::string level_str; f->dump_string("level", level_to_str(level)); @@ -131,5530 +130,5806 @@ void Option::dump(Formatter *f) const } -std::vector