diff --git a/.drone.yml b/.drone.yml index 61598a6..c710fd4 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,13 +12,16 @@ steps: - pip3 install requests python-dotenv --quiet - python3 deploy/portainer/deploy.py --PORTAINER https://dvportainer.privatedns.org - --API_KEY=ptr_RwxH2Cd+htdD2FoFiG46erT9beyvj9VoF3BrQPtDH3Q= + --PORTAINER_API_KEY=ptr_RwxH2Cd+htdD2FoFiG46erT9beyvj9VoF3BrQPtDH3Q= --PORTAINER_EP=CICD-runner + --GITEA_API_KEY=f449c74ec7f04e54fe1e481eae43492b34cea406 --DEPLOY_REPO_URL=${DRONE_REPO_LINK} --DEPLOY_REF=${DRONE_COMMIT_REF} --DEPLOY_HOST=dvdemo.privatedns.org --DEPLOY_NAME=${DRONE_COMMIT_SHA} trigger: - branch: - - main \ No newline at end of file + event: + - pull_request + action: + - opened \ No newline at end of file diff --git a/deploy/portainer/.env b/deploy/portainer/.env index 3c5f482..948fad3 100644 --- a/deploy/portainer/.env +++ b/deploy/portainer/.env @@ -1,8 +1,9 @@ -PORTAINER=https://dvportainer.privatedns.org -API_KEY=ptr_RwxH2Cd+htdD2FoFiG46erT9beyvj9VoF3BrQPtDH3Q= -PORTAINER_EP=CICD-runner -DEPLOY_REPO_URL=https://dvgit.privatedns.org/lars/DeployTests -DEPLOY_REF=refs/heads/main -DEPLOY_HOST=dvdemo.privatedns.org -DEPLOY_PROJECT=ManualDeployTests +PORTAINER=https://dvportainer.privatedns.org +PORTAINER_API_KEY=ptr_RwxH2Cd+htdD2FoFiG46erT9beyvj9VoF3BrQPtDH3Q= +PORTAINER_EP=CICD-runner +GITEA_API_KEY=f449c74ec7f04e54fe1e481eae43492b34cea406 +DEPLOY_REPO_URL=https://dvgit.privatedns.org/lars/DeployTests +DEPLOY_REF=refs/heads/main +DEPLOY_HOST=dvdemo.privatedns.org +DEPLOY_PROJECT=ManualDeployTests DEPLOY_NAME=ManualDeploy \ No newline at end of file diff --git a/deploy/portainer/deploy.py b/deploy/portainer/deploy.py index 7a613e4..583e291 100644 --- a/deploy/portainer/deploy.py +++ b/deploy/portainer/deploy.py @@ -5,16 +5,19 @@ import sys import argparse import requests import json +import uuid from dotenv import load_dotenv from string import Template from pathlib import Path +from urllib.parse import urlparse load_dotenv() required_env_vars = { 'PORTAINER': 'The portainer instance to deploy to', - 'API_KEY': 'API-Key to access portainer instance', + 'PORTAINER_API_KEY': 'API-Key to access portainer instance', 'PORTAINER_EP': 'Portainer Environment EndPoint to deploy to', + 'GITEA_API_KEY': 'API-Key to access Gitea instance', 'DEPLOY_REPO_URL': 'The repository URL to deploy', 'DEPLOY_REF': 'The git ref to deploy', 'DEPLOY_HOST': 'The host name under which the deployment will be reachable', @@ -41,24 +44,29 @@ if not_parsed: parser.print_help() sys.exit(1) -portainer=args.PORTAINER -api_key=args.API_KEY -portainer_ep=args.PORTAINER_EP - # Deploy variables to substitute in portainer deploy template deploy_variables = {key: getattr(args, key) for key in ['DEPLOY_REPO_URL', 'DEPLOY_HOST', 'DEPLOY_NAME', 'DEPLOY_REF'] } +deploy_variables['DEPLOY_WEBHOOK'] = str(uuid.uuid4()) + +portainer=args.PORTAINER +portainer_api_key=args.PORTAINER_API_KEY +portainer_ep=args.PORTAINER_EP +gitea_api_key=args.GITEA_API_KEY +deploy_repo=deploy_variables['DEPLOY_REPO_URL'] +deploy_webhook=deploy_variables['DEPLOY_WEBHOOK'] +deploy_ref=deploy_variables['DEPLOY_REF'] ### Find CICD-runner portainer environment endpointId ### -headers = { +portainer_headers = { 'Content-Type': 'application/json', - 'X-API-Key': api_key, + 'X-API-Key': portainer_api_key, } -url = f'{portainer}/api/endpoints' +endpoint_url = f'{portainer}/api/endpoints' json_endpoints = None try: - response = requests.get(url, headers=headers) + response = requests.get(endpoint_url, headers=portainer_headers) response.raise_for_status() # Raise HTTPError for bad requests json_endpoints = response.json() @@ -77,26 +85,75 @@ else: ### Template substitution for the portainer stack deployment ### -portainer_deploy_json = None -template_file = f'{Path( __file__ ).parent.absolute()}/portainer_deploy.template.json' -with open(template_file, 'r') as file: - portainer_template = Template(file.read()) - -# Perform variable substitution -portainer_deploy_json = portainer_template.substitute(**deploy_variables) +portainer_deploy_payload = { + "additionalFiles": [ + "deploy/portainer/portainer_deploy.docker-compose.yml" + ], + "autoUpdate": { + "webhook": f"{deploy_variables['DEPLOY_WEBHOOK']}" + }, + "composeFile": "docker-compose.yml", + "env": [ + { + "name": "HOST", + "value": f"{deploy_variables['DEPLOY_HOST']}" + }, + { + "name": "COMPOSE_PROJECT_NAME", + "value": f"{deploy_variables['DEPLOY_NAME']}" + } + ], + "fromAppTemplate": False, + "name": f"{deploy_variables['DEPLOY_NAME']}", + "repositoryAuthentication": True, + "repositoryUsername": "cicd", + "repositoryPassword": "gJ6@$7ZjWGyV4%i", + "repositoryReferenceName": f"{deploy_variables['DEPLOY_REF']}", + "repositoryURL": f"{deploy_variables['DEPLOY_REPO_URL']}", + "tlsskipVerify": False +} ### Deploy to portainer ### -headers = { - 'Content-Type': 'application/json', - 'X-API-Key': api_key, -} -url = f'{portainer}/api/stacks/create/standalone/repository?endpointId={endpoint_id}' +deploy_url = f'{portainer}/api/stacks/create/standalone/repository?endpointId={endpoint_id}' try: - response = requests.post(url, headers=headers, json=json.loads(portainer_deploy_json)) + response = requests.post(deploy_url, headers=portainer_headers, json=portainer_deploy_payload) response.raise_for_status() # Raise HTTPError for bad requests - response_data = response.json() # Parse response JSON + deploy_response = response.json() except requests.exceptions.RequestException as err: raise Exception(f'Could not deploy portainer stack: {err}') +### Add Webhook to Gitea ### +repo_url = urlparse(deploy_repo) +gitea = f"{repo_url.scheme}://{repo_url.netloc}" +repo_path = repo_url.path +repo_parts = repo_path.strip('/').split('/') +owner = repo_parts[0] +repo = repo_parts[1] + +ref_parts = deploy_ref.strip('/').split('/') +branch = ref_parts[2] + +webhook_payload = { + "type": "gitea", + "branch_filter": f"{branch}", + "config": { + "url": f"{portainer}/api/stacks/webhooks/{deploy_webhook}", + "content_type": "json" + }, + "events": ["push"], # You can specify other events as needed + "active": True +} + +webhook_url = f'{gitea}/api/v1/repos/{owner}/{repo}/hooks' +webhook_headers = { + "Authorization": f"token {gitea_api_key}" +} +try: + response = requests.post(webhook_url, headers=webhook_headers, json=webhook_payload) + response.raise_for_status() # Raise HTTPError for bad requests + webhook_response = response.json() + +except requests.exceptions.RequestException as err: + raise Exception(f'Could not add webhook to Gitea: {err}') print(f'Successfully deployed project') \ No newline at end of file diff --git a/deploy/portainer/portainer_deploy.template.json b/deploy/portainer/portainer_deploy.template.json deleted file mode 100644 index 9a0be1e..0000000 --- a/deploy/portainer/portainer_deploy.template.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "additionalFiles": [ - "deploy/portainer/portainer_deploy.docker-compose.yml" - ], - "autoUpdate": { - "forcePullImage": false, - "forceUpdate": false, - "interval": "1m30s", - "jobID": "15", - "webhook": "05de31a2-79fa-4644-9c12-faa67e5c49f0" - }, - "composeFile": "docker-compose.yml", - "env": [ - { - "name": "HOST", - "value": "${DEPLOY_HOST}" - }, - { - "name": "COMPOSE_PROJECT_NAME", - "value": "${DEPLOY_NAME}" - } - ], - "fromAppTemplate": false, - "name": "${DEPLOY_NAME}", - "repositoryAuthentication": true, - "repositoryUsername": "cicd", - "repositoryPassword": "gJ6@$$7ZjWGyV4%i", - "repositoryReferenceName": "${DEPLOY_REF}", - "repositoryURL": "${DEPLOY_REPO_URL}", - "tlsskipVerify": false -} \ No newline at end of file