scale-catalog/trueupdate/__init__.py

147 lines
5.2 KiB
Python
Raw Normal View History

2022-01-16 14:42:56 +00:00
import subprocess
import sys
import argparse
import time
2022-01-16 14:42:56 +00:00
class Chart(object):
def __setattr__(self, name, value):
if name == 'status':
value = value.casefold()
if 'update_available' in name:
value = True if value.casefold() == "true" else False
super(Chart, self).__setattr__(name, value)
def new_attr(self, attr):
setattr(self, attr, attr)
INSTALLED_CHARTS = []
def parse_headers(charts: str):
for line in charts.split("\n"):
if line.startswith("+-"):
continue
if "name" in line.casefold():
return [col.strip() for col in line.casefold().strip().split("|") if col and col != ""]
def parse_charts(charts: str):
headers = parse_headers(charts)
table_data = charts.split("\n")[3:-2:] # Skip the header part of the table
for row in table_data:
row = [section.strip() for section in row.split("|") if section and section != ""]
chart = Chart()
for item in zip(headers, row):
setattr(chart, item[0], item[1])
INSTALLED_CHARTS.append(chart)
def check_semver(current: str, latest: str):
split_current_semver = current.split(".", 3)
split_latest_semver = latest.split(".", 3)
if split_current_semver[0] != split_latest_semver[0]:
type="major"
if VERSIONING == "major":
2022-01-16 14:42:56 +00:00
return True
if split_current_semver[1] != split_latest_semver[1]:
type="minor"
if VERSIONING != "patch":
2022-01-16 14:42:56 +00:00
return True
if split_current_semver[2] != split_latest_semver[2]:
type="patch"
return True
return False
def execute_upgrades():
2022-01-19 19:41:43 +00:00
if ACTIVE:
if CATALOG == "ALL":
filtered = filter(lambda a: a.update_available and a.status == "active", INSTALLED_CHARTS)
else:
filtered = filter(lambda a: a.update_available and a.status == "active" and a.catalog == CATALOG, INSTALLED_CHARTS)
2022-01-16 14:42:56 +00:00
else:
2022-01-19 19:41:43 +00:00
if CATALOG == "ALL":
filtered = filter(lambda a: a.update_available, INSTALLED_CHARTS)
else:
filtered = filter(lambda a: a.update_available and a.catalog == CATALOG, INSTALLED_CHARTS)
2022-01-16 14:42:56 +00:00
for chart in filtered:
pre_update_ver = chart.human_version
post_update_ver = chart.human_latest_version
split_current_version = chart.human_version.split("_", 1)
current_version = split_current_version[1]
split_latest = chart.human_latest_version.split("_", 1)
latest_version = split_latest[1]
if check_semver(current_version, latest_version):
print(f"Updating {chart.name}... \n")
2022-01-18 22:57:15 +00:00
pre_update_ver = chart.human_version
2022-01-19 16:59:00 +00:00
result = subprocess.run(['cli', '-c', f'app chart_release upgrade release_name="{chart.name}"'], capture_output=True)
2022-01-18 22:57:15 +00:00
post_update_ver = chart.human_latest_version
if "Upgrade complete" not in result.stdout.decode('utf-8'):
print(f"{chart.name} failed to upgrade. \n{result.stdout.decode('utf-8')}")
else:
print(f"{chart.name} upgraded ({pre_update_ver} --> {post_update_ver})")
2022-01-16 14:42:56 +00:00
def fetch_charts():
rawcharts = subprocess.run(["cli", "-c", "app chart_release query"], stdout=subprocess.PIPE)
charts = rawcharts.stdout.decode('utf-8')
return(charts)
def process_args():
global CATALOG
2022-01-19 17:34:20 +00:00
global VERSIONING
global SYNC
global PRUNE
2022-01-19 19:41:43 +00:00
global ACTIVE
parser = argparse.ArgumentParser(description='Update TrueNAS SCALE Apps')
parser.add_argument('--catalog', nargs='?', default='ALL', help='name of the catalog you want to process in caps. Or "ALL" to render all catalogs.')
parser.add_argument('--versioning', nargs='?', default='minor', help='Name of the versioning scheme you want to update. Options: major, minor or patch. Defaults to minor')
parser.add_argument('-s', '--sync', action="store_true", help='sync catalogs before trying to update')
parser.add_argument('-p', '--prune', action="store_true", help='prune old docker images after update')
2022-01-19 19:41:43 +00:00
parser.add_argument('-a', '--active', action="store_true", help='update "active" apps only and ignore "stopped" or "stuck" apps')
args = parser.parse_args()
CATALOG = args.catalog
VERSIONING = args.versioning
if args.sync:
SYNC = True
2022-01-18 23:03:23 +00:00
else:
SYNC = False
if args.prune:
PRUNE = True
else:
PRUNE = False
2022-01-19 19:41:43 +00:00
if args.active:
ACTIVE = True
else:
ACTIVE = False
def sync_catalog():
if SYNC:
print("Syncing Catalogs...\n")
process = subprocess.Popen(["cli", "-c", "app catalog sync_all"], stdout=subprocess.PIPE)
while process.poll() is None:
lines = process.stdout.readline()
2022-01-19 19:34:56 +00:00
print (lines.decode('utf-8'))
temp = process.stdout.read()
if temp:
print (temp.decode('utf-8'))
def docker_prune():
if PRUNE:
print("Pruning old docker images...\n")
2022-01-19 17:59:44 +00:00
process = subprocess.Popen(["docker", "image", "prune", "-af"], stdout=subprocess.PIPE)
2022-01-19 18:12:29 +00:00
print("Images pruned.\n")
2022-01-16 15:07:36 +00:00
def run():
process_args()
print("Starting TrueCharts App updater...\n")
sync_catalog()
2022-01-16 14:59:43 +00:00
charts = fetch_charts()
parse_charts(charts)
print("Executing Updates...\n")
2022-01-16 14:59:43 +00:00
execute_upgrades()
print("Updating Finished\n")
2022-01-19 17:32:38 +00:00
docker_prune()
exit(0)
2022-01-16 14:42:56 +00:00
if __name__ == '__main__':
2022-01-16 14:59:43 +00:00
run()