Compare commits

..

60 Commits

Author SHA1 Message Date
c22287f53b build 2025-12-23 13:44:28 +01:00
f618476534 Update .gitlab-ci.yml file 2025-12-23 13:43:58 +01:00
5865df9abc Update .gitlab-ci.yml file 2025-12-23 13:43:42 +01:00
f83ee560c1 Update .gitlab-ci.yml file 2025-12-23 13:32:45 +01:00
5ce8573013 build 2025-12-23 13:19:41 +01:00
e8191802b1 Update .gitlab-ci.yml file 2025-12-23 13:19:07 +01:00
e546d0cf3f build 2025-12-23 13:16:48 +01:00
daf219329a Update .gitlab-ci.yml file 2025-12-23 13:15:47 +01:00
b601ecc0c3 build 2025-12-23 13:13:44 +01:00
1a8e532a02 build 2025-12-23 12:52:18 +01:00
d6e4db6dd4 Update .gitlab-ci.yml file 2025-12-23 12:52:02 +01:00
78012cec65 build 2025-12-23 12:46:55 +01:00
ba098499f5 Update .gitlab-ci.yml file 2025-12-23 12:45:58 +01:00
ce24b5c00d build 2025-12-23 12:45:09 +01:00
46143a7c12 build 2025-12-23 12:39:42 +01:00
c731fbe0de Merge branch 'main' of gitlab.sectorq.eu:jaydee/portainer 2025-12-23 12:39:36 +01:00
d878a2baa0 build 2025-12-23 12:39:32 +01:00
e280ea67f7 Update .gitlab-ci.yml file 2025-12-23 12:39:03 +01:00
260eb63262 build 2025-12-23 12:37:57 +01:00
41d6ec9914 Update .gitlab-ci.yml file 2025-12-23 12:37:44 +01:00
15e442d49b build 2025-12-23 12:35:33 +01:00
14c31575af build 2025-12-23 12:30:03 +01:00
406513b4b8 Update .gitlab-ci.yml file 2025-12-23 12:29:03 +01:00
0c1b624972 Update .gitlab-ci.yml file 2025-12-23 12:25:05 +01:00
db5209e3fb build 2025-12-23 12:17:24 +01:00
111c70ef00 Update .gitlab-ci.yml file 2025-12-23 12:17:07 +01:00
8bba4d1d18 build 2025-12-23 12:10:06 +01:00
db45a48106 Merge branch 'main' of gitlab.sectorq.eu:jaydee/portainer 2025-12-23 12:10:00 +01:00
53438a3fb0 build 2025-12-23 12:09:56 +01:00
5646e0692d Update .gitlab-ci.yml file 2025-12-23 12:08:17 +01:00
6634cc20fa build 2025-12-23 12:05:41 +01:00
fc9f25a203 Update .gitlab-ci.yml file 2025-12-23 12:05:25 +01:00
8351e9f1b1 Update .gitlab-ci.yml file 2025-12-23 12:05:13 +01:00
d007510704 build 2025-12-23 12:03:42 +01:00
3e202c9fd8 build 2025-12-23 11:55:22 +01:00
d6e5c4087d build 2025-12-23 11:53:06 +01:00
f70ebecc49 build 2025-12-23 11:41:50 +01:00
b8264994c5 Update .gitlab-ci.yml file 2025-12-23 11:41:37 +01:00
6081c44d4c build 2025-12-23 11:40:49 +01:00
abb5fc7708 Update .gitlab-ci.yml file 2025-12-23 11:40:31 +01:00
a9eecac96d build 2025-12-23 11:35:19 +01:00
e7bcee762d build 2025-12-23 11:33:51 +01:00
e3fed3304a Merge branch 'main' of gitlab.sectorq.eu:jaydee/portainer 2025-12-23 11:33:46 +01:00
338aa66565 build 2025-12-23 11:33:42 +01:00
058554a0ea Update .gitlab-ci.yml file 2025-12-23 11:33:19 +01:00
b28a7c8273 build 2025-12-23 11:27:57 +01:00
e464c498ff build 2025-12-23 11:22:46 +01:00
b028a48fc0 Merge branch 'main' of gitlab.sectorq.eu:jaydee/portainer 2025-12-23 11:22:40 +01:00
b2373f7016 build 2025-12-23 11:22:36 +01:00
1b50b3337c Update .gitlab-ci.yml file 2025-12-23 11:22:09 +01:00
ac68b5be6f build 2025-12-23 11:20:43 +01:00
035abffeab Update .gitlab-ci.yml file 2025-12-23 11:20:29 +01:00
6097d2b442 Merge branch 'main' of gitlab.sectorq.eu:jaydee/portainer 2025-12-23 11:19:44 +01:00
55bdff1745 build 2025-12-23 11:19:30 +01:00
b385f3db12 Update .gitlab-ci.yml file 2025-12-23 11:18:49 +01:00
94a3ccfd23 Update .gitlab-ci.yml file 2025-12-23 11:18:03 +01:00
b0c570d7ba build 2025-12-23 11:16:56 +01:00
4339a7d769 build 2025-12-23 10:59:28 +01:00
039078191f build 2025-12-23 10:56:22 +01:00
f5d76d87e0 build 2025-12-23 09:55:31 +01:00
5 changed files with 58 additions and 21 deletions

View File

@@ -1,10 +1,20 @@
stages: # List of stages for jobs, and their order of execution stages: # List of stages for jobs, and their order of execution
# - notify_start
- lint - lint
- build - build
- clean - clean
- notify - notify
variables: variables:
GIT_SSH_COMMAND: "ssh -i /home/gitlab-runner/.ssh/id_rsa -o IdentitiesOnly=yes" GIT_SSH_COMMAND: "ssh -i /home/gitlab-runner/.ssh/id_rsa -o IdentitiesOnly=yes"
# notify_start:
# stage: notify_start # Should be in a later stage than the job that might fail
# script:
# - column=':'
# - echo "${flow_id}"
# - curl -XPOST http://192.168.77.101:8123/api/webhook/voice-notifications-tC_8YKxMJIAaQRV5riKuC7Zl --data-raw 'message=portainer build job started'
# - rm -rf /home/gitlab-runner/builds/1fLwHSKm2/0/jaydee/portainer.tmp
# rules:
# - if: '$CI_COMMIT_MESSAGE =~ /build/'
lint: lint:
stage: lint stage: lint
image: r.sectorq.eu/jaydee/builder-portainer:latest image: r.sectorq.eu/jaydee/builder-portainer:latest
@@ -22,15 +32,19 @@ lint:
build-job: # This job runs in the build stage, which runs first. build-job: # This job runs in the build stage, which runs first.
stage: build stage: build
image: r.sectorq.eu/jaydee/builder-portainer:latest image: r.sectorq.eu/jaydee/builder-portainer:latest
before_script:
- export PYTHONPATH=$PWD
script: script:
- mkdir -p ~/.ssh - mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa
- pyinstaller --onefile portainer.py - ls -la
#- scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dist/portainer jd@192.168.80.222:/myapps/bin/ || true - pyinstaller --onefile --clean --hidden-import=portainer_api portainer.py
- strings dist/portainer | grep portainer_api || true
- scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dist/portainer jd@192.168.80.222:/myapps/bin/ || true
- scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dist/portainer jd@192.168.77.12:/myapps/bin/ || true - scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dist/portainer jd@192.168.77.12:/myapps/bin/ || true
- scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dist/portainer jd@192.168.77.101:/myapps/bin/ || true - scp -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dist/portainer jd@192.168.77.101:/myapps/bin/ || true
- rm -rf /home/gitlab-runner/builds/1fLwHSKm2/0/jaydee/portainer.tmp - rm -rf /home/gitlab-runner/builds/1fLwHSKm2/0/jaydee/portainer.*
artifacts: artifacts:
paths: paths:
- dist/ - dist/
@@ -53,7 +67,7 @@ cleanup_on_failure_job:
script: script:
- rm -rf /home/gitlab-runner/builds/1fLwHSKm2/0/jaydee/portainer.tmp - rm -rf /home/gitlab-runner/builds/1fLwHSKm2/0/jaydee/portainer.tmp
notify: notify_complete:
stage: notify # Should be in a later stage than the job that might fail stage: notify # Should be in a later stage than the job that might fail
when: on_success # <-- This is the key keyword when: on_success # <-- This is the key keyword
script: script:
@@ -61,8 +75,9 @@ notify:
- echo "${flow_id}" - echo "${flow_id}"
- curl -XPOST http://192.168.77.101:8123/api/webhook/voice-notifications-tC_8YKxMJIAaQRV5riKuC7Zl --data-raw 'message=portainer build job completed' - curl -XPOST http://192.168.77.101:8123/api/webhook/voice-notifications-tC_8YKxMJIAaQRV5riKuC7Zl --data-raw 'message=portainer build job completed'
- rm -rf /home/gitlab-runner/builds/1fLwHSKm2/0/jaydee/portainer.tmp - rm -rf /home/gitlab-runner/builds/1fLwHSKm2/0/jaydee/portainer.tmp
rules:
notify2: - if: '$CI_COMMIT_MESSAGE =~ /build/'
notify_failed:
stage: notify # Should be in a later stage than the job that might fail stage: notify # Should be in a later stage than the job that might fail
when: on_failure # <-- This is the key keyword when: on_failure # <-- This is the key keyword
script: script:

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"python.defaultInterpreterPath": "../../venvs/portainer/bin/python"
}

View File

@@ -5,18 +5,15 @@ This module provides a wrapper for interacting with the Portainer API
to manage endpoints, stacks, and containers. to manage endpoints, stacks, and containers.
""" """
# !/myapps/venvs/portainer/bin/python3
import os import os
import logging import logging
import signal import signal
import sys import sys
import json import json
import argparse import argparse
import tty
import termios
import hvac import hvac
from tabulate import tabulate from tabulate import tabulate
from port import Portainer from portainer_api import PortainerApi
from prompt_toolkit import prompt from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.shortcuts import checkboxlist_dialog from prompt_toolkit.shortcuts import checkboxlist_dialog
@@ -39,7 +36,7 @@ else:
raise Exception("Failed to authenticate with Vault") raise Exception("Failed to authenticate with Vault")
# Specify the mount point of your KV engine # Specify the mount point of your KV engine
VERSION = "0.1.19" VERSION = "0.1.42"
defaults = { defaults = {
"endpoint_id": "vm01", "endpoint_id": "vm01",
@@ -139,10 +136,12 @@ parser.add_argument(
) )
parser.add_argument("--update", "-u", action="store_true", help="Update service if it exists") parser.add_argument("--update", "-u", action="store_true", help="Update service if it exists")
parser.add_argument("--debug", "-D", action="store_true") parser.add_argument("--debug", "-D", action="store_true")
parser.add_argument("--launcher", "-L", action="store_true")
parser.add_argument("--gpu", "-g", action="store_true") parser.add_argument("--gpu", "-g", action="store_true")
parser.add_argument("--timeout", type=int, default=10, help="Request timeout seconds") parser.add_argument("--timeout", type=int, default=10, help="Request timeout seconds")
parser.add_argument("--deploy-mode", "-m", type=str, default="git", help="Deploy mode") parser.add_argument("--deploy-mode", "-m", type=str, default="git", help="Deploy mode")
parser.add_argument("--stack-mode", "-w", default=None, help="Stack mode") parser.add_argument("--stack-mode", "-w", default=None, help="Stack mode")
args = parser.parse_args() args = parser.parse_args()
print("Running version:", VERSION) print("Running version:", VERSION)
print("Environment:", args.site) print("Environment:", args.site)
@@ -426,7 +425,7 @@ if __name__ == "__main__":
os.system("cls" if os.name == "nt" else "clear") os.system("cls" if os.name == "nt" else "clear")
# Example: list endpoints # Example: list endpoints
por = Portainer(cur_config["PORTAINER_SITE"], args) por = PortainerApi(cur_config["PORTAINER_SITE"], args)
por.set_defaults(cur_config) por.set_defaults(cur_config)
if args.debug: if args.debug:
por._debug = True por._debug = True
@@ -547,6 +546,8 @@ if __name__ == "__main__":
], ],
) )
por.update_service() por.update_service()
if args.launcher:
input("\nPress ENTER to continue...")
sys.exit() sys.exit()
if args.action == "update_containers": if args.action == "update_containers":
@@ -574,6 +575,8 @@ if __name__ == "__main__":
], ],
) )
por.print_stacks(args) por.print_stacks(args)
if args.launcher:
input("Press ENTER to continue...")
# print(json.dumps(por.all_data, indent=2)) # print(json.dumps(por.all_data, indent=2))
sys.exit() sys.exit()
@@ -588,6 +591,8 @@ if __name__ == "__main__":
], ],
) )
print("\n".join(por.get_containers())) print("\n".join(por.get_containers()))
if args.launcher:
input("\nPress ENTER to continue...")
sys.exit() sys.exit()
if args.action == "update_stack": if args.action == "update_stack":
@@ -601,11 +606,16 @@ if __name__ == "__main__":
) )
por.update_stack(args) por.update_stack(args)
if args.launcher:
input("\nPress ENTER to continue...")
sys.exit() sys.exit()
if args.action == "print_all_data": if args.action == "print_all_data":
print(json.dumps(por.all_data, indent=2)) print(json.dumps(por.all_data, indent=2))
if args.launcher:
input("\nPress ENTER to continue...")
sys.exit() sys.exit()
if args.action == "update_status": if args.action == "update_status":
por.update_status(args.endpoint_id, args.stack) por.update_status(args.endpoint_id, args.stack)
sys.exit() sys.exit()
@@ -617,7 +627,8 @@ if __name__ == "__main__":
export_data.append([i, eps["by_id"][i]]) export_data.append([i, eps["by_id"][i]])
headers = ["EndpointId", "Name"] headers = ["EndpointId", "Name"]
print(tabulate(export_data, headers=headers, tablefmt="github")) print(tabulate(export_data, headers=headers, tablefmt="github"))
if args.launcher:
input("\nPress ENTER to continue...")
sys.exit() sys.exit()
if args.action == "stop_containers": if args.action == "stop_containers":

View File

@@ -21,7 +21,7 @@ from prompt_toolkit.shortcuts import radiolist_dialog
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class Portainer: class PortainerApi:
""" """
Simple wrapper around the module-level Portainer helper functions. Simple wrapper around the module-level Portainer helper functions.
Instantiate with base_url and optional token/timeout and call methods Instantiate with base_url and optional token/timeout and call methods
@@ -532,10 +532,10 @@ class Portainer:
if not args.autostart: if not args.autostart:
time.sleep(120) time.sleep(120)
cont = [] cont = []
for c in self.all_data["containers"][endpoint]: for c in self.all_data["containers"][args.endpoint_id]:
if stack == c or stack == "all": if args.stack == c or args.stack == "all":
cont += self.all_data["containers"][endpoint][c] cont += self.all_data["containers"][args.endpoint_id][c]
self.stop_containers(endpoint, cont) self.stop_containers(args.endpoint_id, cont)
def get_endpoints(self, timeout=10): def get_endpoints(self, timeout=10):
'''Get a list of all endpoints.''' '''Get a list of all endpoints.'''
@@ -914,6 +914,7 @@ class Portainer:
#print(longest) #print(longest)
ok = "\033[92m✔\033[0m" ok = "\033[92m✔\033[0m"
err = "\033[91m✖\033[0m" err = "\033[91m✖\033[0m"
updates = []
for service_id in service_ids: for service_id in service_ids:
# print(self.all_data["containers"][self.args.endpoint_id]) # print(self.all_data["containers"][self.args.endpoint_id])
@@ -934,7 +935,7 @@ class Portainer:
#print("Recreate") #print("Recreate")
self.recreate_container(service_id, pull) self.recreate_container(service_id, pull)
#print(f"Service {service_dict[service_id]:<{longest}} : updated") #print(f"Service {service_dict[service_id]:<{longest}} : updated")
self.gotify_message(f"Service {service_dict[service_id]} updated") updates.append(service_dict[service_id])
print(ok, end=" ") print(ok, end=" ")
for name, hash_, image in self.all_data["containers"][self.args.endpoint_id]: for name, hash_, image in self.all_data["containers"][self.args.endpoint_id]:
if name.startswith(service_dict[service_id]): if name.startswith(service_dict[service_id]):
@@ -942,7 +943,7 @@ class Portainer:
else: else:
print(f"\r\033[4m{service_dict[service_id]:<{longest}}\033[0m ", end="", flush=True) print(f"\r\033[4m{service_dict[service_id]:<{longest}}\033[0m ", end="", flush=True)
#print(f"\033[4m{service_dict[service_id]:<{longest}} {err}\033[0m") #print(f"\033[4m{service_dict[service_id]:<{longest}} {err}\033[0m")
self.gotify_message(f"Service update available for {service_dict[service_id]}") updates.append(service_dict[service_id])
print(err, end=" ") print(err, end=" ")
for name, hash_, image in self.all_data["containers"][self.args.endpoint_id]: for name, hash_, image in self.all_data["containers"][self.args.endpoint_id]:
if name.startswith(service_dict[service_id]): if name.startswith(service_dict[service_id]):
@@ -952,6 +953,11 @@ class Portainer:
for name, hash_, image in self.all_data["containers"][self.args.endpoint_id]: for name, hash_, image in self.all_data["containers"][self.args.endpoint_id]:
if name.startswith(service_dict[service_id]): if name.startswith(service_dict[service_id]):
print(image) print(image)
if len(updates) > 0:
if pull:
self.gotify_message(f"Services updated: {", ".join(updates)}")
else:
self.gotify_message(f"Services updates available: {', '.join(updates)}")
print("\033[?25h", end="") print("\033[?25h", end="")
return True return True
@@ -1352,4 +1358,5 @@ class Portainer:
path = f"/endpoints/{endpoint_id}/docker/secrets/create" path = f"/endpoints/{endpoint_id}/docker/secrets/create"
encoded = base64.b64encode(value.encode()).decode() encoded = base64.b64encode(value.encode()).decode()
data = {"Name": name, "Data": encoded} data = {"Name": name, "Data": encoded}
return self._api_post(path, data, timeout=timeout) return self._api_post(path, data, timeout=timeout)

View File

@@ -5,3 +5,4 @@ tabulate
flake8 flake8
pylint pylint
black black
docker