forked from extern/zfs-auto-snapshot
Compare commits
No commits in common. "master" and "SUNW" have entirely different histories.
@ -1,9 +0,0 @@
|
||||
[ 1.2.5 (Unreleased) ]
|
||||
|
||||
* Start a changelog
|
||||
* Accept PR#94 from aimileus/macos
|
||||
- Replace --utc longform option with -u for macos compatibility
|
||||
* Accept PR#107 from ArakniD/master
|
||||
- Add optional label for snap removals
|
||||
|
||||
-- Jonathan Carter 2019-09-25, 15:24 SAST
|
339
COPYING
339
COPYING
@ -1,339 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
95
Changelog
Normal file
95
Changelog
Normal file
@ -0,0 +1,95 @@
|
||||
0.12
|
||||
|
||||
* Add event-based snapshots
|
||||
* Add support to change the separator character in snapshot names
|
||||
- set the default value of "zfs/sep" to "_"
|
||||
- useful for CIFs clients that previously choked on colons in snapshot names
|
||||
* Improved shutdown speed via http://blogs.sun.com/dp/entry/speeding_to_a_halt
|
||||
* Add support to allow the user disable auto-snapshots of new pools
|
||||
* Bugfix to allow snapshots of datasets with spaces in their names
|
||||
* Bugfix to properly deal with namespace clashes in dataset names
|
||||
* Exported $LAST_SNAP and $PREV_SNAP variables when performing backups
|
||||
- useful to things like the "zfs-backup-to-s3" project on kenai.com
|
||||
|
||||
0.11
|
||||
|
||||
* Add RBAC support
|
||||
- the service now runs under a zfssnap role
|
||||
- service start/stop logs stay under /var/svc/log
|
||||
- other log messages sent to syslog
|
||||
* Add a 'zfs/interval' property value 'none' which doesn't use cron
|
||||
* Add a cache of svcprops to the method script
|
||||
* Add a com.sun:auto-snapshot user property used by all instances,
|
||||
com.sun:auto-snapshot:$LABEL takes precedence
|
||||
* Remove the seconds field of the snapshot name - it's not needed
|
||||
* Changed the way // works with recursive snapshots - ignore
|
||||
snapshot-children, and instead automatically determine when we can take
|
||||
recursive snapshots based on which datasets have the zfs user properties
|
||||
* Set avoidscrub to false by default (bug was fixed in in nv_94)
|
||||
* Bugfix from Dan - Volumes are datasets too
|
||||
* Automatically snapshot everything by setting com.sun:auto-snapshot=true
|
||||
on startup. (this gets done on all top level datasets - an existing
|
||||
property set to false on the top level dataset overrides this)
|
||||
* Check for missed snapshots on startup
|
||||
* Clean up shell style
|
||||
* Clean up preremove script
|
||||
* Remove the bundled GUI applications
|
||||
* Tag the method script with the current changeset during the build
|
||||
* Write this Changelog
|
||||
|
||||
0.10
|
||||
|
||||
* Bugfix from Reid Spencer - Tim can't spell "RECURSIVE" (hah, I can now!:-)
|
||||
* Bugfix from Breandan Dezendorf - Labelled snapshots not being destroyed correctly
|
||||
* Ability to avoid taking snapshots when pool scrubs are in progress
|
||||
|
||||
0.9
|
||||
|
||||
* SVR4 packaging (with ugly postinstall/preremove scripts)
|
||||
* Add some canned instances for frequent,daily,hourly,weekly,monthly snapshots
|
||||
* Add 'zfs/fs-name' '//' property value
|
||||
* Change the timeout for the start/stop methods to infinity
|
||||
* Allow power users to avoid having ':' in snapshot names via $SEP
|
||||
* Add GUI utilities and some basic GNOME integration
|
||||
|
||||
0.8
|
||||
|
||||
* Bugfix from Dick Davies - fencepost error in crontab entries
|
||||
* Add locking around crontab updates
|
||||
* Add zfs/verbose feature for more logging if you really need it
|
||||
|
||||
0.7
|
||||
|
||||
* Bugfix from Bill Sommerfeld - make less logging noise
|
||||
* Add logging to syslog
|
||||
|
||||
0.6
|
||||
|
||||
* Option to take backups using zfs send after snapshots are taken
|
||||
* Allow us to have multiple schedules per filesystem (add labels)
|
||||
* Better fault handling - drop SMF instance to 'maintenance' if stuff goes wrong
|
||||
|
||||
0.5
|
||||
|
||||
* Bugfix from Joe Little - recursive snapshots weren't respecting retention limits
|
||||
|
||||
0.4
|
||||
|
||||
* Make zenity gui work on s10u2
|
||||
* Clean up the logic that the gui uses to name different instances
|
||||
|
||||
0.3
|
||||
|
||||
* Add snapshot retention limits
|
||||
|
||||
0.2
|
||||
|
||||
* Fix the gui to show a different string when changing the interval
|
||||
* Fix a bug where seperate instances were removing each other's cron jobs
|
||||
|
||||
0.1
|
||||
|
||||
* Take periodic snapshots using cron and SMF
|
||||
* Snapshot children
|
||||
* Add zenity gui to create SMF manifests
|
||||
|
55
Makefile
55
Makefile
@ -1,28 +1,33 @@
|
||||
PREFIX := /usr/local
|
||||
DIR = \
|
||||
`basename ${PWD}`
|
||||
ZFS_AUTO_SNAPSHOT_CHANGESET = \
|
||||
`hg identify`
|
||||
|
||||
all:
|
||||
pkg: clean
|
||||
mkdir -p proto
|
||||
find src | cpio -pvdum proto
|
||||
# we tag the method script during the build, which will
|
||||
# only happen if we're building from the original hg source,
|
||||
# not from the dist tarball - see the dist: target.
|
||||
cat src/lib/svc/method/zfs-auto-snapshot | sed -e "s/~ZFS_AUTO_SNAPSHOT_CHANGESET~/${ZFS_AUTO_SNAPSHOT_CHANGESET}/g" > proto/src/lib/svc/method/zfs-auto-snapshot
|
||||
pkgmk -f proto/src/prototype -p `uname -n``date +%Y%m%d%H%M%S` -d proto -r proto/src
|
||||
|
||||
install:
|
||||
install -d $(DESTDIR)/etc/cron.d
|
||||
install -d $(DESTDIR)/etc/cron.daily
|
||||
install -d $(DESTDIR)/etc/cron.hourly
|
||||
install -d $(DESTDIR)/etc/cron.weekly
|
||||
install -d $(DESTDIR)/etc/cron.monthly
|
||||
install -m 0644 etc/zfs-auto-snapshot.cron.frequent $(DESTDIR)/etc/cron.d/zfs-auto-snapshot
|
||||
install etc/zfs-auto-snapshot.cron.hourly $(DESTDIR)/etc/cron.hourly/zfs-auto-snapshot
|
||||
install etc/zfs-auto-snapshot.cron.daily $(DESTDIR)/etc/cron.daily/zfs-auto-snapshot
|
||||
install etc/zfs-auto-snapshot.cron.weekly $(DESTDIR)/etc/cron.weekly/zfs-auto-snapshot
|
||||
install etc/zfs-auto-snapshot.cron.monthly $(DESTDIR)/etc/cron.monthly/zfs-auto-snapshot
|
||||
install -d $(DESTDIR)$(PREFIX)/share/man/man8
|
||||
install -m 0644 src/zfs-auto-snapshot.8 $(DESTDIR)$(PREFIX)/share/man/man8/zfs-auto-snapshot.8
|
||||
install -d $(DESTDIR)$(PREFIX)/sbin
|
||||
install src/zfs-auto-snapshot.sh $(DESTDIR)$(PREFIX)/sbin/zfs-auto-snapshot
|
||||
clean:
|
||||
rm -rf proto/*
|
||||
if [ -d proto ] ; then \
|
||||
rmdir proto ; \
|
||||
fi
|
||||
|
||||
uninstall:
|
||||
rm $(DESTDIR)/etc/cron.d/zfs-auto-snapshot
|
||||
rm $(DESTDIR)/etc/cron.hourly/zfs-auto-snapshot
|
||||
rm $(DESTDIR)/etc/cron.daily/zfs-auto-snapshot
|
||||
rm $(DESTDIR)/etc/cron.weekly/zfs-auto-snapshot
|
||||
rm $(DESTDIR)/etc/cron.monthly/zfs-auto-snapshot
|
||||
rm $(DESTDIR)$(PREFIX)/share/man/man8/zfs-auto-snapshot.8
|
||||
rm $(DESTDIR)$(PREFIX)/sbin/zfs-auto-snapshot
|
||||
dist: clean
|
||||
# save off a copy of the method script before tagging it
|
||||
cp src/lib/svc/method/zfs-auto-snapshot zfs-auto-snapshot.src
|
||||
|
||||
cat src/lib/svc/method/zfs-auto-snapshot | sed -e "s/~ZFS_AUTO_SNAPSHOT_CHANGESET~/${ZFS_AUTO_SNAPSHOT_CHANGESET}/g" > src/lib/svc/method/tagged-method-script
|
||||
mv src/lib/svc/method/tagged-method-script src/lib/svc/method/zfs-auto-snapshot
|
||||
grep "zfs-auto-snapshot changeset" src/lib/svc/method/zfs-auto-snapshot
|
||||
tar cf ${DIR}.tar -C .. ${DIR}/Changelog -C .. ${DIR}/Makefile \
|
||||
-C .. ${DIR}/README.zfs-auto-snapshot.txt -C .. ${DIR}/src
|
||||
gzip ${DIR}.tar
|
||||
|
||||
# drop our saved method script back where we left it
|
||||
cp zfs-auto-snapshot.src src/lib/svc/method/zfs-auto-snapshot
|
||||
|
21
README
21
README
@ -1,21 +0,0 @@
|
||||
zfs-auto-snapshot:
|
||||
|
||||
An alternative implementation of the zfs-auto-snapshot service for Linux
|
||||
that is compatible with zfs-linux and zfs-fuse.
|
||||
|
||||
Automatically create, rotate, and destroy periodic ZFS snapshots. This is
|
||||
the utility that creates the @zfs-auto-snap_frequent, @zfs-auto-snap_hourly,
|
||||
@zfs-auto-snap_daily, @zfs-auto-snap_weekly, and @zfs-auto-snap_monthly
|
||||
snapshots if it is installed.
|
||||
|
||||
This program is a posixly correct bourne shell script. It depends only on
|
||||
the zfs utilities and cron, and can run in the dash shell.
|
||||
|
||||
|
||||
Installation:
|
||||
-------------
|
||||
|
||||
wget https://github.com/zfsonlinux/zfs-auto-snapshot/archive/upstream/1.2.4.tar.gz
|
||||
tar -xzf 1.2.4.tar.gz
|
||||
cd zfs-auto-snapshot-upstream-1.2.4
|
||||
make install
|
187
README.zfs-auto-snapshot.txt
Normal file
187
README.zfs-auto-snapshot.txt
Normal file
@ -0,0 +1,187 @@
|
||||
|
||||
NAME
|
||||
|
||||
ZFS Automatic Snapshot SMF Service, version 0.12
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
This is a simple SMF service which can will take automatic,
|
||||
scheduled snapshots of given ZFS filesystems and can perform simple
|
||||
incremental or full backups of those filesystems.
|
||||
|
||||
Documentation for the service is contained in the manifest file,
|
||||
zfs-auto-snapshot.xml.
|
||||
|
||||
Version 0.11 removes the simple GUI applications that were used to
|
||||
create manifests, or select which filesystems should be included
|
||||
in the canned instances. These are superceded by the time-slider-setup
|
||||
application.
|
||||
|
||||
INSTALLATION
|
||||
|
||||
To install, as root, pkgadd SUNWzfs-auto-snapshot. This package now contains
|
||||
several canned SMF instances. These are:
|
||||
|
||||
online 1:17:43 svc:/system/filesystem/zfs/auto-snapshot:hourly
|
||||
online 1:17:46 svc:/system/filesystem/zfs/auto-snapshot:monthly
|
||||
online 1:17:46 svc:/system/filesystem/zfs/auto-snapshot:daily
|
||||
online 1:17:48 svc:/system/filesystem/zfs/auto-snapshot:frequent
|
||||
online 1:17:49 svc:/system/filesystem/zfs/auto-snapshot:weekly
|
||||
online 1:17:49 svc:/system/filesystem/zfs/auto-snapshot:event
|
||||
|
||||
These instances use the special "//" fs-name to determine which filesystems
|
||||
should be included in each snapshot schedule. See the description for "fs-name"
|
||||
below.
|
||||
|
||||
The included instances have the following properties:
|
||||
|
||||
frequent snapshots every 15 mins, keeping 4 snapshots
|
||||
hourly snapshots every hour, keeping 24 snapshots
|
||||
daily snapshots every day, keeping 31 snapshots
|
||||
weekly snapshots every week, keeping 7 snapshots
|
||||
monthly snapshots every month, keeping 12 snapshots
|
||||
event no automatic snapshots taken, keeps all snapshots
|
||||
|
||||
The :default service instance does not need to be enabled.
|
||||
|
||||
Additional instances of the service can also be created, for example to group
|
||||
related sets of filesystems under a single service instance.
|
||||
|
||||
The properties each instance needs are:
|
||||
|
||||
zfs/fs-name The name of the filesystem. If the special filesystem
|
||||
name "//" is used, then the system snapshots only
|
||||
filesystems with the zfs user property
|
||||
"com.sun:auto-snapshot:<label>" set to true, so to take
|
||||
frequent snapshots of tank/timf, run the following zfs
|
||||
command:
|
||||
|
||||
# zfs set com.sun:auto-snapshot:frequent=true tank/timf
|
||||
|
||||
The "snap-children" property is ignored when using this
|
||||
fs-name value. Instead, the system automatically determines
|
||||
when it's able to take recursive, vs. non-recursive snapshots
|
||||
of the system, based on the values of the ZFS user properties.
|
||||
|
||||
zfs/interval [ hours | days | months | none]
|
||||
When set to none, we don't take automatic snapshots, but
|
||||
leave an SMF instance available for users to manually
|
||||
fire the method script whenever they want - useful for
|
||||
snapshotting on system events. This is used by the
|
||||
svc:/system/filesystem/zfs/auto-snapshot:event instance.
|
||||
|
||||
zfs/keep How many snapshots to retain - eg. setting this to "4"
|
||||
would keep only the four most recent snapshots. When each
|
||||
new snapshot is taken, the oldest is destroyed. If a snapshot
|
||||
has been cloned, the service will drop to maintenance mode
|
||||
when attempting to destroy that snapshot. Setting to "all"
|
||||
keeps all snapshots.
|
||||
|
||||
zfs/period How often you want to take snapshots, in intervals
|
||||
set according to "zfs/interval"
|
||||
(eg. every 10 days)
|
||||
|
||||
zfs/offset The time from the start of the current interval at which
|
||||
snapshots should be taken, expressed in seconds. For example
|
||||
to take snapshots hourly at 15 minutes into the hour,
|
||||
zfs/offset = 900 (60 sec. * 15) To take daily snapshots at
|
||||
15:43, zfs/offset = 56580.
|
||||
|
||||
zfs/snapshot-children "true" if you would like to recursively take snapshots
|
||||
of all child filesystems of the specified fs-name.
|
||||
This value is ignored when setting zfs/fs-name='//'
|
||||
|
||||
zfs/backup [ full | incremental | none ]
|
||||
|
||||
zfs/backup-save-cmd The command string used to save the backup stream.
|
||||
|
||||
zfs/backup-lock You shouldn't need to change this - but it should be
|
||||
set to "unlocked" by default. We use it to indicate when
|
||||
a backup is running.
|
||||
|
||||
zfs/label A label that can be used to differentiate this set of
|
||||
snapshots from others, not required. If multiple
|
||||
schedules are running on the same machine, using distinct
|
||||
labels for each schedule is needed - otherwise one
|
||||
schedule could remove snapshots taken by another schedule
|
||||
according to it's snapshot-retention policy.
|
||||
(see "zfs/keep")
|
||||
|
||||
|
||||
zfs/verbose Set to false by default, setting to true makes the
|
||||
service produce more output about what it's doing.
|
||||
|
||||
zfs/avoidscrub Set to false by default, this determines whether
|
||||
we should avoid taking snapshots on any pools that have
|
||||
a scrub or resilver in progress.
|
||||
More info in the bugid:
|
||||
6343667 need itinerary so interrupted scrub/resilver
|
||||
doesn't have to start over
|
||||
|
||||
zfs/sep A character used to separate components of the snapshot
|
||||
name generated by the service. Set to '_' by default.
|
||||
(the original character ':' caused problems for CIFS
|
||||
clients)
|
||||
|
||||
zfs/auto-include Set to true by default, this determines whether we should
|
||||
set a property on all new pools (pools where com.sun:auto-snapshot
|
||||
isn't already set) telling the system to automatically include
|
||||
all datasets in that pool in the default schedules. Setting to
|
||||
false will prevent newly imported pools from being snapshotted.
|
||||
|
||||
|
||||
An example instance manifest is included in this archive.
|
||||
|
||||
|
||||
ZFS PROPERTIES
|
||||
|
||||
See the description of 'zfs/fs-name' above for details on the com.sun:auto-snapshot
|
||||
property, used to select datasets for inclusion into each snapshot schedule.
|
||||
|
||||
The 'com.sun:auto-snapshot-desc' property is set on every snapshot taken
|
||||
by the service. Values for this property are not defined and are left to the individual
|
||||
user. The service sets a value of 'Missed snapshot' in this property when snapshots
|
||||
are taken on service start (due to a previous scheduled snapshot being missed)
|
||||
|
||||
Similarly, users can invoke the method script with an optional string which is then set
|
||||
as a value to this property.
|
||||
|
||||
eg.
|
||||
|
||||
# /lib/svc/method/zfs-auto-snapshot svc:/system/filesystem/zfs/auto-snapshot:event "Samba connect"
|
||||
# zfs get com.sun:auto-snapshot-desc rpool/timf@zfs-auto-snap_event-2009-06-22-1240
|
||||
NAME PROPERTY VALUE SOURCE
|
||||
rpool/timf@zfs-auto-snap_event-2009-06-22-1240 com.sun:auto-snapshot-desc Samba connect local
|
||||
|
||||
|
||||
SECURITY
|
||||
|
||||
The service is run by a restricted role "zfssnap", which is created when installing
|
||||
the service if it doesn't already exist. It has the "ZFS File System Administration"
|
||||
RBAC Profile, as well as the solaris.smf.manage.zfs-auto-snapshot Authorization.
|
||||
In order to see what the service is doing, you can view the SMF log files in
|
||||
/var/svc/log for each service instance and syslog, with more detailed logging output
|
||||
being sent to syslog when the "zfs/verbose" option is enabled.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
|
||||
|
||||
More background about this service, along with implementation comments can be
|
||||
found in web log posts at:
|
||||
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_snapshots_prototype_1
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_snapshots_smf_service
|
||||
http://blogs.sun.com/timf/entry/and_also_for_s10u2_zfs
|
||||
http://blogs.sun.com/timf/entry/smf_philosophy_more_on_zfs
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_snapshots_now_with
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_snapshot_service_logging
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_snapshots_0_8
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_for_the_people
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_snapshots_0_10
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_snapshots_0_11
|
||||
http://blogs.sun.com/timf/entry/zfs_automatic_snapshots_0_12
|
||||
|
||||
The ZFS Automatic Snapshot SMF Service is released under the terms of the CDDL.
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Only call zfs-auto-snapshot if it's available
|
||||
which zfs-auto-snapshot > /dev/null || exit 0
|
||||
|
||||
exec zfs-auto-snapshot --quiet --syslog --label=daily --keep=31 //
|
@ -1,3 +0,0 @@
|
||||
PATH="/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
|
||||
|
||||
*/15 * * * * root which zfs-auto-snapshot > /dev/null || exit 0 ; zfs-auto-snapshot --quiet --syslog --label=frequent --keep=4 //
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Only call zfs-auto-snapshot if it's available
|
||||
which zfs-auto-snapshot > /dev/null || exit 0
|
||||
|
||||
exec zfs-auto-snapshot --quiet --syslog --label=hourly --keep=24 //
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Only call zfs-auto-snapshot if it's available
|
||||
which zfs-auto-snapshot > /dev/null || exit 0
|
||||
|
||||
exec zfs-auto-snapshot --quiet --syslog --label=monthly --keep=12 //
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Only call zfs-auto-snapshot if it's available
|
||||
which zfs-auto-snapshot > /dev/null || exit 0
|
||||
|
||||
exec zfs-auto-snapshot --quiet --syslog --label=weekly --keep=8 //
|
62
src/auto-snapshot-instance.xml
Normal file
62
src/auto-snapshot-instance.xml
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
|
||||
<service_bundle type='manifest' name='tank-timf-torrent,foo'>
|
||||
<service
|
||||
name='system/filesystem/zfs/auto-snapshot'
|
||||
type='service'
|
||||
version='0.11'>
|
||||
<create_default_instance enabled='false' />
|
||||
|
||||
<instance name='tank-timf-torrent,foo' enabled='false' >
|
||||
|
||||
<exec_method
|
||||
type='method'
|
||||
name='start'
|
||||
timeout_seconds='10' />
|
||||
|
||||
<exec_method
|
||||
type='method'
|
||||
name='stop'
|
||||
exec='/lib/svc/method/zfs-auto-snapshot stop'
|
||||
timeout_seconds='10' />
|
||||
|
||||
<property_group name='startd' type='framework'>
|
||||
<propval name='duration' type='astring' value='transient' />
|
||||
</property_group>
|
||||
|
||||
<!-- properties for zfs automatic snapshots -->
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="tank/timf/torrent"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="hours"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="14"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="16"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="incremental"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="ssh timf@hostname /usr/bin/pfexec /usr/sbin/zfs receive tank/backup"
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="foo"
|
||||
override="true"/>
|
||||
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
<stability value='Unstable' />
|
||||
</service>
|
||||
</service_bundle>
|
2
src/copyright
Normal file
2
src/copyright
Normal file
@ -0,0 +1,2 @@
|
||||
Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
Use is subject to license terms.
|
116
src/i.manifest
Executable file
116
src/i.manifest
Executable file
@ -0,0 +1,116 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License (the "License").
|
||||
# You may not use this file except in compliance with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or http://www.opensolaris.org/os/licensing.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
#
|
||||
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
# Use is subject to license terms.
|
||||
#
|
||||
# i.manifest - smf(5) service manifest install class action script
|
||||
#
|
||||
|
||||
repfile=$PKG_INSTALL_ROOT/etc/svc/repository.db
|
||||
export repfile
|
||||
|
||||
SVCCFG=/usr/sbin/svccfg
|
||||
AWK=/usr/bin/awk
|
||||
RM=/usr/bin/rm
|
||||
CP=/usr/bin/cp
|
||||
MV=/usr/bin/mv
|
||||
CHMOD=/usr/bin/chmod
|
||||
CHOWN=/usr/bin/chown
|
||||
|
||||
#
|
||||
# Helper function. Handle services deathrow file.
|
||||
# Arguments: $1:manifest file.
|
||||
#
|
||||
svc_deathrow()
|
||||
{
|
||||
TEMP=/tmp/svc_deathrow.$$
|
||||
DEATHROW_FILE=${PKG_INSTALL_ROOT}/etc/svc/deathrow
|
||||
#
|
||||
# Services deathrow file handling, file format:
|
||||
# <fmri>< ><manifest file>< ><package name>
|
||||
# (field separator is a space character)
|
||||
#
|
||||
if [ -s ${DEATHROW_FILE} ]; then
|
||||
#
|
||||
# Manifest file could be from another Solaris version, bypass
|
||||
# the service bundle and validation (we only need the fmris
|
||||
# list). Calling svccfg inventory with SVCCFG_NOVALIDATE=1 is
|
||||
# safe because there is no access to the alternate repository.
|
||||
#
|
||||
ENTITIES=`SVCCFG_NOVALIDATE=1 $SVCCFG inventory $1`
|
||||
for fmri in $ENTITIES; do
|
||||
#
|
||||
# If fmri matches one in deathrow file, remove the
|
||||
# line from the file.
|
||||
#
|
||||
>${TEMP}
|
||||
$AWK "(\$1==\"$fmri\") \
|
||||
{next}; {print}" ${DEATHROW_FILE} >>${TEMP} && \
|
||||
$MV ${TEMP} ${DEATHROW_FILE}
|
||||
$RM -f ${TEMP}
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# If the repository does not yet exist, create it from the appropriate seed. If
|
||||
# for some reason the seeds do not exist, svccfg(1M) will create the repository
|
||||
# automatically.
|
||||
#
|
||||
if [ ! -f $repfile ]; then
|
||||
if [ -n "$SUNW_PKG_INSTALL_ZONENAME" -a \
|
||||
"$SUNW_PKG_INSTALL_ZONENAME" != "global" ]; then
|
||||
[ -f $PKG_INSTALL_ROOT/lib/svc/seed/nonglobal.db ] && \
|
||||
$CP $PKG_INSTALL_ROOT/lib/svc/seed/nonglobal.db $repfile
|
||||
else
|
||||
[ -f $PKG_INSTALL_ROOT/lib/svc/seed/global.db ] && \
|
||||
$CP $PKG_INSTALL_ROOT/lib/svc/seed/global.db $repfile
|
||||
fi
|
||||
$CHMOD 0600 $repfile
|
||||
$CHOWN root:sys $repfile
|
||||
fi
|
||||
|
||||
if [ ! -r $PKG_INSTALL_ROOT/etc/svc/volatile/repository_door ]; then
|
||||
#
|
||||
# smf(5) is not presently running for the destination environment.
|
||||
# Since we presently cannot refresh without a running svc.startd(1M), we
|
||||
# cannot consistently handle dependent placement. Defer to next boot.
|
||||
#
|
||||
while read src dst; do
|
||||
$CP -p $src $dst
|
||||
# deathrow handling
|
||||
svc_deathrow $dst
|
||||
done
|
||||
else
|
||||
#
|
||||
# Local package install.
|
||||
#
|
||||
while read src dst; do
|
||||
$CP -p $src $dst
|
||||
|
||||
[ "$PKG_INSTALL_ROOT" = "" -o "$PKG_INSTALL_ROOT" = "/" ] && \
|
||||
SVCCFG_CHECKHASH=1 $SVCCFG import $dst
|
||||
done
|
||||
fi
|
||||
|
||||
exit 0
|
1067
src/lib/svc/method/zfs-auto-snapshot
Normal file
1067
src/lib/svc/method/zfs-auto-snapshot
Normal file
File diff suppressed because it is too large
Load Diff
24
src/pkginfo
Normal file
24
src/pkginfo
Normal file
@ -0,0 +1,24 @@
|
||||
LC_MESSAGES=C
|
||||
LANG=C
|
||||
TZ=Eire
|
||||
PATH=/sbin:/usr/sbin:/usr/bin:/usr/sadm/install/bin
|
||||
OAMBASE=/usr/sadm/sysadm
|
||||
SITENAME=Sun Microsystems, Inc.
|
||||
PKG=SUNWzfs-auto-snapshot
|
||||
NAME=ZFS Automatic Snapshot Service
|
||||
ARCH=all
|
||||
BASEDIR=/
|
||||
VERSION=0.12
|
||||
MAXINST=1
|
||||
CATEGORY=application
|
||||
DESC=Takes automatic snapshots of ZFS filesystems on a periodic basis.
|
||||
PSTAMP=~PSTAMP~
|
||||
VENDOR=Sun Microsystems, Inc.
|
||||
HOTLINE=Please contact your local service provider
|
||||
CLASSES=none manifest
|
||||
EMAIL=zfs-auto-snapshot@opensolaris.org
|
||||
SUNW_PKGVERS=1.0
|
||||
SUNW_PKG_ALLZONES=false
|
||||
SUNW_PKG_HOLLOW=false
|
||||
PKG_NONABI_SYMLINKS=true
|
||||
PKGINST=SUNWzfs-auto-snapshot
|
74
src/postinstall
Executable file
74
src/postinstall
Executable file
@ -0,0 +1,74 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License, Version 1.0 only
|
||||
# (the "License"). You may not use this file except in compliance
|
||||
# with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or http://www.opensolaris.org/os/licensing.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
# Use is subject to license terms.
|
||||
#
|
||||
|
||||
# a postinstall script - adds zfssnap role.
|
||||
# Return 0 if a user exists, 1 otherwise.
|
||||
#
|
||||
|
||||
# Check if the first argument is 0, settting our return
|
||||
# variable to an error otherwise
|
||||
#
|
||||
check_error() {
|
||||
RETURN_CODE=$1
|
||||
ERROR="$2"
|
||||
if [ "$RETURN_CODE" -ne 0 ] ; then
|
||||
echo "ERROR: $ERROR"
|
||||
fi
|
||||
}
|
||||
|
||||
user_exists() {
|
||||
USER=$1
|
||||
/usr/bin/grep "^$USER:" $BASEDIR/etc/passwd > /dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
auth_exists() {
|
||||
AUTH=$1
|
||||
/usr/bin/grep "^$AUTH:" $BASEDIR/etc/security/auth_attr > /dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
# add our authorization
|
||||
auth_exists solaris.smf.manage.zfs-auto-snapshot
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "solaris.smf.manage.zfs-auto-snapshot:::Manage the ZFS Automatic Snapshot Service::" \
|
||||
>> /etc/security/auth_attr
|
||||
fi
|
||||
|
||||
# add the zfssnap role - probably only works on a local system :-(
|
||||
user_exists zfssnap
|
||||
if [ $? -ne 0 ] ; then
|
||||
/usr/sbin/roleadd -d / -u 51 -c "ZFS Automatic Snapshots role" \
|
||||
-P "ZFS File System Management" \
|
||||
-A solaris.smf.manage.zfs-auto-snapshot -m zfssnap
|
||||
check_error $? "Unable to create zfssnap role!"
|
||||
/usr/bin/passwd -r files -N zfssnap
|
||||
check_error $? "Unable to make zfssnap a no-password account"
|
||||
else
|
||||
echo "zfssnap role already exists."
|
||||
fi
|
||||
|
15
src/prototype
Normal file
15
src/prototype
Normal file
@ -0,0 +1,15 @@
|
||||
i pkginfo
|
||||
i copyright
|
||||
i postinstall
|
||||
i i.manifest
|
||||
i r.manifest
|
||||
d none lib 0755 root bin
|
||||
d none lib/svc 0755 root bin
|
||||
d none lib/svc/method 0755 root bin
|
||||
f none lib/svc/method/zfs-auto-snapshot 0755 root bin
|
||||
d none var 0755 root sys
|
||||
d none var/svc 0755 root sys
|
||||
d none var/svc/manifest 0755 root sys
|
||||
d none var/svc/manifest/system 0755 root sys
|
||||
d none var/svc/manifest/system/filesystem 0755 root sys
|
||||
f manifest var/svc/manifest/system/filesystem/auto-snapshot.xml 0644 root sys
|
186
src/r.manifest
Executable file
186
src/r.manifest
Executable file
@ -0,0 +1,186 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License (the "License").
|
||||
# You may not use this file except in compliance with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or http://www.opensolaris.org/os/licensing.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
#
|
||||
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||
# Use is subject to license terms.
|
||||
#
|
||||
#
|
||||
# r.manifest - smf(5) manifest remove class action script
|
||||
#
|
||||
|
||||
MFSTSCAN=/lib/svc/bin/mfstscan
|
||||
SVCCFG=/usr/sbin/svccfg
|
||||
SVCPROP=/usr/bin/svcprop
|
||||
SVCADM=/usr/sbin/svcadm
|
||||
AWK=/usr/bin/awk
|
||||
CP=/usr/bin/cp
|
||||
RM=/usr/bin/rm
|
||||
|
||||
# number of seconds to wait before killing processes
|
||||
STOP_DELAY=60
|
||||
|
||||
#
|
||||
# Helper function. Delete the manifest hash value.
|
||||
# Arguments: $1: manifest file.
|
||||
#
|
||||
svc_delhash()
|
||||
{
|
||||
$SVCCFG delhash $1 >/dev/null 2>&1
|
||||
if [ "$?" != "0" ];then
|
||||
# this Solaris release doesn't have delhash command
|
||||
pg_name=`$MFSTSCAN -t $1`
|
||||
if $SVCPROP -q -p $pg_name smf/manifest; then
|
||||
$SVCCFG -s smf/manifest delpg $pg_name
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Helper function. Handle services deathrow file.
|
||||
# Arguments: $1:manifest file, $2:package name.
|
||||
#
|
||||
svc_deathrow()
|
||||
{
|
||||
DEATHROW_FILE=${PKG_INSTALL_ROOT}/etc/svc/deathrow
|
||||
# remove alternate root from manifest path
|
||||
manifest=`echo "${PKG_INSTALL_ROOT} $1" | $AWK \
|
||||
'{ print substr($2, length($1)+1); }'`
|
||||
#
|
||||
# Services deathrow file handling, file format:
|
||||
# <fmri>< ><manifest file>< ><package name>
|
||||
# (field separator is a space character)
|
||||
#
|
||||
# Manifest file could be from another Solaris version, bypass the
|
||||
# the service bundle and validation (we only need the fmris list).
|
||||
# Calling svccfg inventory with SVCCFG_NOVALIDATE=1 is safe because
|
||||
# there is no access to the alternate repository.
|
||||
#
|
||||
ENTITIES=`SVCCFG_NOVALIDATE=1 $SVCCFG inventory $1`
|
||||
for fmri in $ENTITIES; do
|
||||
# add to services deathrow file
|
||||
echo ${fmri} ${manifest} $2 >> ${DEATHROW_FILE}
|
||||
done
|
||||
}
|
||||
|
||||
wait_disable() {
|
||||
svcinst=$1
|
||||
wait_time=$2
|
||||
|
||||
while [ ${nsec:=0} -lt $wait_time ]; do
|
||||
state=`$SVCPROP -p restarter/state $svcinst`
|
||||
if [ "$state" = "disabled" -o "$state" = "maintenance" ]; then
|
||||
nstate=`$SVCPROP -p restarter/next_state $svcinst`
|
||||
if [ "$nstate" = "none" ]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
/usr/bin/sleep 1
|
||||
nsec=`expr ${nsec} + 1`
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ "$PKG_INSTALL_ROOT" != "" -a "$PKG_INSTALL_ROOT" != "/" ]; then
|
||||
#
|
||||
# We can't safely disable the service in this case.
|
||||
#
|
||||
smf_alive=no
|
||||
else
|
||||
#
|
||||
# We can verify if the service is disabled prior to
|
||||
# removal.
|
||||
#
|
||||
if [ -r /etc/svc/volatile/repository_door ]; then
|
||||
smf_alive=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
while read mfst; do
|
||||
if [ "$smf_alive" = "yes" ]; then
|
||||
ENTITIES=`$SVCCFG inventory $mfst`
|
||||
|
||||
for fmri in $ENTITIES; do
|
||||
|
||||
# Determine whether fmri refers to an instance or a service.
|
||||
$SVCPROP -p restarter/state $fmri >/dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
# this is a service fmri, all instances have been deleted
|
||||
$SVCCFG delete $fmri 2>/dev/null
|
||||
# process next instance
|
||||
continue
|
||||
fi
|
||||
|
||||
#
|
||||
# Try to disable the instance within a reasonable amount of time
|
||||
# (eg. 60 secs). If it fails, forcibly delete the instance.
|
||||
#
|
||||
echo "Waiting up to $STOP_DELAY seconds for $fmri to stop..."
|
||||
$SVCADM disable $fmri 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
wait_disable $fmri $STOP_DELAY
|
||||
if [ $? -eq 0 ]; then
|
||||
# the instance is disabled and can be safely deleted
|
||||
$SVCCFG delete $fmri 2>/dev/null
|
||||
# process next instance
|
||||
continue
|
||||
fi
|
||||
echo "Failed to disable $fmri after $STOP_DELAY seconds"
|
||||
else
|
||||
echo "Failed to disable $fmri"
|
||||
fi
|
||||
|
||||
echo "Force deleting $fmri"
|
||||
|
||||
ctid=`$SVCPROP -p restarter/contract $fmri 2>/dev/null`
|
||||
tctid=`$SVCPROP -p restarter/transient_contract $fmri 2>/dev/null`
|
||||
|
||||
$SVCCFG delete -f $fmri
|
||||
|
||||
#
|
||||
# Kill any remaining processes.
|
||||
# pkill must occur after the delete to prevent startd
|
||||
# from retrying the STOP method.
|
||||
#
|
||||
if [ -n "${tctid}" -a "${tctid}" -gt 1 ]; then
|
||||
# kill the STOP method processes
|
||||
/usr/bin/pkill -9 -c $tctid
|
||||
fi
|
||||
if [ -n "${ctid}" -a "${ctid}" -gt 1 ]; then
|
||||
# kill any remaining running processes for the instance
|
||||
/usr/bin/pkill -9 -c $ctid
|
||||
fi
|
||||
done
|
||||
|
||||
#
|
||||
# Delete the manifest hash value.
|
||||
#
|
||||
svc_delhash $mfst
|
||||
else
|
||||
# deathrow handling
|
||||
svc_deathrow $mfst $PKGINST
|
||||
fi
|
||||
|
||||
$RM -f $mfst
|
||||
done
|
||||
|
||||
exit 0
|
59
src/samples/auto-snapshot-space-archive.xml
Normal file
59
src/samples/auto-snapshot-space-archive.xml
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
|
||||
<service_bundle type='manifest' name='space-archive'>
|
||||
|
||||
<!-- a simple instance that snapshots the space/archive filesystem every 6 hours -->
|
||||
|
||||
<service
|
||||
name='system/filesystem/zfs/auto-snapshot'
|
||||
type='service'
|
||||
version='0.12'>
|
||||
<create_default_instance enabled='false' />
|
||||
|
||||
<instance name='space-archive' enabled='false' >
|
||||
|
||||
<property_group name='startd' type='framework'>
|
||||
<propval name='duration' type='astring' value='transient' />
|
||||
</property_group>
|
||||
|
||||
<!-- properties for zfs automatic snapshots -->
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="space/archive"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="hours"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="6"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="2"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="none"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value=""
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value=""
|
||||
override="true"/>
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
<propval name="avoidscrub" type="boolean" value="true"
|
||||
override="true"/>
|
||||
<propval name="sep" type="astring" value="_"
|
||||
override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
<stability value='Unstable' />
|
||||
</service>
|
||||
</service_bundle>
|
62
src/samples/auto-snapshot-space-timf,backup.xml
Normal file
62
src/samples/auto-snapshot-space-timf,backup.xml
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
|
||||
<service_bundle type='manifest' name='space-timf,backup'>
|
||||
|
||||
<!-- A service instance that backs up space/timf every month, keeping
|
||||
122 months of snapshots. It saves each snapshot stream into the /extra
|
||||
filesystem, naming the files according to the snapshot name -->
|
||||
|
||||
<service
|
||||
name='system/filesystem/zfs/auto-snapshot'
|
||||
type='service'
|
||||
version='0.12'>
|
||||
<create_default_instance enabled='false' />
|
||||
|
||||
<instance name='space-timf,backup' enabled='false' >
|
||||
|
||||
<property_group name='startd' type='framework'>
|
||||
<propval name='duration' type='astring' value='transient' />
|
||||
</property_group>
|
||||
|
||||
<!-- properties for zfs automatic snapshots -->
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="space/timf"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="months"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="1"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="122"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="full"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="eval cat > /extra/`echo $LAST_SNAP | sed -e 's#/#-#g'`"
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="backup"
|
||||
override="true"/>
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
<propval name="avoidscrub" type="boolean" value="true"
|
||||
override="true"/>
|
||||
<propval name="sep" type="astring" value="_"
|
||||
override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
<stability value='Unstable' />
|
||||
</service>
|
||||
</service_bundle>
|
551
src/var/svc/manifest/system/filesystem/auto-snapshot.xml
Normal file
551
src/var/svc/manifest/system/filesystem/auto-snapshot.xml
Normal file
@ -0,0 +1,551 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
|
||||
<!--
|
||||
|
||||
CDDL HEADER START
|
||||
|
||||
The contents of this file are subject to the terms of the
|
||||
Common Development and Distribution License, Version 1.0 only
|
||||
(the "License"). You may not use this file except in compliance
|
||||
with the License.
|
||||
|
||||
You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
or http://www.opensolaris.org/os/licensing.
|
||||
See the License for the specific language governing permissions
|
||||
and limitations under the License.
|
||||
|
||||
When distributing Covered Code, include this CDDL HEADER in each
|
||||
file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
If applicable, add the following below this CDDL HEADER, with the
|
||||
fields enclosed by brackets "[]" replaced with your own identifying
|
||||
information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
CDDL HEADER END
|
||||
|
||||
Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
Use is subject to license terms.
|
||||
|
||||
-->
|
||||
|
||||
<service_bundle type='manifest' name='SUNWzfs-auto-snapshot:filesystem-auto-snapshot'>
|
||||
|
||||
<service
|
||||
name='system/filesystem/zfs/auto-snapshot'
|
||||
type='service'
|
||||
version='0.12'>
|
||||
|
||||
<!-- we need to be multi-user -->
|
||||
<dependency
|
||||
name='multi-user'
|
||||
grouping='require_all'
|
||||
restart_on='none'
|
||||
type='service'>
|
||||
<service_fmri value='svc:/milestone/multi-user' />
|
||||
</dependency>
|
||||
|
||||
<!-- we also need cron -->
|
||||
<dependency
|
||||
name="cron"
|
||||
grouping="require_all"
|
||||
restart_on="none"
|
||||
type="service">
|
||||
<service_fmri value="svc:/system/cron" />
|
||||
</dependency>
|
||||
|
||||
<exec_method
|
||||
type='method'
|
||||
name='start'
|
||||
exec='/lib/svc/method/zfs-auto-snapshot start'
|
||||
timeout_seconds='0'>
|
||||
<method_context>
|
||||
<method_credential user='zfssnap' group='daemon' />
|
||||
</method_context>
|
||||
</exec_method>
|
||||
|
||||
<exec_method
|
||||
type='method'
|
||||
name='stop'
|
||||
exec='/lib/svc/method/zfs-auto-snapshot stop'
|
||||
timeout_seconds='0' >
|
||||
<method_context>
|
||||
<method_credential user='zfssnap' group='daemon' />
|
||||
</method_context>
|
||||
</exec_method>
|
||||
|
||||
<property_group name='startd' type='framework'>
|
||||
<propval name='duration' type='astring' value='transient' />
|
||||
</property_group>
|
||||
|
||||
<property_group name='general' type='framework'>
|
||||
<propval name='action_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
<propval name='value_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
</property_group>
|
||||
|
||||
|
||||
<!-- The properties we expect that any instance will define:
|
||||
|
||||
fs-name : The name of the filesystem we want to snapshot.
|
||||
|
||||
The special filesystem name "//" indicates we should
|
||||
look at the com.sun:auto-snapshot ZFS user
|
||||
properties on datasets, set to "true" if the dataset
|
||||
should have snapshots taken by this instance.
|
||||
|
||||
If unset, snapshots will not be taken by this instance.
|
||||
|
||||
The snapshot-children property is ignored when using
|
||||
this setting, instead the system will automatically
|
||||
determine how to take snapshots, based on which datasets
|
||||
have true, false or unset property values.
|
||||
|
||||
Setting com.sun:auto-snapshot:<label> will override
|
||||
the general setting for com.sun:auto-snapshot.
|
||||
|
||||
|
||||
interval : minutes | hours | days | months | none
|
||||
|
||||
For the interval "none" a cron job is not created for that
|
||||
instance - instead the user can manually fire the method
|
||||
script to take snapshots defined by the rest of the properties
|
||||
in the instance. The period and offset values are ignored in
|
||||
this case.
|
||||
|
||||
period : How many (m,h,d,m) do we wait between snapshots
|
||||
|
||||
offset : The offset into the time period we want
|
||||
|
||||
keep : How many snapshots we should keep, otherwise, we
|
||||
delete the oldest when we hit this threshold
|
||||
|
||||
snapshot-children : Whether we should recursively snapshot
|
||||
all filesystems contained within. Ignored when
|
||||
using the "//" fs-name value.
|
||||
|
||||
backup : If we want to perform a "zfs send" for our backup
|
||||
we set this - either to "full" or "incremental".
|
||||
If set to "none", we don't perform backups.
|
||||
|
||||
backup-save-cmd : A command string to save the backup - if unset,
|
||||
we return an error and move the service to
|
||||
maintenance.
|
||||
|
||||
backup-lock : A string we set when a backup operation is in
|
||||
progress, to prevent two backups from the same
|
||||
service instance running into each other. Not
|
||||
completely flawless, but okay. Due to 6338294,
|
||||
we use the keyword "unlocked" to indicate that
|
||||
the lock is not held.
|
||||
|
||||
label : A string that allows us to differentiate this set
|
||||
of snapshot schedules from others configured for the
|
||||
same filesystem. This is not usually needed and can
|
||||
be left unset, but it can be useful in some
|
||||
situations (particularly for backups).
|
||||
|
||||
verbose : Set to false by default, setting to true results
|
||||
in the service printing more detail in the log
|
||||
about what it's doing.
|
||||
|
||||
avoidscrub : Set to false by default, this determines whether
|
||||
we should avoid taking snapshots on any pools that have
|
||||
a scrub or resilver in progress.
|
||||
More info in the bugid:
|
||||
6343667 need itinerary so interrupted scrub/resilver
|
||||
doesn't have to start over
|
||||
|
||||
sep: Set to '_' by default, this is the character used to
|
||||
separate datestamps used in snapshot names.
|
||||
|
||||
auto-include: Set to 'true' by default, this determines whether
|
||||
on startup, we should set a property on all new pools
|
||||
seen by the service telling the service to take snapshots
|
||||
on that pool.
|
||||
|
||||
-->
|
||||
<property_group name="zfs" type="application">
|
||||
<propval name="fs-name" type="astring" value="Not set" override="true"/>
|
||||
<propval name="interval" type="astring" value="Not set" override="true"/>
|
||||
<propval name="offset" type="astring" value="Not set" override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="false"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="all" override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="none" override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="" override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="" override="true"/>
|
||||
<propval name="verbose" type="boolean" value="false" override="true"/>
|
||||
<propval name="avoidscrub" type="boolean" value="false" override="true"/>
|
||||
<propval name="sep" type="astring" value="_" override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true" override="true"/>
|
||||
</property_group>
|
||||
|
||||
|
||||
<!-- We now define a set of default instances to take frequent,
|
||||
hourly, daily, weekly and monthly snapshots -->
|
||||
|
||||
|
||||
<!-- This instance recursively snapshots all
|
||||
filesystems marked with the ZFS User Property
|
||||
com.sun:auto-snapshot:frequent=true every
|
||||
15 minutes, and keeps 4 of these snapshots into the past.
|
||||
-->
|
||||
|
||||
<instance name='frequent' enabled='false' >
|
||||
|
||||
<property_group name='general' type='framework'>
|
||||
<propval name='action_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
<propval name='value_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
</property_group>
|
||||
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="//"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="minutes"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="15"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="4"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="none"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="not set"
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="frequent"
|
||||
override="true"/>
|
||||
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
<propval name="avoidscrub" type="boolean" value="false"
|
||||
override="false"/>
|
||||
|
||||
<propval name="sep" type="astring" value="_"
|
||||
override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true" override="true"/>
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
<!-- This instance recursively snapshots all
|
||||
filesystems marked with the ZFS User Property
|
||||
com.sun:auto-snapshot:hourly=true every
|
||||
hour, and keeps 24 of these snapshots into the past.
|
||||
-->
|
||||
|
||||
<instance name='hourly' enabled='false' >
|
||||
|
||||
<property_group name='general' type='framework'>
|
||||
<propval name='action_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
<propval name='value_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
</property_group>
|
||||
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="//"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="hours"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="1"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="24"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="none"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="not set"
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="hourly"
|
||||
override="true"/>
|
||||
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
<propval name="avoidscrub" type="boolean" value="false"
|
||||
override="false"/>
|
||||
|
||||
<propval name="sep" type="astring" value="_"
|
||||
override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true" override="true"/>
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
|
||||
<!-- This instance recursively snapshots all
|
||||
filesystems marked with the ZFS User Property
|
||||
com.sun:auto-snapshot:daily=true every
|
||||
day, and keeps 31 of these snapshots into the past.
|
||||
-->
|
||||
|
||||
<instance name='daily' enabled='false' >
|
||||
|
||||
<property_group name='general' type='framework'>
|
||||
<propval name='action_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
<propval name='value_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
</property_group>
|
||||
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="//"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="days"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="1"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="31"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="none"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="not set"
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="daily"
|
||||
override="true"/>
|
||||
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
<propval name="avoidscrub" type="boolean" value="false"
|
||||
override="false"/>
|
||||
|
||||
<propval name="sep" type="astring" value="_"
|
||||
override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true" override="true"/>
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
<!-- This instance recursively snapshots all
|
||||
filesystems marked with the ZFS User Property
|
||||
com.sun:auto-snapshot:weekly=true every
|
||||
7 days, and keeps 4 of these snapshots into the past.
|
||||
-->
|
||||
|
||||
<instance name='weekly' enabled='false' >
|
||||
|
||||
<property_group name='general' type='framework'>
|
||||
<propval name='action_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
<propval name='value_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
</property_group>
|
||||
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="//"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="days"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="7"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="4"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="none"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="not set"
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="weekly"
|
||||
override="true"/>
|
||||
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
<propval name="avoidscrub" type="boolean" value="false"
|
||||
override="false"/>
|
||||
|
||||
<propval name="sep" type="astring" value="_"
|
||||
override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true" override="true"/>
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
|
||||
<!-- This instance recursively snapshots all
|
||||
filesystems marked with the ZFS User Property
|
||||
com.sun:auto-snapshot:monthly=true every
|
||||
month, and keeps 12 of these snapshots into the past.
|
||||
-->
|
||||
|
||||
<instance name='monthly' enabled='false' >
|
||||
|
||||
<property_group name='general' type='framework'>
|
||||
<propval name='action_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
<propval name='value_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
</property_group>
|
||||
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="//"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="months"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="1"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="12"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="none"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="not set"
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="monthly"
|
||||
override="true"/>
|
||||
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
<propval name="avoidscrub" type="boolean" value="true"
|
||||
override="false"/>
|
||||
|
||||
<propval name="sep" type="astring" value="_"
|
||||
override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true" override="true"/>
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
|
||||
<!-- This instance takes snapshots on events, rather than
|
||||
being called from cron. Events are tagged by a string
|
||||
argument to the method script. Filesystems marked with
|
||||
the ZFS User Property com.sun:auto-snapshot:event=true
|
||||
are included in this schedule. We do not destroy event
|
||||
driven snapshots, however that can be overridden in the
|
||||
SMF instance properties.
|
||||
-->
|
||||
|
||||
<instance name='event' enabled='true' >
|
||||
|
||||
<property_group name='general' type='framework'>
|
||||
<propval name='action_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
<propval name='value_authorization' type='astring'
|
||||
value='solaris.smf.manage.zfs-auto-snapshot' />
|
||||
</property_group>
|
||||
|
||||
<property_group name="zfs" type="application">
|
||||
|
||||
<propval name="fs-name" type="astring" value="//"
|
||||
override="true"/>
|
||||
<propval name="interval" type="astring" value="none"
|
||||
override="true"/>
|
||||
<propval name="period" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="offset" type="astring" value="0"
|
||||
override="true"/>
|
||||
<propval name="keep" type="astring" value="all"
|
||||
override="true"/>
|
||||
<propval name="snapshot-children" type="boolean" value="true"
|
||||
override="true"/>
|
||||
|
||||
<propval name="backup" type="astring" value="none"
|
||||
override="true"/>
|
||||
<propval name="backup-save-cmd" type="astring" value="not set"
|
||||
override="true"/>
|
||||
<propval name="backup-lock" type="astring" value="unlocked"
|
||||
override="true"/>
|
||||
|
||||
<propval name="label" type="astring" value="event"
|
||||
override="true"/>
|
||||
|
||||
<propval name="verbose" type="boolean" value="false"
|
||||
override="true"/>
|
||||
|
||||
<propval name="avoidscrub" type="boolean" value="true"
|
||||
override="false"/>
|
||||
|
||||
<propval name="sep" type="astring" value="_"
|
||||
override="true"/>
|
||||
<propval name="auto-include" type="boolean" value="true" override="true"/>
|
||||
|
||||
</property_group>
|
||||
|
||||
</instance>
|
||||
|
||||
|
||||
|
||||
|
||||
<stability value='Unstable' />
|
||||
|
||||
<template>
|
||||
<common_name>
|
||||
<loctext xml:lang='C'>ZFS automatic snapshots</loctext>
|
||||
</common_name>
|
||||
<description>
|
||||
<loctext xml:lang='C'>
|
||||
This service provides system support for taking automatic snapshots of ZFS
|
||||
filesystems.
|
||||
|
||||
In order to use this service, you must create a service instance per set of automatic snapshots you want to take.
|
||||
|
||||
The on starting a service instance, a cron job corresponding to the properties set in the instance is created on the host. This cron job will regularly take snapshots of the specified ZFS filesystem.
|
||||
|
||||
On stopping the service, that cron job is removed.
|
||||
|
||||
We also have the ability to perform backups, done using the "zfs send" command. A property set in the service called "backup-save-cmd" can be configured as the command used to save the backup stream. See the zfs(1M) man page for an example. The backups can be either "full" backups, or "incremental" backups - for each incremental backup, a full backup must be configured first. If for some reason an incremental backup fails, a full backup is performed instead.
|
||||
|
||||
By default, snapshots will be taken of any datasets resident on pools that are currently being scrubbed or resilvered. This can behaviour can be changed using the zfs/avoid scrub service property.
|
||||
|
||||
Care should be taken when configuring backups to ensure that the time granularity of the cron job is sufficient to allow the backup to complete between invocations of each backup. We perform locking to ensure that two backups of the same filesystem cannot run simultaneously, but will move the service into "maintenance" state should this occur.
|
||||
</loctext>
|
||||
</description>
|
||||
</template>
|
||||
</service>
|
||||
</service_bundle>
|
@ -1,91 +0,0 @@
|
||||
.TH ZFS-AUTO-SNAPSHOT "8" "June 16, 2013" "zfs-auto-snapshot.sh" "System Administration Commands"
|
||||
.SH NAME
|
||||
zfs-auto-snapshot \- take regular ZFS snapshots
|
||||
.SH SYNOPSIS
|
||||
.B zfs-auto-snapshot
|
||||
[\fIoptions\fR] [\fI-l label\fR] \fI<'//' | name \fR[\fIname\fR...]\fI>\fR
|
||||
.SH DESCRIPTION
|
||||
.B zfs-auto-snapshot
|
||||
automatically creates, rotates, and destroys snapshots for all your
|
||||
ZFS datasets, and is compatible with both zfsonlinux and zfs-fuse.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-\-default\-exclude\fR
|
||||
By default \fBzfs-auto-snapshot\fR will snapshot all datasets except
|
||||
for those in which the user-property \fBcom.sun:auto-snapshot\fR is
|
||||
set to \fBfalse\fR. This option reverses the behavior and requires
|
||||
\fBcom.sun:auto-snapshot\fR to be set to \fBtrue\fR.
|
||||
.TP
|
||||
\fB\-d\fR, \fB\-\-debug\fR
|
||||
Print debugging messages.
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-event\fR=\fIEVENT\fR
|
||||
Set the com.sun:auto\-snapshot\-desc property to EVENT.
|
||||
.TP
|
||||
\fB\-\-fast\fR
|
||||
Use a faster zfs list invocation.
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-dry\-run\fR
|
||||
Print actions without actually doing anything.
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-skip\-scrub\fR
|
||||
Do not snapshot filesystems in scrubbing pools.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Print the usage message.
|
||||
.TP
|
||||
\fB\-k\fR, \fB\-\-keep\fR=\fINUM\fR
|
||||
Keep NUM recent snapshots and destroy older snapshots.
|
||||
.TP
|
||||
\fB\-l\fR, \fB\-\-label\fR=\fILAB\fR
|
||||
LAB is usually 'hourly', 'daily', or 'monthly'.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-prefix\fR=\fIPRE\fR
|
||||
PRE is 'zfs\-auto\-snap' by default.
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
Suppress warnings and notices at the console.
|
||||
.TP
|
||||
\fB\-\-send\-full\fR=\fIF\fR
|
||||
Send zfs full backup. Unimplemented.
|
||||
.TP
|
||||
\fB\-\-send\-incr\fR=\fIF\fR
|
||||
Send zfs incremental backup. Unimplemented.
|
||||
.TP
|
||||
\fB\-\-sep\fR=\fICHAR\fR
|
||||
Use CHAR to separate date stamps in snapshot names.
|
||||
.TP
|
||||
\fB\-g\fR, \fB\-\-syslog\fR
|
||||
Write messages into the system log.
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-recursive\fR
|
||||
Snapshot named filesystem and all descendants.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Print info messages.
|
||||
.TP
|
||||
\fB\-\-pre-snapshot\fR=\fICOMMAND\fR
|
||||
Command to run before each dataset is snapshotted.
|
||||
It is passed the dataset and snapshot name. If it
|
||||
returns non-zero, snapshotting this dataset is
|
||||
aborted.
|
||||
.TP
|
||||
\fB\-\-post-snapshot\fR=\fICOMMAND\fR
|
||||
Command to run after each dataset is snapshotted.
|
||||
It is passed the dataset and snapshot name.
|
||||
.TP
|
||||
\fB\-\-destroy-only\fR
|
||||
Do not create new snapshots, but do destroy older
|
||||
snapshots. Has no effect unless used with \fB\-k\fR.
|
||||
.IP
|
||||
A non-obvious use may be construction of cron jobs or
|
||||
scripts that run pre-snapshot command(s), then run
|
||||
zfs-auto-snapshot (without \fB\-k\fR) to quickly
|
||||
snapshot all datasets, then run post-snapshot
|
||||
command(s) and clean up with zfs-auto-snapshot
|
||||
\fB\-\-destroy-only\fR.
|
||||
.TP
|
||||
name
|
||||
Filesystem and volume names, or '//' for all ZFS datasets.
|
||||
.SH SEE ALSO
|
||||
.BR zfs (8)
|
@ -1,631 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# zfs-auto-snapshot for Linux
|
||||
# Automatically create, rotate, and destroy periodic ZFS snapshots.
|
||||
# Copyright 2011 Darik Horn <dajhorn@vanadac.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
# Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
# Set the field separator to a literal tab and newline.
|
||||
IFS="
|
||||
"
|
||||
|
||||
# Set default program options.
|
||||
opt_backup_full=''
|
||||
opt_backup_incremental=''
|
||||
opt_default_exclude=''
|
||||
opt_dry_run=''
|
||||
opt_event='-'
|
||||
opt_fast_zfs_list=''
|
||||
opt_keep=''
|
||||
opt_label=''
|
||||
opt_prefix='zfs-auto-snap'
|
||||
opt_recursive=''
|
||||
opt_sep='_'
|
||||
opt_setauto=''
|
||||
opt_syslog=''
|
||||
opt_skip_scrub=''
|
||||
opt_verbose=''
|
||||
opt_pre_snapshot=''
|
||||
opt_post_snapshot=''
|
||||
opt_do_snapshots=1
|
||||
opt_min_size=0
|
||||
|
||||
# Global summary statistics.
|
||||
DESTRUCTION_COUNT='0'
|
||||
SNAPSHOT_COUNT='0'
|
||||
WARNING_COUNT='0'
|
||||
|
||||
# Other global variables.
|
||||
SNAPSHOTS_OLD=''
|
||||
|
||||
|
||||
print_usage ()
|
||||
{
|
||||
echo "Usage: $0 [options] [-l label] <'//' | name [name...]>
|
||||
--default-exclude Exclude datasets if com.sun:auto-snapshot is unset.
|
||||
-d, --debug Print debugging messages.
|
||||
-e, --event=EVENT Set the com.sun:auto-snapshot-desc property to EVENT.
|
||||
--fast Use a faster zfs list invocation.
|
||||
-n, --dry-run Print actions without actually doing anything.
|
||||
-s, --skip-scrub Do not snapshot filesystems in scrubbing pools.
|
||||
-h, --help Print this usage message.
|
||||
-k, --keep=NUM Keep NUM recent snapshots and destroy older snapshots.
|
||||
-l, --label=LAB LAB is usually 'hourly', 'daily', or 'monthly'.
|
||||
-p, --prefix=PRE PRE is 'zfs-auto-snap' by default.
|
||||
-q, --quiet Suppress warnings and notices at the console.
|
||||
--send-full=F Send zfs full backup. Unimplemented.
|
||||
--send-incr=F Send zfs incremental backup. Unimplemented.
|
||||
--sep=CHAR Use CHAR to separate date stamps in snapshot names.
|
||||
-g, --syslog Write messages into the system log.
|
||||
-r, --recursive Snapshot named filesystem and all descendants.
|
||||
-v, --verbose Print info messages.
|
||||
--destroy-only Only destroy older snapshots, do not create new ones.
|
||||
name Filesystem and volume names, or '//' for all ZFS datasets.
|
||||
"
|
||||
}
|
||||
|
||||
|
||||
print_log () # level, message, ...
|
||||
{
|
||||
LEVEL=$1
|
||||
shift 1
|
||||
|
||||
case $LEVEL in
|
||||
(eme*)
|
||||
test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.emerge $*
|
||||
echo Emergency: $* 1>&2
|
||||
;;
|
||||
(ale*)
|
||||
test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.alert $*
|
||||
echo Alert: $* 1>&2
|
||||
;;
|
||||
(cri*)
|
||||
test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.crit $*
|
||||
echo Critical: $* 1>&2
|
||||
;;
|
||||
(err*)
|
||||
test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.err $*
|
||||
echo Error: $* 1>&2
|
||||
;;
|
||||
(war*)
|
||||
test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.warning $*
|
||||
test -z "$opt_quiet" && echo Warning: $* 1>&2
|
||||
;;
|
||||
(not*)
|
||||
test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.notice $*
|
||||
test -z "$opt_quiet" && echo $*
|
||||
;;
|
||||
(inf*)
|
||||
# test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.info $*
|
||||
test -z "$opt_quiet" && test -n "$opt_verbose" && echo $*
|
||||
;;
|
||||
(deb*)
|
||||
# test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.debug $*
|
||||
test -n "$opt_debug" && echo Debug: $*
|
||||
;;
|
||||
(*)
|
||||
test -n "$opt_syslog" && logger -t "$opt_prefix" $*
|
||||
echo $* 1>&2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
do_run () # [argv]
|
||||
{
|
||||
if [ -n "$opt_dry_run" ]
|
||||
then
|
||||
echo $*
|
||||
RC="$?"
|
||||
else
|
||||
eval $*
|
||||
RC="$?"
|
||||
if [ "$RC" -eq '0' ]
|
||||
then
|
||||
print_log debug "$*"
|
||||
else
|
||||
print_log warning "$* returned $RC"
|
||||
fi
|
||||
fi
|
||||
return "$RC"
|
||||
}
|
||||
|
||||
|
||||
do_snapshots () # properties, flags, snapname, oldglob, [targets...]
|
||||
{
|
||||
local PROPS="$1"
|
||||
local FLAGS="$2"
|
||||
local NAME="$3"
|
||||
local GLOB="$4"
|
||||
local TARGETS="$5"
|
||||
local KEEP=''
|
||||
local RUNSNAP=1
|
||||
|
||||
# global DESTRUCTION_COUNT
|
||||
# global SNAPSHOT_COUNT
|
||||
# global WARNING_COUNT
|
||||
# global SNAPSHOTS_OLD
|
||||
|
||||
for ii in $TARGETS
|
||||
do
|
||||
# Check if size check is > 0
|
||||
size_check_skip=0
|
||||
if [ "$opt_min_size" -gt 0 ]
|
||||
then
|
||||
bytes_written=`zfs get -Hp -o value written $ii`
|
||||
kb_written=$(( $bytes_written / 1024 ))
|
||||
if [ "$kb_written" -lt "$opt_min_size" ]
|
||||
then
|
||||
size_check_skip=1
|
||||
if [ $opt_verbose -gt 0 ]
|
||||
then
|
||||
echo "Skipping target $ii, only $kb_written kB written since last snap. opt_min_size is $opt_min_size"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$opt_do_snapshots" -a "$size_check_skip" -eq 0 ]
|
||||
then
|
||||
if [ "$opt_pre_snapshot" != "" ]
|
||||
then
|
||||
do_run "$opt_pre_snapshot $ii $NAME" || RUNSNAP=0
|
||||
fi
|
||||
if [ $RUNSNAP -eq 1 ] && do_run "zfs snapshot $PROPS $FLAGS '$ii@$NAME'"
|
||||
then
|
||||
[ "$opt_post_snapshot" != "" ] && do_run "$opt_post_snapshot $ii $NAME"
|
||||
SNAPSHOT_COUNT=$(( $SNAPSHOT_COUNT + 1 ))
|
||||
else
|
||||
WARNING_COUNT=$(( $WARNING_COUNT + 1 ))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Retain at most $opt_keep number of old snapshots of this filesystem,
|
||||
# including the one that was just recently created.
|
||||
test -z "$opt_keep" && continue
|
||||
KEEP="$opt_keep"
|
||||
|
||||
# ASSERT: The old snapshot list is sorted by increasing age.
|
||||
for jj in $SNAPSHOTS_OLD
|
||||
do
|
||||
# Check whether this is an old snapshot of the filesystem.
|
||||
if [ -z "${jj#$ii@$GLOB}" ]
|
||||
then
|
||||
KEEP=$(( $KEEP - 1 ))
|
||||
if [ "$KEEP" -le '0' ]
|
||||
then
|
||||
if do_run "zfs destroy -d $FLAGS '$jj'"
|
||||
then
|
||||
DESTRUCTION_COUNT=$(( $DESTRUCTION_COUNT + 1 ))
|
||||
else
|
||||
WARNING_COUNT=$(( $WARNING_COUNT + 1 ))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# main ()
|
||||
# {
|
||||
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
GETOPT_BIN="$(brew --prefix gnu-getopt 2> /dev/null || echo /usr/local)/bin/getopt"
|
||||
else
|
||||
GETOPT_BIN="getopt"
|
||||
fi
|
||||
|
||||
GETOPT=$($GETOPT_BIN \
|
||||
--longoptions=default-exclude,dry-run,fast,skip-scrub,recursive \
|
||||
--longoptions=event:,keep:,label:,prefix:,sep: \
|
||||
--longoptions=debug,help,quiet,syslog,verbose \
|
||||
--longoptions=pre-snapshot:,post-snapshot:,destroy-only \
|
||||
--longoptions=min-size: \
|
||||
--options=dnshe:l:k:p:rs:qgvm: \
|
||||
-- "$@" ) \
|
||||
|| exit 128
|
||||
|
||||
eval set -- "$GETOPT"
|
||||
|
||||
while [ "$#" -gt '0' ]
|
||||
do
|
||||
case "$1" in
|
||||
(-d|--debug)
|
||||
opt_debug='1'
|
||||
opt_quiet=''
|
||||
opt_verbose='1'
|
||||
shift 1
|
||||
;;
|
||||
(--default-exclude)
|
||||
opt_default_exclude='1'
|
||||
shift 1
|
||||
;;
|
||||
(-e|--event)
|
||||
if [ "${#2}" -gt '1024' ]
|
||||
then
|
||||
print_log error "The $1 parameter must be less than 1025 characters."
|
||||
exit 139
|
||||
elif [ "${#2}" -gt '0' ]
|
||||
then
|
||||
opt_event="$2"
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
(--fast)
|
||||
opt_fast_zfs_list='1'
|
||||
shift 1
|
||||
;;
|
||||
(-n|--dry-run)
|
||||
opt_dry_run='1'
|
||||
shift 1
|
||||
;;
|
||||
(-s|--skip-scrub)
|
||||
opt_skip_scrub='1'
|
||||
shift 1
|
||||
;;
|
||||
(-h|--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
(-k|--keep)
|
||||
if ! test "$2" -gt '0' 2>/dev/null
|
||||
then
|
||||
print_log error "The $1 parameter must be a positive integer."
|
||||
exit 129
|
||||
fi
|
||||
opt_keep="$2"
|
||||
shift 2
|
||||
;;
|
||||
(-l|--label)
|
||||
opt_label="$2"
|
||||
shift 2
|
||||
;;
|
||||
(-m|--min-size)
|
||||
opt_min_size="$2"
|
||||
shift 2
|
||||
;;
|
||||
(-p|--prefix)
|
||||
opt_prefix="$2"
|
||||
while test "${#opt_prefix}" -gt '0'
|
||||
do
|
||||
case $opt_prefix in
|
||||
([![:alnum:]_.:\ -]*)
|
||||
print_log error "The $1 parameter must be alphanumeric."
|
||||
exit 130
|
||||
;;
|
||||
esac
|
||||
opt_prefix="${opt_prefix#?}"
|
||||
done
|
||||
opt_prefix="$2"
|
||||
shift 2
|
||||
;;
|
||||
(-q|--quiet)
|
||||
opt_debug=''
|
||||
opt_quiet='1'
|
||||
opt_verbose=''
|
||||
shift 1
|
||||
;;
|
||||
(-r|--recursive)
|
||||
opt_recursive='1'
|
||||
shift 1
|
||||
;;
|
||||
(--sep)
|
||||
case "$2" in
|
||||
([[:alnum:]_.:\ -])
|
||||
:
|
||||
;;
|
||||
('')
|
||||
print_log error "The $1 parameter must be non-empty."
|
||||
exit 131
|
||||
;;
|
||||
(*)
|
||||
print_log error "The $1 parameter must be one alphanumeric character."
|
||||
exit 132
|
||||
;;
|
||||
esac
|
||||
opt_sep="$2"
|
||||
shift 2
|
||||
;;
|
||||
(-g|--syslog)
|
||||
opt_syslog='1'
|
||||
shift 1
|
||||
;;
|
||||
(-v|--verbose)
|
||||
opt_quiet=''
|
||||
opt_verbose='1'
|
||||
shift 1
|
||||
;;
|
||||
(--pre-snapshot)
|
||||
opt_pre_snapshot="$2"
|
||||
shift 2
|
||||
;;
|
||||
(--post-snapshot)
|
||||
opt_post_snapshot="$2"
|
||||
shift 2
|
||||
;;
|
||||
(--destroy-only)
|
||||
opt_do_snapshots=''
|
||||
shift 1
|
||||
;;
|
||||
(--)
|
||||
shift 1
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$#" -eq '0' ]
|
||||
then
|
||||
print_log error "The filesystem argument list is empty."
|
||||
exit 133
|
||||
fi
|
||||
|
||||
# Count the number of times '//' appears on the command line.
|
||||
SLASHIES='0'
|
||||
for ii in "$@"
|
||||
do
|
||||
test "$ii" = '//' && SLASHIES=$(( $SLASHIES + 1 ))
|
||||
done
|
||||
|
||||
if [ "$#" -gt '1' -a "$SLASHIES" -gt '0' ]
|
||||
then
|
||||
print_log error "The // must be the only argument if it is given."
|
||||
exit 134
|
||||
fi
|
||||
|
||||
# These are the only times that `zpool status` or `zfs list` are invoked, so
|
||||
# this program for Linux has a much better runtime complexity than the similar
|
||||
# Solaris implementation.
|
||||
|
||||
ZPOOL_STATUS=$(env LC_ALL=C zpool status 2>&1 ) \
|
||||
|| { print_log error "zpool status $?: $ZPOOL_STATUS"; exit 135; }
|
||||
|
||||
|
||||
ZFS_LIST=$(env LC_ALL=C zfs list -H -t filesystem,volume -s name \
|
||||
-o name,com.sun:auto-snapshot,com.sun:auto-snapshot:"$opt_label") \
|
||||
|| { print_log error "zfs list $?: $ZFS_LIST"; exit 136; }
|
||||
|
||||
if [ -n "$opt_fast_zfs_list" ]
|
||||
then
|
||||
# Check if a snapshot label is being used, in which case restrict the old
|
||||
# snapshot removal to only snapshots with the same label format
|
||||
if [ -n "$opt_label" ]
|
||||
then
|
||||
SNAPSHOTS_OLD=$(env LC_ALL=C zfs list -H -t snapshot -o name -s name | \
|
||||
grep "$opt_prefix"_"$opt_label" | \
|
||||
awk '{ print substr( $0, length($0) - 14, length($0) ) " " $0}' | \
|
||||
sort -r -k1,1 -k2,2 | \
|
||||
awk '{ print substr( $0, 17, length($0) )}') \
|
||||
|| { print_log error "zfs list $?: $SNAPSHOTS_OLD"; exit 137; }
|
||||
else
|
||||
SNAPSHOTS_OLD=$(env LC_ALL=C zfs list -H -t snapshot -o name -s name | \
|
||||
grep $opt_prefix | \
|
||||
awk '{ print substr( $0, length($0) - 14, length($0) ) " " $0}' | \
|
||||
sort -r -k1,1 -k2,2 | \
|
||||
awk '{ print substr( $0, 17, length($0) )}') \
|
||||
|| { print_log error "zfs list $?: $SNAPSHOTS_OLD"; exit 137; }
|
||||
fi
|
||||
else
|
||||
SNAPSHOTS_OLD=$(env LC_ALL=C zfs list -H -t snapshot -S creation -o name) \
|
||||
|| { print_log error "zfs list $?: $SNAPSHOTS_OLD"; exit 137; }
|
||||
fi
|
||||
|
||||
# Verify that each argument is a filesystem or volume.
|
||||
for ii in "$@"
|
||||
do
|
||||
test "$ii" = '//' && continue 1
|
||||
while read NAME PROPERTIES
|
||||
do
|
||||
test "$ii" = "$NAME" && continue 2
|
||||
done <<-HERE
|
||||
$ZFS_LIST
|
||||
HERE
|
||||
print_log error "$ii is not a ZFS filesystem or volume."
|
||||
exit 138
|
||||
done
|
||||
|
||||
# Get a list of pools that are being scrubbed.
|
||||
ZPOOLS_SCRUBBING=$(echo "$ZPOOL_STATUS" | awk -F ': ' \
|
||||
'$1 ~ /^ *pool$/ { pool = $2 } ; \
|
||||
$1 ~ /^ *scan$/ && $2 ~ /scrub in progress/ { print pool }' \
|
||||
| sort )
|
||||
|
||||
# Get a list of pools that cannot do a snapshot.
|
||||
ZPOOLS_NOTREADY=$(echo "$ZPOOL_STATUS" | awk -F ': ' \
|
||||
'$1 ~ /^ *pool$/ { pool = $2 } ; \
|
||||
$1 ~ /^ *state$/ && $2 !~ /ONLINE|DEGRADED/ { print pool } ' \
|
||||
| sort)
|
||||
|
||||
# Get a list of datasets for which snapshots are explicitly disabled.
|
||||
NOAUTO=$(echo "$ZFS_LIST" | awk -F '\t' \
|
||||
'tolower($2) ~ /false/ || tolower($3) ~ /false/ {print $1}')
|
||||
|
||||
# If the --default-exclude flag is set, then exclude all datasets that lack
|
||||
# an explicit com.sun:auto-snapshot* property. Otherwise, include them.
|
||||
if [ -n "$opt_default_exclude" ]
|
||||
then
|
||||
# Get a list of datasets for which snapshots are explicitly enabled.
|
||||
CANDIDATES=$(echo "$ZFS_LIST" | awk -F '\t' \
|
||||
'tolower($2) ~ /true/ || tolower($3) ~ /true/ {print $1}')
|
||||
else
|
||||
# Invert the NOAUTO list.
|
||||
CANDIDATES=$(echo "$ZFS_LIST" | awk -F '\t' \
|
||||
'tolower($2) !~ /false/ && tolower($3) !~ /false/ {print $1}')
|
||||
fi
|
||||
|
||||
# Initialize the list of datasets that will get a recursive snapshot.
|
||||
TARGETS_RECURSIVE=''
|
||||
|
||||
# Initialize the list of datasets that will get a non-recursive snapshot.
|
||||
TARGETS_REGULAR=''
|
||||
|
||||
for ii in $CANDIDATES
|
||||
do
|
||||
# Qualify dataset names so variable globbing works properly.
|
||||
# Suppose ii=tanker/foo and jj=tank sometime during the loop.
|
||||
# Just testing "$ii" != ${ii#$jj} would incorrectly match.
|
||||
iii="$ii/"
|
||||
|
||||
|
||||
# Exclude datasets
|
||||
# * that are not named on the command line or
|
||||
# * those whose prefix is not on the command line (if --recursive flag is set)
|
||||
IN_ARGS='0'
|
||||
for jj in "$@"
|
||||
do
|
||||
# Ibid regarding iii.
|
||||
jjj="$jj/"
|
||||
|
||||
if [ "$jj" = '//' -o "$jj" = "$ii" ]
|
||||
then
|
||||
IN_ARGS=$(( $IN_ARGS + 1 ))
|
||||
elif [ -n "$opt_recursive" -a "$iii" != "${iii#$jjj}" ]
|
||||
then
|
||||
IN_ARGS=$(( $IN_ARGS + 1 ))
|
||||
fi
|
||||
done
|
||||
if [ "$IN_ARGS" -eq '0' ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Exclude datasets in pools that cannot do a snapshot.
|
||||
for jj in $ZPOOLS_NOTREADY
|
||||
do
|
||||
# Ibid regarding iii.
|
||||
jjj="$jj/"
|
||||
|
||||
# Check whether the pool name is a prefix of the dataset name.
|
||||
if [ "$iii" != "${iii#$jjj}" ]
|
||||
then
|
||||
print_log info "Excluding $ii because pool $jj is not ready."
|
||||
continue 2
|
||||
fi
|
||||
done
|
||||
|
||||
# Exclude datasets in scrubbing pools if the --skip-scrub flag is set.
|
||||
test -n "$opt_skip_scrub" && for jj in $ZPOOLS_SCRUBBING
|
||||
do
|
||||
# Ibid regarding iii.
|
||||
jjj="$jj/"
|
||||
|
||||
# Check whether the pool name is a prefix of the dataset name.
|
||||
if [ "$iii" != "${iii#$jjj}" ]
|
||||
then
|
||||
print_log info "Excluding $ii because pool $jj is scrubbing."
|
||||
continue 2
|
||||
fi
|
||||
done
|
||||
|
||||
for jj in $NOAUTO
|
||||
do
|
||||
# Ibid regarding iii.
|
||||
jjj="$jj/"
|
||||
|
||||
# The --recursive switch only matters for non-wild arguments.
|
||||
if [ -z "$opt_recursive" -a "$1" != '//' ]
|
||||
then
|
||||
# Snapshot this dataset non-recursively.
|
||||
print_log debug "Including $ii for regular snapshot."
|
||||
TARGETS_REGULAR="${TARGETS_REGULAR:+$TARGETS_REGULAR }$ii" # nb: \t
|
||||
continue 2
|
||||
# Check whether the candidate name is a prefix of any excluded dataset name.
|
||||
elif [ "$jjj" != "${jjj#$iii}" ]
|
||||
then
|
||||
# Snapshot this dataset non-recursively.
|
||||
print_log debug "Including $ii for regular snapshot."
|
||||
TARGETS_REGULAR="${TARGETS_REGULAR:+$TARGETS_REGULAR }$ii" # nb: \t
|
||||
continue 2
|
||||
fi
|
||||
done
|
||||
|
||||
for jj in $TARGETS_RECURSIVE
|
||||
do
|
||||
# Ibid regarding iii.
|
||||
jjj="$jj/"
|
||||
|
||||
# Check whether any included dataset is a prefix of the candidate name.
|
||||
if [ "$iii" != "${iii#$jjj}" ]
|
||||
then
|
||||
print_log debug "Excluding $ii because $jj includes it recursively."
|
||||
continue 2
|
||||
fi
|
||||
done
|
||||
|
||||
# Append this candidate to the recursive snapshot list because it:
|
||||
#
|
||||
# * Does not have an exclusionary property.
|
||||
# * Is in a pool that can currently do snapshots.
|
||||
# * Does not have an excluded descendent filesystem.
|
||||
# * Is not the descendant of an already included filesystem.
|
||||
#
|
||||
print_log debug "Including $ii for recursive snapshot."
|
||||
TARGETS_RECURSIVE="${TARGETS_RECURSIVE:+$TARGETS_RECURSIVE }$ii" # nb: \t
|
||||
done
|
||||
|
||||
# Linux lacks SMF and the notion of an FMRI event, but always set this property
|
||||
# because the SUNW program does. The dash character is the default.
|
||||
SNAPPROP="-o com.sun:auto-snapshot-desc='$opt_event'"
|
||||
|
||||
# ISO style date; fifteen characters: YYYY-MM-DD-HHMM
|
||||
# On Solaris %H%M expands to 12h34.
|
||||
# We use the shortfirm -u here because --utc is not supported on macos.
|
||||
DATE=$(date -u +%F-%H%M)
|
||||
|
||||
# The snapshot name after the @ symbol.
|
||||
SNAPNAME="${opt_prefix:+$opt_prefix$opt_sep}${opt_label:+$opt_label}-$DATE"
|
||||
|
||||
# The expression for matching old snapshots. -YYYY-MM-DD-HHMM
|
||||
SNAPGLOB="${opt_prefix:+$opt_prefix$opt_sep}${opt_label:+$opt_label}-???????????????"
|
||||
|
||||
if [ -n "$opt_do_snapshots" ]
|
||||
then
|
||||
test -n "$TARGETS_REGULAR" \
|
||||
&& print_log info "Doing regular snapshots of $TARGETS_REGULAR"
|
||||
|
||||
test -n "$TARGETS_RECURSIVE" \
|
||||
&& print_log info "Doing recursive snapshots of $TARGETS_RECURSIVE"
|
||||
|
||||
if test -n "$opt_keep" && [ "$opt_keep" -ge "1" ]
|
||||
then
|
||||
print_log info "Destroying all but the newest $opt_keep snapshots of each dataset."
|
||||
fi
|
||||
elif test -n "$opt_keep" && [ "$opt_keep" -ge "1" ]
|
||||
then
|
||||
test -n "$TARGETS_REGULAR" \
|
||||
&& print_log info "Destroying all but the newest $opt_keep snapshots of $TARGETS_REGULAR"
|
||||
|
||||
test -n "$TARGETS_RECURSIVE" \
|
||||
&& print_log info "Recursively destroying all but the newest $opt_keep snapshots of $TARGETS_RECURSIVE"
|
||||
else
|
||||
print_log notice "Only destroying snapshots, but count of snapshots to preserve not given. Nothing to do."
|
||||
fi
|
||||
|
||||
test -n "$opt_dry_run" \
|
||||
&& print_log info "Doing a dry run. Not running these commands..."
|
||||
|
||||
do_snapshots "$SNAPPROP" "" "$SNAPNAME" "$SNAPGLOB" "$TARGETS_REGULAR"
|
||||
do_snapshots "$SNAPPROP" "-r" "$SNAPNAME" "$SNAPGLOB" "$TARGETS_RECURSIVE"
|
||||
|
||||
print_log notice "@$SNAPNAME," \
|
||||
"$SNAPSHOT_COUNT created," \
|
||||
"$DESTRUCTION_COUNT destroyed," \
|
||||
"$WARNING_COUNT warnings."
|
||||
|
||||
exit 0
|
||||
# }
|
Loading…
Reference in New Issue
Block a user