This commit is contained in:
2025-12-02 21:04:41 +01:00
parent c1fcb94962
commit c722b5f723
2 changed files with 296 additions and 237 deletions

88
port.py
View File

@@ -5,6 +5,9 @@ import uuid
import shutil import shutil
import time import time
import logging import logging
import base64
import tabulate
from git import Repo
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
@@ -185,8 +188,8 @@ class Portainer:
try: try:
webhooks[s['EndpointId']] = {"webhook": {}} webhooks[s['EndpointId']] = {"webhook": {}}
webhooks[self.endpoints["by_id"][s['EndpointId']]] = {"webhook": {}} webhooks[self.endpoints["by_id"][s['EndpointId']]] = {"webhook": {}}
except: except Exception as e:
pass logger.debug(f"Exception while getting webhooks for endpoint {s['EndpointId']}: {e}")
if not s['EndpointId'] in self.stacks_all: if not s['EndpointId'] in self.stacks_all:
self.stacks_all[s['EndpointId']] = {"by_id": {}, "by_name": {}} self.stacks_all[s['EndpointId']] = {"by_id": {}, "by_name": {}}
self.stacks_all[self.endpoints["by_id"][s['EndpointId']]] = {"by_id": {}, "by_name": {}} self.stacks_all[self.endpoints["by_id"][s['EndpointId']]] = {"by_id": {}, "by_name": {}}
@@ -198,7 +201,7 @@ class Portainer:
# print(s) # print(s)
if "AutoUpdate" in s and s["AutoUpdate"] is not None: if "AutoUpdate" in s and s["AutoUpdate"] is not None:
if type(s["AutoUpdate"]) == dict and "Webhook" in s["AutoUpdate"]: if type(s["AutoUpdate"]) is dict and "Webhook" in s["AutoUpdate"]:
# print(self.endpoints["by_id"][s['EndpointId']], s['Name'], s["AutoUpdate"]['Webhook']) # print(self.endpoints["by_id"][s['EndpointId']], s['Name'], s["AutoUpdate"]['Webhook'])
# print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") # print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW")
webhooks[s['EndpointId']][s['Name']] = s['AutoUpdate']['Webhook'] webhooks[s['EndpointId']][s['Name']] = s['AutoUpdate']['Webhook']
@@ -255,24 +258,25 @@ class Portainer:
cont = [] cont = []
data = {} data = {}
if endpoint == "all": if endpoint == "all":
for s in self.all_data["endpoints"]["by_id"]: for s in self.all_data["endpoints"]["by_id"]:
# print(s) # print(s)
if stack == "all": if stack == "all":
if not s in self.all_data["stacks"]: if s not in self.all_data["stacks"]:
continue continue
if self.all_data["endpoints_status"][s] != 1: if self.all_data["endpoints_status"][s] != 1:
# print(f"Endpoint {self.all_data["endpoints"]["by_id"][s]} is offline") # print(f"Endpoint {self.all_data["endpoints"]["by_id"][s]} is offline")
continue continue
for e in self.all_data["stacks"][s]["by_name"]: for e in self.all_data["stacks"][s]["by_name"]:
path = f"/endpoints/{s}/docker/containers/json?all=1&filters={{\"label\": [\"com.docker.compose.project={e}\"]}}" path = (
f"/endpoints/{s}/docker/containers/json"
f"?all=1&filters={{\"label\": [\"com.docker.compose.project={e}\"]}}"
)
logging.info(f"request : {path}") logging.info(f"request : {path}")
try: try:
containers = self.api_get(path) containers = self.api_get(path)
except: except Exception as e:
print(f"failed to get containers from {path}") print(f"failed to get containers from {path}: {e}")
continue continue
contr = [] contr = []
try: try:
for c in containers: for c in containers:
@@ -282,8 +286,11 @@ class Portainer:
data[self.all_data["endpoints"]["by_id"][s]][e] = contr data[self.all_data["endpoints"]["by_id"][s]][e] = contr
else: else:
data[self.all_data["endpoints"]["by_id"][s]] = {e: contr} data[self.all_data["endpoints"]["by_id"][s]] = {e: contr}
except: except Exception as e:
print("lalalal") logger.debug(
f"Exception while getting containers for stack {e} ",
f"on endpoint {self.all_data['endpoints']['by_id'][s]}: {e}"
)
# print(data) # print(data)
self.all_data["containers"] = data self.all_data["containers"] = data
else: else:
@@ -291,13 +298,13 @@ class Portainer:
for i in self.all_data["containers"][endpoint][stack]: for i in self.all_data["containers"][endpoint][stack]:
cont.append(i) cont.append(i)
return cont return cont
def stop_containers(self, endpoint, containers, timeout=130): def stop_containers(self, endpoint, containers, timeout=130):
if self.all_data["endpoints_status"][endpoint] != 1: if self.all_data["endpoints_status"][endpoint] != 1:
print(f"Endpoint {self.get_endpoint_name(endpoint)} is offline") print(f"Endpoint {self.get_endpoint_name(endpoint)} is offline")
ep_id = self.endpoints["by_name"][endpoint] ep_id = self.endpoints["by_name"][endpoint]
def stop(c): def stop(c):
print(f" > Stopping {c}") print(f" > Stopping {c}")
self.api_post_no_body( self.api_post_no_body(
@@ -309,12 +316,11 @@ class Portainer:
# for c in containers: # for c in containers:
# print(f" > Stopping {c}") # print(f" > Stopping {c}")
# self.api_post_no_body(f"/endpoints/{self.endpoints["by_name"][endpoint]}/docker/containers/{c}/stop") # self.api_post_no_body(f"/endpoints/{self.endpoints["by_name"][endpoint]}/docker/containers/{c}/stop")
# return 0 # return 0
def start_containers(self, endpoint, containers, timeout=130): def start_containers(self, endpoint, containers, timeout=130):
ep_id = self.endpoints["by_name"][endpoint] ep_id = self.endpoints["by_name"][endpoint]
def stop(c): def stop(c):
print(f" > Starting {c}") print(f" > Starting {c}")
self.api_post_no_body( self.api_post_no_body(
@@ -337,6 +343,8 @@ class Portainer:
ans = self.api_post_no_body( ans = self.api_post_no_body(
f"/stacks/webhooks/{c[1]}" f"/stacks/webhooks/{c[1]}"
) )
logger.debug(f"Update response for stack {c[0]} on endpoint {endpoint}: {ans}")
def stop(): def stop():
cont = [] cont = []
for c in self.all_data["containers"][endpoint]: for c in self.all_data["containers"][endpoint]:
@@ -390,7 +398,6 @@ class Portainer:
def get_stack(self, stack=None, endpoint_id=None, timeout=None): def get_stack(self, stack=None, endpoint_id=None, timeout=None):
self.get_stacks(endpoint_id) self.get_stacks(endpoint_id)
if not self.is_number(endpoint_id): if not self.is_number(endpoint_id):
endpoint_id = int(self.endpoints["by_name"][endpoint_id]) endpoint_id = int(self.endpoints["by_name"][endpoint_id])
self.stack_id = [] self.stack_id = []
@@ -403,11 +410,25 @@ class Portainer:
else: else:
for s in self.stacks: for s in self.stacks:
# print(s) # print(s)
if (stack is not None and s.get("Id") == stack and endpoint_id == s.get("EndpointId")) or str(s.get("Name")) == str(stack) and endpoint_id == int(s.get("EndpointId")): match_by_id = (
stack is not None
and s.get("Id") == stack
and endpoint_id == s.get("EndpointId")
)
match_by_name = (
str(s.get("Name")) == str(stack)
and endpoint_id == int(s.get("EndpointId")) # Ensure types match for comparison
)
if match_by_id or match_by_name:
# if (stack is not None and s.get("Id") == stack and endpoint_id == s.get("EndpointId"))
# or str(s.get("Name")) == str(stack) and endpoint_id == int(s.get("EndpointId")):
self.stack_id = s.get("Id") self.stack_id = s.get("Id")
self.stack_name = s.get("Name") self.stack_name = s.get("Name")
self.stack_ids.append(s.get("Id")) self.stack_ids.append(s.get("Id"))
return s return s
raise ValueError(f"Stack not found: {stack}") raise ValueError(f"Stack not found: {stack}")
def create_stack(self, endpoint, stack=None, mode="git", autostart=False, swarm=False, timeout=None): def create_stack(self, endpoint, stack=None, mode="git", autostart=False, swarm=False, timeout=None):
@@ -427,11 +448,9 @@ class Portainer:
Repo.clone_from(self.git_url, self.repo_dir) Repo.clone_from(self.git_url, self.repo_dir)
if mode == "git": if mode == "git":
path = f"/stacks/create/{p}/repository" path = f"/stacks/create/{p}/repository"
if self.endpoint_id is not None: if self.endpoint_id is not None:
path += f"?endpointId={self.endpoint_id}" path += f"?endpointId={self.endpoint_id}"
if stack == "all": if stack == "all":
if self.endpoint_name == "rack": if self.endpoint_name == "rack":
stacks = self.rack_stacks stacks = self.rack_stacks
@@ -447,17 +466,21 @@ class Portainer:
# input(json.dumps(self.stacks_all, indent=2)) # input(json.dumps(self.stacks_all, indent=2))
for stack in stacks: for stack in stacks:
if self.endpoint_id in self.stacks_all: if self.endpoint_id in self.stacks_all:
if stack in self.stacks_all[self.endpoint_id]['by_id'] or stack in self.stacks_all[self.endpoint_id]['by_name']:
# Check if the stack exists by ID or name
stack_check = (
stack in self.stacks_all[self.endpoint_id]['by_id']
or stack in self.stacks_all[self.endpoint_id]['by_name']
)
if stack_check:
print(f"Stack {stack} already exist") print(f"Stack {stack} already exist")
continue continue
print(f"Working on {stack}") print(f"Working on {stack}")
envs = [] envs = []
if os.path.exists(f"{env_path}"): if os.path.exists(f"{env_path}"):
f = open(f"{env_path}", "r") f = open(f"{env_path}", "r")
env_vars = f.read().splitlines() env_vars = f.read().splitlines()
for ev in env_vars: for ev in env_vars:
if ev.startswith("#") or ev.strip() == "": if ev.startswith("#") or ev.strip() == "":
continue continue
@@ -484,9 +507,6 @@ class Portainer:
else: else:
e['value'] = "syslog" e['value'] = "syslog"
uid = uuid.uuid4() uid = uuid.uuid4()
# print(uid) # print(uid)
req = { req = {
@@ -540,7 +560,7 @@ class Portainer:
try: try:
# print(self.endpoint_id) # print(self.endpoint_id)
# print(stack) # print(stack)
stck2 = self.get_stack(stack, self.endpoint_id) self.get_stack(stack, self.endpoint_id)
created = True created = True
break break
except Exception as e: except Exception as e:
@@ -550,6 +570,7 @@ class Portainer:
if tries > 50: if tries > 50:
print(f"Error retrieving stack {stack} after creation: {self.endpoint_name}") print(f"Error retrieving stack {stack} after creation: {self.endpoint_name}")
break break
logger.debug(f"Exception while getting stack {stack}: {e}")
if created: if created:
if stack != "pihole": if stack != "pihole":
@@ -618,10 +639,9 @@ class Portainer:
def print_stacks(self, endpoint="all"): def print_stacks(self, endpoint="all"):
stacks = self.get_stacks() stacks = self.get_stacks()
count = 0 count = 0
lst = []
data = [] data = []
for stack in stacks: for stack in stacks:
if endpoint != None: if endpoint is not None:
if not stack['EndpointId'] in self.endpoints['by_id']: if not stack['EndpointId'] in self.endpoints['by_id']:
continue continue
if endpoint != "all": if endpoint != "all":
@@ -631,6 +651,7 @@ class Portainer:
data.append([stack['Id'], stack['Name'], self.endpoints['by_id'][stack['EndpointId']]]) data.append([stack['Id'], stack['Name'], self.endpoints['by_id'][stack['EndpointId']]])
except KeyError as e: except KeyError as e:
data.append([stack['Id'], stack['Name'], "?"]) data.append([stack['Id'], stack['Name'], "?"])
logger.debug(f"KeyError getting endpoint name for stack {stack['Name']}: {e}")
count += 1 count += 1
headers = ["StackID", "Name", "Endpoint"] headers = ["StackID", "Name", "Endpoint"]
@@ -638,10 +659,10 @@ class Portainer:
print(f"Total stacks: {count}") print(f"Total stacks: {count}")
def start_stack(self, stack=None, endpoint_id=None): def start_stack(self, stack=None, endpoint_id=None):
if endpoint_id != None: if endpoint_id is not None:
print("Getting endpoint") print("Getting endpoint")
self.get_endpoint(endpoint_id) self.get_endpoint(endpoint_id)
if stack != None: if stack is not None:
self.get_stack(stack, endpoint_id) self.get_stack(stack, endpoint_id)
for stack in self.stack_ids: for stack in self.stack_ids:
path = f"/stacks/{stack}/start" path = f"/stacks/{stack}/start"
@@ -660,12 +681,12 @@ class Portainer:
def stop_stack(self, stack, endpoint_id): def stop_stack(self, stack, endpoint_id):
print(f"Stopping stack {stack}") print(f"Stopping stack {stack}")
if endpoint_id != None: if endpoint_id is not None:
self.get_endpoint(endpoint_id) self.get_endpoint(endpoint_id)
if stack == "all": if stack == "all":
self.get_stack(stack, endpoint_id) self.get_stack(stack, endpoint_id)
else: else:
if stack != None: if stack is not None:
self.stack_ids = [self.get_stack(stack, endpoint_id)["Id"]] self.stack_ids = [self.get_stack(stack, endpoint_id)["Id"]]
for stack in self.stack_ids: for stack in self.stack_ids:
path = f"/stacks/{stack}/stop" path = f"/stacks/{stack}/stop"
@@ -674,7 +695,7 @@ class Portainer:
try: try:
resp = self.api_post_no_body(path, timeout=120) resp = self.api_post_no_body(path, timeout=120)
except NameError as e: except NameError as e:
print(f"Error stoping stack: {e}") print(f"Error stopping stack: {e}")
return [] return []
if "Id" in json.loads(resp): if "Id" in json.loads(resp):
print(f"Stack {self.stacks_all[self.endpoint_id]['by_id'][stack]} : stopped") print(f"Stack {self.stacks_all[self.endpoint_id]['by_id'][stack]} : stopped")
@@ -694,7 +715,6 @@ class Portainer:
self.endpoint_name = endpoint_id self.endpoint_name = endpoint_id
self.endpoint_id = self.endpoints["by_name"][endpoint_id] self.endpoint_id = self.endpoints["by_name"][endpoint_id]
if not self.is_number(endpoint_id): if not self.is_number(endpoint_id):
endpoint_id = int(self.endpoints["by_name"][endpoint_id]) endpoint_id = int(self.endpoints["by_name"][endpoint_id])
@@ -716,9 +736,11 @@ class Portainer:
path += f"?endpointId={endpoint_id}&removeVolumes=true" path += f"?endpointId={endpoint_id}&removeVolumes=true"
paths.append([self.get_endpoint_name(endpoint_id), s['Name'], path]) paths.append([self.get_endpoint_name(endpoint_id), s['Name'], path])
# input(paths) # input(paths)
def delete(c): def delete(c):
print(f"Delete stack {c[1]} from {c[0]} ") print(f"Delete stack {c[1]} from {c[0]} ")
out = self.api_delete(c[2]) out = self.api_delete(c[2])
logger.debug(f"Deleted stack {c[1]} from {c[0]}: {out}")
with ThreadPoolExecutor(max_workers=10) as exe: with ThreadPoolExecutor(max_workers=10) as exe:
exe.map(delete, paths) exe.map(delete, paths)

View File

@@ -3,12 +3,8 @@ import os
import sys import sys
import requests import requests
import json import json
import uuid
import argparse import argparse
import shutil
import time
from tabulate import tabulate from tabulate import tabulate
from git import Repo # pip install gitpython
from port import Portainer from port import Portainer
import logging import logging
VERSION = "0.0.1" VERSION = "0.0.1"
@@ -24,8 +20,11 @@ defaults = {
parser = argparse.ArgumentParser(description="Portainer helper - use env vars or pass credentials.") parser = argparse.ArgumentParser(description="Portainer helper - use env vars or pass credentials.")
parser.add_argument("--base", "-b", default=os.getenv("PORTAINER_URL", \ parser.add_argument("--base",
"https://portainer.example.com"),help="Base URL for Portainer (ENV: PORTAINER_URL)") "-b",
default=os.getenv("PORTAINER_URL", "https://portainer.example.com"),
help="Base URL for Portainer (ENV: PORTAINER_URL)"
)
parser.add_argument("--site", "-t", type=str, default=None, help="Site") parser.add_argument("--site", "-t", type=str, default=None, help="Site")
parser.add_argument("--endpoint-id", "-e", type=str, default=None, help="Endpoint ID to limit stack operations") parser.add_argument("--endpoint-id", "-e", type=str, default=None, help="Endpoint ID to limit stack operations")
parser.add_argument("--refresh-environment", "-R", action="store_true", help="List endpoints") parser.add_argument("--refresh-environment", "-R", action="store_true", help="List endpoints")
@@ -33,9 +32,9 @@ parser.add_argument("--list-endpoints","-E", action="store_true", help="List end
parser.add_argument("--list-stacks", "-l", action="store_true", help="List stacks") parser.add_argument("--list-stacks", "-l", action="store_true", help="List stacks")
parser.add_argument("--print-all-data", "-A", action="store_true", help="List stacks") parser.add_argument("--print-all-data", "-A", action="store_true", help="List stacks")
parser.add_argument("--list-containers", "-c", action="store_true", help="List containers") parser.add_argument("--list-containers", "-c", action="store_true", help="List containers")
parser.add_argument("--update-stack", "-U", action="store_true", help="Update stacls") parser.add_argument("--update-stack", "-U", action="store_true", help="Update stacks")
parser.add_argument("--stop-containers", "-O", action="store_true", help="Stop containers") parser.add_argument("--stop-containers", "-O", action="store_true", help="Stop containers")
parser.add_argument("--start-containers", "-X", action="store_true", help="Stop containers") parser.add_argument("--start-containers", "-X", action="store_true", help="Start containers")
parser.add_argument("--update-status", "-S", action="store_true", help="Update status") parser.add_argument("--update-status", "-S", action="store_true", help="Update status")
parser.add_argument("--get-stack", metavar="NAME_OR_ID", help="Get stack by name or numeric id") parser.add_argument("--get-stack", metavar="NAME_OR_ID", help="Get stack by name or numeric id")
parser.add_argument("--action", "-a", type=str, default=None, help="Action to perform") parser.add_argument("--action", "-a", type=str, default=None, help="Action to perform")
@@ -62,16 +61,36 @@ print("Environment:", args.site)
_LOG_LEVEL = "INFO" _LOG_LEVEL = "INFO"
LOG_FILE = "/tmp/portainer.log" LOG_FILE = "/tmp/portainer.log"
if _LOG_LEVEL == "DEBUG": if _LOG_LEVEL == "DEBUG":
logging.basicConfig(filename=LOG_FILE, level=logging.DEBUG, format='%(asctime)s : %(levelname)s : %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') logging.basicConfig(
logging.debug('using debug loging') filename=LOG_FILE,
level=logging.DEBUG,
format='%(asctime)s : %(levelname)s : %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p'
)
logging.debug('using debug logging')
elif _LOG_LEVEL == "ERROR": elif _LOG_LEVEL == "ERROR":
logging.basicConfig(filename=LOG_FILE, level=logging.ERROR, format='%(asctime)s : %(levelname)s : %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') logging.basicConfig(
logging.info('using error loging') filename=LOG_FILE,
level=logging.ERROR,
format='%(asctime)s : %(levelname)s : %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p'
)
logging.info('using error logging')
elif _LOG_LEVEL == "SCAN": elif _LOG_LEVEL == "SCAN":
logging.basicConfig(filename=LOG_FILE, level=logging.DEBUG, format='%(asctime)s : %(levelname)s : %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') logging.basicConfig(
logging.info('using error loging') filename=LOG_FILE,
level=logging.DEBUG,
format='%(asctime)s : %(levelname)s : %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p'
)
logging.info('using scan logging')
else: else:
logging.basicConfig(filename=LOG_FILE, level=logging.INFO, format='%(asctime)s : %(levelname)s : %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format='%(asctime)s : %(levelname)s : %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p'
)
logging.info("script started") logging.info("script started")
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -83,9 +102,12 @@ else:
base = os.getenv("PORTAINER_URL", "https://port.sectorq.eu/api") base = os.getenv("PORTAINER_URL", "https://port.sectorq.eu/api")
portainer_api_key = "ptr_/5RkMCT/j3BTaL32vMSDtXFi76yOXRKVFOrUtzMsl5Y=" portainer_api_key = "ptr_/5RkMCT/j3BTaL32vMSDtXFi76yOXRKVFOrUtzMsl5Y="
def wl(msg): def wl(msg):
if args.debug: if args.debug:
print(msg) print(msg)
def is_number(s): def is_number(s):
"""Check if the input string is a number.""" """Check if the input string is a number."""
try: try:
@@ -95,7 +117,6 @@ def is_number(s):
return False return False
def get_portainer_token(base_url, username=None, password=None, timeout=10): def get_portainer_token(base_url, username=None, password=None, timeout=10):
""" """
Authenticate to Portainer and return a JWT token. Authenticate to Portainer and return a JWT token.
@@ -114,6 +135,8 @@ def get_portainer_token(base_url, username=None, password=None, timeout=10):
if not token: if not token:
raise ValueError(f"No token found in response: {data}") raise ValueError(f"No token found in response: {data}")
return token return token
def prompt_missing_args(args, defaults, fields): def prompt_missing_args(args, defaults, fields):
""" """
fields = [("arg_name", "Prompt text")] fields = [("arg_name", "Prompt text")]
@@ -132,11 +155,27 @@ def prompt_missing_args(args, defaults, fields):
setattr(args, field, value) setattr(args, field, value)
return args return args
if __name__ == "__main__": if __name__ == "__main__":
# Example usage: set PORTAINER_USER and PORTAINER_PASS in env, or pass literals below. # Example usage: set PORTAINER_USER and PORTAINER_PASS in env, or pass literals below.
# token = get_portainer_token(base,"admin","l4c1j4yd33Du5lo") # or get_portainer_token(base, "admin", "secret") # token = get_portainer_token(base,"admin","l4c1j4yd33Du5lo") # or get_portainer_token(base, "admin", "secret")
if args.action == None: if args.action is None:
actions = ["delete_stack","create_stack","stop_stack","start_stack","list_stacks","update_stack","secrets","print_all_data","list_endpoints","list_containers","stop_containers","start_containers","refresh_environment","refresh_status","update_status"] actions = ["delete_stack",
"create_stack",
"stop_stack",
"start_stack",
"list_stacks",
"update_stack",
"secrets",
"print_all_data",
"list_endpoints",
"list_containers",
"stop_containers",
"start_containers",
"refresh_environment",
"refresh_status",
"update_status"]
print("Possible actions: ") print("Possible actions: ")
i = 1 i = 1
for a in actions: for a in actions:
@@ -150,7 +189,7 @@ if __name__ == "__main__":
por = Portainer(base, token) por = Portainer(base, token)
if args.action == "secrets": if args.action == "secrets":
if args.endpoint_id == None: if args.endpoint_id is None:
args.endpoint_id = input("Endpoint ID is required for creating secrets : ") args.endpoint_id = input("Endpoint ID is required for creating secrets : ")
secrets = { secrets = {
@@ -182,23 +221,21 @@ if __name__ == "__main__":
("stack_mode", "Stack mode (swarm or compose)"), ("stack_mode", "Stack mode (swarm or compose)"),
("deploy_mode", "Deploy mode (git or upload)") ("deploy_mode", "Deploy mode (git or upload)")
]) ])
por.create_stack(args.endpoint_id, args.stack, args.deploy_mode, args.autostart, args.stack_mode) por.create_stack(args.endpoint_id, args.stack, args.deploy_mode, args.autostart, args.stack_mode)
sys.exit() sys.exit()
if args.action == "stop_stack": if args.action == "stop_stack":
if args.endpoint_id == None: if args.endpoint_id is None:
args.endpoint_id = input("Endpoint ID is required for stopping stacks : ") args.endpoint_id = input("Endpoint ID is required for stopping stacks : ")
if args.stack == None: if args.stack is None:
args.stack = input("Stack name or ID is required for stopping stacks : ") args.stack = input("Stack name or ID is required for stopping stacks : ")
por.stop_stack(args.stack, args.endpoint_id) por.stop_stack(args.stack, args.endpoint_id)
sys.exit() sys.exit()
if args.action == "start_stack": if args.action == "start_stack":
if args.endpoint_id == None: if args.endpoint_id is None:
args.endpoint_id = input("Endpoint ID is required for starting stacks : ") args.endpoint_id = input("Endpoint ID is required for starting stacks : ")
if args.stack == None: if args.stack is None:
args.stack = input("Stack name or ID is required for starting stacks : ") args.stack = input("Stack name or ID is required for starting stacks : ")
por.start_stack(args.stack, args.endpoint_id) por.start_stack(args.stack, args.endpoint_id)
sys.exit() sys.exit()