
    VhY                         d dl mZmZmZ eZdZdZdZd dl	Z	d dl
mZ d dlmZ d dlmZmZ dd	Z G d
 de      Zd Zedk(  r e        yy)    )absolute_importdivisionprint_functiona  
module: proxmox_backup
author: "Raphael Grieger (@IamLunchbox) <r.grieger@hotmail.com>"
short_description: Start a VM backup in Proxmox VE cluster
version_added: 10.1.0
description:
  - Allows you to create backups of KVM and LXC guests in Proxmox VE cluster.
  - Offers the GUI functionality of creating a single backup as well as using the run-now functionality from the cluster backup
    schedule.
  - The mininum required privileges to use this module are C(VM.Backup) and C(Datastore.AllocateSpace) for the respective
    VMs and storage.
  - Most options are optional and if unspecified will be chosen by the Cluster and its default values.
  - Note that this module B(is not idempotent). It always starts a new backup (when not in check mode).
attributes:
  check_mode:
    support: full
  diff_mode:
    support: none
options:
  backup_mode:
    description:
      - The mode how Proxmox performs backups. The default is, to create a runtime snapshot including memory.
      - Check U(https://pve.proxmox.com/pve-docs/chapter-vzdump.html#_backup_modes) for an explanation of the differences.
    type: str
    choices: ["snapshot", "suspend", "stop"]
    default: snapshot
  bandwidth:
    description:
      - Limit the I/O bandwidth (in KiB/s) to write backup. V(0) is unlimited.
    type: int
  change_detection_mode:
    description:
      - Set the change detection mode (available from Proxmox VE 8.3).
      - It is only used when backing up containers, Proxmox silently ignores this option when applied to kvm guests.
    type: str
    choices: ["legacy", "data", "metadata"]
  compress:
    description:
      - Enable additional compression of the backup archive.
      - V(0) will use the Proxmox recommended value, depending on your storage target.
    type: str
    choices: ["0", "1", "gzip", "lzo", "zstd"]
  compression_threads:
    description:
      - The number of threads zstd will use to compress the backup.
      - V(0) uses 50% of the available cores, anything larger than V(0) will use exactly as many threads.
      - Is ignored if you specify O(compress=gzip) or O(compress=lzo).
    type: int
  description:
    description:
      - Specify the description of the backup.
      - Needs to be a single line, newline and backslash need to be escaped as V(\\n) and V(\\\\) respectively.
      - If you need variable interpolation, you can set the content as usual through ansible jinja templating and/or let Proxmox
        substitute templates.
      - Proxmox currently supports V({{cluster}}), V({{guestname}}), V({{node}}), and V({{vmid}}) as templating variables.
        Since this is also a jinja delimiter, you need to set these values as raw jinja.
    default: "{{guestname}}"
    type: str
  fleecing:
    description:
      - Enable backup fleecing. Works only for virtual machines and their disks.
      - Must be entered as a string, containing key-value pairs in a list.
    type: str
  mode:
    description:
      - Specifices the mode to select backup targets.
    choices: ["include", "all", "pool"]
    required: true
    type: str
  node:
    description:
      - Only execute the backup job for the given node.
      - This option is usually used if O(mode=all).
      - If you specify a node ID and your vmids or pool do not reside there, they will not be backed up!
    type: str
  notification_mode:
    description:
      - Determine which notification system to use.
    type: str
    choices: ["auto", "legacy-sendmail", "notification-system"]
    default: auto
  performance_tweaks:
    description:
      - Enable other performance-related settings.
      - Must be entered as a string, containing comma separated key-value pairs.
      - 'For example: V(max-workers=2,pbs-entries-max=2).'
    type: str
  pool:
    description:
      - Specify a pool name to limit backups to guests to the given pool.
      - Required, when O(mode=pool).
      - Also required, when your user only has VM.Backup permission for this single pool.
    type: str
  protected:
    description:
      - Marks backups as protected.
      - '"Might fail, when the PBS backend has verify enabled due to this bug: U(https://bugzilla.proxmox.com/show_bug.cgi?id=4289)".'
    type: bool
  retention:
    description:
      - Use custom retention options instead of those from the default cluster configuration (which is usually V("keep-all=1")).
      - Always requires Datastore.Allocate permission at the storage endpoint.
      - Specifying a retention time other than V(keep-all=1) might trigger pruning on the datastore, if an existing backup
        should be deleted due to your specified timeframe.
      - Deleting requires C(Datastore.Modify) or C(Datastore.Prune) permissions on the backup storage.
    type: str
  storage:
    description:
      - Store the backup archive on this storage.
    type: str
    required: true
  vmids:
    description:
      - The instance IDs to be backed up.
      - Only valid, if O(mode=include).
    type: list
    elements: int
  wait:
    description:
      - Wait for the backup to be finished.
      - Fails, if job does not succeed successfully within the given timeout.
    type: bool
    default: false
  wait_timeout:
    description:
      - Seconds to wait for the backup to be finished.
      - Will only be evaluated, if O(wait=true).
    type: int
    default: 10
requirements: ["proxmoxer", "requests"]
extends_documentation_fragment:
  - community.general.proxmox.actiongroup_proxmox
  - community.general.proxmox.documentation
  - community.general.attributes
a  
- name: Backup all vms in the Proxmox cluster to storage mypbs
  community.general.proxmox_backup:
    api_user: root@pam
    api_password: secret
    api_host: node1
    storage: mypbs
    mode: all

- name: Backup VMID 100 by stopping it and set an individual retention
  community.general.proxmox_backup:
    api_user: root@pam
    api_password: secret
    api_host: node1
    backup-mode: stop
    mode: include
    retention: keep-daily=5, keep-last=14, keep-monthly=4, keep-weekly=4, keep-yearly=0
    storage: mypbs
    vmid: [100]

- name: Backup all vms on node node2 to storage mypbs and wait for the task to finish
  community.general.proxmox_backup:
    api_user: test@pve
    api_password: 1q2w3e
    api_host: node2
    storage: mypbs
    mode: all
    node: node2
    wait: true
    wait_timeout: 30

- name: Use all the options
  community.general.proxmox_backup:
    api_user: root@pam
    api_password: secret
    api_host: node1
    bandwidth: 1000
    backup_mode: suspend
    compress: zstd
    compression_threads: 0
    description: A single backup for {% raw %}{{ guestname }}{% endraw %}
    mode: include
    notification_mode: notification-system
    protected: true
    retention: keep-monthly=1, keep-weekly=1
    storage: mypbs
    vmids:
      - 100
      - 101
a  
backups:
  description: List of nodes and their task IDs.
  returned: on success
  type: list
  elements: dict
  contains:
    node:
      description: Node ID.
      returned: on success
      type: str
    status:
      description: Last known task status. Will be unknown, if O(wait=false).
      returned: on success
      type: str
      choices: ["unknown", "success", "failed"]
    upid:
      description: >-
        Proxmox cluster UPID, which is needed to lookup task info. Returns OK, when a cluster node did not create a task after
        being called, for example due to no matching targets.
      returned: on success
      type: str
N)AnsibleModule)	to_native)ProxmoxAnsibleproxmox_auth_argument_specc                 8     t         fd|D              S )Nc              3   h   K   | ])  }j                  |i       j                        k(   + y wN)get).0scopedefaultexpected
permissionpermission_trees     t/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/general/plugins/modules/proxmox_backup.py	<genexpr>z!has_permission.<locals>.<genexpr>   s1     nW\""5"-11*gF(Rns   /2)any)r   r   search_scopesr   r   s   `` ``r   has_permissionr      s    n`mnnn    c                   n    e Zd Zd ZddZd Zd Zd Zd Zd Z	d	 Z
d
 Zd Zd Zd Zd Zd Zd Zd Zy)ProxmoxBackupAnsiblec                 ^    | j                   j                  j                  j                         S r   )proxmox_apiaccesspermissionsr   )selfs    r   _get_permissionsz%ProxmoxBackupAnsible._get_permissions   s#    &&226688r   Nc                 b    | j                   j                  j                  j                  |      S )Ntype)r   cluster	resourcesr   )r    resource_types     r   _get_resourcesz#ProxmoxBackupAnsible._get_resources   s(    ''1155=5IIr   c                     | j                   j                  |      j                  |      j                  j	                         S r   )r   nodestaskslogr   r    nodeupids      r   _get_tasklogz!ProxmoxBackupAnsible._get_tasklog   s3    %%d+11$7;;??AAr   c                     | j                   j                  |      j                  |      j                  j	                         S r   )r   r*   r+   statusr   r-   s      r   _get_taskokz ProxmoxBackupAnsible._get_taskok   s3    %%d+11$7>>BBDDr   c                 l     | j                   j                  |      j                  j                  di |S )N )r   r*   vzdumppost)r    r.   request_bodys      r   _post_vzdumpz!ProxmoxBackupAnsible._post_vzdump   s/    7t%%d+2277G,GGr   c                     g }|D ]^  }| j                  ||      }|dk7  r)dj                  d | j                  ||      D              }nd}|j                  ||dd|z  dg       ` |S )NOK, c              3   &   K   | ]	  }|d      yw)tNr5   )r   logentrys     r   r   z6ProxmoxBackupAnsible.request_backup.<locals>.<genexpr>  s     #`hHSM#`s    unknownz%s)r.   r/   r2   r,   )r9   joinr0   extend)r    r8   node_endpointstask_idsr.   r/   tasklogs          r   request_backupz#ProxmoxBackupAnsible.request_backup   s     " 	hD$$T<8Dt|))#`$BSBSTXZ^B_#``OOdDIVZ]dVdefg	h r   c                     | j                  d      D cg c]  }|d   dk(  r|d    }}|r%||vr!| j                  j                  d|z         |S |r|gS |S c c}w )Nr.   r2   onlinez8Node %s was specified, but does not exist on the clustermsg)r(   module	fail_json)r    r.   itemr*   s       r   check_relevant_nodesz)ProxmoxBackupAnsible.check_relevant_nodes  s     ++F3
H~) L
 

 D%KK!!&`cg&g!h  6M
s   Ac                 2   t        |dddd|z   g      s| j                  j                  dd       |s|r-t        |ddgd	
      r| j                  j                  dd       |r3t        |dddd|z   g      s| j                  j                  dd       y y y )NzDatastore.AllocateSpace/z	/storage/r   Fz;Insufficient permission: Datastore.AllocateSpace is missingchangedrK   z
Sys.Modifyr   )r   r   zaInsufficient permission: Performance_tweaks and bandwidth require 'Sys.Modify' permission for '/'zDatastore.Allocatez/storagez[Insufficient permissions: Custom retention was requested, but Datastore.Allocate is missingr   rL   rM   )r    r   storage	bandwidthperformance	retentions         r   check_storage_permissionsz.ProxmoxBackupAnsible.check_storage_permissions  s     k+DUXZegru|g|T}~KK!!%5r!s.lcfbgrs*tKK!!%  6Y!  Z!+/CTWYcepszezS{|%%e  :W%  X } r   c                    t        |dddg      }|r|st        |dd|z   d|z   dz   g      }|svg }|D ]<  }dt        |      z   }t        |d|gdd	      s#|j                  t        |             > |r/| j                  j	                  d
ddj                  |      z         d}|s| j                  j	                  d
d       y y )N	VM.BackuprQ   /vmsrR   /pool/z/vms/   r   )r   r   r   FzLInsufficient permissions: You dont have the VM.Backup permission for VMID %sr<   rS   TzBInsufficient permissions: You do not have the VM.Backup permission)r   strappendrL   rM   rB   )r    r   vmidspoolsufficient_permissionsfailed_vmidsvmvm_paths           r   check_vmid_backup_permissionz1ProxmoxBackupAnsible.check_vmid_backup_permission)  s    !/[Y\^dXe!f.%3K]ehl]lnvy}n}  AG  oG  ]H  &I"% L 1!CG+!+{7)]^ijk ''B01 %%! (IIIl+(, & - &*"%KK!!%5y!z &r   c                 v    t        |dddg|rd|z   gng z         s| j                  j                  dd       y y )	Nr\   rQ   r]   r^   rR   Fz@Insufficient permissions: You dont have the VM.Backup permissionrS   rU   )r    r   rc   s      r   check_general_backup_permissionz4ProxmoxBackupAnsible.check_general_backup_permission@  sE    k;sFmlpX`cgXgWhvxFyzKK!!%5w!x {r   c                     | j                  d       }|D cg c]  }|d   |k(  s| }}|s!| j                  j                  dd|z         y y c c}w )Nr#   rV   Fz(Storage %s does not exist in the clusterrS   )get_storagesrL   rM   )r    rV   r.   storagesstorageentryvalidated_storagepaths         r   check_if_storage_existsz,ProxmoxBackupAnsible.check_if_storage_existsD  sj    $$$$/BJ q,l[dNeipNp q q$KK!!> "  % !rs
   AAc                 0   | j                  d      D cg c]  }|d   	 }}|s| j                  j                  d       y |D cg c]  }||vst        |       }}|r.| j                  j                  ddj	                  |      z         y y c c}w c c}w )Nrf   vmidzcVM.Audit permission is missing or there are no VMs. This task might fail if one VMID does not existzBVMIDs %s not found. This task will fail if one VMID does not existr<   )r(   rL   warnr`   rB   )r    rb   rf   cluster_vmidsvmids_not_founds        r   check_vmidsz ProxmoxBackupAnsible.check_vmidsN  s    .2.A.A$.GHFHHKKuw-2Nrb6M3r7NNKKT		/*+,  I
 Os   B	BBc                    g }g }|D ]-  }|d   dk7  r|j                  |       |j                  |       / t        j                         }	 |D ]N  }|d   dk(  s	 | j                  |d   |d         }|d   dk(  r|d   dk(  rd|d<   |d   dk(  r|d   d	k(  rd
|d<   P t        |D 	cg c]  }	|	d   dk7  s|	 c}	      t        |      k(  rnt        j                         ||z   kD  r|D cg c]  }|d   dk(  r|d    }
}|D cg c]  }|d   d
k(  s|d    }}|r@| j                  j                  ddj                  |
      ddj                  |             | j                  j                  ddj                  |
      z         t        j                  d       Xg }|D ]Y  }|d   d
k(  sdj                  | j                  |d   |d         D cg c]  }|d   	 c}      }|j                  |d|       [ |r.| j                  j                  ddj                  |      z         |D ]?  }dj                  | j                  |d   |d         D cg c]  }|d   	 c}      }||d<   A |j                  |       |S # t        $ r0}| j                  j                  d|d   d|       Y d }~qd }~ww xY wc c}	w c c}w c c}w c c}w c c}w )Nr/   r;   r2   rA   r.   stopped
exitstatussuccessz
job errorsfailedz)Unable to retrieve API task ID from node z: rJ   zOReached timeout while waiting for backup task. Nodes, who reached the timeout: r<   z. Nodes, which failed: zYReached timeout while waiting for creating VM snapshot. Nodes who reached the timeout: %sr_   r>   z]An error occured creating the backups. These are the last log lines from the failed nodes: %sr,   )ra   timer3   	ExceptionrL   rM   lenrB   sleepr0   rC   )r    timeout	raw_tasksr+   ok_tasksr.   
start_timer2   erN   timeouted_nodesfailed_nodes
error_logsr?   rF   s                  r   wait_for_timeoutz%ProxmoxBackupAnsible.wait_for_timeoutZ  s@     	&DF|t#T"%		& YY[
 y>Y.	y "&!1!1$v,V!M!(+y8VL=QUY=Y-6DN!(+y8VL=QUa=a-5DNy UJTd8n	.IDJKsSXzYyy{Z'11 !&#H~2 L# #
 :?]$x.T\B\V]]KK)) ?3TYY|5LN * O
 %%8IIo./ & 0 JJqMA D 
 	>DH~)))4CTCTUYZ`UacghncoCp$qxXc]$qr!!dG"<=	> KK!!I		*%& " '
  	"Diit?P?PQUV\Q]_cdj_k?l m8# mnG!DK	"
 	XQ % y--gklrgsuv2w-xxyJ#
  ^  %r !nsC   AJ(K6K,KKKK
K
	K%J??Kc	                     | j                         }	| j                  ||       | j                  |	||||       |dk(  r| j                  |	||       y | j	                  |	|       y )Ninclude)r!   rp   rZ   rh   rj   )
r    rV   moder.   rW   performance_tweaksrY   rc   rb   r   s
             r   permission_checkz%ProxmoxBackupAnsible.permission_check  sg     ++-$$Wd3&&)-?	L9--k5$G00dCr   c                 p   g d}i }|D ]-  \  }}|j                  |      s|j                  |||   i       / |d   dk(  r|j                  dd        d|d<   nQ|d   dk(  r*|j                  dd        |j                  dd        d|d<   n|d   dk(  r|j                  dd        d|d<   |j                  d      r,|j                  dd	j                  d
 |d   D              i       dD ],  }|j                  |      s||   j	                  dd      ||<   . dD ]  }|j                  |      sd||<    |S )N))bwlimitrW   )compressr   )fleecingr   )r   backup_mode)znotes-templatedescription)znotification-modenotification_mode)zpbs-change-detection-modechange_detection_mode)rX   r   )rc   rc   )	protectedr   )prune-backupsrY   )rV   rV   )zstdcompression_threads)rr   rb   r   r   rc   r   allrr   r_   ,c              3   2   K   | ]  }t        |        y wr   )r`   )r   rr   s     r   r   zBProxmoxBackupAnsible.prepare_request_parameters.<locals>.<genexpr>  s     1]#d)1]s   )r   rX    r@   )r   )r   updatepoprB   replace)r    module_argumentspost_paramsr8   newoldkeys          r   prepare_request_parametersz/ProxmoxBackupAnsible.prepare_request_parameters  sy   * # 	BHC##C(##S*:3*?$@A	B
 F#y0VT*"#Lf%.VT*VT*"#Lf%/VT*"#L F#1]U[H\1])] ^_ 4 	GC$$0$5$=$=c2$FS!	G " 	&C$$%S!	& r   c                     | j                  |      }|rg S | j                  ||      }g }|d   r| j                  |d   |      }|r|S |S )Nwaitwait_timeout)r   rG   r   )r    r   
check_moderD   r8   rE   updated_task_idss          r   backup_createz"ProxmoxBackupAnsible.backup_create  sf    
 667GHI&&|^DF##44 0( <#3AAr   r   )__name__
__module____qualname__r!   r(   r0   r3   r9   rG   rO   rZ   rh   rj   rp   rv   r   r   r   r   r5   r   r   r   r      s^    9JBEH
X${.y
,@DD&.`Br   r   c            
         t               } i dddg dddddid	dg d
dddg dddddidddddddidddg dddddidddg dddddidddidddidddid ddd!d"d#dd$d%dd&dd'dd(di}| j                  |       t        | dd)d*g+      }t        |      }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }	|j                  d    }
|j                  d"   }|j                  |
|||||	||       |j                  d   d,k(  r|j                  |j                  d"          |j                  |j                  d         }	 |j                  |j                  |j                  |      }|j                  r|j                  dd/0       y t        D cg c]  }|d1   d2k(  s| c}      t        |      k(  r|j                  |d&d30       y |j                  d%   r|j                  |dd40       y |j                  |dd50       y # t        $ r(}|j                  d-t        |      z  .       Y d }~d }~ww xY wc c}w )6Nr   r`   snapshot)r   suspendstop)r$   r   choicesrW   r$   intr   )legacydatametadata)r$   r   r   )01gziplzor   r   r   z{{guestname}})r$   r   r   r   T)r   r   rc   )r$   requiredr   r.   r   auto)r   zlegacy-sendmailznotification-systemr   rc   r   boolrY   rV   )r$   r   rb   list)r$   elementsr   Fr   
   )r   r   )rb   T)r   rc   )rc   )argument_specsupports_check_moderequired_ifr   z*Creating backups failed with exception: %srJ   zBackups would be created)backupsrT   rK   r/   r;   z0Backup request sent to proxmox, no tasks createdzBackups succeededzBackup tasks created)r	   r   r   r   paramsr   rv   rO   r   r   r}   rM   r   	exit_jsonr~   )module_argsbackup_argsrL   proxmoxrW   r   r.   r   rc   rY   rV   rb   rD   resultr   entrys                   r   mainr     sM   ,.K8*Ihi8fe_8 	 %<Z![8 	U/PQ	8
 	8 	/B8 	VUO8 	D=WX8 	8 	eK}~8 	vuo8 	8 	ff%8 	fe_8 	Et48  	&e4!8" 	E2#8$ 	26%8K& {#! 1'
F #6*Gk*I== D== D';<== Dk*ImmI&GMM'"E }}V	)FMM'2311&--2GHNZ&&v}}f6G6GX ;UV	A5=D+@eA	Bc&k	Q<no	v	;NO 	3 	 	5  ZIIVWLXYYZ Bs$   
'I J)J	I?I::I?__main__)r   r_   )
__future__r   r   r   r$   __metaclass__DOCUMENTATIONEXAMPLESRETURNr|   ansible.module_utils.basicr   +ansible.module_utils.common.text.convertersr   Bansible_collections.community.general.plugins.module_utils.proxmoxr   r	   r   r   r   r   r5   r   r   <module>r      sk    A @FP1f
0  4 A yoCB> CBLE5P zF r   