lib/zfs_mgmt.rb in zfs_mgmt-0.3.5 vs lib/zfs_mgmt.rb in zfs_mgmt-0.3.6
- old
+ new
@@ -1,8 +1,9 @@
# coding: utf-8
require "zfs_mgmt/version"
require "zfs_mgmt/restic"
+require "zfs_mgmt/zfs_mgr"
require 'pp'
require 'date'
require 'logger'
require 'text-table'
require 'open3'
@@ -62,11 +63,49 @@
return md[1].to_i * $time_specs[md[2].downcase]
else
return md[1].to_i
end
end
-
+
+ def self.zfs_holds(snapshot)
+ com = ['zfs', 'holds', '-H', snapshot]
+ $logger.debug("#{com.join(' ')}")
+ out = %x(#{com.join(' ')})
+ unless $?.success?
+ errstr = "unable to retrieves holds for snapshot: #{snapshot}"
+ $logger.error(errstr)
+ raise errstr
+ end
+ a = []
+ out.split("\n").each do |ln|
+ a.push(ln.split("\t")[1])
+ end
+ a
+ end
+
+ def self.zfs_hold(hold,snapshot)
+ com = ['zfs', 'hold', hold, snapshot]
+ $logger.debug("#{com.join(' ')}")
+ system(com.join(' '))
+ unless $?.success?
+ errstr = "unable to set hold: #{hold} for snapshot: #{snapshot}"
+ $logger.error(errstr)
+ raise errstr
+ end
+ end
+
+ def self.zfs_release(hold,snapshot)
+ com = ['zfs', 'release', hold, snapshot]
+ $logger.debug("#{com.join(' ')}")
+ system(com.join(' '))
+ unless $?.success?
+ errstr = "unable to release hold: #{hold} for snapshot: #{snapshot}"
+ $logger.error(errstr)
+ raise errstr
+ end
+ end
+
def self.zfsget(properties: ['name'],types: ['filesystem','volume'],zfs: '')
results={}
com = ['zfs', 'get', '-Hp', properties.join(','), '-t', types.join(','), zfs]
so,se,status = Open3.capture3(com.join(' '))
if status.signaled?
@@ -190,28 +229,29 @@
true
end
}
return saved,saved_snaps,deleteme
end
- def self.zfs_managed_list(filter: '.+')
+ def self.zfs_managed_list(filter: '.+', properties: custom_properties(), property_match: { 'zfsmgmt:manage' => 'true' } )
zfss = [] # array of arrays
- zfsget(properties: custom_properties()).each do |zfs,props|
+ zfsget(properties: properties).each do |zfs,props|
unless /#{filter}/ =~ zfs
next
end
- unless props.has_key?('zfsmgmt:manage') and props['zfsmgmt:manage'] == 'true'
- next
+ managed = true
+ property_match.each do |k,v|
+ unless props.has_key?(k) and props[k] == v
+ managed = false
+ break
+ end
end
+ next unless managed
snaps = self.zfsget(properties: ['name','creation','userrefs','used','written','referenced'],types: ['snapshot'], zfs: zfs)
if snaps.length == 0
$logger.warn("unable to process this zfs, no snapshots at all: #{zfs}")
next
end
- unless props.has_key?('zfsmgmt:policy') and policy = policy_parser(props['zfsmgmt:policy'])
- $logger.error("zfs_mgmt is configured to manage #{zfs}, but there is no valid policy configuration, skipping")
- next # zfs
- end
zfss.push([zfs,props,snaps])
end
return zfss
end
def self.snapshot_policy(verbopt: false, debugopt: false, filter: '.+')
@@ -220,10 +260,14 @@
else
$logger.level = Logger::INFO
end
zfs_managed_list(filter: filter).each do |zdata|
(zfs,props,snaps) = zdata
+ unless props.has_key?('zfsmgmt:policy') and policy_parser(props['zfsmgmt:policy'])
+ $logger.error("zfs_mgmt is configured to manage #{zfs}, but there is no valid policy configuration, skipping")
+ next # zfs
+ end
# call the function that decides who to save and who to delete
(saved,saved_snaps,deleteme) = snapshot_destroy_policy(zfs,props,snaps)
if saved_snaps.length == 0
$logger.info("no snapshots marked as saved by policy for #{zfs}")
@@ -245,10 +289,15 @@
else
$logger.level = Logger::INFO
end
zfs_managed_list(filter: filter).each do |zdata|
(zfs,props,snaps) = zdata
+ unless props.has_key?('zfsmgmt:policy') and policy_parser(props['zfsmgmt:policy'])
+ $logger.error("zfs_mgmt is configured to manage #{zfs}, but there is no valid policy configuration, skipping")
+ next # zfs
+ end
+
# call the function that decides who to save and who to delete
(saved,saved_snaps,deleteme) = snapshot_destroy_policy(zfs,props,snaps)
$logger.info("deleting #{deleteme.length} snapshots for #{zfs}")
deleteme.reverse! # oldest first for removal
@@ -328,31 +377,8 @@
end
com.push("#{zfs}@#{[prefix,dt.strftime(ts)].join('-')}")
$logger.info(com)
system(com.join(' '))
end
- end
- end
-end
-class ZfsMgmtList < Thor
- class_option :filter, :type => :string, :default => '.+',
- :desc => 'only act on zfs matching this regexp'
- desc "stale", "list all zfs with stale snapshots"
- method_option :age, :desc => "timeframe outside of which the zfs will be considered stale", :default => '1d'
- def stale()
- cutoff = Time.at(Time.now.to_i - ZfsMgmt.timespec_to_seconds(options[:age]))
- table = Text::Table.new
- table.head = ['zfs','snapshot','age']
- table.rows = []
- ZfsMgmt.zfs_managed_list(filter: options[:filter]).each do |blob|
- zfs,props,snaps = blob
- last = snaps.keys.sort { |a,b| snaps[a]['creation'] <=> snaps[b]['creation'] }.last
- snap_time = Time.at(snaps[last]['creation'])
- if snap_time < cutoff
- table.rows << [zfs,last.split('@')[1],snap_time]
- end
- end
- if table.rows.count > 0
- print table.to_s
end
end
end