1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3 4# Copyright: (c) 2016, Abdoul Bah (@helldorado) <bahabdoul at gmail.com> 5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 7from __future__ import absolute_import, division, print_function 8__metaclass__ = type 9 10DOCUMENTATION = r''' 11--- 12module: proxmox_kvm 13short_description: Management of Qemu(KVM) Virtual Machines in Proxmox VE cluster. 14description: 15 - Allows you to create/delete/stop Qemu(KVM) Virtual Machines in Proxmox VE cluster. 16 - From community.general 4.0.0 on, there will be no default values, see I(proxmox_default_behavior). 17author: "Abdoul Bah (@helldorado) <bahabdoul at gmail.com>" 18options: 19 acpi: 20 description: 21 - Specify if ACPI should be enabled/disabled. 22 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 23 option has a default of C(yes). Note that the default value of I(proxmox_default_behavior) 24 changes in community.general 4.0.0. 25 type: bool 26 agent: 27 description: 28 - Specify if the QEMU Guest Agent should be enabled/disabled. 29 type: bool 30 args: 31 description: 32 - Pass arbitrary arguments to kvm. 33 - This option is for experts only! 34 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 35 option has a default of C(-serial unix:/var/run/qemu-server/<vmid>.serial,server,nowait). 36 Note that the default value of I(proxmox_default_behavior) changes in community.general 4.0.0. 37 type: str 38 autostart: 39 description: 40 - Specify if the VM should be automatically restarted after crash (currently ignored in PVE API). 41 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 42 option has a default of C(no). Note that the default value of I(proxmox_default_behavior) 43 changes in community.general 4.0.0. 44 type: bool 45 balloon: 46 description: 47 - Specify the amount of RAM for the VM in MB. 48 - Using zero disables the balloon driver. 49 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 50 option has a default of C(0). Note that the default value of I(proxmox_default_behavior) 51 changes in community.general 4.0.0. 52 type: int 53 bios: 54 description: 55 - Specify the BIOS implementation. 56 type: str 57 choices: ['seabios', 'ovmf'] 58 boot: 59 description: 60 - Specify the boot order -> boot on floppy C(a), hard disk C(c), CD-ROM C(d), or network C(n). 61 - You can combine to set order. 62 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 63 option has a default of C(cnd). Note that the default value of I(proxmox_default_behavior) 64 changes in community.general 4.0.0. 65 type: str 66 bootdisk: 67 description: 68 - Enable booting from specified disk. C((ide|sata|scsi|virtio)\d+) 69 type: str 70 cicustom: 71 description: 72 - 'cloud-init: Specify custom files to replace the automatically generated ones at start.' 73 type: str 74 version_added: 1.3.0 75 cipassword: 76 description: 77 - 'cloud-init: password of default user to create.' 78 type: str 79 version_added: 1.3.0 80 citype: 81 description: 82 - 'cloud-init: Specifies the cloud-init configuration format.' 83 - The default depends on the configured operating system type (C(ostype)). 84 - We use the C(nocloud) format for Linux, and C(configdrive2) for Windows. 85 type: str 86 choices: ['nocloud', 'configdrive2'] 87 version_added: 1.3.0 88 ciuser: 89 description: 90 - 'cloud-init: username of default user to create.' 91 type: str 92 version_added: 1.3.0 93 clone: 94 description: 95 - Name of VM to be cloned. If C(vmid) is setted, C(clone) can take arbitrary value but required for initiating the clone. 96 type: str 97 cores: 98 description: 99 - Specify number of cores per socket. 100 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 101 option has a default of C(1). Note that the default value of I(proxmox_default_behavior) 102 changes in community.general 4.0.0. 103 type: int 104 cpu: 105 description: 106 - Specify emulated CPU type. 107 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 108 option has a default of C(kvm64). Note that the default value of I(proxmox_default_behavior) 109 changes in community.general 4.0.0. 110 type: str 111 cpulimit: 112 description: 113 - Specify if CPU usage will be limited. Value 0 indicates no CPU limit. 114 - If the computer has 2 CPUs, it has total of '2' CPU time 115 type: int 116 cpuunits: 117 description: 118 - Specify CPU weight for a VM. 119 - You can disable fair-scheduler configuration by setting this to 0 120 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 121 option has a default of C(1000). Note that the default value of I(proxmox_default_behavior) 122 changes in community.general 4.0.0. 123 type: int 124 delete: 125 description: 126 - Specify a list of settings you want to delete. 127 type: str 128 description: 129 description: 130 - Specify the description for the VM. Only used on the configuration web interface. 131 - This is saved as comment inside the configuration file. 132 type: str 133 digest: 134 description: 135 - Specify if to prevent changes if current configuration file has different SHA1 digest. 136 - This can be used to prevent concurrent modifications. 137 type: str 138 force: 139 description: 140 - Allow to force stop VM. 141 - Can be used with states C(stopped), C(restarted) and C(absent). 142 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 143 option has a default of C(no). Note that the default value of I(proxmox_default_behavior) 144 changes in community.general 4.0.0. 145 type: bool 146 format: 147 description: 148 - Target drive's backing file's data format. 149 - Used only with clone 150 - Use I(format=unspecified) and I(full=false) for a linked clone. 151 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 152 option has a default of C(qcow2). If I(proxmox_default_behavior) is set to C(no_defaults), 153 not specifying this option is equivalent to setting it to C(unspecified). 154 Note that the default value of I(proxmox_default_behavior) changes in community.general 4.0.0. 155 type: str 156 choices: [ "cloop", "cow", "qcow", "qcow2", "qed", "raw", "vmdk", "unspecified" ] 157 freeze: 158 description: 159 - Specify if PVE should freeze CPU at startup (use 'c' monitor command to start execution). 160 type: bool 161 full: 162 description: 163 - Create a full copy of all disk. This is always done when you clone a normal VM. 164 - For VM templates, we try to create a linked clone by default. 165 - Used only with clone 166 type: bool 167 default: 'yes' 168 hostpci: 169 description: 170 - Specify a hash/dictionary of map host pci devices into guest. C(hostpci='{"key":"value", "key":"value"}'). 171 - Keys allowed are - C(hostpci[n]) where 0 ≤ n ≤ N. 172 - Values allowed are - C("host="HOSTPCIID[;HOSTPCIID2...]",pcie="1|0",rombar="1|0",x-vga="1|0""). 173 - The C(host) parameter is Host PCI device pass through. HOSTPCIID syntax is C(bus:dev.func) (hexadecimal numbers). 174 - C(pcie=boolean) I(default=0) Choose the PCI-express bus (needs the q35 machine model). 175 - C(rombar=boolean) I(default=1) Specify whether or not the device's ROM will be visible in the guest's memory map. 176 - C(x-vga=boolean) I(default=0) Enable vfio-vga device support. 177 - /!\ This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care. 178 type: dict 179 hotplug: 180 description: 181 - Selectively enable hotplug features. 182 - This is a comma separated list of hotplug features C('network', 'disk', 'cpu', 'memory' and 'usb'). 183 - Value 0 disables hotplug completely and value 1 is an alias for the default C('network,disk,usb'). 184 type: str 185 hugepages: 186 description: 187 - Enable/disable hugepages memory. 188 type: str 189 choices: ['any', '2', '1024'] 190 ide: 191 description: 192 - A hash/dictionary of volume used as IDE hard disk or CD-ROM. C(ide='{"key":"value", "key":"value"}'). 193 - Keys allowed are - C(ide[n]) where 0 ≤ n ≤ 3. 194 - Values allowed are - C("storage:size,format=value"). 195 - C(storage) is the storage identifier where to create the disk. 196 - C(size) is the size of the disk in GB. 197 - C(format) is the drive's backing file's data format. C(qcow2|raw|subvol). 198 type: dict 199 ipconfig: 200 description: 201 - 'cloud-init: Set the IP configuration.' 202 - A hash/dictionary of network ip configurations. C(ipconfig='{"key":"value", "key":"value"}'). 203 - Keys allowed are - C(ipconfig[n]) where 0 ≤ n ≤ network interfaces. 204 - Values allowed are - C("[gw=<GatewayIPv4>] [,gw6=<GatewayIPv6>] [,ip=<IPv4Format/CIDR>] [,ip6=<IPv6Format/CIDR>]"). 205 - 'cloud-init: Specify IP addresses and gateways for the corresponding interface.' 206 - IP addresses use CIDR notation, gateways are optional but they should be in the same subnet of specified IP address. 207 - The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided. 208 - For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. 209 - If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4. 210 type: dict 211 version_added: 1.3.0 212 keyboard: 213 description: 214 - Sets the keyboard layout for VNC server. 215 type: str 216 kvm: 217 description: 218 - Enable/disable KVM hardware virtualization. 219 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 220 option has a default of C(yes). Note that the default value of I(proxmox_default_behavior) 221 changes in community.general 4.0.0. 222 type: bool 223 localtime: 224 description: 225 - Sets the real time clock to local time. 226 - This is enabled by default if ostype indicates a Microsoft OS. 227 type: bool 228 lock: 229 description: 230 - Lock/unlock the VM. 231 type: str 232 choices: ['migrate', 'backup', 'snapshot', 'rollback'] 233 machine: 234 description: 235 - Specifies the Qemu machine type. 236 - type => C((pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)) 237 type: str 238 memory: 239 description: 240 - Memory size in MB for instance. 241 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 242 option has a default of C(512). Note that the default value of I(proxmox_default_behavior) 243 changes in community.general 4.0.0. 244 type: int 245 migrate_downtime: 246 description: 247 - Sets maximum tolerated downtime (in seconds) for migrations. 248 type: int 249 migrate_speed: 250 description: 251 - Sets maximum speed (in MB/s) for migrations. 252 - A value of 0 is no limit. 253 type: int 254 name: 255 description: 256 - Specifies the VM name. Only used on the configuration web interface. 257 - Required only for C(state=present). 258 type: str 259 nameservers: 260 description: 261 - 'cloud-init: DNS server IP address(es).' 262 - If unset, PVE host settings are used. 263 type: list 264 elements: str 265 version_added: 1.3.0 266 net: 267 description: 268 - A hash/dictionary of network interfaces for the VM. C(net='{"key":"value", "key":"value"}'). 269 - Keys allowed are - C(net[n]) where 0 ≤ n ≤ N. 270 - Values allowed are - C("model="XX:XX:XX:XX:XX:XX",bridge="value",rate="value",tag="value",firewall="1|0",trunks="vlanid""). 271 - Model is one of C(e1000 e1000-82540em e1000-82544gc e1000-82545em i82551 i82557b i82559er ne2k_isa ne2k_pci pcnet rtl8139 virtio vmxnet3). 272 - C(XX:XX:XX:XX:XX:XX) should be an unique MAC address. This is automatically generated if not specified. 273 - The C(bridge) parameter can be used to automatically add the interface to a bridge device. The Proxmox VE standard bridge is called 'vmbr0'. 274 - Option C(rate) is used to limit traffic bandwidth from and to this interface. It is specified as floating point number, unit is 'Megabytes per second'. 275 - If you specify no bridge, we create a kvm 'user' (NATed) network device, which provides DHCP and DNS services. 276 type: dict 277 newid: 278 description: 279 - VMID for the clone. Used only with clone. 280 - If newid is not set, the next available VM ID will be fetched from ProxmoxAPI. 281 type: int 282 numa: 283 description: 284 - A hash/dictionaries of NUMA topology. C(numa='{"key":"value", "key":"value"}'). 285 - Keys allowed are - C(numa[n]) where 0 ≤ n ≤ N. 286 - Values allowed are - C("cpu="<id[-id];...>",hostnodes="<id[-id];...>",memory="number",policy="(bind|interleave|preferred)""). 287 - C(cpus) CPUs accessing this NUMA node. 288 - C(hostnodes) Host NUMA nodes to use. 289 - C(memory) Amount of memory this NUMA node provides. 290 - C(policy) NUMA allocation policy. 291 type: dict 292 numa_enabled: 293 description: 294 - Enables NUMA. 295 type: bool 296 onboot: 297 description: 298 - Specifies whether a VM will be started during system bootup. 299 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 300 option has a default of C(yes). Note that the default value of I(proxmox_default_behavior) 301 changes in community.general 4.0.0. 302 type: bool 303 ostype: 304 description: 305 - Specifies guest operating system. This is used to enable special optimization/features for specific operating systems. 306 - The l26 is Linux 2.6/3.X Kernel. 307 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 308 option has a default of C(l26). Note that the default value of I(proxmox_default_behavior) 309 changes in community.general 4.0.0. 310 type: str 311 choices: ['other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7', 'win8', 'win10', 'l24', 'l26', 'solaris'] 312 parallel: 313 description: 314 - A hash/dictionary of map host parallel devices. C(parallel='{"key":"value", "key":"value"}'). 315 - Keys allowed are - (parallel[n]) where 0 ≤ n ≤ 2. 316 - Values allowed are - C("/dev/parport\d+|/dev/usb/lp\d+"). 317 type: dict 318 protection: 319 description: 320 - Enable/disable the protection flag of the VM. This will enable/disable the remove VM and remove disk operations. 321 type: bool 322 reboot: 323 description: 324 - Allow reboot. If set to C(yes), the VM exit on reboot. 325 type: bool 326 revert: 327 description: 328 - Revert a pending change. 329 type: str 330 sata: 331 description: 332 - A hash/dictionary of volume used as sata hard disk or CD-ROM. C(sata='{"key":"value", "key":"value"}'). 333 - Keys allowed are - C(sata[n]) where 0 ≤ n ≤ 5. 334 - Values allowed are - C("storage:size,format=value"). 335 - C(storage) is the storage identifier where to create the disk. 336 - C(size) is the size of the disk in GB. 337 - C(format) is the drive's backing file's data format. C(qcow2|raw|subvol). 338 type: dict 339 scsi: 340 description: 341 - A hash/dictionary of volume used as SCSI hard disk or CD-ROM. C(scsi='{"key":"value", "key":"value"}'). 342 - Keys allowed are - C(sata[n]) where 0 ≤ n ≤ 13. 343 - Values allowed are - C("storage:size,format=value"). 344 - C(storage) is the storage identifier where to create the disk. 345 - C(size) is the size of the disk in GB. 346 - C(format) is the drive's backing file's data format. C(qcow2|raw|subvol). 347 type: dict 348 scsihw: 349 description: 350 - Specifies the SCSI controller model. 351 type: str 352 choices: ['lsi', 'lsi53c810', 'virtio-scsi-pci', 'virtio-scsi-single', 'megasas', 'pvscsi'] 353 searchdomains: 354 description: 355 - 'cloud-init: Sets DNS search domain(s).' 356 - If unset, PVE host settings are used. 357 type: list 358 elements: str 359 version_added: 1.3.0 360 serial: 361 description: 362 - A hash/dictionary of serial device to create inside the VM. C('{"key":"value", "key":"value"}'). 363 - Keys allowed are - serial[n](str; required) where 0 ≤ n ≤ 3. 364 - Values allowed are - C((/dev/.+|socket)). 365 - /!\ If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care. 366 type: dict 367 shares: 368 description: 369 - Rets amount of memory shares for auto-ballooning. (0 - 50000). 370 - The larger the number is, the more memory this VM gets. 371 - The number is relative to weights of all other running VMs. 372 - Using 0 disables auto-ballooning, this means no limit. 373 type: int 374 skiplock: 375 description: 376 - Ignore locks 377 - Only root is allowed to use this option. 378 type: bool 379 smbios: 380 description: 381 - Specifies SMBIOS type 1 fields. 382 type: str 383 snapname: 384 description: 385 - The name of the snapshot. Used only with clone. 386 type: str 387 sockets: 388 description: 389 - Sets the number of CPU sockets. (1 - N). 390 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 391 option has a default of C(1). Note that the default value of I(proxmox_default_behavior) 392 changes in community.general 4.0.0. 393 type: int 394 sshkeys: 395 description: 396 - 'cloud-init: SSH key to assign to the default user. NOT TESTED with multiple keys but a multi-line value should work.' 397 type: str 398 version_added: 1.3.0 399 startdate: 400 description: 401 - Sets the initial date of the real time clock. 402 - Valid format for date are C('now') or C('2016-09-25T16:01:21') or C('2016-09-25'). 403 type: str 404 startup: 405 description: 406 - Startup and shutdown behavior. C([[order=]\d+] [,up=\d+] [,down=\d+]). 407 - Order is a non-negative number defining the general startup order. 408 - Shutdown in done with reverse ordering. 409 type: str 410 state: 411 description: 412 - Indicates desired state of the instance. 413 - If C(current), the current state of the VM will be fetched. You can access it with C(results.status) 414 type: str 415 choices: ['present', 'started', 'absent', 'stopped', 'restarted','current'] 416 default: present 417 storage: 418 description: 419 - Target storage for full clone. 420 type: str 421 tablet: 422 description: 423 - Enables/disables the USB tablet device. 424 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 425 option has a default of C(no). Note that the default value of I(proxmox_default_behavior) 426 changes in community.general 4.0.0. 427 type: bool 428 tags: 429 description: 430 - List of tags to apply to the VM instance. 431 - Tags must start with C([a-z0-9_]) followed by zero or more of the following characters C([a-z0-9_-+.]). 432 - Tags are only available in Proxmox 6+. 433 type: list 434 elements: str 435 version_added: 2.3.0 436 target: 437 description: 438 - Target node. Only allowed if the original VM is on shared storage. 439 - Used only with clone 440 type: str 441 tdf: 442 description: 443 - Enables/disables time drift fix. 444 type: bool 445 template: 446 description: 447 - Enables/disables the template. 448 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 449 option has a default of C(no). Note that the default value of I(proxmox_default_behavior) 450 changes in community.general 4.0.0. 451 type: bool 452 timeout: 453 description: 454 - Timeout for operations. 455 type: int 456 default: 30 457 update: 458 description: 459 - If C(yes), the VM will be updated with new value. 460 - Cause of the operations of the API and security reasons, I have disabled the update of the following parameters 461 - C(net, virtio, ide, sata, scsi). Per example updating C(net) update the MAC address and C(virtio) create always new disk... 462 - Update of C(pool) is disabled. It needs an additional API endpoint not covered by this module. 463 type: bool 464 default: 'no' 465 vcpus: 466 description: 467 - Sets number of hotplugged vcpus. 468 type: int 469 vga: 470 description: 471 - Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'. 472 - If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this 473 option has a default of C(std). Note that the default value of I(proxmox_default_behavior) 474 changes in community.general 4.0.0. 475 type: str 476 choices: ['std', 'cirrus', 'vmware', 'qxl', 'serial0', 'serial1', 'serial2', 'serial3', 'qxl2', 'qxl3', 'qxl4'] 477 virtio: 478 description: 479 - A hash/dictionary of volume used as VIRTIO hard disk. C(virtio='{"key":"value", "key":"value"}'). 480 - Keys allowed are - C(virto[n]) where 0 ≤ n ≤ 15. 481 - Values allowed are - C("storage:size,format=value"). 482 - C(storage) is the storage identifier where to create the disk. 483 - C(size) is the size of the disk in GB. 484 - C(format) is the drive's backing file's data format. C(qcow2|raw|subvol). 485 type: dict 486 watchdog: 487 description: 488 - Creates a virtual hardware watchdog device. 489 type: str 490 proxmox_default_behavior: 491 description: 492 - Various module options used to have default values. This cause problems when 493 user expects different behavior from proxmox by default or fill options which cause 494 problems when they have been set. 495 - The default value is C(compatibility), which will ensure that the default values 496 are used when the values are not explicitly specified by the user. 497 - From community.general 4.0.0 on, the default value will switch to C(no_defaults). To avoid 498 deprecation warnings, please set I(proxmox_default_behavior) to an explicit 499 value. 500 - This affects the I(acpi), I(autostart), I(balloon), I(boot), I(cores), I(cpu), 501 I(cpuunits), I(force), I(format), I(kvm), I(memory), I(onboot), I(ostype), I(sockets), 502 I(tablet), I(template), I(vga), options. 503 type: str 504 choices: 505 - compatibility 506 - no_defaults 507 version_added: "1.3.0" 508extends_documentation_fragment: 509 - community.general.proxmox.documentation 510 - community.general.proxmox.selection 511''' 512 513EXAMPLES = ''' 514- name: Create new VM with minimal options 515 community.general.proxmox_kvm: 516 api_user: root@pam 517 api_password: secret 518 api_host: helldorado 519 name: spynal 520 node: sabrewulf 521 522- name: Create new VM with minimal options and given vmid 523 community.general.proxmox_kvm: 524 api_user: root@pam 525 api_password: secret 526 api_host: helldorado 527 name: spynal 528 node: sabrewulf 529 vmid: 100 530 531- name: Create new VM with two network interface options 532 community.general.proxmox_kvm: 533 api_user: root@pam 534 api_password: secret 535 api_host: helldorado 536 name: spynal 537 node: sabrewulf 538 net: 539 net0: 'virtio,bridge=vmbr1,rate=200' 540 net1: 'e1000,bridge=vmbr2' 541 542- name: Create new VM with one network interface, three virto hard disk, 4 cores, and 2 vcpus 543 community.general.proxmox_kvm: 544 api_user: root@pam 545 api_password: secret 546 api_host: helldorado 547 name: spynal 548 node: sabrewulf 549 net: 550 net0: 'virtio,bridge=vmbr1,rate=200' 551 virtio: 552 virtio0: 'VMs_LVM:10' 553 virtio1: 'VMs:2,format=qcow2' 554 virtio2: 'VMs:5,format=raw' 555 cores: 4 556 vcpus: 2 557 558- name: > 559 Clone VM with only source VM name. 560 The VM source is spynal. 561 The target VM name is zavala 562 community.general.proxmox_kvm: 563 api_user: root@pam 564 api_password: secret 565 api_host: helldorado 566 clone: spynal 567 name: zavala 568 node: sabrewulf 569 storage: VMs 570 format: qcow2 571 timeout: 500 572 573- name: > 574 Create linked clone VM with only source VM name. 575 The VM source is spynal. 576 The target VM name is zavala 577 community.general.proxmox_kvm: 578 api_user: root@pam 579 api_password: secret 580 api_host: helldorado 581 clone: spynal 582 name: zavala 583 node: sabrewulf 584 storage: VMs 585 full: no 586 format: unspecified 587 timeout: 500 588 589- name: Clone VM with source vmid and target newid and raw format 590 community.general.proxmox_kvm: 591 api_user: root@pam 592 api_password: secret 593 api_host: helldorado 594 clone: arbitrary_name 595 vmid: 108 596 newid: 152 597 name: zavala 598 node: sabrewulf 599 storage: LVM_STO 600 format: raw 601 timeout: 300 602 603- name: Create new VM and lock it for snapshot 604 community.general.proxmox_kvm: 605 api_user: root@pam 606 api_password: secret 607 api_host: helldorado 608 name: spynal 609 node: sabrewulf 610 lock: snapshot 611 612- name: Create new VM and set protection to disable the remove VM and remove disk operations 613 community.general.proxmox_kvm: 614 api_user: root@pam 615 api_password: secret 616 api_host: helldorado 617 name: spynal 618 node: sabrewulf 619 protection: yes 620 621- name: Create new VM using cloud-init with a username and password 622 community.general.proxmox_kvm: 623 node: sabrewulf 624 api_user: root@pam 625 api_password: secret 626 api_host: helldorado 627 name: spynal 628 ide: 629 ide2: 'local:cloudinit,format=qcow2' 630 ciuser: mylinuxuser 631 cipassword: supersecret 632 searchdomains: 'mydomain.internal' 633 nameservers: 1.1.1.1 634 net: 635 net0: 'virtio,bridge=vmbr1,tag=77' 636 ipconfig: 637 ipconfig0: 'ip=192.168.1.1/24,gw=192.168.1.1' 638 639- name: Create new VM using Cloud-Init with an ssh key 640 community.general.proxmox_kvm: 641 node: sabrewulf 642 api_user: root@pam 643 api_password: secret 644 api_host: helldorado 645 name: spynal 646 ide: 647 ide2: 'local:cloudinit,format=qcow2' 648 sshkeys: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILJkVm98B71lD5XHfihwcYHE9TVpsJmK1vR1JcaU82L+' 649 searchdomains: 'mydomain.internal' 650 nameservers: 651 - '1.1.1.1' 652 - '8.8.8.8' 653 net: 654 net0: 'virtio,bridge=vmbr1,tag=77' 655 ipconfig: 656 ipconfig0: 'ip=192.168.1.1/24' 657 658- name: Start VM 659 community.general.proxmox_kvm: 660 api_user: root@pam 661 api_password: secret 662 api_host: helldorado 663 name: spynal 664 node: sabrewulf 665 state: started 666 667- name: Stop VM 668 community.general.proxmox_kvm: 669 api_user: root@pam 670 api_password: secret 671 api_host: helldorado 672 name: spynal 673 node: sabrewulf 674 state: stopped 675 676- name: Stop VM with force 677 community.general.proxmox_kvm: 678 api_user: root@pam 679 api_password: secret 680 api_host: helldorado 681 name: spynal 682 node: sabrewulf 683 state: stopped 684 force: yes 685 686- name: Restart VM 687 community.general.proxmox_kvm: 688 api_user: root@pam 689 api_password: secret 690 api_host: helldorado 691 name: spynal 692 node: sabrewulf 693 state: restarted 694 695- name: Remove VM 696 community.general.proxmox_kvm: 697 api_user: root@pam 698 api_password: secret 699 api_host: helldorado 700 name: spynal 701 node: sabrewulf 702 state: absent 703 704- name: Get VM current state 705 community.general.proxmox_kvm: 706 api_user: root@pam 707 api_password: secret 708 api_host: helldorado 709 name: spynal 710 node: sabrewulf 711 state: current 712 713- name: Update VM configuration 714 community.general.proxmox_kvm: 715 api_user: root@pam 716 api_password: secret 717 api_host: helldorado 718 name: spynal 719 node: sabrewulf 720 cores: 8 721 memory: 16384 722 update: yes 723 724- name: Delete QEMU parameters 725 community.general.proxmox_kvm: 726 api_user: root@pam 727 api_password: secret 728 api_host: helldorado 729 name: spynal 730 node: sabrewulf 731 delete: 'args,template,cpulimit' 732 733- name: Revert a pending change 734 community.general.proxmox_kvm: 735 api_user: root@pam 736 api_password: secret 737 api_host: helldorado 738 name: spynal 739 node: sabrewulf 740 revert: 'template,cpulimit' 741''' 742 743RETURN = ''' 744vmid: 745 description: The VM vmid. 746 returned: success 747 type: int 748 sample: 115 749status: 750 description: The current virtual machine status. 751 returned: success, not clone, not absent, not update 752 type: str 753 sample: running 754msg: 755 description: A short message 756 returned: always 757 type: str 758 sample: "VM kropta with vmid = 110 is running" 759''' 760 761import re 762import time 763import traceback 764from distutils.version import LooseVersion 765from ansible.module_utils.six.moves.urllib.parse import quote 766 767try: 768 from proxmoxer import ProxmoxAPI 769 HAS_PROXMOXER = True 770except ImportError: 771 HAS_PROXMOXER = False 772 773from ansible.module_utils.basic import AnsibleModule, env_fallback 774from ansible.module_utils.common.text.converters import to_native 775 776 777def get_nextvmid(module, proxmox): 778 try: 779 vmid = proxmox.cluster.nextid.get() 780 return vmid 781 except Exception as e: 782 module.fail_json(msg="Unable to get next vmid. Failed with exception: %s" % to_native(e), 783 exception=traceback.format_exc()) 784 785 786def get_vmid(proxmox, name): 787 return [vm['vmid'] for vm in proxmox.cluster.resources.get(type='vm') if vm.get('name') == name] 788 789 790def get_vm(proxmox, vmid): 791 return [vm for vm in proxmox.cluster.resources.get(type='vm') if vm['vmid'] == int(vmid)] 792 793 794def node_check(proxmox, node): 795 return [True for nd in proxmox.nodes.get() if nd['node'] == node] 796 797 798def get_vminfo(module, proxmox, node, vmid, **kwargs): 799 global results 800 results = {} 801 mac = {} 802 devices = {} 803 try: 804 vm = proxmox.nodes(node).qemu(vmid).config.get() 805 except Exception as e: 806 module.fail_json(msg='Getting information for VM with vmid = %s failed with exception: %s' % (vmid, e)) 807 808 # Sanitize kwargs. Remove not defined args and ensure True and False converted to int. 809 kwargs = dict((k, v) for k, v in kwargs.items() if v is not None) 810 811 # Convert all dict in kwargs to elements. 812 # For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n] 813 for k in list(kwargs.keys()): 814 if isinstance(kwargs[k], dict): 815 kwargs.update(kwargs[k]) 816 del kwargs[k] 817 818 # Split information by type 819 re_net = re.compile(r'net[0-9]') 820 re_dev = re.compile(r'(virtio|ide|scsi|sata)[0-9]') 821 for k in kwargs.keys(): 822 if re_net.match(k): 823 mac[k] = parse_mac(vm[k]) 824 elif re_dev.match(k): 825 devices[k] = parse_dev(vm[k]) 826 827 results['mac'] = mac 828 results['devices'] = devices 829 results['vmid'] = int(vmid) 830 831 832def parse_mac(netstr): 833 return re.search('=(.*?),', netstr).group(1) 834 835 836def parse_dev(devstr): 837 return re.search('(.*?)(,|$)', devstr).group(1) 838 839 840def settings(proxmox, vmid, node, **kwargs): 841 proxmox_node = proxmox.nodes(node) 842 843 # Sanitize kwargs. Remove not defined args and ensure True and False converted to int. 844 kwargs = dict((k, v) for k, v in kwargs.items() if v is not None) 845 846 return proxmox_node.qemu(vmid).config.set(**kwargs) is None 847 848 849def wait_for_task(module, proxmox, node, taskid): 850 timeout = module.params['timeout'] 851 852 while timeout: 853 task = proxmox.nodes(node).tasks(taskid).status.get() 854 if task['status'] == 'stopped' and task['exitstatus'] == 'OK': 855 # Wait an extra second as the API can be a ahead of the hypervisor 856 time.sleep(1) 857 return True 858 timeout = timeout - 1 859 if timeout == 0: 860 break 861 time.sleep(1) 862 return False 863 864 865def create_vm(module, proxmox, vmid, newid, node, name, memory, cpu, cores, sockets, update, **kwargs): 866 # Available only in PVE 4 867 only_v4 = ['force', 'protection', 'skiplock'] 868 only_v6 = ['ciuser', 'cipassword', 'sshkeys', 'ipconfig', 'tags'] 869 870 # valide clone parameters 871 valid_clone_params = ['format', 'full', 'pool', 'snapname', 'storage', 'target'] 872 clone_params = {} 873 # Default args for vm. Note: -args option is for experts only. It allows you to pass arbitrary arguments to kvm. 874 vm_args = "-serial unix:/var/run/qemu-server/{0}.serial,server,nowait".format(vmid) 875 876 proxmox_node = proxmox.nodes(node) 877 878 # Sanitize kwargs. Remove not defined args and ensure True and False converted to int. 879 kwargs = dict((k, v) for k, v in kwargs.items() if v is not None) 880 kwargs.update(dict([k, int(v)] for k, v in kwargs.items() if isinstance(v, bool))) 881 882 # The features work only on PVE 4+ 883 if PVE_MAJOR_VERSION < 4: 884 for p in only_v4: 885 if p in kwargs: 886 del kwargs[p] 887 888 # The features work only on PVE 6 889 if PVE_MAJOR_VERSION < 6: 890 for p in only_v6: 891 if p in kwargs: 892 del kwargs[p] 893 894 # 'sshkeys' param expects an urlencoded string 895 if 'sshkeys' in kwargs: 896 urlencoded_ssh_keys = quote(kwargs['sshkeys'], safe='') 897 kwargs['sshkeys'] = str(urlencoded_ssh_keys) 898 899 # If update, don't update disk (virtio, ide, sata, scsi) and network interface 900 # pool parameter not supported by qemu/<vmid>/config endpoint on "update" (PVE 6.2) - only with "create" 901 if update: 902 if 'virtio' in kwargs: 903 del kwargs['virtio'] 904 if 'sata' in kwargs: 905 del kwargs['sata'] 906 if 'scsi' in kwargs: 907 del kwargs['scsi'] 908 if 'ide' in kwargs: 909 del kwargs['ide'] 910 if 'net' in kwargs: 911 del kwargs['net'] 912 if 'force' in kwargs: 913 del kwargs['force'] 914 if 'pool' in kwargs: 915 del kwargs['pool'] 916 917 # Convert all dict in kwargs to elements. 918 # For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n], ipconfig[n] 919 for k in list(kwargs.keys()): 920 if isinstance(kwargs[k], dict): 921 kwargs.update(kwargs[k]) 922 del kwargs[k] 923 924 # Rename numa_enabled to numa. According the API documentation 925 if 'numa_enabled' in kwargs: 926 kwargs['numa'] = kwargs['numa_enabled'] 927 del kwargs['numa_enabled'] 928 929 # PVE api expects strings for the following params 930 if 'nameservers' in module.params: 931 nameservers = module.params.pop('nameservers') 932 if nameservers: 933 kwargs['nameserver'] = ' '.join(nameservers) 934 if 'searchdomains' in module.params: 935 searchdomains = module.params.pop('searchdomains') 936 if searchdomains: 937 kwargs['searchdomain'] = ' '.join(searchdomains) 938 939 # VM tags are expected to be valid and presented as a comma/semi-colon delimited string 940 if 'tags' in kwargs: 941 re_tag = re.compile(r'^[a-z0-9_][a-z0-9_\-\+\.]*$') 942 for tag in kwargs['tags']: 943 if not re_tag.match(tag): 944 module.fail_json(msg='%s is not a valid tag' % tag) 945 kwargs['tags'] = ",".join(kwargs['tags']) 946 947 # -args and skiplock require root@pam user - but can not use api tokens 948 if module.params['api_user'] == "root@pam" and module.params['args'] is None: 949 if not update and module.params['proxmox_default_behavior'] == 'compatibility': 950 kwargs['args'] = vm_args 951 elif module.params['api_user'] == "root@pam" and module.params['args'] is not None: 952 kwargs['args'] = module.params['args'] 953 elif module.params['api_user'] != "root@pam" and module.params['args'] is not None: 954 module.fail_json(msg='args parameter require root@pam user. ') 955 956 if module.params['api_user'] != "root@pam" and module.params['skiplock'] is not None: 957 module.fail_json(msg='skiplock parameter require root@pam user. ') 958 959 if update: 960 if proxmox_node.qemu(vmid).config.set(name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs) is None: 961 return True 962 else: 963 return False 964 elif module.params['clone'] is not None: 965 for param in valid_clone_params: 966 if module.params[param] is not None: 967 clone_params[param] = module.params[param] 968 clone_params.update(dict([k, int(v)] for k, v in clone_params.items() if isinstance(v, bool))) 969 taskid = proxmox_node.qemu(vmid).clone.post(newid=newid, name=name, **clone_params) 970 else: 971 taskid = proxmox_node.qemu.create(vmid=vmid, name=name, memory=memory, cpu=cpu, cores=cores, sockets=sockets, **kwargs) 972 973 if not wait_for_task(module, proxmox, node, taskid): 974 module.fail_json(msg='Reached timeout while waiting for creating VM. Last line in task before timeout: %s' % 975 proxmox_node.tasks(taskid).log.get()[:1]) 976 return False 977 return True 978 979 980def start_vm(module, proxmox, vm): 981 vmid = vm[0]['vmid'] 982 proxmox_node = proxmox.nodes(vm[0]['node']) 983 taskid = proxmox_node.qemu(vmid).status.start.post() 984 if not wait_for_task(module, proxmox, vm[0]['node'], taskid): 985 module.fail_json(msg='Reached timeout while waiting for starting VM. Last line in task before timeout: %s' % 986 proxmox_node.tasks(taskid).log.get()[:1]) 987 return False 988 return True 989 990 991def stop_vm(module, proxmox, vm, force): 992 vmid = vm[0]['vmid'] 993 proxmox_node = proxmox.nodes(vm[0]['node']) 994 taskid = proxmox_node.qemu(vmid).status.shutdown.post(forceStop=(1 if force else 0)) 995 if not wait_for_task(module, proxmox, vm[0]['node'], taskid): 996 module.fail_json(msg='Reached timeout while waiting for stopping VM. Last line in task before timeout: %s' % 997 proxmox_node.tasks(taskid).log.get()[:1]) 998 return False 999 return True 1000 1001 1002def proxmox_version(proxmox): 1003 apireturn = proxmox.version.get() 1004 return LooseVersion(apireturn['version']) 1005 1006 1007def main(): 1008 module = AnsibleModule( 1009 argument_spec=dict( 1010 acpi=dict(type='bool'), 1011 agent=dict(type='bool'), 1012 args=dict(type='str'), 1013 api_host=dict(required=True), 1014 api_password=dict(no_log=True, fallback=(env_fallback, ['PROXMOX_PASSWORD'])), 1015 api_token_id=dict(no_log=True), 1016 api_token_secret=dict(no_log=True), 1017 api_user=dict(required=True), 1018 autostart=dict(type='bool'), 1019 balloon=dict(type='int'), 1020 bios=dict(choices=['seabios', 'ovmf']), 1021 boot=dict(type='str'), 1022 bootdisk=dict(type='str'), 1023 cicustom=dict(type='str'), 1024 cipassword=dict(type='str', no_log=True), 1025 citype=dict(type='str', choices=['nocloud', 'configdrive2']), 1026 ciuser=dict(type='str'), 1027 clone=dict(type='str'), 1028 cores=dict(type='int'), 1029 cpu=dict(type='str'), 1030 cpulimit=dict(type='int'), 1031 cpuunits=dict(type='int'), 1032 delete=dict(type='str'), 1033 description=dict(type='str'), 1034 digest=dict(type='str'), 1035 force=dict(type='bool'), 1036 format=dict(type='str', choices=['cloop', 'cow', 'qcow', 'qcow2', 'qed', 'raw', 'vmdk', 'unspecified']), 1037 freeze=dict(type='bool'), 1038 full=dict(type='bool', default=True), 1039 hostpci=dict(type='dict'), 1040 hotplug=dict(type='str'), 1041 hugepages=dict(choices=['any', '2', '1024']), 1042 ide=dict(type='dict'), 1043 ipconfig=dict(type='dict'), 1044 keyboard=dict(type='str'), 1045 kvm=dict(type='bool'), 1046 localtime=dict(type='bool'), 1047 lock=dict(choices=['migrate', 'backup', 'snapshot', 'rollback']), 1048 machine=dict(type='str'), 1049 memory=dict(type='int'), 1050 migrate_downtime=dict(type='int'), 1051 migrate_speed=dict(type='int'), 1052 name=dict(type='str'), 1053 nameservers=dict(type='list', elements='str'), 1054 net=dict(type='dict'), 1055 newid=dict(type='int'), 1056 node=dict(), 1057 numa=dict(type='dict'), 1058 numa_enabled=dict(type='bool'), 1059 onboot=dict(type='bool'), 1060 ostype=dict(choices=['other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7', 'win8', 'win10', 'l24', 'l26', 'solaris']), 1061 parallel=dict(type='dict'), 1062 pool=dict(type='str'), 1063 protection=dict(type='bool'), 1064 reboot=dict(type='bool'), 1065 revert=dict(type='str'), 1066 sata=dict(type='dict'), 1067 scsi=dict(type='dict'), 1068 scsihw=dict(choices=['lsi', 'lsi53c810', 'virtio-scsi-pci', 'virtio-scsi-single', 'megasas', 'pvscsi']), 1069 serial=dict(type='dict'), 1070 searchdomains=dict(type='list', elements='str'), 1071 shares=dict(type='int'), 1072 skiplock=dict(type='bool'), 1073 smbios=dict(type='str'), 1074 snapname=dict(type='str'), 1075 sockets=dict(type='int'), 1076 sshkeys=dict(type='str', no_log=False), 1077 startdate=dict(type='str'), 1078 startup=dict(), 1079 state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'current']), 1080 storage=dict(type='str'), 1081 tablet=dict(type='bool'), 1082 tags=dict(type='list', elements='str'), 1083 target=dict(type='str'), 1084 tdf=dict(type='bool'), 1085 template=dict(type='bool'), 1086 timeout=dict(type='int', default=30), 1087 update=dict(type='bool', default=False), 1088 validate_certs=dict(type='bool', default=False), 1089 vcpus=dict(type='int'), 1090 vga=dict(choices=['std', 'cirrus', 'vmware', 'qxl', 'serial0', 'serial1', 'serial2', 'serial3', 'qxl2', 'qxl3', 'qxl4']), 1091 virtio=dict(type='dict'), 1092 vmid=dict(type='int'), 1093 watchdog=dict(), 1094 proxmox_default_behavior=dict(type='str', choices=['compatibility', 'no_defaults']), 1095 ), 1096 mutually_exclusive=[('delete', 'revert'), ('delete', 'update'), ('revert', 'update'), ('clone', 'update'), ('clone', 'delete'), ('clone', 'revert')], 1097 required_together=[('api_token_id', 'api_token_secret')], 1098 required_one_of=[('name', 'vmid'), ('api_password', 'api_token_id')], 1099 required_if=[('state', 'present', ['node'])], 1100 ) 1101 1102 if not HAS_PROXMOXER: 1103 module.fail_json(msg='proxmoxer required for this module') 1104 1105 api_host = module.params['api_host'] 1106 api_password = module.params['api_password'] 1107 api_token_id = module.params['api_token_id'] 1108 api_token_secret = module.params['api_token_secret'] 1109 api_user = module.params['api_user'] 1110 clone = module.params['clone'] 1111 cpu = module.params['cpu'] 1112 cores = module.params['cores'] 1113 delete = module.params['delete'] 1114 memory = module.params['memory'] 1115 name = module.params['name'] 1116 newid = module.params['newid'] 1117 node = module.params['node'] 1118 revert = module.params['revert'] 1119 sockets = module.params['sockets'] 1120 state = module.params['state'] 1121 update = bool(module.params['update']) 1122 vmid = module.params['vmid'] 1123 validate_certs = module.params['validate_certs'] 1124 1125 if module.params['proxmox_default_behavior'] is None: 1126 module.params['proxmox_default_behavior'] = 'compatibility' 1127 module.deprecate( 1128 'The proxmox_default_behavior option will change its default value from "compatibility" to ' 1129 '"no_defaults" in community.general 4.0.0. To remove this warning, please specify an explicit value for it now', 1130 version='4.0.0', collection_name='community.general' 1131 ) 1132 if module.params['proxmox_default_behavior'] == 'compatibility': 1133 old_default_values = dict( 1134 acpi=True, 1135 autostart=False, 1136 balloon=0, 1137 boot='cnd', 1138 cores=1, 1139 cpu='kvm64', 1140 cpuunits=1000, 1141 format='qcow2', 1142 kvm=True, 1143 memory=512, 1144 ostype='l26', 1145 sockets=1, 1146 tablet=False, 1147 template=False, 1148 vga='std', 1149 ) 1150 for param, value in old_default_values.items(): 1151 if module.params[param] is None: 1152 module.params[param] = value 1153 1154 if module.params['format'] == 'unspecified': 1155 module.params['format'] = None 1156 1157 auth_args = {'user': api_user} 1158 if not (api_token_id and api_token_secret): 1159 auth_args['password'] = api_password 1160 else: 1161 auth_args['token_name'] = api_token_id 1162 auth_args['token_value'] = api_token_secret 1163 1164 try: 1165 proxmox = ProxmoxAPI(api_host, verify_ssl=validate_certs, **auth_args) 1166 global PVE_MAJOR_VERSION 1167 version = proxmox_version(proxmox) 1168 PVE_MAJOR_VERSION = 3 if version < LooseVersion('4.0') else version.version[0] 1169 except Exception as e: 1170 module.fail_json(msg='authorization on proxmox cluster failed with exception: %s' % e) 1171 1172 # If vmid is not defined then retrieve its value from the vm name, 1173 # the cloned vm name or retrieve the next free VM id from ProxmoxAPI. 1174 if not vmid: 1175 if state == 'present' and not update and not clone and not delete and not revert: 1176 try: 1177 vmid = get_nextvmid(module, proxmox) 1178 except Exception: 1179 module.fail_json(msg="Can't get the next vmid for VM {0} automatically. Ensure your cluster state is good".format(name)) 1180 else: 1181 clone_target = clone or name 1182 try: 1183 vmid = get_vmid(proxmox, clone_target)[0] 1184 except Exception: 1185 vmid = -1 1186 1187 if clone is not None: 1188 # If newid is not defined then retrieve the next free id from ProxmoxAPI 1189 if not newid: 1190 try: 1191 newid = get_nextvmid(module, proxmox) 1192 except Exception: 1193 module.fail_json(msg="Can't get the next vmid for VM {0} automatically. Ensure your cluster state is good".format(name)) 1194 1195 # Ensure source VM name exists when cloning 1196 if -1 == vmid: 1197 module.fail_json(msg='VM with name = %s does not exist in cluster' % clone) 1198 1199 # Ensure source VM id exists when cloning 1200 if not get_vm(proxmox, vmid): 1201 module.fail_json(vmid=vmid, msg='VM with vmid = %s does not exist in cluster' % vmid) 1202 1203 # Ensure the choosen VM name doesn't already exist when cloning 1204 existing_vmid = get_vmid(proxmox, name) 1205 if existing_vmid: 1206 module.exit_json(changed=False, vmid=existing_vmid[0], msg="VM with name <%s> already exists" % name) 1207 1208 # Ensure the choosen VM id doesn't already exist when cloning 1209 if get_vm(proxmox, newid): 1210 module.exit_json(changed=False, vmid=vmid, msg="vmid %s with VM name %s already exists" % (newid, name)) 1211 1212 if delete is not None: 1213 try: 1214 settings(proxmox, vmid, node, delete=delete) 1215 module.exit_json(changed=True, vmid=vmid, msg="Settings has deleted on VM {0} with vmid {1}".format(name, vmid)) 1216 except Exception as e: 1217 module.fail_json(vmid=vmid, msg='Unable to delete settings on VM {0} with vmid {1}: '.format(name, vmid) + str(e)) 1218 1219 if revert is not None: 1220 try: 1221 settings(proxmox, vmid, node, revert=revert) 1222 module.exit_json(changed=True, vmid=vmid, msg="Settings has reverted on VM {0} with vmid {1}".format(name, vmid)) 1223 except Exception as e: 1224 module.fail_json(vmid=vmid, msg='Unable to revert settings on VM {0} with vmid {1}: Maybe is not a pending task... '.format(name, vmid) + str(e)) 1225 1226 if state == 'present': 1227 try: 1228 if get_vm(proxmox, vmid) and not (update or clone): 1229 module.exit_json(changed=False, vmid=vmid, msg="VM with vmid <%s> already exists" % vmid) 1230 elif get_vmid(proxmox, name) and not (update or clone): 1231 module.exit_json(changed=False, vmid=get_vmid(proxmox, name)[0], msg="VM with name <%s> already exists" % name) 1232 elif not (node, name): 1233 module.fail_json(msg='node, name is mandatory for creating/updating vm') 1234 elif not node_check(proxmox, node): 1235 module.fail_json(msg="node '%s' does not exist in cluster" % node) 1236 1237 create_vm(module, proxmox, vmid, newid, node, name, memory, cpu, cores, sockets, update, 1238 acpi=module.params['acpi'], 1239 agent=module.params['agent'], 1240 autostart=module.params['autostart'], 1241 balloon=module.params['balloon'], 1242 bios=module.params['bios'], 1243 boot=module.params['boot'], 1244 bootdisk=module.params['bootdisk'], 1245 cicustom=module.params['cicustom'], 1246 cipassword=module.params['cipassword'], 1247 citype=module.params['citype'], 1248 ciuser=module.params['ciuser'], 1249 cpulimit=module.params['cpulimit'], 1250 cpuunits=module.params['cpuunits'], 1251 description=module.params['description'], 1252 digest=module.params['digest'], 1253 force=module.params['force'], 1254 freeze=module.params['freeze'], 1255 hostpci=module.params['hostpci'], 1256 hotplug=module.params['hotplug'], 1257 hugepages=module.params['hugepages'], 1258 ide=module.params['ide'], 1259 ipconfig=module.params['ipconfig'], 1260 keyboard=module.params['keyboard'], 1261 kvm=module.params['kvm'], 1262 localtime=module.params['localtime'], 1263 lock=module.params['lock'], 1264 machine=module.params['machine'], 1265 migrate_downtime=module.params['migrate_downtime'], 1266 migrate_speed=module.params['migrate_speed'], 1267 net=module.params['net'], 1268 numa=module.params['numa'], 1269 numa_enabled=module.params['numa_enabled'], 1270 onboot=module.params['onboot'], 1271 ostype=module.params['ostype'], 1272 parallel=module.params['parallel'], 1273 pool=module.params['pool'], 1274 protection=module.params['protection'], 1275 reboot=module.params['reboot'], 1276 sata=module.params['sata'], 1277 scsi=module.params['scsi'], 1278 scsihw=module.params['scsihw'], 1279 serial=module.params['serial'], 1280 shares=module.params['shares'], 1281 skiplock=module.params['skiplock'], 1282 smbios1=module.params['smbios'], 1283 snapname=module.params['snapname'], 1284 sshkeys=module.params['sshkeys'], 1285 startdate=module.params['startdate'], 1286 startup=module.params['startup'], 1287 tablet=module.params['tablet'], 1288 tags=module.params['tags'], 1289 target=module.params['target'], 1290 tdf=module.params['tdf'], 1291 template=module.params['template'], 1292 vcpus=module.params['vcpus'], 1293 vga=module.params['vga'], 1294 virtio=module.params['virtio'], 1295 watchdog=module.params['watchdog']) 1296 1297 if not clone: 1298 get_vminfo(module, proxmox, node, vmid, 1299 ide=module.params['ide'], 1300 net=module.params['net'], 1301 sata=module.params['sata'], 1302 scsi=module.params['scsi'], 1303 virtio=module.params['virtio']) 1304 if update: 1305 module.exit_json(changed=True, vmid=vmid, msg="VM %s with vmid %s updated" % (name, vmid)) 1306 elif clone is not None: 1307 module.exit_json(changed=True, vmid=newid, msg="VM %s with newid %s cloned from vm with vmid %s" % (name, newid, vmid)) 1308 else: 1309 module.exit_json(changed=True, msg="VM %s with vmid %s deployed" % (name, vmid), **results) 1310 except Exception as e: 1311 if update: 1312 module.fail_json(vmid=vmid, msg="Unable to update vm {0} with vmid {1}=".format(name, vmid) + str(e)) 1313 elif clone is not None: 1314 module.fail_json(vmid=vmid, msg="Unable to clone vm {0} from vmid {1}=".format(name, vmid) + str(e)) 1315 else: 1316 module.fail_json(vmid=vmid, msg="creation of qemu VM %s with vmid %s failed with exception=%s" % (name, vmid, e)) 1317 1318 elif state == 'started': 1319 status = {} 1320 try: 1321 if -1 == vmid: 1322 module.fail_json(msg='VM with name = %s does not exist in cluster' % name) 1323 vm = get_vm(proxmox, vmid) 1324 if not vm: 1325 module.fail_json(vmid=vmid, msg='VM with vmid <%s> does not exist in cluster' % vmid) 1326 status['status'] = vm[0]['status'] 1327 if vm[0]['status'] == 'running': 1328 module.exit_json(changed=False, vmid=vmid, msg="VM %s is already running" % vmid, **status) 1329 1330 if start_vm(module, proxmox, vm): 1331 module.exit_json(changed=True, vmid=vmid, msg="VM %s started" % vmid, **status) 1332 except Exception as e: 1333 module.fail_json(vmid=vmid, msg="starting of VM %s failed with exception: %s" % (vmid, e), **status) 1334 1335 elif state == 'stopped': 1336 status = {} 1337 try: 1338 if -1 == vmid: 1339 module.fail_json(msg='VM with name = %s does not exist in cluster' % name) 1340 1341 vm = get_vm(proxmox, vmid) 1342 if not vm: 1343 module.fail_json(vmid=vmid, msg='VM with vmid = %s does not exist in cluster' % vmid) 1344 1345 status['status'] = vm[0]['status'] 1346 if vm[0]['status'] == 'stopped': 1347 module.exit_json(changed=False, vmid=vmid, msg="VM %s is already stopped" % vmid, **status) 1348 1349 if stop_vm(module, proxmox, vm, force=module.params['force']): 1350 module.exit_json(changed=True, vmid=vmid, msg="VM %s is shutting down" % vmid, **status) 1351 except Exception as e: 1352 module.fail_json(vmid=vmid, msg="stopping of VM %s failed with exception: %s" % (vmid, e), **status) 1353 1354 elif state == 'restarted': 1355 status = {} 1356 try: 1357 if -1 == vmid: 1358 module.fail_json(msg='VM with name = %s does not exist in cluster' % name) 1359 1360 vm = get_vm(proxmox, vmid) 1361 if not vm: 1362 module.fail_json(vmid=vmid, msg='VM with vmid = %s does not exist in cluster' % vmid) 1363 status['status'] = vm[0]['status'] 1364 if vm[0]['status'] == 'stopped': 1365 module.exit_json(changed=False, vmid=vmid, msg="VM %s is not running" % vmid, **status) 1366 1367 if stop_vm(module, proxmox, vm, force=module.params['force']) and start_vm(module, proxmox, vm): 1368 module.exit_json(changed=True, vmid=vmid, msg="VM %s is restarted" % vmid, **status) 1369 except Exception as e: 1370 module.fail_json(vmid=vmid, msg="restarting of VM %s failed with exception: %s" % (vmid, e), **status) 1371 1372 elif state == 'absent': 1373 status = {} 1374 try: 1375 vm = get_vm(proxmox, vmid) 1376 if not vm: 1377 module.exit_json(changed=False, vmid=vmid) 1378 1379 proxmox_node = proxmox.nodes(vm[0]['node']) 1380 status['status'] = vm[0]['status'] 1381 if vm[0]['status'] == 'running': 1382 if module.params['force']: 1383 stop_vm(module, proxmox, vm, True) 1384 else: 1385 module.exit_json(changed=False, vmid=vmid, msg="VM %s is running. Stop it before deletion or use force=yes." % vmid) 1386 taskid = proxmox_node.qemu.delete(vmid) 1387 if not wait_for_task(module, proxmox, vm[0]['node'], taskid): 1388 module.fail_json(msg='Reached timeout while waiting for removing VM. Last line in task before timeout: %s' % 1389 proxmox_node.tasks(taskid).log.get()[:1]) 1390 else: 1391 module.exit_json(changed=True, vmid=vmid, msg="VM %s removed" % vmid) 1392 except Exception as e: 1393 module.fail_json(msg="deletion of VM %s failed with exception: %s" % (vmid, e)) 1394 1395 elif state == 'current': 1396 status = {} 1397 if -1 == vmid: 1398 module.fail_json(msg='VM with name = %s does not exist in cluster' % name) 1399 vm = get_vm(proxmox, vmid) 1400 if not vm: 1401 module.fail_json(msg='VM with vmid = %s does not exist in cluster' % vmid) 1402 if not name: 1403 name = vm[0]['name'] 1404 current = proxmox.nodes(vm[0]['node']).qemu(vmid).status.current.get()['status'] 1405 status['status'] = current 1406 if status: 1407 module.exit_json(changed=False, vmid=vmid, msg="VM %s with vmid = %s is %s" % (name, vmid, current), **status) 1408 1409 1410if __name__ == '__main__': 1411 main() 1412