From c320aadd0b5d70b7683dee1d82bb60353c1b6735 Mon Sep 17 00:00:00 2001 From: chatton Date: Fri, 7 Jul 2023 17:53:43 +0100 Subject: [PATCH] bookstack working --- .../chatton/portainer/FILES.json | 2 +- .../chatton/portainer/MANIFEST.json | 2 +- .../plugins/modules/portainer_stack.py | 40 +++++++++++------ playbooks/setup-homelab.yml | 19 ++++++-- requirements.yml | 2 +- roles/portainer_bookstack/defaults/main.yml | 18 ++++++++ roles/portainer_bookstack/tasks/main.yml | 43 +++++++++++++++++++ 7 files changed, 106 insertions(+), 20 deletions(-) create mode 100644 roles/portainer_bookstack/defaults/main.yml create mode 100644 roles/portainer_bookstack/tasks/main.yml diff --git a/collections/ansible_collections/chatton/portainer/FILES.json b/collections/ansible_collections/chatton/portainer/FILES.json index 0697d40..a217c2e 100644 --- a/collections/ansible_collections/chatton/portainer/FILES.json +++ b/collections/ansible_collections/chatton/portainer/FILES.json @@ -60,7 +60,7 @@ "name": "plugins/modules/portainer_stack.py", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "e75fa1655aed9c13955315a80aa9a3f0b54ac1bc386697756bb308e0cfe4ecbb", + "chksum_sha256": "8f8c5a3fcefa02becec7dad10442e92db1b40dccdd43e297baa273a03f260105", "format": 1 }, { diff --git a/collections/ansible_collections/chatton/portainer/MANIFEST.json b/collections/ansible_collections/chatton/portainer/MANIFEST.json index 884cde7..ba313e7 100644 --- a/collections/ansible_collections/chatton/portainer/MANIFEST.json +++ b/collections/ansible_collections/chatton/portainer/MANIFEST.json @@ -23,7 +23,7 @@ "name": "FILES.json", "ftype": "file", "chksum_type": "sha256", - "chksum_sha256": "a3d632538c4fb62677f3dceb2b32648f6688932bfa4354ad1ad21ecd1e031a7d", + "chksum_sha256": "df6db8314d203f2365d1ff4253d6d793197067dced93c835a6b88074c18d4921", "format": 1 }, "format": 1 diff --git a/collections/ansible_collections/chatton/portainer/plugins/modules/portainer_stack.py b/collections/ansible_collections/chatton/portainer/plugins/modules/portainer_stack.py index dc9a8a8..582737c 100644 --- a/collections/ansible_collections/chatton/portainer/plugins/modules/portainer_stack.py +++ b/collections/ansible_collections/chatton/portainer/plugins/modules/portainer_stack.py @@ -16,6 +16,8 @@ except ImportError: _query_params_to_string, ) +import yaml + DOCUMENTATION = r""" --- module: portainer_stack @@ -117,17 +119,15 @@ def _create_stack(client, module, file_contents): def _update_stack(client, module, stack_id): target_stack_name = module.params["stack_name"] - with open(module.params["docker_compose_file_path"]) as f: - file_contents = f.read() + contents = _get_stack_contents(module.params) return client.put( f"stacks/{stack_id}?&endpointId={client.endpoint}", body={ "name": target_stack_name, - "stackFileContent": file_contents, + "stackFileContent": contents, }, ) - def handle_state_present(client, module): result = dict(changed=False, stack_name=module.params["stack_name"]) @@ -135,8 +135,7 @@ def handle_state_present(client, module): stacks = client.get("stacks") result["stacks"] = stacks - with open(module.params["docker_compose_file_path"]) as f: - file_contents = f.read() + contents = _get_stack_contents(module.params) target_stack_name = module.params["stack_name"] for stack in stacks: @@ -146,7 +145,7 @@ def handle_state_present(client, module): break if not already_exists: - stack = _create_stack(client, module, file_contents) + stack = _create_stack(client, module, contents) result["changed"] = True result["stack_id"] = stack["Id"] module.exit_json(**result) @@ -158,7 +157,7 @@ def handle_state_present(client, module): ) result["are_equal"] = ( - current_file_contents_resp["StackFileContent"] == file_contents + current_file_contents_resp["StackFileContent"] == contents ) if result["are_equal"]: module.exit_json(**result) @@ -191,13 +190,22 @@ def handle_state_absent(client, module): ) result["changed"] = True module.exit_json(**result) +def _get_stack_contents(params): + if params.get("docker_compose_file_path"): + with open(params["docker_compose_file_path"]) as f: + return f.read() + if params.get("definition"): + return yaml.dump(params["definition"], indent=4) + + raise ValueError("No docker_compose_file_path or definition provided.") def run_module(): # define available arguments/parameters a user can pass to the module module_args = dict( stack_name=dict(type="str", required=True), docker_compose_file_path=dict(type="str"), + definition=dict(type=dict), username=dict(type="str", default="admin"), password=dict(type="str", required=True, no_log=True), endpoint_id=dict(type="int", required=True), @@ -205,11 +213,6 @@ def run_module(): state=dict(type="str", default="present", choices=["present", "absent"]), ) - required_if = [ - # docker compose file is only required if we are ensuring the stack is present. - ["state", "present", ("docker_compose_file_path",)], - ] - state_fns = {"present": handle_state_present, "absent": handle_state_absent} # the AnsibleModule object will be our abstraction working with Ansible @@ -218,7 +221,16 @@ def run_module(): # supports check mode module = AnsibleModule( argument_spec=module_args, - required_if=required_if, + # required_if = [ + # docker compose file is only required if we are ensuring the stack is present. + # ["state", "present", ("docker_compose_file_path",)], + # ], + mutually_exclusive=[ + ('docker_compose_file_path', 'definition'), + ], + required_one_of=[ + ('docker_compose_file_path', 'definition'), + ], # TODO: support check mode supports_check_mode=False, ) diff --git a/playbooks/setup-homelab.yml b/playbooks/setup-homelab.yml index 452abdb..e044b04 100644 --- a/playbooks/setup-homelab.yml +++ b/playbooks/setup-homelab.yml @@ -55,13 +55,26 @@ - role: setup_compose_services tags: [compose] -- name: Setup and deploy portainer services. - hosts: servers + +- name: Setup and deploy portainer services (snunmu). + hosts: snunmu become: true pre_tasks: - name: Include vault variables. ansible.builtin.include_vars: '../{{ vault_file }}' tags: [always] roles: - - role: setup_hosted_services + - role: portainer_bookstack tags: [services] + + +#- name: Setup and deploy portainer services. +# hosts: servers +# become: true +# pre_tasks: +# - name: Include vault variables. +# ansible.builtin.include_vars: '../{{ vault_file }}' +# tags: [always] +# roles: +# - role: setup_hosted_services +# tags: [services] diff --git a/requirements.yml b/requirements.yml index e805a97..cd6a07b 100644 --- a/requirements.yml +++ b/requirements.yml @@ -8,7 +8,7 @@ roles: collections: - name: https://github.com/chatton/ansible-portainer.git type: git - version: master + version: support_definition - name: https://github.com/chatton/ansible-docker-backup.git type: git version: master diff --git a/roles/portainer_bookstack/defaults/main.yml b/roles/portainer_bookstack/defaults/main.yml new file mode 100644 index 0000000..5483522 --- /dev/null +++ b/roles/portainer_bookstack/defaults/main.yml @@ -0,0 +1,18 @@ +--- +bookstack_image: linuxserver/bookstack +bookstack_tag: 23.06.1 +bookstack_backup_enabled: true +bookstack_backup_schedule: "nightly" +bookstack_puid: 1000 +bookstack_pgid: 1000 +bookstack_db_host: qnap +bookstack_database: bookstackapp +bookstack_db_user: bookstack +bookstack_app_url: https://bookstack.cianhatton.ie +bookstack_expose_port: 6875 +bookstack_restart_policy: unless-stopped +bookstack_container_name: bookstack +bookstack_portainer_stack_name: bookstack +bookstack_docker_backup_restore_force: false +bookstack_docker_backup_restore_latest_s3_key: true +bookstack_docker_backup_fail_on_no_s3_backups: false diff --git a/roles/portainer_bookstack/tasks/main.yml b/roles/portainer_bookstack/tasks/main.yml new file mode 100644 index 0000000..345087e --- /dev/null +++ b/roles/portainer_bookstack/tasks/main.yml @@ -0,0 +1,43 @@ +--- +- name: "Bookstack | Restore any missing volumes from S3" + ansible.builtin.include_role: + name: chatton.docker_backup.docker_s3_volume_restore + vars: + docker_backup_restore_force: "{{ bookstack_docker_backup_restore_force }}" + docker_backup_restore_latest_s3_key: "{{ bookstack_docker_backup_restore_latest_s3_key }}" + docker_backup_fail_on_no_s3_backups: "{{ bookstack_docker_backup_fail_on_no_s3_backups }}" + docker_backup_s3_volume: + name: "{{ bookstack_portainer_stack_name }}_config" + +- name: "Bookstack | Update Portainer." + chatton.portainer.portainer_stack: + username: admin + password: '{{ portainer.password }}' + base_url: '{{ portainer_base_url }}' + stack_name: '{{ bookstack_portainer_stack_name }}' + endpoint_id: '{{ portainer_endpoint }}' + state: present + definition: + version: "3.1" + services: + bookstack: + labels: + ie.cianhatton.backup.enabled: "{{ bookstack_backup_enabled }}" + ie.cianhatton.backup.schedule: "{{ bookstack_backup_schedule }}" + image: "{{ bookstack_image }}:{{ bookstack_tag }}" + container_name: "{{ bookstack_container_name }}" + environment: + - PUID={{ bookstack_puid }} + - PGID={{ bookstack_pgid }} + - DB_HOST={{ bookstack_db_host }} + - DB_USER={{ bookstack_db_user }} + - DB_PASS={{ bookstack_password }} + - DB_DATABASE={{ bookstack_database }} + - APP_URL={{ bookstack_app_url }} + volumes: + - config:/config" + ports: + - "{{ bookstack_expose_port }}:80" + restart: "{{ bookstack_restart_policy }}" + volumes: + config: {}