22
22
type:
23
23
required: true
24
24
aliases: [ "storagetype" ]
25
- choices: [ "dir", "nfs", "rbd", "lvm", "lvmthin", "cephfs", "zfspool" ]
25
+ choices: [ "dir", "nfs", "rbd", "lvm", "lvmthin", "cephfs", "zfspool", "btrfs" ]
26
26
description:
27
27
- Type of storage, must be supported by Proxmox.
28
28
disable:
98
98
required: false
99
99
description:
100
100
- Use ZFS thin-provisioning.
101
+ is_mountpoint:
102
+ required: false
103
+ description:
104
+ - Specifies whether or not the given path is an externally managed
105
+ mountpoint.
101
106
102
107
author:
103
108
- Fabien Brachere (@fbrachere)
154
159
- 10.0.0.1
155
160
- 10.0.0.2
156
161
- 10.0.0.3
162
+ - name: Create a Proxmox Backup Server storage type
163
+ proxmox_storage:
164
+ name: pbs1
165
+ type: pbs
166
+ content: [ "backup" ]
167
+ server: 192.168.122.2
168
+ username: user@pbs
169
+ password: PBSPassword1
170
+ datastore: main
171
+ fingerprint: f2:fb:85:76:d2:2a:c4:96:5c:6e:d8:71:37:36:06:17:09:55:f7:04:e3:74:bb:aa:9e:26:85:92:63:c8:b9:23
172
+ encryption_key: autogen
157
173
- name: Create a ZFS storage type
158
174
proxmox_storage:
159
175
name: zfs1
170
186
from ansible .module_utils ._text import to_text
171
187
from ansible .module_utils .pvesh import ProxmoxShellError
172
188
import ansible .module_utils .pvesh as pvesh
189
+ import re
190
+ import json
191
+ from json import JSONDecodeError , loads as parse_json
192
+
173
193
174
194
class ProxmoxStorage (object ):
175
195
def __init__ (self , module ):
176
196
self .module = module
177
197
self .name = module .params ['name' ]
178
198
self .state = module .params ['state' ]
179
- self . type = module . params [ 'type' ]
199
+ # Globally applicable PVE API arguments
180
200
self .disable = module .params ['disable' ]
181
201
self .content = module .params ['content' ]
182
202
self .nodes = module .params ['nodes' ]
203
+ self .type = module .params ['type' ]
204
+ # Remaining PVE API arguments (depending on type) past this point
205
+ self .datastore = module .params ['datastore' ]
206
+ self .encryption_key = module .params ['encryption_key' ]
207
+ self .fingerprint = module .params ['fingerprint' ]
208
+ self .password = module .params ['password' ]
183
209
self .path = module .params ['path' ]
184
210
self .pool = module .params ['pool' ]
185
211
self .monhost = module .params ['monhost' ]
@@ -192,7 +218,26 @@ def __init__(self, module):
192
218
self .vgname = module .params ['vgname' ]
193
219
self .thinpool = module .params ['thinpool' ]
194
220
self .sparse = module .params ['sparse' ]
195
-
221
+ self .is_mountpoint = module .params ['is_mountpoint' ]
222
+
223
+ # Validate the parameters given to us
224
+ fingerprint_re = re .compile ('^([A-Fa-f0-9]{2}:){31}[A-Fa-f0-9]{2}$' )
225
+ if self .fingerprint is not None and not fingerprint_re .match (self .fingerprint ):
226
+ self .module .fail_json (msg = (f"fingerprint must be of the format, "
227
+ f"{ fingerprint_re .pattern } ." ))
228
+
229
+ if self .type == 'pbs' :
230
+ if self .content != ['backup' ]:
231
+ self .module .fail_json (msg = "PBS storage type only supports the "
232
+ "'backup' content type." )
233
+ try :
234
+ if self .encryption_key not in ["autogen" , None ]:
235
+ parse_json (self .encryption_key )
236
+ except JSONDecodeError :
237
+ self .module .fail_json (msg = ("encryption_key needs to be valid "
238
+ "JSON or set to 'autogen'." ))
239
+
240
+ # Attempt to retrieve current/live storage definitions
196
241
try :
197
242
self .existing_storages = pvesh .get ("storage" )
198
243
except ProxmoxShellError as e :
@@ -202,9 +247,9 @@ def lookup(self):
202
247
for item in self .existing_storages :
203
248
if item ['storage' ] == self .name :
204
249
# pvesh doesn't return the disable param value if it's false,
205
- # so we set it to False .
250
+ # so we set it to 0, which is what PVE would normally use .
206
251
if item .get ('disable' ) is None :
207
- item ['disable' ] = False
252
+ item ['disable' ] = 0
208
253
return item
209
254
return None
210
255
@@ -218,13 +263,25 @@ def prepare_storage_args(self):
218
263
args = {}
219
264
220
265
args ['type' ] = self .type
221
- args ['content' ] = ',' .join (self .content )
266
+ if self .content is not None and len (self .content ) > 0 :
267
+ args ['content' ] = ',' .join (self .content )
268
+ else :
269
+ # PVE uses "none" to represent when no content types are selected
270
+ args ['content' ] = 'none'
222
271
if self .nodes is not None :
223
272
args ['nodes' ] = ',' .join (self .nodes )
224
273
if self .disable is not None :
225
- args ['disable' ] = self .disable
226
- else :
227
- args ['disable' ] = False
274
+ args ['disable' ] = 1 if self .disable else 0
275
+ if self .datastore is not None :
276
+ args ['datastore' ] = self .datastore
277
+ if self .encryption_key is not None :
278
+ args ['encryption-key' ] = self .encryption_key
279
+ if self .fingerprint is not None :
280
+ args ['fingerprint' ] = self .fingerprint
281
+ if self .master_pubkey is not None :
282
+ args ['master-pubkey' ] = self .master_pubkey
283
+ if self .password is not None :
284
+ args ['password' ] = self .password
228
285
if self .path is not None :
229
286
args ['path' ] = self .path
230
287
if self .pool is not None :
@@ -234,7 +291,7 @@ def prepare_storage_args(self):
234
291
if self .username is not None :
235
292
args ['username' ] = self .username
236
293
if self .krbd is not None :
237
- args ['krbd' ] = self .krbd
294
+ args ['krbd' ] = 1 if self .krbd else 0
238
295
if self .maxfiles is not None :
239
296
args ['maxfiles' ] = self .maxfiles
240
297
if self .server is not None :
@@ -248,7 +305,9 @@ def prepare_storage_args(self):
248
305
if self .thinpool is not None :
249
306
args ['thinpool' ] = self .thinpool
250
307
if self .sparse is not None :
251
- args ['sparse' ] = self .sparse
308
+ args ['sparse' ] = 1 if self .sparse else 0
309
+ if self .is_mountpoint is not None :
310
+ args ['is_mountpoint' ] = 1 if self .is_mountpoint else 0
252
311
253
312
if self .maxfiles is not None and 'backup' not in self .content :
254
313
self .module .fail_json (msg = "maxfiles is not allowed when there is no 'backup' in content" )
@@ -275,7 +334,8 @@ def modify_storage(self):
275
334
276
335
for key in new_storage :
277
336
if key == 'content' :
278
- if set (self .content ) != set (lookup .get ('content' , '' ).split (',' )):
337
+ if set (new_storage ['content' ].split (',' )) \
338
+ != set (lookup .get ('content' , '' ).split (',' )):
279
339
updated_fields .append (key )
280
340
staged_storage [key ] = new_storage [key ]
281
341
elif key == 'monhost' :
@@ -318,13 +378,20 @@ def main():
318
378
# Refer to https://pve.proxmox.com/pve-docs/api-viewer/index.html
319
379
module_args = dict (
320
380
name = dict (type = 'str' , required = True , aliases = ['storage' , 'storageid' ]),
381
+ state = dict (default = 'present' , choices = ['present' , 'absent' ], type = 'str' ),
382
+ # Globally applicable PVE API arguments
321
383
content = dict (type = 'list' , required = True , aliases = ['storagetype' ]),
384
+ disable = dict (required = False , type = 'bool' , default = False ),
322
385
nodes = dict (type = 'list' , required = False , default = None ),
323
386
type = dict (default = None , type = 'str' , required = True ,
324
387
choices = ["dir" , "nfs" , "rbd" , "lvm" , "lvmthin" , "cephfs" ,
325
- "zfspool" ]),
326
- disable = dict (required = False , type = 'bool' , default = False ),
327
- state = dict (default = 'present' , choices = ['present' , 'absent' ], type = 'str' ),
388
+ "zfspool" , "btrfs" , "pbs" ]),
389
+ # Remaining PVE API arguments (depending on type) past this point
390
+ datastore = dict (default = None , type = 'str' , required = False ),
391
+ encryption_key = dict (default = None , type = 'str' , required = False ),
392
+ fingerprint = dict (default = None , type = 'str' , required = False ),
393
+ master_pubkey = dict (default = None , type = 'str' , required = False ),
394
+ password = dict (default = None , type = 'str' , required = False ),
328
395
path = dict (default = None , required = False , type = 'str' ),
329
396
pool = dict (default = None , type = 'str' , required = False ),
330
397
monhost = dict (default = None , type = 'list' , required = False ),
@@ -337,6 +404,7 @@ def main():
337
404
vgname = dict (default = None , type = 'str' , required = False ),
338
405
thinpool = dict (default = None , type = 'str' , required = False ),
339
406
sparse = dict (default = None , type = 'bool' , required = False ),
407
+ is_mountpoint = dict (default = None , type = 'bool' , required = False ),
340
408
)
341
409
342
410
module = AnsibleModule (
@@ -350,7 +418,12 @@ def main():
350
418
["type" , "lvm" , ["vgname" , "content" ]],
351
419
["type" , "lvmthin" , ["vgname" , "thinpool" , "content" ]],
352
420
["type" , "zfspool" , ["pool" , "content" ]],
353
- ]
421
+ ["type" , "btrfs" , ["path" , "content" ]],
422
+ ["type" , "pbs" , ["server" , "username" , "password" , "datastore" ]]
423
+ ],
424
+ required_by = {
425
+ "master_pubkey" : "encryption_key"
426
+ }
354
427
)
355
428
storage = ProxmoxStorage (module )
356
429
0 commit comments