"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "salt/states/zfs.py" between
salt-3002.1.tar.gz and salt-3002.2.tar.gz

About: SaltStack is a systems management software for data center automation, cloud orchestration, server provisioning, configuration management and more. Community version.

zfs.py  (salt-3002.1):zfs.py  (salt-3002.2)
# -*- coding: utf-8 -*-
""" """
States for managing zfs datasets States for managing zfs datasets
:maintainer: Jorge Schrauwen <sjorge@blackdot.be> :maintainer: Jorge Schrauwen <sjorge@blackdot.be>
:maturity: new :maturity: new
:depends: salt.utils.zfs, salt.modules.zfs :depends: salt.utils.zfs, salt.modules.zfs
:platform: smartos, illumos, solaris, freebsd, linux :platform: smartos, illumos, solaris, freebsd, linux
.. versionadded:: 2016.3.0 .. versionadded:: 2016.3.0
.. versionchanged:: 2018.3.1 .. versionchanged:: 2018.3.1
skipping to change at line 46 skipping to change at line 45
- snapshot: test/shares/yuki@frozen - snapshot: test/shares/yuki@frozen
test/shares/moka: test/shares/moka:
zfs.filesystem_present: zfs.filesystem_present:
- cloned_from: test/shares/yuki@frozen - cloned_from: test/shares/yuki@frozen
test/shares/moka@tsukune: test/shares/moka@tsukune:
zfs.snapshot_absent zfs.snapshot_absent
""" """
from __future__ import absolute_import, print_function, unicode_literals
# Import Python libs
import logging import logging
from datetime import datetime from datetime import datetime
# Import Salt libs
from salt.utils.odict import OrderedDict from salt.utils.odict import OrderedDict
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# Define the state's virtual name # Define the state's virtual name
__virtualname__ = "zfs" __virtualname__ = "zfs"
# Compare modifiers for zfs.schedule_snapshot # Compare modifiers for zfs.schedule_snapshot
comp_hour = {"minute": 0} comp_hour = {"minute": 0}
comp_day = {"minute": 0, "hour": 0} comp_day = {"minute": 0, "hour": 0}
skipping to change at line 110 skipping to change at line 106
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.destroy"]( mod_res = __salt__["zfs.destroy"](
name, **{"force": force, "recursive": recursive} name, **{"force": force, "recursive": recursive}
) )
else: else:
mod_res = OrderedDict([("destroyed", True)]) mod_res = OrderedDict([("destroyed", True)])
ret["result"] = mod_res["destroyed"] ret["result"] = mod_res["destroyed"]
if ret["result"]: if ret["result"]:
ret["changes"][name] = "destroyed" ret["changes"][name] = "destroyed"
ret["comment"] = "{0} {1} was destroyed".format(dataset_type, name,) ret["comment"] = "{} {} was destroyed".format(dataset_type, name,)
else: else:
ret["comment"] = "failed to destroy {0} {1}".format(dataset_type, na me,) ret["comment"] = "failed to destroy {} {}".format(dataset_type, name ,)
if "error" in mod_res: if "error" in mod_res:
ret["comment"] = mod_res["error"] ret["comment"] = mod_res["error"]
else: else:
## NOTE: no dataset found with name of the dataset_type ## NOTE: no dataset found with name of the dataset_type
ret["comment"] = "{0} {1} is absent".format(dataset_type, name) ret["comment"] = "{} {} is absent".format(dataset_type, name)
return ret return ret
def filesystem_absent(name, force=False, recursive=False): def filesystem_absent(name, force=False, recursive=False):
""" """
ensure filesystem is absent on the system ensure filesystem is absent on the system
name : string name : string
name of filesystem name of filesystem
force : boolean force : boolean
skipping to change at line 143 skipping to change at line 139
If a volume with ``name`` exists, this state will succeed without If a volume with ``name`` exists, this state will succeed without
destroying the volume specified by ``name``. This module is dataset type sensitive. destroying the volume specified by ``name``. This module is dataset type sensitive.
""" """
if not __utils__["zfs.is_dataset"](name): if not __utils__["zfs.is_dataset"](name):
ret = { ret = {
"name": name, "name": name,
"changes": {}, "changes": {},
"result": False, "result": False,
"comment": "invalid dataset name: {0}".format(name), "comment": "invalid dataset name: {}".format(name),
} }
else: else:
ret = _absent(name, "filesystem", force, recursive) ret = _absent(name, "filesystem", force, recursive)
return ret return ret
def volume_absent(name, force=False, recursive=False): def volume_absent(name, force=False, recursive=False):
""" """
ensure volume is absent on the system ensure volume is absent on the system
name : string name : string
skipping to change at line 171 skipping to change at line 167
If a filesystem with ``name`` exists, this state will succeed without If a filesystem with ``name`` exists, this state will succeed without
destroying the filesystem specified by ``name``. This module is dataset type sensitive. destroying the filesystem specified by ``name``. This module is dataset type sensitive.
""" """
if not __utils__["zfs.is_dataset"](name): if not __utils__["zfs.is_dataset"](name):
ret = { ret = {
"name": name, "name": name,
"changes": {}, "changes": {},
"result": False, "result": False,
"comment": "invalid dataset name: {0}".format(name), "comment": "invalid dataset name: {}".format(name),
} }
else: else:
ret = _absent(name, "volume", force, recursive) ret = _absent(name, "volume", force, recursive)
return ret return ret
def snapshot_absent(name, force=False, recursive=False): def snapshot_absent(name, force=False, recursive=False):
""" """
ensure snapshot is absent on the system ensure snapshot is absent on the system
name : string name : string
skipping to change at line 194 skipping to change at line 190
try harder to destroy the dataset (zfs destroy -f) try harder to destroy the dataset (zfs destroy -f)
recursive : boolean recursive : boolean
also destroy all the child datasets (zfs destroy -r) also destroy all the child datasets (zfs destroy -r)
""" """
if not __utils__["zfs.is_snapshot"](name): if not __utils__["zfs.is_snapshot"](name):
ret = { ret = {
"name": name, "name": name,
"changes": {}, "changes": {},
"result": False, "result": False,
"comment": "invalid snapshot name: {0}".format(name), "comment": "invalid snapshot name: {}".format(name),
} }
else: else:
ret = _absent(name, "snapshot", force, recursive) ret = _absent(name, "snapshot", force, recursive)
return ret return ret
def bookmark_absent(name, force=False, recursive=False): def bookmark_absent(name, force=False, recursive=False):
""" """
ensure bookmark is absent on the system ensure bookmark is absent on the system
name : string name : string
skipping to change at line 217 skipping to change at line 213
try harder to destroy the dataset (zfs destroy -f) try harder to destroy the dataset (zfs destroy -f)
recursive : boolean recursive : boolean
also destroy all the child datasets (zfs destroy -r) also destroy all the child datasets (zfs destroy -r)
""" """
if not __utils__["zfs.is_bookmark"](name): if not __utils__["zfs.is_bookmark"](name):
ret = { ret = {
"name": name, "name": name,
"changes": {}, "changes": {},
"result": False, "result": False,
"comment": "invalid bookmark name: {0}".format(name), "comment": "invalid bookmark name: {}".format(name),
} }
else: else:
ret = _absent(name, "bookmark", force, recursive) ret = _absent(name, "bookmark", force, recursive)
return ret return ret
def hold_absent(name, snapshot, recursive=False): def hold_absent(name, snapshot, recursive=False):
""" """
ensure hold is absent on the system ensure hold is absent on the system
name : string name : string
skipping to change at line 244 skipping to change at line 240
""" """
ret = {"name": name, "changes": {}, "result": True, "comment": ""} ret = {"name": name, "changes": {}, "result": True, "comment": ""}
## log configuration ## log configuration
log.debug("zfs.hold_absent::%s::config::snapshot = %s", name, snapshot) log.debug("zfs.hold_absent::%s::config::snapshot = %s", name, snapshot)
log.debug("zfs.hold_absent::%s::config::recursive = %s", name, recursive) log.debug("zfs.hold_absent::%s::config::recursive = %s", name, recursive)
## check we have a snapshot/tag name ## check we have a snapshot/tag name
if not __utils__["zfs.is_snapshot"](snapshot): if not __utils__["zfs.is_snapshot"](snapshot):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid snapshot name: {0}".format(snapshot) ret["comment"] = "invalid snapshot name: {}".format(snapshot)
return ret return ret
if ( if (
__utils__["zfs.is_snapshot"](name) __utils__["zfs.is_snapshot"](name)
or __utils__["zfs.is_bookmark"](name) or __utils__["zfs.is_bookmark"](name)
or name == "error" or name == "error"
): ):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid tag name: {0}".format(name) ret["comment"] = "invalid tag name: {}".format(name)
return ret return ret
## release hold if required ## release hold if required
holds = __salt__["zfs.holds"](snapshot) holds = __salt__["zfs.holds"](snapshot)
if name in holds: if name in holds:
## NOTE: hold found for snapshot, release it ## NOTE: hold found for snapshot, release it
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.release"]( mod_res = __salt__["zfs.release"](
name, snapshot, **{"recursive": recursive} name, snapshot, **{"recursive": recursive}
) )
else: else:
mod_res = OrderedDict([("released", True)]) mod_res = OrderedDict([("released", True)])
ret["result"] = mod_res["released"] ret["result"] = mod_res["released"]
if ret["result"]: if ret["result"]:
ret["changes"] = {snapshot: {name: "released"}} ret["changes"] = {snapshot: {name: "released"}}
ret["comment"] = "hold {0} released".format(name,) ret["comment"] = "hold {} released".format(name,)
else: else:
ret["comment"] = "failed to release hold {0}".format(name,) ret["comment"] = "failed to release hold {}".format(name,)
if "error" in mod_res: if "error" in mod_res:
ret["comment"] = mod_res["error"] ret["comment"] = mod_res["error"]
elif "error" in holds: elif "error" in holds:
## NOTE: we have an error ## NOTE: we have an error
ret["result"] = False ret["result"] = False
ret["comment"] = holds["error"] ret["comment"] = holds["error"]
else: else:
## NOTE: no hold found with name for snapshot ## NOTE: no hold found with name for snapshot
ret["comment"] = "hold {0} is absent".format(name,) ret["comment"] = "hold {} is absent".format(name,)
return ret return ret
def hold_present(name, snapshot, recursive=False): def hold_present(name, snapshot, recursive=False):
""" """
ensure hold is present on the system ensure hold is present on the system
name : string name : string
name of holdt name of holdt
snapshot : string snapshot : string
skipping to change at line 306 skipping to change at line 302
""" """
ret = {"name": name, "changes": {}, "result": True, "comment": ""} ret = {"name": name, "changes": {}, "result": True, "comment": ""}
## log configuration ## log configuration
log.debug("zfs.hold_present::%s::config::snapshot = %s", name, snapshot) log.debug("zfs.hold_present::%s::config::snapshot = %s", name, snapshot)
log.debug("zfs.hold_present::%s::config::recursive = %s", name, recursive) log.debug("zfs.hold_present::%s::config::recursive = %s", name, recursive)
## check we have a snapshot/tag name ## check we have a snapshot/tag name
if not __utils__["zfs.is_snapshot"](snapshot): if not __utils__["zfs.is_snapshot"](snapshot):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid snapshot name: {0}".format(snapshot) ret["comment"] = "invalid snapshot name: {}".format(snapshot)
return ret return ret
if ( if (
__utils__["zfs.is_snapshot"](name) __utils__["zfs.is_snapshot"](name)
or __utils__["zfs.is_bookmark"](name) or __utils__["zfs.is_bookmark"](name)
or name == "error" or name == "error"
): ):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid tag name: {0}".format(name) ret["comment"] = "invalid tag name: {}".format(name)
return ret return ret
## place hold if required ## place hold if required
holds = __salt__["zfs.holds"](snapshot) holds = __salt__["zfs.holds"](snapshot)
if name in holds: if name in holds:
## NOTE: hold with name already exists for snapshot ## NOTE: hold with name already exists for snapshot
ret["comment"] = "hold {0} is present for {1}".format(name, snapshot,) ret["comment"] = "hold {} is present for {}".format(name, snapshot,)
else: else:
## NOTE: no hold found with name for snapshot ## NOTE: no hold found with name for snapshot
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.hold"](name, snapshot, **{"recursive": recur sive}) mod_res = __salt__["zfs.hold"](name, snapshot, **{"recursive": recur sive})
else: else:
mod_res = OrderedDict([("held", True)]) mod_res = OrderedDict([("held", True)])
ret["result"] = mod_res["held"] ret["result"] = mod_res["held"]
if ret["result"]: if ret["result"]:
ret["changes"] = OrderedDict([(snapshot, OrderedDict([(name, "held") ]))]) ret["changes"] = OrderedDict([(snapshot, OrderedDict([(name, "held") ]))])
ret["comment"] = "hold {0} added to {1}".format(name, snapshot) ret["comment"] = "hold {} added to {}".format(name, snapshot)
else: else:
ret["comment"] = "failed to add hold {0} to {1}".format(name, snapsh ot) ret["comment"] = "failed to add hold {} to {}".format(name, snapshot )
if "error" in mod_res: if "error" in mod_res:
ret["comment"] = mod_res["error"] ret["comment"] = mod_res["error"]
return ret return ret
def _dataset_present( def _dataset_present(
dataset_type, dataset_type,
name, name,
volume_size=None, volume_size=None,
sparse=False, sparse=False,
skipping to change at line 419 skipping to change at line 415
log.debug( log.debug(
"zfs.%s_present::%s::config::cloned_from = %s", dataset_type, name, clon ed_from "zfs.%s_present::%s::config::cloned_from = %s", dataset_type, name, clon ed_from
) )
log.debug( log.debug(
"zfs.%s_present::%s::config::properties = %s", dataset_type, name, prope rties "zfs.%s_present::%s::config::properties = %s", dataset_type, name, prope rties
) )
## check we have valid filesystem name/volume name/clone snapshot ## check we have valid filesystem name/volume name/clone snapshot
if not __utils__["zfs.is_dataset"](name): if not __utils__["zfs.is_dataset"](name):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid dataset name: {0}".format(name) ret["comment"] = "invalid dataset name: {}".format(name)
return ret return ret
if cloned_from and not __utils__["zfs.is_snapshot"](cloned_from): if cloned_from and not __utils__["zfs.is_snapshot"](cloned_from):
ret["result"] = False ret["result"] = False
ret["comment"] = "{0} is not a snapshot".format(cloned_from) ret["comment"] = "{} is not a snapshot".format(cloned_from)
return ret return ret
## ensure dataset is in correct state ## ensure dataset is in correct state
## NOTE: update the dataset ## NOTE: update the dataset
if __salt__["zfs.exists"](name, **{"type": dataset_type}): if __salt__["zfs.exists"](name, **{"type": dataset_type}):
## NOTE: fetch current volume properties ## NOTE: fetch current volume properties
properties_current = __salt__["zfs.get"]( properties_current = __salt__["zfs.get"](
name, type=dataset_type, fields="value", depth=0, parsable=True, name, type=dataset_type, fields="value", depth=0, parsable=True,
).get(name, OrderedDict()) ).get(name, OrderedDict())
skipping to change at line 471 skipping to change at line 467
mod_res = OrderedDict([("set", True)]) mod_res = OrderedDict([("set", True)])
if mod_res["set"]: if mod_res["set"]:
if name not in ret["changes"]: if name not in ret["changes"]:
ret["changes"][name] = {} ret["changes"][name] = {}
ret["changes"][name][prop] = properties[prop] ret["changes"][name][prop] = properties[prop]
else: else:
ret["result"] = False ret["result"] = False
if ret["comment"] == "": if ret["comment"] == "":
ret["comment"] = "The following properties were not updated: " ret["comment"] = "The following properties were not updated: "
ret["comment"] = "{0} {1}".format(ret["comment"], prop) ret["comment"] = "{} {}".format(ret["comment"], prop)
## NOTE: update comment ## NOTE: update comment
if ret["result"] and name in ret["changes"]: if ret["result"] and name in ret["changes"]:
ret["comment"] = "{0} {1} was updated".format(dataset_type, name) ret["comment"] = "{} {} was updated".format(dataset_type, name)
elif ret["result"]: elif ret["result"]:
ret["comment"] = "{0} {1} is uptodate".format(dataset_type, name) ret["comment"] = "{} {} is uptodate".format(dataset_type, name)
else: else:
ret["comment"] = "{0} {1} failed to be updated".format(dataset_type, name) ret["comment"] = "{} {} failed to be updated".format(dataset_type, n ame)
## NOTE: create or clone the dataset ## NOTE: create or clone the dataset
else: else:
mod_res_action = "cloned" if cloned_from else "created" mod_res_action = "cloned" if cloned_from else "created"
if __opts__["test"]: if __opts__["test"]:
## NOTE: pretend to create/clone ## NOTE: pretend to create/clone
mod_res = OrderedDict([(mod_res_action, True)]) mod_res = OrderedDict([(mod_res_action, True)])
elif cloned_from: elif cloned_from:
## NOTE: add volsize to properties ## NOTE: add volsize to properties
if volume_size: if volume_size:
skipping to change at line 515 skipping to change at line 511
"volume_size": volume_size, "volume_size": volume_size,
"sparse": sparse, "sparse": sparse,
} }
) )
ret["result"] = mod_res[mod_res_action] ret["result"] = mod_res[mod_res_action]
if ret["result"]: if ret["result"]:
ret["changes"][name] = mod_res_action ret["changes"][name] = mod_res_action
if properties: if properties:
ret["changes"][name] = properties ret["changes"][name] = properties
ret["comment"] = "{0} {1} was {2}".format( ret["comment"] = "{} {} was {}".format(dataset_type, name, mod_res_a
dataset_type, name, mod_res_action, ction,)
)
else: else:
ret["comment"] = "failed to {0} {1} {2}".format( ret["comment"] = "failed to {} {} {}".format(
mod_res_action[:-1], dataset_type, name, mod_res_action[:-1], dataset_type, name,
) )
if "error" in mod_res: if "error" in mod_res:
ret["comment"] = mod_res["error"] ret["comment"] = mod_res["error"]
return ret return ret
def filesystem_present(name, create_parent=False, properties=None, cloned_from=N one): def filesystem_present(name, create_parent=False, properties=None, cloned_from=N one):
""" """
ensure filesystem exists and has properties set ensure filesystem exists and has properties set
skipping to change at line 626 skipping to change at line 620
""" """
ret = {"name": name, "changes": {}, "result": True, "comment": ""} ret = {"name": name, "changes": {}, "result": True, "comment": ""}
## log configuration ## log configuration
log.debug("zfs.bookmark_present::%s::config::snapshot = %s", name, snapshot) log.debug("zfs.bookmark_present::%s::config::snapshot = %s", name, snapshot)
## check we have valid snapshot/bookmark name ## check we have valid snapshot/bookmark name
if not __utils__["zfs.is_snapshot"](snapshot): if not __utils__["zfs.is_snapshot"](snapshot):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid snapshot name: {0}".format(name) ret["comment"] = "invalid snapshot name: {}".format(name)
return ret return ret
if "#" not in name and "/" not in name: if "#" not in name and "/" not in name:
## NOTE: simple snapshot name ## NOTE: simple snapshot name
# take the snapshot name and replace the snapshot but with the si mple name # take the snapshot name and replace the snapshot but with the si mple name
# e.g. pool/fs@snap + bm --> pool/fs#bm # e.g. pool/fs@snap + bm --> pool/fs#bm
name = "{0}#{1}".format(snapshot[: snapshot.index("@")], name) name = "{}#{}".format(snapshot[: snapshot.index("@")], name)
ret["name"] = name ret["name"] = name
if not __utils__["zfs.is_bookmark"](name): if not __utils__["zfs.is_bookmark"](name):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid bookmark name: {0}".format(name) ret["comment"] = "invalid bookmark name: {}".format(name)
return ret return ret
## ensure bookmark exists ## ensure bookmark exists
if not __salt__["zfs.exists"](name, **{"type": "bookmark"}): if not __salt__["zfs.exists"](name, **{"type": "bookmark"}):
## NOTE: bookmark the snapshot ## NOTE: bookmark the snapshot
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.bookmark"](snapshot, name) mod_res = __salt__["zfs.bookmark"](snapshot, name)
else: else:
mod_res = OrderedDict([("bookmarked", True)]) mod_res = OrderedDict([("bookmarked", True)])
ret["result"] = mod_res["bookmarked"] ret["result"] = mod_res["bookmarked"]
if ret["result"]: if ret["result"]:
ret["changes"][name] = snapshot ret["changes"][name] = snapshot
ret["comment"] = "{0} bookmarked as {1}".format(snapshot, name) ret["comment"] = "{} bookmarked as {}".format(snapshot, name)
else: else:
ret["comment"] = "failed to bookmark {0}".format(snapshot) ret["comment"] = "failed to bookmark {}".format(snapshot)
if "error" in mod_res: if "error" in mod_res:
ret["comment"] = mod_res["error"] ret["comment"] = mod_res["error"]
else: else:
## NOTE: bookmark already exists ## NOTE: bookmark already exists
ret["comment"] = "bookmark is present" ret["comment"] = "bookmark is present"
return ret return ret
def snapshot_present(name, recursive=False, properties=None): def snapshot_present(name, recursive=False, properties=None):
""" """
skipping to change at line 691 skipping to change at line 685
log.debug("zfs.snapshot_present::%s::config::recursive = %s", name, recursiv e) log.debug("zfs.snapshot_present::%s::config::recursive = %s", name, recursiv e)
log.debug("zfs.snapshot_present::%s::config::properties = %s", name, propert ies) log.debug("zfs.snapshot_present::%s::config::properties = %s", name, propert ies)
## ensure properties are zfs values ## ensure properties are zfs values
if properties: if properties:
properties = __utils__["zfs.from_auto_dict"](properties) properties = __utils__["zfs.from_auto_dict"](properties)
## check we have valid snapshot name ## check we have valid snapshot name
if not __utils__["zfs.is_snapshot"](name): if not __utils__["zfs.is_snapshot"](name):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid snapshot name: {0}".format(name) ret["comment"] = "invalid snapshot name: {}".format(name)
return ret return ret
## ensure snapshot exits ## ensure snapshot exits
if not __salt__["zfs.exists"](name, **{"type": "snapshot"}): if not __salt__["zfs.exists"](name, **{"type": "snapshot"}):
## NOTE: create the snapshot ## NOTE: create the snapshot
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.snapshot"]( mod_res = __salt__["zfs.snapshot"](
name, **{"recursive": recursive, "properties": properties} name, **{"recursive": recursive, "properties": properties}
) )
else: else:
mod_res = OrderedDict([("snapshotted", True)]) mod_res = OrderedDict([("snapshotted", True)])
ret["result"] = mod_res["snapshotted"] ret["result"] = mod_res["snapshotted"]
if ret["result"]: if ret["result"]:
ret["changes"][name] = "snapshotted" ret["changes"][name] = "snapshotted"
if properties: if properties:
ret["changes"][name] = properties ret["changes"][name] = properties
ret["comment"] = "snapshot {0} was created".format(name) ret["comment"] = "snapshot {} was created".format(name)
else: else:
ret["comment"] = "failed to create snapshot {0}".format(name) ret["comment"] = "failed to create snapshot {}".format(name)
if "error" in mod_res: if "error" in mod_res:
ret["comment"] = mod_res["error"] ret["comment"] = mod_res["error"]
else: else:
## NOTE: snapshot already exists ## NOTE: snapshot already exists
ret["comment"] = "snapshot is present" ret["comment"] = "snapshot is present"
return ret return ret
def promoted(name): def promoted(name):
""" """
skipping to change at line 738 skipping to change at line 732
only one dataset can be the origin, only one dataset can be the origin,
if you promote a clone the original will now point to the promoted datas et if you promote a clone the original will now point to the promoted datas et
""" """
ret = {"name": name, "changes": {}, "result": True, "comment": ""} ret = {"name": name, "changes": {}, "result": True, "comment": ""}
## check we if we have a valid dataset name ## check we if we have a valid dataset name
if not __utils__["zfs.is_dataset"](name): if not __utils__["zfs.is_dataset"](name):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid dataset name: {0}".format(name) ret["comment"] = "invalid dataset name: {}".format(name)
return ret return ret
## ensure dataset is the primary instance ## ensure dataset is the primary instance
if not __salt__["zfs.exists"](name, **{"type": "filesystem,volume"}): if not __salt__["zfs.exists"](name, **{"type": "filesystem,volume"}):
## NOTE: we don't have a dataset ## NOTE: we don't have a dataset
ret["result"] = False ret["result"] = False
ret["comment"] = "dataset {0} does not exist".format(name) ret["comment"] = "dataset {} does not exist".format(name)
else: else:
## NOTE: check if we have a blank origin (-) ## NOTE: check if we have a blank origin (-)
if ( if (
__salt__["zfs.get"]( __salt__["zfs.get"](
name, **{"properties": "origin", "fields": "value", "parsable": True} name, **{"properties": "origin", "fields": "value", "parsable": True}
)[name]["origin"]["value"] )[name]["origin"]["value"]
== "-" == "-"
): ):
## NOTE: we're already promoted ## NOTE: we're already promoted
ret["comment"] = "{0} already promoted".format(name) ret["comment"] = "{} already promoted".format(name)
else: else:
## NOTE: promote dataset ## NOTE: promote dataset
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.promote"](name) mod_res = __salt__["zfs.promote"](name)
else: else:
mod_res = OrderedDict([("promoted", True)]) mod_res = OrderedDict([("promoted", True)])
ret["result"] = mod_res["promoted"] ret["result"] = mod_res["promoted"]
if ret["result"]: if ret["result"]:
ret["changes"][name] = "promoted" ret["changes"][name] = "promoted"
ret["comment"] = "{0} promoted".format(name) ret["comment"] = "{} promoted".format(name)
else: else:
ret["comment"] = "failed to promote {0}".format(name) ret["comment"] = "failed to promote {}".format(name)
if "error" in mod_res: if "error" in mod_res:
ret["comment"] = mod_res["error"] ret["comment"] = mod_res["error"]
return ret return ret
def _schedule_snapshot_retrieve(dataset, prefix, snapshots): def _schedule_snapshot_retrieve(dataset, prefix, snapshots):
""" """
Update snapshots dict with current snapshots Update snapshots dict with current snapshots
dataset: string dataset: string
skipping to change at line 798 skipping to change at line 792
for snap in sorted( for snap in sorted(
__salt__["zfs.list"]( __salt__["zfs.list"](
dataset, **{"recursive": True, "depth": 1, "type": "snapshot"} dataset, **{"recursive": True, "depth": 1, "type": "snapshot"}
).keys() ).keys()
): ):
## NOTE: we only want the actualy name ## NOTE: we only want the actualy name
## myzpool/data@zbck-20171201_000248 -> zbck-20171201_000248 ## myzpool/data@zbck-20171201_000248 -> zbck-20171201_000248
snap_name = snap[snap.index("@") + 1 :] snap_name = snap[snap.index("@") + 1 :]
## NOTE: we only want snapshots matching our prefix ## NOTE: we only want snapshots matching our prefix
if not snap_name.startswith("{0}-".format(prefix)): if not snap_name.startswith("{}-".format(prefix)):
continue continue
## NOTE: retrieve the holds for this snapshot ## NOTE: retrieve the holds for this snapshot
snap_holds = __salt__["zfs.holds"](snap) snap_holds = __salt__["zfs.holds"](snap)
## NOTE: this snapshot has no holds, eligable for pruning ## NOTE: this snapshot has no holds, eligable for pruning
if not snap_holds: if not snap_holds:
snapshots["_prunable"].append(snap) snapshots["_prunable"].append(snap)
## NOTE: update snapshots based on holds (if any) ## NOTE: update snapshots based on holds (if any)
skipping to change at line 849 skipping to change at line 843
snapshots["_create"][snapshot_create_name] = [] snapshots["_create"][snapshot_create_name] = []
for hold, hold_count in snapshots["_schedule"].items(): for hold, hold_count in snapshots["_schedule"].items():
## NOTE: skip hold if we don't keep snapshots for it ## NOTE: skip hold if we don't keep snapshots for it
if hold_count == 0: if hold_count == 0:
continue continue
## NOTE: figure out if we need the current hold on the new snapshot ## NOTE: figure out if we need the current hold on the new snapshot
if snapshots[hold]: if snapshots[hold]:
## NOTE: extract datetime from snapshot name ## NOTE: extract datetime from snapshot name
timestamp = datetime.strptime( timestamp = datetime.strptime(
snapshots[hold][-1], "{0}@{1}-%Y%m%d_%H%M%S".format(dataset, pre fix), snapshots[hold][-1], "{}@{}-%Y%m%d_%H%M%S".format(dataset, prefi x),
).replace(second=0, microsecond=0) ).replace(second=0, microsecond=0)
## NOTE: compare current timestamp to timestamp from snapshot ## NOTE: compare current timestamp to timestamp from snapshot
if hold == "minute" and timestamp_now <= timestamp: if hold == "minute" and timestamp_now <= timestamp:
continue continue
elif hold == "hour" and timestamp_now.replace( elif hold == "hour" and timestamp_now.replace(
**comp_hour **comp_hour
) <= timestamp.replace(**comp_hour): ) <= timestamp.replace(**comp_hour):
continue continue
elif hold == "day" and timestamp_now.replace( elif hold == "day" and timestamp_now.replace(
skipping to change at line 916 skipping to change at line 910
## initialize defaults ## initialize defaults
schedule_holds = ["minute", "hour", "day", "month", "year"] schedule_holds = ["minute", "hour", "day", "month", "year"]
snapshots = OrderedDict( snapshots = OrderedDict(
[("_create", OrderedDict()), ("_prunable", []), ("_schedule", OrderedDic t())] [("_create", OrderedDict()), ("_prunable", []), ("_schedule", OrderedDic t())]
) )
## strict configuration validation ## strict configuration validation
## NOTE: we need a valid dataset ## NOTE: we need a valid dataset
if not __utils__["zfs.is_dataset"](name): if not __utils__["zfs.is_dataset"](name):
ret["result"] = False ret["result"] = False
ret["comment"] = "invalid dataset name: {0}".format(name) ret["comment"] = "invalid dataset name: {}".format(name)
if not __salt__["zfs.exists"](name, **{"type": "filesystem,volume"}): if not __salt__["zfs.exists"](name, **{"type": "filesystem,volume"}):
ret["comment"] = "dataset {0} does not exist".format(name) ret["comment"] = "dataset {} does not exist".format(name)
ret["result"] = False ret["result"] = False
## NOTE: prefix must be 4 or longer ## NOTE: prefix must be 4 or longer
if not prefix or len(prefix) < 4: if not prefix or len(prefix) < 4:
ret["comment"] = "prefix ({0}) must be at least 4 long".format(prefix) ret["comment"] = "prefix ({}) must be at least 4 long".format(prefix)
ret["result"] = False ret["result"] = False
## NOTE: validate schedule ## NOTE: validate schedule
total_count = 0 total_count = 0
for hold in schedule_holds: for hold in schedule_holds:
snapshots[hold] = [] snapshots[hold] = []
if hold not in schedule: if hold not in schedule:
snapshots["_schedule"][hold] = 0 snapshots["_schedule"][hold] = 0
elif isinstance(schedule[hold], int): elif isinstance(schedule[hold], int):
snapshots["_schedule"][hold] = schedule[hold] snapshots["_schedule"][hold] = schedule[hold]
else: else:
ret["result"] = False ret["result"] = False
ret["comment"] = "schedule value for {0} is not an integer".format(h old,) ret["comment"] = "schedule value for {} is not an integer".format(ho ld,)
break break
total_count += snapshots["_schedule"][hold] total_count += snapshots["_schedule"][hold]
if ret["result"] and total_count == 0: if ret["result"] and total_count == 0:
ret["result"] = False ret["result"] = False
ret["comment"] = "schedule is not valid, you need to keep atleast 1 snap shot" ret["comment"] = "schedule is not valid, you need to keep atleast 1 snap shot"
## NOTE: return if configuration is not valid ## NOTE: return if configuration is not valid
if not ret["result"]: if not ret["result"]:
return ret return ret
skipping to change at line 975 skipping to change at line 969
## NOTE: create snapshot ## NOTE: create snapshot
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.snapshot"]( mod_res = __salt__["zfs.snapshot"](
snapshot_name, **{"recursive": recursive} snapshot_name, **{"recursive": recursive}
) )
else: else:
mod_res = OrderedDict([("snapshotted", True)]) mod_res = OrderedDict([("snapshotted", True)])
if not mod_res["snapshotted"]: if not mod_res["snapshotted"]:
ret["result"] = False ret["result"] = False
ret["comment"] = "error creating snapshot ({0})".format(snapshot_nam e) ret["comment"] = "error creating snapshot ({})".format(snapshot_name )
else: else:
## NOTE: create holds (if we have a snapshot) ## NOTE: create holds (if we have a snapshot)
for hold in snapshot_holds: for hold in snapshot_holds:
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.hold"]( mod_res = __salt__["zfs.hold"](
hold, snapshot_name, **{"recursive": recursive} hold, snapshot_name, **{"recursive": recursive}
) )
else: else:
mod_res = OrderedDict([("held", True)]) mod_res = OrderedDict([("held", True)])
if not mod_res["held"]: if not mod_res["held"]:
ret["result"] = False ret["result"] = False
ret["comment"] = "error adding hold ({0}) to snapshot ({1})" .format( ret["comment"] = "error adding hold ({}) to snapshot ({})".f ormat(
hold, snapshot_name, hold, snapshot_name,
) )
break break
snapshots[hold].append(snapshot_name) snapshots[hold].append(snapshot_name)
if ret["result"]: if ret["result"]:
ret["comment"] = "scheduled snapshots updated" ret["comment"] = "scheduled snapshots updated"
if "created" not in ret["changes"]: if "created" not in ret["changes"]:
ret["changes"]["created"] = [] ret["changes"]["created"] = []
skipping to change at line 1017 skipping to change at line 1011
## NOTE: release hold for snapshot ## NOTE: release hold for snapshot
if not __opts__["test"]: if not __opts__["test"]:
mod_res = __salt__["zfs.release"]( mod_res = __salt__["zfs.release"](
hold, snapshot_name, **{"recursive": recursive} hold, snapshot_name, **{"recursive": recursive}
) )
else: else:
mod_res = OrderedDict([("released", True)]) mod_res = OrderedDict([("released", True)])
if not mod_res["released"]: if not mod_res["released"]:
ret["result"] = False ret["result"] = False
ret["comment"] = "error adding hold ({0}) to snapshot ({1})".for mat( ret["comment"] = "error adding hold ({}) to snapshot ({})".forma t(
hold, snapshot_name, hold, snapshot_name,
) )
## NOTE: mark as prunable ## NOTE: mark as prunable
if not __salt__["zfs.holds"](snapshot_name): if not __salt__["zfs.holds"](snapshot_name):
snapshots["_prunable"].append(snapshot_name) snapshots["_prunable"].append(snapshot_name)
## prune snapshot(s) ## prune snapshot(s)
for snapshot_name in snapshots["_prunable"]: for snapshot_name in snapshots["_prunable"]:
## NOTE: destroy snapshot ## NOTE: destroy snapshot
 End of changes. 51 change blocks. 
53 lines changed or deleted 48 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)