Skip to content

Commit cf67089

Browse files
committed
Implement shared and prune_backups options for proxmox_storage module
- add `prune_backups` option and all associated consistency checks, mark `maxfiles` as deprecated - add `shared` option - mark `encryption_key` and `password` options as `no_log` to prevent logging secret values to console - fixes for typos
1 parent 7754460 commit cf67089

File tree

1 file changed

+115
-9
lines changed

1 file changed

+115
-9
lines changed

library/proxmox_storage.py

Lines changed: 115 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747
type: list
4848
description:
4949
- List of cluster node names where this storage is usable.
50+
shared:
51+
required: false
52+
type: bool
53+
description:
54+
- Indicate that this is a single storage with the same contents on all nodes (or all listed in the O(nodes) option).
55+
- It will not make the contents of a local storage automatically accessible to other nodes, it just marks an already shared storage as such!
5056
path:
5157
required: false
5258
description:
@@ -74,6 +80,39 @@
7480
default: 0
7581
description:
7682
- Maximal number of backup files per VM. 0 for unlimited.
83+
- Deprecated, use O(prune_backups) instead. Replace either by C(keep-last) or, in case C(maxfiles) was C(0) for unlimited retention, by C(keep-all).
84+
prune_backups:
85+
required: false
86+
type: list
87+
elements: dict
88+
description:
89+
- Specifies how to prune backups.
90+
- The retention options are processed in the order given. Each option only covers backups within its time period. The next option does not take care of already covered backups. It will only consider older backups.
91+
suboptions:
92+
option:
93+
required: true
94+
choices:
95+
- keep-all
96+
- keep-last
97+
- keep-hourly
98+
- keep-daily
99+
- keep-weekly
100+
- keep-monthly
101+
- keep-yearly
102+
description:
103+
- The retention option to use.
104+
- C(keep-all): Keep all backups. This option is mutually exclusive with the other options.
105+
- C(keep-last): Keep the last n backups.
106+
- C(keep-hourly): Keep backups for the last n hours. If there is more than one backup for a single hour, only the latest is kept.
107+
- C(keep-daily): Keep backups for the last n days. If there is more than one backup for a single day, only the latest is kept.
108+
- C(keep-weekly): Keep backups for the last n weeks. If there is more than one backup for a single week, only the latest is kept. Weeks start on Monday and end on Sunday. The software uses the ISO week date-system and handles weeks at the end of the year correctly.
109+
- C(keep-monthly): Keep backups for the last n months. If there is more than one backup for a single month, only the latest is kept.
110+
- C(keep-yearly): Keep backups for the last n years. If there is more than one backup for a single year, only the latest is kept.
111+
value:
112+
required: true
113+
description:
114+
- The number of backups to keep.
115+
- For C(keep-all) option, this value must be a C(bool). For all other options, this value must be an C(int).
77116
export:
78117
required: false
79118
description:
@@ -114,7 +153,7 @@
114153
subdir:
115154
required: false
116155
- specifies the folder in the share dir to use for proxmox
117-
(useful to seperate proxmox content from other content)
156+
(useful to separate proxmox content from other content)
118157
domain:
119158
required: false
120159
- Specifies Realm to use for NTLM/LDAPS Authentification if using
@@ -131,7 +170,9 @@
131170
type: dir
132171
path: /mydir
133172
content: [ "images", "iso", "backup" ]
134-
maxfiles: 3
173+
prune_backups:
174+
- option: keep-all
175+
value: 1
135176
- name: Create an RBD storage type
136177
proxmox_storage:
137178
name: ceph1
@@ -170,7 +211,7 @@
170211
name: cephfs1
171212
type: cephfs
172213
content: [ "snippets", "vztmpl", "iso" ]
173-
nodes: [ "proxmox1", "proxmox2"]
214+
nodes: [ "proxmox1", "proxmox2" ]
174215
monhost:
175216
- 10.0.0.1
176217
- 10.0.0.2
@@ -228,6 +269,7 @@ def __init__(self, module):
228269
self.disable = module.params['disable']
229270
self.content = module.params['content']
230271
self.nodes = module.params['nodes']
272+
self.shared = module.params['shared']
231273
self.type = module.params['type']
232274
# Remaining PVE API arguments (depending on type) past this point
233275
self.datastore = module.params['datastore']
@@ -241,6 +283,7 @@ def __init__(self, module):
241283
self.username = module.params['username']
242284
self.krbd = module.params['krbd']
243285
self.maxfiles = module.params['maxfiles']
286+
self.prune_backups = module.params['prune_backups']
244287
self.server = module.params['server']
245288
self.export = module.params['export']
246289
self.options = module.params['options']
@@ -306,6 +349,8 @@ def prepare_storage_args(self):
306349
args['content'] = 'none'
307350
if self.nodes is not None:
308351
args['nodes'] = ','.join(self.nodes)
352+
if self.shared is not None:
353+
args['shared'] = 1 if self.shared else 0
309354
if self.disable is not None:
310355
args['disable'] = 1 if self.disable else 0
311356
if self.datastore is not None:
@@ -355,8 +400,44 @@ def prepare_storage_args(self):
355400
if self.share is not None:
356401
args['share'] = self.share
357402
# end cifs
358-
if self.maxfiles is not None and 'backup' not in self.content:
359-
self.module.fail_json(msg="maxfiles is not allowed when there is no 'backup' in content")
403+
if self.maxfiles is not None:
404+
self.module.warn("'maxfiles' parameter is deprecated, use 'prune_backups' parameter instead")
405+
if "backup" not in self.content:
406+
self.module.fail_json(
407+
msg="'maxfiles' parameter is not allowed when there is no 'backup' in 'content' parameter"
408+
)
409+
if self.prune_backups is not None:
410+
if "backup" not in self.content:
411+
self.module.fail_json(
412+
msg="'prune_backups' parameter is not allowed when there is no 'backup' in 'content' parameter"
413+
)
414+
415+
if len(self.prune_backups) != len(set(cfg["option"] for cfg in self.prune_backups)):
416+
self.module.fail_json(msg="'prune_backups' parameter has duplicate entries")
417+
418+
keep_all_entries = [cfg for cfg in self.prune_backups if cfg["option"] == "keep-all"]
419+
keep_all_entry = keep_all_entries[0] if len(keep_all_entries) > 0 else None
420+
other_entries = [cfg for cfg in self.prune_backups if cfg["option"] != "keep-all"]
421+
if keep_all_entry and len(other_entries) > 0:
422+
self.module.fail_json(
423+
msg="'keep-all' is mutually exclusive with other options in 'prune_backups' parameter"
424+
)
425+
426+
if keep_all_entry and type(keep_all_entry["value"]) is not bool:
427+
self.module.fail_json(msg="value of 'keep-all' option must be a boolean in 'prune_backups' parameter")
428+
if any(type(cfg["value"]) is not int for cfg in other_entries):
429+
self.module.fail_json(
430+
msg="all values except for the 'keep-all' option must be integers in 'prune_backups' parameter"
431+
)
432+
433+
args["prune-backups"] = (
434+
"keep-all={value}".format(value=(1 if keep_all_entry["value"] else 0))
435+
if keep_all_entry
436+
else ",".join(
437+
map(lambda cfg: "{}={}".format(cfg["option"], cfg["value"]), other_entries)
438+
)
439+
)
440+
360441
if self.krbd is not None and self.type != 'rbd':
361442
self.module.fail_json(msg="krbd is only allowed with 'rbd' storage type")
362443

@@ -429,21 +510,43 @@ def main():
429510
content=dict(type='list', required=True, aliases=['storagetype']),
430511
disable=dict(required=False, type='bool', default=False),
431512
nodes=dict(type='list', required=False, default=None),
513+
shared=dict(type='bool', required=False, default=None),
432514
type=dict(default=None, type='str', required=True,
433515
choices=["dir", "nfs", "rbd", "lvm", "lvmthin", "cephfs",
434516
"zfspool", "btrfs", "pbs", "cifs"]),
435517
# Remaining PVE API arguments (depending on type) past this point
436518
datastore=dict(default=None, type='str', required=False),
437-
encryption_key=dict(default=None, type='str', required=False),
519+
encryption_key=dict(default=None, type='str', required=False, no_log=True),
438520
fingerprint=dict(default=None, type='str', required=False),
439521
master_pubkey=dict(default=None, type='str', required=False),
440-
password=dict(default=None, type='str', required=False),
522+
password=dict(default=None, type='str', required=False, no_log=True),
441523
path=dict(default=None, required=False, type='str'),
442524
pool=dict(default=None, type='str', required=False),
443525
monhost=dict(default=None, type='list', required=False),
444526
username=dict(default=None, type='str', required=False),
445527
krbd=dict(default=None, type='bool', required=False),
446528
maxfiles=dict(default=None, type='int', required=False),
529+
prune_backups=dict(
530+
default=None,
531+
type='list',
532+
elements='dict',
533+
required=False,
534+
options=dict(
535+
option=dict(
536+
required=True,
537+
choices=[
538+
'keep-all',
539+
'keep-last',
540+
'keep-hourly',
541+
'keep-daily',
542+
'keep-weekly',
543+
'keep-monthly',
544+
'keep-yearly',
545+
],
546+
),
547+
value=dict(required=True, type='raw'),
548+
),
549+
),
447550
export=dict(default=None, type='str', required=False),
448551
server=dict(default=None, type='str', required=False),
449552
options=dict(default=None, type='str', required=False),
@@ -474,7 +577,10 @@ def main():
474577
],
475578
required_by={
476579
"master_pubkey": "encryption_key"
477-
}
580+
},
581+
mutually_exclusive=[
582+
["maxfiles", "prune_backups"],
583+
],
478584
)
479585
storage = ProxmoxStorage(module)
480586

@@ -499,7 +605,7 @@ def main():
499605
error = storage.create_storage()
500606
else:
501607
# modify storage (check mode is ok)
502-
(updated_fields,error) = storage.modify_storage()
608+
(updated_fields, error) = storage.modify_storage()
503609

504610
if updated_fields:
505611
result['changed'] = True

0 commit comments

Comments
 (0)