--- - name: Create a test Portainer stack via SSH tunnel hosts: localhost connection: local gather_facts: false vars: # Bastion SSH bastion_host: bdc.cci17.fr bastion_port: 17100 bastion_user: ansible # Portainer (via tunnel local) portainer_url: https://127.0.0.1:9443 # Stack test stack_name: test-stack-semaphore stack_type: 2 # 2 = Docker standalone, 1 = Swarm # Tunnel SSH ssh_control_socket: /tmp/ssh-tunnel-portainer-9443.sock # Compose minimal de test stack_compose: | services: web: image: nginx:alpine restart: unless-stopped tasks: - block: - name: Check local port 9443 is free shell: ss -lnt | grep -q ':9443 ' register: port_in_use changed_when: false failed_when: port_in_use.rc == 0 - name: Open SSH tunnel to Portainer shell: > ssh -p {{ bastion_port }} -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -M -S {{ ssh_control_socket }} -f -N -L 127.0.0.1:9443:10.30.0.151:9443 {{ bastion_user }}@{{ bastion_host }} changed_when: true - name: Wait for tunnel to be ready wait_for: host: 127.0.0.1 port: 9443 timeout: 20 - name: Check Portainer API uri: url: "{{ portainer_url }}/api/status" method: GET validate_certs: false headers: X-API-Key: "{{ lookup('env','PORTAINER_API_KEY') }}" status_code: [200] - name: Get Portainer endpoints uri: url: "{{ portainer_url }}/api/endpoints" method: GET validate_certs: false headers: X-API-Key: "{{ lookup('env','PORTAINER_API_KEY') }}" register: endpoints_resp - name: Select first endpoint set_fact: endpoint_id: "{{ endpoints_resp.json[0].Id }}" - name: Create test stack uri: url: "{{ portainer_url }}/api/stacks?type={{ stack_type }}&method=string&endpointId={{ endpoint_id }}" method: POST validate_certs: false headers: X-API-Key: "{{ lookup('env','PORTAINER_API_KEY') }}" Content-Type: application/json body_format: json body: Name: "{{ stack_name }}" StackFileContent: "{{ stack_compose }}" Env: [] status_code: [200, 201, 409] register: create_stack - name: Result debug: msg: > Stack creation HTTP status {{ create_stack.status }} (409 means the stack already exists) always: - name: Close SSH tunnel shell: > test -S {{ ssh_control_socket }} && ssh -p {{ bastion_port }} -S {{ ssh_control_socket }} -O exit {{ bastion_user }}@{{ bastion_host }} || true ignore_errors: true