|
|
|
@ -19,9 +19,8 @@ required_env_vars = {
|
|
|
|
|
'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_BRANCH': 'The branch to deploy',
|
|
|
|
|
'DEPLOY_HOST': 'The host name under which the deployment will be reachable',
|
|
|
|
|
'DEPLOY_NAME': 'Custom name to use as the deployment name',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Try getting all arguments from (in order): 1 command line, 2 .env file, 3 Environment
|
|
|
|
@ -44,26 +43,14 @@ if not_parsed:
|
|
|
|
|
parser.print_help()
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
# 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']
|
|
|
|
|
deploy_webhook = str(uuid.uuid4())
|
|
|
|
|
|
|
|
|
|
### Find CICD-runner portainer environment endpointId ###
|
|
|
|
|
portainer_headers = {
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
'X-API-Key': portainer_api_key,
|
|
|
|
|
'X-API-Key': args.PORTAINER_API_KEY
|
|
|
|
|
}
|
|
|
|
|
endpoint_url = f'{portainer}/api/endpoints'
|
|
|
|
|
endpoint_url = f'{args.PORTAINER}/api/endpoints'
|
|
|
|
|
json_endpoints = None
|
|
|
|
|
try:
|
|
|
|
|
response = requests.get(endpoint_url, headers=portainer_headers)
|
|
|
|
@ -75,14 +62,20 @@ except requests.exceptions.RequestException as err:
|
|
|
|
|
|
|
|
|
|
endpoint_id = None
|
|
|
|
|
for endpoint in json_endpoints:
|
|
|
|
|
if endpoint["Name"] == portainer_ep:
|
|
|
|
|
if endpoint["Name"] == args.PORTAINER_EP:
|
|
|
|
|
endpoint_id = endpoint["Id"]
|
|
|
|
|
break
|
|
|
|
|
if endpoint_id is None:
|
|
|
|
|
raise Exception(f'Portainer endpoint \'{portainer_ep}\' not found.')
|
|
|
|
|
raise Exception(f'Portainer endpoint \'{args.PORTAINER_EP}\' not found.')
|
|
|
|
|
else:
|
|
|
|
|
print(f'Found portainer endpoint \'{portainer_ep}\' has id: \'{endpoint_id}\'.')
|
|
|
|
|
print(f'Found portainer endpoint \'{args.PORTAINER_EP}\' has id: \'{endpoint_id}\'.')
|
|
|
|
|
|
|
|
|
|
repo_url = urlparse(args.DEPLOY_REPO_URL)
|
|
|
|
|
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]
|
|
|
|
|
|
|
|
|
|
### Template substitution for the portainer stack deployment ###
|
|
|
|
|
portainer_deploy_payload = {
|
|
|
|
@ -90,31 +83,31 @@ portainer_deploy_payload = {
|
|
|
|
|
"deploy/portainer/portainer_deploy.docker-compose.yml"
|
|
|
|
|
],
|
|
|
|
|
"autoUpdate": {
|
|
|
|
|
"webhook": f"{deploy_variables['DEPLOY_WEBHOOK']}"
|
|
|
|
|
"webhook": deploy_webhook
|
|
|
|
|
},
|
|
|
|
|
"composeFile": "docker-compose.yml",
|
|
|
|
|
"env": [
|
|
|
|
|
{
|
|
|
|
|
"name": "HOST",
|
|
|
|
|
"value": f"{deploy_variables['DEPLOY_HOST']}"
|
|
|
|
|
"value": args.DEPLOY_HOST
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "COMPOSE_PROJECT_NAME",
|
|
|
|
|
"value": f"{deploy_variables['DEPLOY_NAME']}"
|
|
|
|
|
"value": args.DEPLOY_BRANCH
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"fromAppTemplate": False,
|
|
|
|
|
"name": f"{deploy_variables['DEPLOY_NAME']}",
|
|
|
|
|
"name": f"{owner}_{repo}_{args.DEPLOY_BRANCH.replace('/', '_')}".lower(),
|
|
|
|
|
"repositoryAuthentication": True,
|
|
|
|
|
"repositoryUsername": "cicd",
|
|
|
|
|
"repositoryPassword": "gJ6@$7ZjWGyV4%i",
|
|
|
|
|
"repositoryReferenceName": f"{deploy_variables['DEPLOY_REF']}",
|
|
|
|
|
"repositoryURL": f"{deploy_variables['DEPLOY_REPO_URL']}",
|
|
|
|
|
"repositoryReferenceName": f"refs/heads/{args.DEPLOY_BRANCH}",
|
|
|
|
|
"repositoryURL": args.DEPLOY_REPO_URL,
|
|
|
|
|
"tlsskipVerify": False
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
### Deploy to portainer ###
|
|
|
|
|
deploy_url = f'{portainer}/api/stacks/create/standalone/repository?endpointId={endpoint_id}'
|
|
|
|
|
deploy_url = f'{args.PORTAINER}/api/stacks/create/standalone/repository?endpointId={endpoint_id}'
|
|
|
|
|
try:
|
|
|
|
|
response = requests.post(deploy_url, headers=portainer_headers, json=portainer_deploy_payload)
|
|
|
|
|
response.raise_for_status() # Raise HTTPError for bad requests
|
|
|
|
@ -124,30 +117,20 @@ 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[-1]
|
|
|
|
|
|
|
|
|
|
webhook_payload = {
|
|
|
|
|
"type": "gitea",
|
|
|
|
|
"branch_filter": f"{branch}",
|
|
|
|
|
"branch_filter": f"{args.DEPLOY_BRANCH}",
|
|
|
|
|
"config": {
|
|
|
|
|
"url": f"{portainer}/api/stacks/webhooks/{deploy_webhook}",
|
|
|
|
|
"url": f"{args.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_url = f'{gitea}/api/v1/repos/{repo_path}/hooks'
|
|
|
|
|
webhook_headers = {
|
|
|
|
|
"Authorization": f"token {gitea_api_key}"
|
|
|
|
|
"Authorization": f"token {args.GITEA_API_KEY}"
|
|
|
|
|
}
|
|
|
|
|
try:
|
|
|
|
|
response = requests.post(webhook_url, headers=webhook_headers, json=webhook_payload)
|
|
|
|
|