Archived
0
This repository has been archived on 2022-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
Files
project-ctl/ctl.py
dedic-one e9fbcbed90 update
2022-02-17 19:50:42 +03:00

242 lines
5.6 KiB
Python
Executable File

#!/usr/bin/python3
# vi: ts=2 sw=2 et :
## Dependencies
# pip install pyhocon
# - https://github.com/chimpler/pyhocon
from pyhocon import ConfigFactory
from subprocess import Popen, PIPE, STDOUT
import subprocess
import sys
import os
import pty
def di_syscall(cmd, workdir='.'):
#print('[dbg] CMD: %s | WD: %s' % (cmd, workdir))
process = subprocess.run(cmd, capture_output=True, cwd=workdir)
return (process.stdout.decode("utf-8").strip(), process.stderr.decode("utf-8").strip())
def di_syscall_follow(cmd):
#print('[dbg] CMD: %s' % (cmd))
process = Popen(cmd, stdout=PIPE, stderr=STDOUT)
try:
while True:
line = process.stdout.readline()
if not line:
break
else:
print(line.decode('utf-8').strip())
except KeyboardInterrupt:
print('')
def di_syscall_interactive(cmd):
#print('[dbg] CMD: %s' % (cmd))
pty.spawn(cmd)
def print_help_exit():
print('Use: [container.conf] command')
exit()
def create_default_config():
conf_d = {}
conf_d['shell'] = 'sh'
conf_d['upd-sig'] = 'HUP'
return ConfigFactory.from_dict(conf_d)
def get_config(path):
if os.path.isfile(path):
conf = ConfigFactory.parse_file(path)
return conf
else:
return None
def create_example_config():
conf_raw = """{
# Container name
name: example--config
# Name container in log/output/console
title: Example Config
# Image container
image: hello-world:linux
# (optional) Shell command for container
shell: sh
# (optional) Signal for update configuration in container
upd-sig: HUP
# (optional) Arguments|Params for containered application
cmd: [
--arg_key
value
]
# (optional) Ports
ports: [
0.0.0.0:8080:80
]
# (optional) Volumes
volumes: [
/etc/timezone:/etc/timezone:ro
/etc/localtime:/etc/localtime:ro
]
# (optional) Environment
env: {
ENV_KEY: value
}
}"""
fd = open('./container.conf', 'w')
fd.write(conf_raw)
fd.close()
# -------------------------- #
class Container:
def __init__(self, conf, workdir):
self.conf = conf
self.workdir = workdir
def status(self):
self.__require_exists()
if self.is_run():
print('%s running' % (self.conf['title']))
else:
print('%s container down' % (self.conf['title']))
out, err = di_syscall(['podman', 'logs', '--tail', '5', self.conf['name']])
if err: print(err)
else: print(out)
def start(self):
if not self.is_run():
cmd = ['podman', 'run', '-d', '--name', self.conf['name']]
for volume in self.conf['volumes']:
cmd.append('--volume')
cmd.append(volume)
for publish in self.conf['ports']:
cmd.append('--publish')
cmd.append(publish)
if self.conf.get('env', None) is not None:
for env_name in self.conf['env'].keys():
cmd.append('--env')
cmd.append('%s=%s' % (env_name, self.conf['env'][env_name]))
cmd.append(self.conf['image'])
if self.conf.get('cmd', None) is not None:
for arg in self.conf['cmd']:
cmd.append('%s' % arg)
container_id, err = di_syscall(cmd, self.workdir)
if err:
print('ERROR')
print(err)
else:
print('Container %s started [%s]' % (self.conf['title'], container_id))
else:
print('%s is runned' % self.conf['title'])
def stop(self):
self.__require_exists()
if self.is_run():
print('Stop %s container...' % (self.conf['title']))
cid, err = di_syscall(['podman', 'stop', self.conf['name']])
if err:
print(err)
print('Remove %s container...' % (self.conf['title']))
cid, err = di_syscall(['podman', 'rm', self.conf['name']])
if err:
print(err)
def logs(self):
self.__require_exists()
di_syscall_follow(['podman', 'logs', '--tail', '10', '-f', self.conf['name']])
def shell(self):
self.__require_run()
print('Enter shell in %s container...' % self.conf['title'])
di_syscall_interactive(['podman', 'exec', '-it', self.conf['name'], self.conf['shell']])
def update(self):
self.__require_run()
print('Update config %s...' % self.conf['title'])
di_syscall(['podman', 'kill', '--signal=%s' % self.conf['upg-sig'], self.conf['name']])
def is_run(self):
return len(di_syscall(['podman', 'ps', '--filter', 'name=%s' % (self.conf['name']), '-q'])[0]) > 0
def is_exists(self):
return len(di_syscall(['podman', 'ps', '--filter', 'name=%s' % (self.conf['name']), '-qa'])[0]) > 0
def __require_run(self):
if not self.is_run():
print('%s not runned' % self.conf['title'])
exit()
def __require_exists(self):
if not self.is_exists():
print('%s not exists' % self.conf['title'])
exit()
# -------------------------- #
if len(sys.argv) == 1:
print_help_exit()
if sys.argv[1] == 'init':
print('Create example config')
create_example_config()
exit()
conf = None
begin_index_commands = None
workdir = None
if os.path.isfile(sys.argv[1]):
conf = get_config(sys.argv[1])
begin_index_commands = 2
workdir = os.path.dirname(sys.argv[1])
if len(workdir) == 0: workdir = '.'
else:
conf = get_config('container.conf')
begin_index_commands = 1
workdir = '.'
if conf is None:
print_help_exit()
conf = conf.with_fallback(create_default_config())
container = Container(conf, workdir)
command = sys.argv[begin_index_commands]
if command == 'start':
container.start()
elif command == 'status':
container.status()
elif command == 'stop':
container.stop()
elif command == 'logs':
container.logs()
elif command == 'restart':
container.stop()
container.start()
elif command == 'shell':
container.shell()
elif command == 'update':
container.update()
else:
print_help_exit()