diff --git a/.travis.yml b/.travis.yml index 60e073c5..6da53b70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,23 +8,21 @@ cache: matrix: fast_finish: true env: - - ANSIBLE_GIT_VERSION='devel' # 2.6.x development branch - - ANSIBLE_VERSION='<2.6.0' # 2.5.x - - ANSIBLE_VERSION='<2.5.0' # 2.4.x +- ANSIBLE_GIT_VERSION='devel' # 2.8.x development branch +- ANSIBLE_VERSION='<2.8.0' # 2.7.x +- ANSIBLE_VERSION='<2.7.0' # 2.6.x install: - if [ "$ANSIBLE_GIT_VERSION" ]; then pip install "https://github.com/ansible/ansible/archive/${ANSIBLE_GIT_VERSION}.tar.gz"; - elif [ "$ANSIBLE_VERSION" ]; then pip install "ansible${ANSIBLE_VERSION}"; - else pip install ansible; fi; - pip install jmespath + else pip install "ansible${ANSIBLE_VERSION}"; fi; + pip install --pre ansible-lint; pip install jmespath - ansible --version -# The following is needed for default Ansible 2.3 installations -- 'sudo mkdir -p /etc/ansible/roles && sudo chown $(whoami): /etc/ansible/roles' - ansible-galaxy install lae.travis-lxc - ansible-playbook tests/install.yml -i tests/inventory - git archive --format tar.gz HEAD > lae.proxmox.tar.gz && ansible-galaxy install lae.proxmox.tar.gz,$(git rev-parse HEAD),lae.proxmox && rm lae.proxmox.tar.gz before_script: cd tests/ script: +- ansible-lint ../ || true - ansible-playbook -i inventory deploy.yml --syntax-check - ansible-playbook -i inventory -v deploy.yml --skip skiponlxc - 'ANSIBLE_STDOUT_CALLBACK=debug unbuffer ansible-playbook --skip skiponlxc -vv @@ -33,8 +31,7 @@ script: (echo "Idempotence: PASS"; exit 0) || (echo "Idempotence: FAIL"; exit 1)' - ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook -i inventory -v test.yml notifications: - webhooks: https://galaxy.ansible.com/api/v1/notifications/ - irc: - on_success: change - channels: - secure: "uNnWy3ToabL7W4mP2jTqdbV3do408Sl4N53D9T3vvcpCOLrdHeSagq+Juto3q4Z2bF/zpwHp05y5pJU0N3Fsb4W1C2jUnGvbwEYFRK+cTUsMUT+rrcHByF2e/nMBi1GEPysGfXtNMlEIe+rlKNTCFvfngnp2lTmcs4QBtQh+eS1YQBr8mdizCDWi28FygMTma87VdQ10Af0XkXWHgVHYfh4MARGfkMmCWjZqBHaKV5xTZ7xVzndGN7T3XiehRnD44iQNT6PaYZFRqUWV8S8BROhwOZIlgwEX3t/gxiGKLOHoI/cubm2H8aKEhSMl18MUZxET7CK4vwVpEnlqTQihsLkkuM7zfvsUWEQA03ZsZDAAnnIykbfQDMVBexOfZwv/5xdX5qTy2aghr7c/+LUf8N86Hj+TDGfWBioNhuPYBj5lghw0a+p002kKjjmgr2tTZpghIdHzmRqjne2ZbcIH3lBMWftzDHtBxuUTAaxaGP75VqH0JF5lGUvZL49VPtb8tGff0BVi0+YuHdlDAoIL6ACC6qQlgyVEZhZ170QS0Ez9s+pkMa1rpj4BsxBKZog3TKEad4K+CcewarwCgCEGxG2S4E1ugeZoCVtP8Gr4CC/51axhbATCPqYSQnNXKXo6vP3Gw3VBOcKx/Ku8uR+Kcdj7oEoAcJRF5eZFMG1y5Wk=" + webhooks: + urls: + - https://galaxy.ansible.com/api/v1/notifications/ + - https://t2d.idolactiviti.es/notify diff --git a/README.md b/README.md index e079d55c..c210bb4b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ lae.proxmox Installs and configures a Proxmox 5.x cluster with the following features: - Ensures all hosts can connect to one another as root -- Ability to create/manage groups, users, and access control lists +- Ability to create/manage groups, users, access control lists and storage - Ability to create or add nodes to a PVE cluster - IPMI watchdog support - BYO HTTPS certificate support @@ -46,8 +46,6 @@ Copy the following playbook to a file like `install_proxmox.yml`: Install this role and a role for configuring NTP: - # Changing ownership of the roles directory may be necessary: - sudo chown $(whoami): /etc/ansible/roles ansible-galaxy install lae.proxmox geerlingguy.ntp Now you can perform the installation: @@ -64,6 +62,11 @@ file containing a list of hosts). Once complete, you should be able to access your Proxmox VE instance at `https://$SSH_HOST_FQDN:8006`. +## Support/Contributing + +For support or if you'd like to contribute to this role but want guidance, feel +free to join this Discord server: https://discord.gg/cjqr6Fg + ## Deploying a fully-featured PVE 5.x cluster Create a new playbook directory. We call ours `lab-cluster`. Our playbook will @@ -167,6 +170,13 @@ pve_acls: - path: / roles: [ "Administrator" ] groups: [ "ops" ] +pve_storages: + - name: localdir + type: dir + content: [ "images", "iso", "backup" ] + path: /plop + maxfiles: 4 + interfaces_template: "interfaces-{{ pve_group }}.j2" ``` @@ -201,6 +211,10 @@ are already in existing clusters with different names. must already exist) to access PVE and gives them the Administrator role as part of the `ops` group. Read the **User and ACL Management** section for more info. +`pve_storages` allows to create different types of storage and configure them. +The backend needs to be supported by [Proxmox](https://pve.proxmox.com/pve-docs/chapter-pvesm.html). +Read the **Storage Management** section for more info. + `interfaces_template` is set to the path of a template we'll use for configuring the network on these Debian machines. This is only necessary if you want to manage networking from Ansible rather than manually or via each host in PVE. @@ -266,7 +280,7 @@ Finally, let's write our playbook. `site.yml` will look something like this: template: src: "{{ interfaces_template }}" dest: /etc/network/interfaces - register: __configure_interfaces + register: _configure_interfaces - block: - name: Reboot for networking changes @@ -277,7 +291,7 @@ Finally, let's write our playbook. `site.yml` will look something like this: - name: Wait for server to come back online wait_for_connection: delay: 15 - when: __configure_interfaces is changed + when: _configure_interfaces is changed - hosts: pve become: True @@ -362,6 +376,7 @@ pve_repository_line: "deb http://download.proxmox.com/debian/pve stretch pve-no- pve_remove_subscription_warning: true # patches the subscription warning messages in proxmox if you are using the community edition pve_extra_packages: [] # Any extra packages you may want to install, e.g. ngrep pve_run_system_upgrades: false # Let role perform system upgrades +pve_run_proxmox_upgrades: true # Let role perform Proxmox VE upgrades pve_check_for_kernel_update: true # Runs a script on the host to check kernel versions pve_reboot_on_kernel_update: false # If set to true, will automatically reboot the machine on kernel updates pve_remove_old_kernels: true # Currently removes kernel from main Debian repository @@ -376,6 +391,7 @@ pve_zfs_enabled: no # Specifies whether or not to install and configure ZFS pack pve_ssl_letsencrypt: false # Specifies whether or not to obtain a SSL certificate using Let's Encrypt pve_groups: [] # List of group definitions to manage in PVE. See section on User Management. pve_users: [] # List of user definitions to manage in PVE. See section on User Management. +pve_storages: [] # List of storages to manage in PVE. See section on Storage Management. ``` To enable clustering with this role, configure the following variables appropriately: @@ -465,15 +481,65 @@ pve_acls: Refer to `library/proxmox_acl.py` [link][acl-module] for module documentation. +## Storage Management + +You can use this role to manage storage within Proxmox VE (both in +single server deployments and cluster deployments). For now, the only supported +types are `dir`, `rbd`, `nfs`, `lvm` and `lvmthin`. +Here are some examples. + +``` +pve_storages: + - name: dir1 + type: dir + content: [ "images", "iso", "backup" ] + path: /ploup + disable: no + maxfiles: 4 + - name: ceph1 + type: rbd + content: [ "images", "rootdir" ] + nodes: [ "lab-node01.local", "lab-node02.local" ] + username: admin + pool: rbd + krbd: yes + monhost: + - 10.0.0.1 + - 10.0.0.2 + - 10.0.0.3 + - name: nfs1 + type: nfs + content: [ "images", "iso" ] + server: 192.168.122.2 + export: /data + - name: lvm1 + type: lvm + content: [ "images", "rootdir" ] + vgname: vg1 + - name: lvmthin1 + type: lvmthin + content: [ "images", "rootdir" ] + vgname: vg2 + thinpool: data +``` + +Refer to `library/proxmox_storage.py` [link][storage-module] for module +documentation. + ## Contributors -Musee Ullah ([@lae](https://github.com/lae), ) -Engin Dumlu ([@roadrunner](https://github.com/roadrunner)) -Jonas Meurer ([@mejo-](https://github.com/mejo-)) +Musee Ullah ([@lae](https://github.com/lae), ) +Engin Dumlu ([@roadrunner](https://github.com/roadrunner)) +Jonas Meurer ([@mejo-](https://github.com/mejo-)) +Ondrej Flider ([@SniperCZE](https://github.com/SniperCZE)) +niko2 ([@niko2](https://github.com/niko2)) +Christian Aublet ([@caublet](https://github.com/caublet)) +Fabien Brachere ([@Fbrachere](https://github.com/Fbrachere)) -[pve-cluster]: https://pve.proxmox.com/wiki/Proxmox_VE_4.x_Cluster +[pve-cluster]: https://pve.proxmox.com/wiki/Cluster_Manager [install-ansible]: http://docs.ansible.com/ansible/intro_installation.html [pvecm-network]: https://pve.proxmox.com/pve-docs/chapter-pvecm.html#_separate_cluster_network [user-module]: https://github.com/lae/ansible-role-proxmox/blob/master/library/proxmox_user.py [group-module]: https://github.com/lae/ansible-role-proxmox/blob/master/library/proxmox_group.py [acl-module]: https://github.com/lae/ansible-role-proxmox/blob/master/library/proxmox_group.py +[storage-module]: https://github.com/lae/ansible-role-proxmox/blob/master/library/proxmox_storage.py diff --git a/defaults/main.yml b/defaults/main.yml index c6599521..5510e55b 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -9,6 +9,7 @@ pve_check_for_kernel_update: true pve_reboot_on_kernel_update: false pve_remove_old_kernels: true pve_run_system_upgrades: false +pve_run_proxmox_upgrades: true pve_watchdog: none pve_watchdog_ipmi_action: power_cycle pve_watchdog_ipmi_timeout: 10 @@ -27,3 +28,4 @@ pve_ssl_letsencrypt: false pve_groups: [] pve_users: [] pve_acls: [] +pve_storages: [] diff --git a/files/00_remove_checked_command_stretch.patch b/files/00_remove_checked_command.patch similarity index 100% rename from files/00_remove_checked_command_stretch.patch rename to files/00_remove_checked_command.patch diff --git a/files/00_remove_checked_command_jessie.patch b/files/00_remove_checked_command_jessie.patch deleted file mode 100644 index b1be7285..00000000 --- a/files/00_remove_checked_command_jessie.patch +++ /dev/null @@ -1,75 +0,0 @@ ---- /usr/share/pve-manager/js/pvemanagerlib.js 2018-01-17 08:18:41.000000000 +0000 -+++ /usr/share/pve-manager/js/pvemanagerlib.js 2018-03-03 09:59:41.521312774 +0000 -@@ -788,37 +788,6 @@ - } - }, - -- checked_command: function(orig_cmd) { -- PVE.Utils.API2Request({ -- url: '/nodes/localhost/subscription', -- method: 'GET', -- //waitMsgTarget: me, -- failure: function(response, opts) { -- Ext.Msg.alert(gettext('Error'), response.htmlStatus); -- }, -- success: function(response, opts) { -- var data = response.result.data; -- -- if (data.status !== 'Active') { -- Ext.Msg.show({ -- title: gettext('No valid subscription'), -- icon: Ext.Msg.WARNING, -- msg: PVE.Utils.noSubKeyHtml, -- buttons: Ext.Msg.OK, -- callback: function(btn) { -- if (btn !== 'ok') { -- return; -- } -- orig_cmd(); -- } -- }); -- } else { -- orig_cmd(); -- } -- } -- }); -- }, -- - task_desc_table: { - diskinit: [ 'Disk', gettext('Initialize Disk with GPT') ], - vncproxy: [ 'VM/CT', gettext('Console') ], -@@ -17078,7 +17047,7 @@ - var version_btn = new Ext.Button({ - text: gettext('Package versions'), - handler: function(){ -- PVE.Utils.checked_command(function() { me.showVersions(); }); -+ me.showVersions(); - } - }); - -@@ -18340,7 +18309,7 @@ - { - text: gettext('System Report'), - handler: function() { -- PVE.Utils.checked_command(function (){ me.showReport(); }); -+ me.showReport(); - } - } - ], -@@ -18431,7 +18400,7 @@ - var update_btn = new Ext.Button({ - text: gettext('Refresh'), - handler: function(){ -- PVE.Utils.checked_command(function() { apt_command('update'); }); -+ apt_command('update'); - } - }); - -@@ -35093,7 +35062,6 @@ - handler: function(data) { - me.login = null; - me.updateLoginData(data); -- PVE.Utils.checked_command(function() {}); // display subscription status - } - }); - } diff --git a/files/proxmox-ve-release-4.x.asc b/files/proxmox-ve-release-4.x.asc deleted file mode 100644 index 26f8be9b..00000000 --- a/files/proxmox-ve-release-4.x.asc +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v2.2.1 (GNU/Linux) - -mQGiBEkGw8URBACes0Nn6KGrblcNfylEonfSuqEyCDz4P0SoPc09ieqhacdJYZZu -gOJkdAQMESUvVG9S/KolkQI0eR3VqW5PxdC7Uon8lnLofy+iicJhaZvBQA8voOJ9 -Myv4SrrBPrsa64pLppZ2zYJ2Vj+x26tvYRG1L8G20FDKejnrcLmAOLz+twCgo5rj -Lcyh1gGAE/ktluKIS6EpfmsEAJAjyiiDs2HZcBh7RrlV25kZEk7rwwrrMXmkGpBb -iElZjbRY6cHl+IvwEHD89ShuADuiEOVMqQ8nSbaFQAblqBK+Q1klZUxmppw1UfG5 -+x3X7MrULg0YAgAMqwBPgYrAYfV6tdzO3HY6dP5aRNBVYxCgvnXpHw4XW4GC8qRO -NmBPBACLSxG4Q2md/6jHVnoQT4UsPA5Nn2imKsLqS62WQBQyM8W+LtlyxT+QAf+t -+D/XFv5ZUQQq766cR4WnmOkNLAqmFaSrUF2T58UPxOC6TsTkrFkI+kVJFqHedag2 -9n+EFXK/DzrsmElWiMyYuMYkOzNn/2cbYnpLq4zO5cwi7BNoRrQxUHJveG1veCBS -ZWxlYXNlIEtleSA8cHJveG1veC1yZWxlYXNlQHByb3htb3guY29tPohgBBMRAgAg -BQJJBsPFAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQwjrH9JiH+VqTLwCf -TVzFdNADeZ00bKpyE8u4BHZJK+4AmwVbhpnb4EkSHYqNhrhEIVSynxm0uQINBEkG -w8oQCAD323YC4+yp1fJGyI2o8GjnPWKRbmJPhoaeungGkFD0M2Ke2/NlgoQnwwyH -FRCLxmjc48r++hlSN+OhVuGrvSl5mh0R3Tv5m17OD1KmkAMT9TcrZ7mqn2D79iv3 -TkO27Z76Rs+Wnfu/dc+85wCJDGx9oK8hmJTu6Qc62AkdVCfTULoKSQ3u7LFkGQP9 -I+wtOLnLIc8TpGNuwJ97gIAsfZEkbg3zS39loPwQdIV4b48Hfiz7uMEc4Zwx2bqL -+6sp1vK3jfr7Vb1vQyqG9pvDQ5LSbjh9PCCEmbLtyEIDx8hogNZ9M0ShgZzOwRj4 -vF/sdAdxIT4/7TlMi8jzZqFYSDN/AAMFCACBFBtH1KF45gt70BwgDDv+2zxCy3nP -3kT2W2f2P3OzTSsu0HGGrIZFtllemAVv89sXlJvZEOzIDvWFizwTiaSW0orj1ni4 -Rz5tNIKnv2T1nJbKWnK7hKO+VKopSCADfFW4FxOwnkV1tV/k7WtCsP+y7X4b/9PA -EFDYY81MZo3pXvvk989SmoNL2mAdcVYRn1vVCAsciVX6QZFuaupFl4J+57G0OO9P -tNXn9Hesw7qMo0H52WLp/l8WOhKcghV3+2V4NgpPqZiWD0bOclSO41gmeRWyNo0h -lVzmRVZF0Np9gXzIBVvaq3pHMglb8rOLm/AsNxgZlDe1PqJiSWFZR96EiEkEGBEC -AAkFAkkGw8oCGwwACgkQwjrH9JiH+VrCsgCfQQwtSer1YsUF9zYG5jzVONe2Ms0A -nRwQSm7uGTkFGHhEVkqTPwzNUzg6 -=6GBj ------END PGP PUBLIC KEY BLOCK----- diff --git a/library/proxmox_storage.py b/library/proxmox_storage.py new file mode 100755 index 00000000..64932e74 --- /dev/null +++ b/library/proxmox_storage.py @@ -0,0 +1,362 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +ANSIBLE_METADATA = { + 'metadata_version': '0.1', + 'status': ['preview'], + 'supported_by': 'fbrachere' +} + +DOCUMENTATION = ''' +--- +module: proxmox_storage + +short_description: Manages the storage in Proxmox + +options: + name: + required: true + aliases: [ "storage", "storageid" ] + description: + - Name of the storage. + type: + required: true + aliases: [ "storagetype" ] + choices: [ "dir", "nfs", "rbd", "lvm", "lvmthin" ] + description: + - Type of storage, must be supported by Proxmox. + disable: + required: false + description: Disable the storage. + state: + required: false + default: "present" + choices: [ "present", "absent" ] + description: + - Specifies whether this storage should exist or not. + content: + required: true + aliases: [ "storagecontent" ] + type: list + choices: [ "images", "rootdir", "vztmpl", "backup", "iso" ] + description: + - Contents supported by the storage, not all storage + types support all content types. + nodes: + required: false + type: list + description: + - List of cluster node names where this storage is usable. + path: + required: false + description: + - File system path. + pool: + required: false + description: + - Ceph pool name. + monhost: + required: false + type: list + description: + - Monitor addresses of the ceph cluster. + username: + required: false + description: + - User name (RBD) who access to ceph cluster. + krbd: + required: false + default: 0 + description: + - Always access rbd through krbd kernel module. + maxfiles: + required: false + default: 0 + description: + - Maximal number of backup files per VM. 0 for unlimited. + export: + required: false + description: + - NFS export path + server: + required: false + description: + - Server IP or DNS name. + options: + required: false + description: + - NFS mount options. + vgname: + required: false + description: + - LVM volume group name. This must point to an existing volume group. + thinpool: + required: false + description: + - The name of the LVM thin pool. + +author: + - Fabien Brachere (@fbrachere) +''' + +EXAMPLES = ''' +- name: Create a directory storage type + proxmox_storage: + name: dir1 + type: dir + path: /mydir + content: [ "images", "iso", "backup" ] + maxfiles: 3 +- name: Create an RBD storage type + proxmox_storage: + name: ceph1 + type: rbd + content: [ "images", "rootdir" ] + nodes: [ "proxmox1", "proxmox2" ] + username: admin + pool: rbd + krbd: yes + monhost: + - 10.0.0.1 + - 10.0.0.2 + - 10.0.0.3 +- name: Create an NFS storage type + proxmox_storage: + name: nfs1 + type: nfs + content: [ "images", "iso" ] + server: 192.168.122.2 + export: /data +- name: Create an LVM storage type + proxmox_storage: + name: lvm1 + type: lvm + content: [ "images", "rootdir" ] + vgname: vg1 +- name: Create an LVM-thin storage type + proxmox_storage: + name: lvmthin1 + type: lvmthin + content: [ "images", "rootdir" ] + vgname: vg2 + thinpool: data +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_text +from ansible.module_utils.pvesh import ProxmoxShellError +import ansible.module_utils.pvesh as pvesh + +class ProxmoxStorage(object): + def __init__(self, module): + self.module = module + self.name = module.params['name'] + self.state = module.params['state'] + self.type = module.params['type'] + self.disable = module.params['disable'] + self.content = module.params['content'] + self.nodes = module.params['nodes'] + self.path = module.params['path'] + self.pool = module.params['pool'] + self.monhost = module.params['monhost'] + self.username = module.params['username'] + self.krbd = module.params['krbd'] + self.maxfiles = module.params['maxfiles'] + self.server = module.params['server'] + self.export = module.params['export'] + self.options = module.params['options'] + self.vgname = module.params['vgname'] + self.thinpool = module.params['thinpool'] + + try: + self.existing_storages = pvesh.get("storage") + except ProxmoxShellError as e: + self.module.fail_json(msg=e.message, status_code=e.status_code) + + def lookup(self): + for item in self.existing_storages: + if item['storage'] == self.name: + # pvesh doesn't return the disable param value if it's false, + # so we set it to False. + if item.get('disable') is None: + item['disable'] = False + return item + return None + + def exists(self): + for item in self.existing_storages: + if item["storage"] == self.name: + return True + return False + + def prepare_storage_args(self): + args = {} + + args['type'] = self.type + args['content'] = ','.join(self.content) + if self.nodes is not None: + args['nodes'] = ','.join(self.nodes) + if self.disable is not None: + args['disable'] = self.disable + else: + args['disable'] = False + if self.path is not None: + args['path'] = self.path + if self.pool is not None: + args['pool'] = self.pool + if self.monhost is not None: + args['monhost'] = ','.join(self.monhost) + if self.username is not None: + args['username'] = self.username + if self.krbd is not None: + args['krbd'] = self.krbd + if self.maxfiles is not None: + args['maxfiles'] = self.maxfiles + if self.server is not None: + args['server'] = self.server + if self.export is not None: + args['export'] = self.export + if self.options is not None: + args['options'] = self.options + if self.vgname is not None: + args['vgname'] = self.vgname + if self.thinpool is not None: + args['thinpool'] = self.thinpool + + if self.maxfiles is not None and 'backup' not in self.content: + self.module.fail_json(msg="maxfiles is not allowed when there is no 'backup' in content") + if self.krbd is not None and self.type != 'rbd': + self.module.fail_json(msg="krbd is only allowed with 'rbd' storage type") + + return args + + def create_storage(self): + new_storage = self.prepare_storage_args() + try: + pvesh.create("storage", storage=self.name, **new_storage) + return None + except ProxmoxShellError as e: + return e.message + + def modify_storage(self): + lookup = self.lookup() + new_storage = self.prepare_storage_args() + + staged_storage = {} + updated_fields = [] + error = None + + for key in new_storage: + if key == 'content': + if set(self.content) != set(lookup.get('content', '').split(',')): + updated_fields.append(key) + staged_storage[key] = new_storage[key] + elif key == 'monhost': + if set(self.monhost) != set(lookup.get('monhost', '').split(',')): + updated_fields.append(key) + staged_storage[key] = new_storage[key] + elif key == 'nodes': + if set(self.nodes) != set(lookup.get('nodes', '').split(',')): + updated_fields.append(key) + staged_storage[key] = new_storage[key] + else: + new_value = to_text(new_storage[key]) if isinstance(new_storage[key], str) else new_storage[key] + if key not in lookup or new_value != lookup[key]: + updated_fields.append(key) + staged_storage[key] = new_storage[key] + + if self.module.check_mode: + self.module.exit_json(changed=bool(updated_fields), expected_changes=updated_fields) + + if not updated_fields: + # No changes necessary + return (updated_fields, error) + + try: + pvesh.set("storage/{}".format(self.name), **staged_storage) + except ProxmoxShellError as e: + error = e.message + + return (updated_fields, error) + + + def remove_storage(self): + try: + pvesh.delete("storage/{}".format(self.name)) + return (True, None) + except ProxmoxShellError as e: + return (False, e.message) + +def main(): + # Refer to https://pve.proxmox.com/pve-docs/api-viewer/index.html + module_args = dict( + name=dict(type='str', required=True, aliases=['storage', 'storageid']), + content=dict(type='list', required=True, aliases=['storagetype']), + nodes=dict(type='list', required=False, default=None), + type=dict(default=None, type='str', required=True, + choices=["dir", "nfs", "rbd", "lvm", "lvmthin"]), + disable=dict(required=False, type='bool', default=False), + state=dict(default='present', choices=['present', 'absent'], type='str'), + path=dict(default=None, required=False, type='str'), + pool=dict(default=None, type='str', required=False), + monhost=dict(default=None, type='list', required=False), + username=dict(default=None, type='str', required=False), + krbd=dict(default=None, type='bool', required=False), + maxfiles=dict(default=None, type='int', required=False), + export=dict(default=None, type='str', required=False), + server=dict(default=None, type='str', required=False), + options=dict(default=None, type='str', required=False), + vgname=dict(default=None, type='str', required=False), + thinpool=dict(default=None, type='str', required=False), + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True, + required_if=[ + ["type", "dir", ["path", "content"]], + ["type", "rbd", ["pool", "content", "monhost", "username"]], + ["type", "nfs", ["server", "content", "export"]], + ["type", "lvm", ["vgname", "content"]], + ["type", "lvmthin", ["vgname", "thinpool", "content"]], + ] + ) + storage = ProxmoxStorage(module) + + changed = False + error = None + result = {} + result['state'] = storage.state + result['changed'] = False + + if storage.state == 'absent': + if storage.exists(): + result['changed'] = True + if module.check_mode: + module.exit_json(**result) + (changed, error) = storage.remove_storage() + elif storage.state == 'present': + if not storage.exists(): + result['changed'] = True + if module.check_mode: + module.exit_json(**result) + + error = storage.create_storage() + else: + # modify storage (check mode is ok) + (updated_fields,error) = storage.modify_storage() + + if updated_fields: + result['changed'] = True + result['updated_fields'] = updated_fields + + if error is not None: + module.fail_json(name=storage.name, msg=error) + + module.exit_json(**result) + +if __name__ == '__main__': + main() diff --git a/meta/main.yml b/meta/main.yml index 0339be3a..220c3dbe 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,6 +1,6 @@ galaxy_info: author: Musee Ullah - description: Installs and configures Proxmox 5.x and 4.x (for clustering) + description: Installs and configures Proxmox 5.x (for clustering) company: FireEye, Inc. license: MIT @@ -9,7 +9,6 @@ galaxy_info: platforms: - name: Debian versions: - - jessie - stretch galaxy_tags: diff --git a/module_utils/pvesh.py b/module_utils/pvesh.py index c66ae508..66bf9417 100644 --- a/module_utils/pvesh.py +++ b/module_utils/pvesh.py @@ -21,7 +21,8 @@ def run_command(handler, resource, **params): command = [ "/usr/bin/pvesh", handler, - resource] + resource, + "--output=json"] for parameter, value in params.iteritems(): command += ["-{}".format(parameter), "{}".format(value)] @@ -29,7 +30,7 @@ def run_command(handler, resource, **params): (result, stderr) = pipe.communicate() stderr = stderr.splitlines() - if stderr[0] == "200 OK": + if len(stderr) == 0: if not result: return {u"status": 200} diff --git a/tasks/disable_nmi_watchdog.yml b/tasks/disable_nmi_watchdog.yml index 1fe504f5..2979eda5 100644 --- a/tasks/disable_nmi_watchdog.yml +++ b/tasks/disable_nmi_watchdog.yml @@ -9,7 +9,7 @@ name: softdog state: absent ignore_errors: true - register: __pve_rmmod_softdog + register: _pve_rmmod_softdog - block: - name: Stop watchdog-mux @@ -24,18 +24,18 @@ name: softdog state: absent - when: __pve_rmmod_softdog is failed + when: _pve_rmmod_softdog is failed - name: Disable nmi_watchdog via GRUB config lineinfile: dest: /etc/default/grub line: 'GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX nmi_watchdog=0"' insertafter: '^GRUB_CMDLINE_LINUX="' - register: __pve_grub + register: _pve_grub - name: Update GRUB configuration command: update-grub - register: __pve_grub_update - failed_when: ('error' in __pve_grub_update.stderr) - when: __pve_grub is changed + register: _pve_grub_update + failed_when: ('error' in _pve_grub_update.stderr) + when: _pve_grub is changed tags: skiponlxc diff --git a/tasks/identify_needed_packages.yml b/tasks/identify_needed_packages.yml index af1c29d2..f9172561 100644 --- a/tasks/identify_needed_packages.yml +++ b/tasks/identify_needed_packages.yml @@ -1,7 +1,7 @@ --- - name: Stage packages needed for base PVE installation set_fact: - __pve_install_packages: + _pve_install_packages: - proxmox-ve - postfix - open-iscsi @@ -10,14 +10,14 @@ - name: Stage patch package if we need to patch the subscription message set_fact: - __pve_install_packages: "{{ __pve_install_packages | union(['patch']) }}" + _pve_install_packages: "{{ _pve_install_packages | union(['patch']) }}" when: "'pve-no-subscription' in pve_repository_line" - name: Stage ZFS packages if ZFS is enabled set_fact: - __pve_install_packages: "{{ __pve_install_packages | union(['zfsutils-linux', 'zfs-initramfs', 'zfs-zed']) }}" + _pve_install_packages: "{{ _pve_install_packages | union(['zfsutils-linux', 'zfs-initramfs', 'zfs-zed']) }}" when: pve_zfs_enabled - name: Stage any extra packages the user has specified set_fact: - __pve_install_packages: "{{ __pve_install_packages | union(pve_extra_packages) }}" + _pve_install_packages: "{{ _pve_install_packages | union(pve_extra_packages) }}" diff --git a/tasks/ipmi_watchdog.yml b/tasks/ipmi_watchdog.yml index d8624b86..6a7ca7a5 100644 --- a/tasks/ipmi_watchdog.yml +++ b/tasks/ipmi_watchdog.yml @@ -10,7 +10,8 @@ - name: Configure ipmi_watchdog module to load on boot copy: - content: "options ipmi_watchdog action={{ pve_watchdog_ipmi_action }} timeout={{ pve_watchdog_ipmi_timeout }} panic_wdt_timeout=10" + content: "options ipmi_watchdog action={{ pve_watchdog_ipmi_action }} \ + timeout={{ pve_watchdog_ipmi_timeout }} panic_wdt_timeout=10" dest: /etc/modprobe.d/ipmi_watchdog.conf - name: Configure PVE HA Manager to use ipmi_watchdog diff --git a/tasks/kernel_module_cleanup.yml b/tasks/kernel_module_cleanup.yml index 35249bdc..2317ecd9 100644 --- a/tasks/kernel_module_cleanup.yml +++ b/tasks/kernel_module_cleanup.yml @@ -20,13 +20,13 @@ dest: /etc/default/grub line: 'GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX nmi_watchdog=0"' state: absent - register: __pve_grub + register: _pve_grub - name: Update GRUB configuration command: update-grub - register: __pve_grub_update - failed_when: ('error' in __pve_grub_update.stderr) - when: __pve_grub is changed + register: _pve_grub_update + failed_when: ('error' in _pve_grub_update.stderr) + when: _pve_grub is changed tags: skiponlxc - name: Remove ipmi_watchdog modprobe configuration diff --git a/tasks/kernel_updates.yml b/tasks/kernel_updates.yml index 4abf95e6..8c14eaf3 100644 --- a/tasks/kernel_updates.yml +++ b/tasks/kernel_updates.yml @@ -2,7 +2,7 @@ - name: Check for kernel update collect_kernel_info: lookup_packages: false - register: __pve_kernel_update + register: _pve_kernel_update when: pve_reboot_on_kernel_update - block: @@ -13,22 +13,19 @@ - name: Wait for server to come back online wait_for_connection: - delay: 15 + delay: 60 when: - pve_reboot_on_kernel_update - - __pve_kernel_update.new_kernel_exists + - _pve_kernel_update.new_kernel_exists - name: Collect kernel package information collect_kernel_info: - register: __pve_kernel + register: _pve_kernel - name: Remove old Debian/PVE kernels apt: - name: "{{ item }}" + name: "{{ ['linux-image-amd64'] + _pve_kernel.old_packages }}" state: absent purge: yes - with_items: - - linux-image-amd64 - - "{{ __pve_kernel.old_packages }}" when: - pve_remove_old_kernels diff --git a/tasks/main.yml b/tasks/main.yml index 20b1f6ef..a974539b 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -3,16 +3,19 @@ - name: Gather distribution specific variables include_vars: "debian-{{ ansible_distribution_release }}.yml" -- assert: +- name: Ensure that we have an IP address for all cluster hosts + assert: that: - "hostvars[item].ansible_default_ipv4.address is defined" msg: "Missing IP address and other information for {{ item }}. Have you gathered its facts?" with_items: "{{ groups[pve_group] }}" -- assert: +- name: Ensure this host is in the group specified + assert: that: - "inventory_hostname in groups[pve_group]" - msg: "This host does not appear to be in the group {{ pve_group }}, did you specify the pve_group host variable correctly?" + msg: "This host does not appear to be in the group {{ pve_group }}, \ + did you specify the pve_group host variable correctly?" when: pve_cluster_enabled - import_tasks: ssh_cluster_config.yml @@ -60,14 +63,17 @@ repo: "{{ pve_repository_line }}" filename: proxmox state: present - register: __pve_repo + register: _pve_repo - name: Run apt-get dist-upgrade on repository changes apt: update_cache: yes cache_valid_time: 3600 upgrade: dist - when: __pve_repo.changed + when: _pve_repo is changed + retries: 2 + register: _dist_upgrade + until: _dist_upgrade is succeeded - name: Perform system upgrades apt: @@ -75,14 +81,19 @@ cache_valid_time: 3600 upgrade: yes when: pve_run_system_upgrades + retries: 2 + register: _system_upgrade + until: _system_upgrade is succeeded - import_tasks: identify_needed_packages.yml - name: Install Proxmox VE and related packages apt: - name: "{{ item }}" - state: latest - with_items: "{{ __pve_install_packages }}" + name: "{{ _pve_install_packages }}" + state: "{{ 'latest' if pve_run_proxmox_upgrades else 'present' }}" + retries: 2 + register: _proxmox_install + until: _proxmox_install is succeeded - block: - name: Remove automatically installed PVE Enterprise repo configuration @@ -91,14 +102,12 @@ filename: pve-enterprise state: absent with_items: - - "deb https://enterprise.proxmox.com/debian jessie pve-enterprise" - "deb https://enterprise.proxmox.com/debian stretch pve-enterprise" - - "deb https://enterprise.proxmox.com/debian/pve jessie pve-enterprise" - "deb https://enterprise.proxmox.com/debian/pve stretch pve-enterprise" - name: Remove subscription check wrapper function in web UI patch: - src: "00_remove_checked_command_{{ ansible_distribution_release }}.patch" + src: "00_remove_checked_command.patch" basedir: / strip: 1 backup: yes @@ -147,6 +156,28 @@ with_items: "{{ pve_acls }}" when: "not pve_cluster_enabled or (pve_cluster_enabled and inventory_hostname == groups[pve_group][0])" +- name: Configure Proxmox Storage + proxmox_storage: + name: "{{ item.name }}" + type: "{{ item.type }}" + disable: "{{ item.disable | default(False) }}" + path: "{{ item.path | default(omit) }}" + content: "{{ item.content | default([]) }}" + nodes: "{{ item.nodes | default(omit) }}" + username: "{{ item.username | default(omit) }}" + pool: "{{ item.pool | default(omit) }}" + monhost: "{{ item.monhost | default(omit) }}" + maxfiles: "{{ item.maxfiles | default(omit) }}" + krbd: "{{ item.krbd | default(omit) }}" + state: "{{ item.state | default('present') }}" + server: "{{ item.server | default(omit) }}" + export: "{{ item.export | default(omit) }}" + options: "{{ item.options | default(omit) }}" + vgname: "{{ item.vgname | default(omit) }}" + thinpool: "{{ item.thinpool | default(omit) }}" + with_items: "{{ pve_storages }}" + when: "not pve_cluster_enabled or (pve_cluster_enabled and inventory_hostname == groups[pve_group][0])" + - import_tasks: ssl_config.yml when: - pve_ssl_private_key is defined diff --git a/tasks/pve_add_node.yml b/tasks/pve_add_node.yml index dbdfeae8..616bfede 100644 --- a/tasks/pve_add_node.yml +++ b/tasks/pve_add_node.yml @@ -1,18 +1,22 @@ --- -- set_fact: - __pve_current_node: "{{ item }}" +- name: Identify what host we're working with (inside outer loop) + set_fact: + _pve_current_node: "{{ item }}" - name: Add node to Proxmox cluster - command: "pvecm add {{ hostvars[groups[pve_group][0]]['ansible_default_ipv4']['address'] }}{{ ' -use_ssh' if ansible_distribution_release == 'stretch' else '' }} -ring0_addr {{ pve_cluster_ring0_addr }}{% if pve_cluster_ring1_addr is defined %} -ring1_addr {{ pve_cluster_ring1_addr }}{% endif %}" + command: "pvecm add {{ hostvars[groups[pve_group][0]]['ansible_default_ipv4']['address'] }}\ + {{ ' -use_ssh' if ansible_distribution_release == 'stretch' else '' }} \ + -ring0_addr {{ pve_cluster_ring0_addr }}{% if pve_cluster_ring1_addr is defined %} \ + -ring1_addr {{ pve_cluster_ring1_addr }}{% endif %}" args: creates: "{{ pve_cluster_conf }}" when: - - "inventory_hostname == __pve_current_node" + - "inventory_hostname == _pve_current_node" - name: Remove stale corosync lock file due to lack of quorum during initialization file: dest: "{{ pve_base_dir }}/priv/lock/file-corosync_conf" state: absent when: - - "inventory_hostname == __pve_current_node" + - "inventory_hostname == _pve_current_node" - "inventory_hostname == groups[pve_group][1]" diff --git a/tasks/pve_cluster_config.yml b/tasks/pve_cluster_config.yml index 21818043..26177566 100644 --- a/tasks/pve_cluster_config.yml +++ b/tasks/pve_cluster_config.yml @@ -2,47 +2,54 @@ - name: Lookup cluster information proxmox_query: query: cluster/status - register: __pve_cluster + register: _pve_cluster - name: Identify if the host is already part of a cluster set_fact: - __pve_active_cluster: '{{ __pve_cluster | json_query(query) }}' - when: "__pve_cluster | json_query(query) | ternary(true, false)" + _pve_active_cluster: '{{ _pve_cluster | json_query(query) }}' + when: "_pve_cluster | json_query(query) | ternary(true, false)" vars: query: "response[?type=='cluster'].name | [0]" - name: Identify all clusters that the hosts in the specified group may be in set_fact: - __pve_found_clusters: "{{ __pve_found_clusters | default([]) | intersect([hostvars[item]['__pve_active_cluster']]) }}" + _pve_found_clusters: "{{ _pve_found_clusters | default([]) | intersect([hostvars[item]['_pve_active_cluster']]) }}" with_items: "{{ groups[pve_group] }}" - when: "'__pve_active_cluster' in hostvars[item]" + when: "'_pve_active_cluster' in hostvars[item]" - name: Ensure that hosts found are not in multiple existing clusters assert: that: - - "(__pve_found_clusters | default([]) | length) <= 1" - msg: "Some or all of the hosts in {{ pve_group }} appear to already be part of two or more different clusters, please ensure groups only have hosts meant to be in one single cluster." + - "(_pve_found_clusters | default([]) | length) <= 1" + msg: "Some or all of the hosts in {{ pve_group }} appear to already be part of two or more different clusters, \ + please ensure groups only have hosts meant to be in one single cluster." - name: Ensure that, if we find an existing cluster, that it matches the specified cluster name assert: that: - - "__pve_found_clusters[0] == pve_cluster_clustername" - msg: "Some or all of the hosts in group '{{ pve_group }}' appear to be in a cluster named '{{ __pve_found_clusters[0] }}', which differs from the specified clustername of '{{ pve_cluster_clustername }}'. Please ensure the clustername is correct. An existing cluster's name cannot be modified." - when: "(__pve_found_clusters | default([]) | length) == 1" + - "_pve_found_clusters[0] == pve_cluster_clustername" + msg: "Some or all of the hosts in group '{{ pve_group }}' appear to be in a cluster named \ + '{{ _pve_found_clusters[0] }}', which differs from the specified clustername of \ + '{{ pve_cluster_clustername }}'. Please ensure the clustername is correct. An existing \ + cluster's name cannot be modified." + when: "(_pve_found_clusters | default([]) | length) == 1" - name: Initialize a Proxmox cluster - command: "pvecm create {{ pve_cluster_clustername }} -bindnet0_addr {{ pve_cluster_bindnet0_addr }} -ring0_addr {{ pve_cluster_ring0_addr }}{% if pve_cluster_bindnet1_addr is defined and pve_cluster_ring1_addr is defined %} -bindnet1_addr {{ pve_cluster_bindnet1_addr }} -ring1_addr {{ pve_cluster_ring1_addr }}{% endif %}" + command: "pvecm create {{ pve_cluster_clustername }} -bindnet0_addr {{ pve_cluster_bindnet0_addr }} \ + -ring0_addr {{ pve_cluster_ring0_addr }}\ + {% if pve_cluster_bindnet1_addr is defined and pve_cluster_ring1_addr is defined %} \ + -bindnet1_addr {{ pve_cluster_bindnet1_addr }} -ring1_addr {{ pve_cluster_ring1_addr }}{% endif %}" args: creates: "{{ pve_cluster_conf }}" when: - - "__pve_found_clusters is not defined" + - "_pve_found_clusters is not defined" - "inventory_hostname == groups[pve_group][0]" - name: Wait for quorum on initialization node proxmox_query: query: cluster/status - register: __pve_cluster_init - until: "(__pve_cluster_init | json_query(query)) == 1" + register: _pve_cluster_init + until: "(_pve_cluster_init | json_query(query)) == 1" retries: 5 delay: 5 when: @@ -53,5 +60,5 @@ - include_tasks: pve_add_node.yml with_items: "{{ groups[pve_group][1:] }}" when: - - "__pve_active_cluster is not defined" + - "_pve_active_cluster is not defined" - "inventory_hostname != groups[pve_group][0]" diff --git a/tasks/ssh_cluster_config.yml b/tasks/ssh_cluster_config.yml index 3d5e9fd5..eff83eee 100644 --- a/tasks/ssh_cluster_config.yml +++ b/tasks/ssh_cluster_config.yml @@ -44,7 +44,7 @@ content: | {% for host in groups[pve_group] %} Match Address {{ hostvars[host].ansible_default_ipv4.address }} - PermitRootLogin {{ pve_sshd_prohibit_password }} + PermitRootLogin prohibit-password {% endfor %} validate: "/usr/sbin/sshd -t -f %s" notify: @@ -63,7 +63,7 @@ - name: Check status of known hosts file stat: path: /etc/ssh/ssh_known_hosts - register: __pve_known_hosts_file + register: _pve_known_hosts_file - name: Add every host's host keys to global known_hosts blockinfile: @@ -77,7 +77,7 @@ {% endfor %} {% endfor %} when: - - "not (__pve_known_hosts_file.stat.islnk is defined and __pve_known_hosts_file.stat.islnk)" + - "not (_pve_known_hosts_file.stat.islnk is defined and _pve_known_hosts_file.stat.islnk)" - name: Add PVE-provided ciphers to SSH client config lineinfile: diff --git a/tasks/ssl_config.yml b/tasks/ssl_config.yml index ed150374..da7d6d5e 100644 --- a/tasks/ssl_config.yml +++ b/tasks/ssl_config.yml @@ -9,8 +9,8 @@ - name: Install PVE SSL certificate chain and key shell: "diff {{ item.src }} {{ item.dest }} >/dev/null 2>&1 || (cp {{ item.src }} {{ item.dest }}; echo changed)" - register: __pve_ssl_diff - changed_when: "'changed' in __pve_ssl_diff.stdout" + register: _pve_ssl_diff + changed_when: "'changed' in _pve_ssl_diff.stdout" with_items: - { src: "/etc/ssl/pveproxy-ssl.key", dest: "/etc/pve/local/pveproxy-ssl.key"} - { src: "/etc/ssl/pveproxy-ssl.pem", dest: "/etc/pve/local/pveproxy-ssl.pem"} diff --git a/tests/group_vars/all b/tests/group_vars/all index 12862b0a..cd4c3fb8 100644 --- a/tests/group_vars/all +++ b/tests/group_vars/all @@ -1,6 +1,7 @@ --- ansible_ssh_user: root +pve_group: pve pve_extra_packages: - sl pve_check_for_kernel_update: false @@ -51,6 +52,31 @@ pve_acls: # This should generate 3 different ACLs (note that this is count shoul - pveapi@pve groups: - test_users +pve_storages: # This should create 2 different storages. + - name: dir1 + type: dir + content: [ "images", "iso", "backup" ] + path: /plop + maxfiles: 4 + - name: ceph1 + type: rbd + content: [ "images", "rootdir" ] + username: admin + pool: rbd + krbd: yes + monhost: + - 10.0.0.1 + - 10.0.0.2 + - 10.0.0.3 + - name: lvm1 + type: lvm + content: [ "images", "rootdir" ] + vgname: vg1 + - name: lvmthin1 + type: lvmthin + content: [ "images", "rootdir" ] + vgname: vg2 + thinpool: data ssl_directory: /home/travis/ssl/ ssl_ca_key_path: "{{ ssl_directory }}/test-ca.key" diff --git a/tests/group_vars/pve4x b/tests/group_vars/pve4x deleted file mode 100644 index 2fe8005b..00000000 --- a/tests/group_vars/pve4x +++ /dev/null @@ -1,2 +0,0 @@ ---- -pve_group: pve4x diff --git a/tests/group_vars/pve5x b/tests/group_vars/pve5x deleted file mode 100644 index efeb8cb6..00000000 --- a/tests/group_vars/pve5x +++ /dev/null @@ -1,2 +0,0 @@ ---- -pve_group: pve5x diff --git a/tests/install.yml b/tests/install.yml index ab72972c..cfed555f 100644 --- a/tests/install.yml +++ b/tests/install.yml @@ -16,9 +16,12 @@ test_profiles: - profile: debian-stretch prefix: proxmox-5- - - profile: debian-jessie - prefix: proxmox-4- test_hosts_per_profile: 3 + container_config: + - "lxc.apparmor.profile = unconfined" + - "lxc.mount.auto = proc:rw sys:rw cgroup-full:rw" + - "lxc.cgroup.devices.allow = a *:* rmw" + - "lxc.mount.entry = /lib/modules/{{ ansible_kernel }} lib/modules/{{ ansible_kernel }} none bind,create=dir,ro 0 0" # Run the following within the containers in the inventory - hosts: all diff --git a/tests/inventory b/tests/inventory index 2e35d1e6..33562d7e 100644 --- a/tests/inventory +++ b/tests/inventory @@ -1,5 +1,2 @@ -[pve5x] +[pve] proxmox-5-[01:03].lxc - -[pve4x] -proxmox-4-[01:03].lxc diff --git a/tests/test.yml b/tests/test.yml index 1a7618df..995dd5b4 100644 --- a/tests/test.yml +++ b/tests/test.yml @@ -6,54 +6,71 @@ url: "https://{{ inventory_hostname }}:8006" - name: Query PVE cluster status - shell: "pvesh get /cluster/status" - register: __pve_cluster + shell: "pvesh get /cluster/status --output=json" + register: _pve_cluster changed_when: False - name: Check that this node is within the cluster and it is in quorum assert: - that: "(__pve_cluster.stdout | from_json | json_query(query)) == 1" + that: "(_pve_cluster.stdout | from_json | json_query(query)) == 1" vars: query: "([?type=='cluster'].quorate)[0]" - name: Query PVE groups - shell: "pvesh get /access/groups" - register: __pve_groups + shell: "pvesh get /access/groups --output=json" + register: _pve_groups changed_when: False - name: Check that PVE groups exist assert: - that: "(__pve_groups.stdout | from_json | json_query(query)) == 1" + that: "(_pve_groups.stdout | from_json | json_query(query)) == 1" vars: query: "length([?groupid=='{{ item.name }}'])" run_once: True with_items: "{{ pve_groups }}" - name: Query PVE users - shell: "pvesh get /access/users" - register: __pve_users + shell: "pvesh get /access/users --output=json" + register: _pve_users changed_when: False - name: Check that PVE users exist assert: - that: "(__pve_users.stdout | from_json | json_query(query)) == 1" + that: "(_pve_users.stdout | from_json | json_query(query)) == 1" vars: query: "length([?userid=='{{ item.name }}'])" run_once: True with_items: "{{ pve_users }}" - name: Query PVE ACLs - shell: "pvesh get /access/acl" - register: __pve_acl + shell: "pvesh get /access/acl --output=json" + register: _pve_acl changed_when: False - name: Check that PVE ACLs exist assert: - that: "(__pve_acl.stdout | from_json | json_query(query)) == 3" + that: "(_pve_acl.stdout | from_json | json_query(query)) == 3" vars: query: "length([])" run_once: True + - name: Query PVE storages + shell: "pvesh get /storage --output=json" + register: _pve_storage + changed_when: False + + - name: Construct storage list + set_fact: + sto_list: "{{ sto_list | default([]) }} + [ '{{ item.name }}' ]" + with_items: "{{ pve_storages }}" + + - name: Check that PVE storages exist + assert: + that: "sto_list is subset(_pve_storage.stdout | from_json | json_query(query))" + vars: + query: "[*].storage" + run_once: True + - block: - name: pvedaemon service status shell: "journalctl --no-pager -xu pvedaemon.service" diff --git a/vars/debian-jessie.yml b/vars/debian-jessie.yml deleted file mode 100644 index 5a508a49..00000000 --- a/vars/debian-jessie.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -pve_release_key: proxmox-ve-release-4.x.asc -pve_release_key_id: C23AC7F49887F95A -pve_ssh_ciphers: "blowfish-cbc,aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc" -pve_sshd_prohibit_password: without-password diff --git a/vars/debian-stretch.yml b/vars/debian-stretch.yml index be3d0e79..d506832e 100644 --- a/vars/debian-stretch.yml +++ b/vars/debian-stretch.yml @@ -2,4 +2,3 @@ pve_release_key: proxmox-ve-release-5.x.asc pve_release_key_id: 0D9A1950E2EF0603 pve_ssh_ciphers: "aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com" -pve_sshd_prohibit_password: prohibit-password