YML executable paths, "logs" subcommand
This commit is contained in:
parent
1214137005
commit
3e1d9510dc
14 changed files with 182 additions and 46 deletions
1
example/Makefile
Symbolic link
1
example/Makefile
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
|
@ -2,6 +2,6 @@ export SUFFIX_PROJECT=.project
|
||||||
export SUFFIX_DOWN=.down
|
export SUFFIX_DOWN=.down
|
||||||
|
|
||||||
export DOCKERNET=kiwinet
|
export DOCKERNET=kiwinet
|
||||||
export DOCKERCIDR=10.13.37.0/24
|
export DOCKERCIDR=10.22.46.0/24
|
||||||
|
|
||||||
export TARGETROOT=/var/kiwi
|
export TARGETROOT=/var/kiwi
|
15
example/hello-world.project/docker-compose.yml
Normal file
15
example/hello-world.project/docker-compose.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
version: "2"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
# reachable from outside
|
||||||
|
default:
|
||||||
|
driver: bridge
|
||||||
|
# interconnects projects
|
||||||
|
kiwihub:
|
||||||
|
external:
|
||||||
|
name: $DOCKERNET
|
||||||
|
|
||||||
|
services:
|
||||||
|
hello-world:
|
||||||
|
image: alpine:latest
|
||||||
|
command: sh -c 'while :; do echo Hello World; sleep 10; done'
|
22
example/kiwi.yml
Normal file
22
example/kiwi.yml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
######################################
|
||||||
|
# kiwi-config instance configuration #
|
||||||
|
######################################
|
||||||
|
|
||||||
|
version: '0.1'
|
||||||
|
|
||||||
|
runtime:
|
||||||
|
storage: /var/kiwi
|
||||||
|
env: null
|
||||||
|
|
||||||
|
markers:
|
||||||
|
project: .project
|
||||||
|
down: .down
|
||||||
|
|
||||||
|
network:
|
||||||
|
name: kiwinet
|
||||||
|
cidr: 10.22.46.0/24
|
||||||
|
|
||||||
|
executables:
|
||||||
|
docker: /usr/bin/docker
|
||||||
|
docker-compose: /usr/local/bin/docker-compose
|
||||||
|
sudo: /usr/bin/sudo
|
1
kiwi.yml
1
kiwi.yml
|
@ -1 +0,0 @@
|
||||||
version: '0.1'
|
|
|
@ -2,12 +2,16 @@
|
||||||
# kiwi-config instance configuration #
|
# kiwi-config instance configuration #
|
||||||
######################################
|
######################################
|
||||||
version:
|
version:
|
||||||
|
runtime:
|
||||||
|
storage: /var/kiwi
|
||||||
|
env: null
|
||||||
markers:
|
markers:
|
||||||
project: .project
|
project: .project
|
||||||
down: .down
|
down: .down
|
||||||
network:
|
network:
|
||||||
name: kiwinet
|
name: kiwinet
|
||||||
cidr: 10.22.46.0/24
|
cidr: 10.22.46.0/24
|
||||||
runtime:
|
executables:
|
||||||
storage: /var/kiwi
|
docker: null
|
||||||
env: null
|
docker-compose: null
|
||||||
|
sudo: null
|
||||||
|
|
|
@ -9,6 +9,7 @@ from .core import KIWI_ROOT, KIWI_CONF_NAME
|
||||||
# CONSTANTS
|
# CONSTANTS
|
||||||
|
|
||||||
DEFAULT_KIWI_CONF_NAME = KIWI_ROOT + "/default.kiwi.yml"
|
DEFAULT_KIWI_CONF_NAME = KIWI_ROOT + "/default.kiwi.yml"
|
||||||
|
VERSION_TAG_NAME = KIWI_ROOT + "/version-tag"
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
@ -49,35 +50,39 @@ class Config:
|
||||||
|
|
||||||
return yml_string
|
return yml_string
|
||||||
|
|
||||||
def __update_from_file(self, filename):
|
def _update_from_file(self, filename):
|
||||||
with open(filename, 'r') as stream:
|
with open(filename, 'r') as stream:
|
||||||
try:
|
try:
|
||||||
self.__yml_content.update(yaml.safe_load(stream))
|
self.__yml_content.update(yaml.safe_load(stream))
|
||||||
except yaml.YAMLError as exc:
|
except yaml.YAMLError as exc:
|
||||||
logging.error(exc)
|
logging.error(exc)
|
||||||
|
|
||||||
def __save_to_file(self, filename):
|
def save(self):
|
||||||
with open(filename, 'w') as stream:
|
with open(KIWI_CONF_NAME, 'w') as stream:
|
||||||
stream.write(str(self))
|
stream.write(str(self))
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def default(cls):
|
|
||||||
result = cls()
|
|
||||||
result.__update_from_file(DEFAULT_KIWI_CONF_NAME)
|
|
||||||
|
|
||||||
with open(KIWI_ROOT + "/version-tag", 'r') as stream:
|
class DefaultConfig(Config):
|
||||||
result.__yml_content["version"] = stream.read().strip()
|
__instance = None
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def get(cls):
|
||||||
result = cls.default()
|
if cls.__instance is None:
|
||||||
|
cls.__instance = cls()
|
||||||
|
cls.__instance._update_from_file(DEFAULT_KIWI_CONF_NAME)
|
||||||
|
|
||||||
|
with open(VERSION_TAG_NAME, 'r') as stream:
|
||||||
|
cls.__instance["version"] = stream.read().strip()
|
||||||
|
|
||||||
|
return cls.__instance
|
||||||
|
|
||||||
|
|
||||||
|
class LoadedConfig(Config):
|
||||||
|
@classmethod
|
||||||
|
def get(cls):
|
||||||
|
result = DefaultConfig.get()
|
||||||
|
|
||||||
if os.path.isfile(KIWI_CONF_NAME):
|
if os.path.isfile(KIWI_CONF_NAME):
|
||||||
result.__update_from_file(KIWI_CONF_NAME)
|
result._update_from_file(KIWI_CONF_NAME)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def save(self):
|
|
||||||
self.__save_to_file(KIWI_CONF_NAME)
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ from .subcommands import *
|
||||||
class Runner:
|
class Runner:
|
||||||
__commands: List[SubCommand] = [
|
__commands: List[SubCommand] = [
|
||||||
InitCommand,
|
InitCommand,
|
||||||
ShowCommand
|
ShowCommand,
|
||||||
|
LogsCommand
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
from .subcommand import SubCommand
|
from ._utils import SubCommand
|
||||||
|
|
||||||
from .init import InitCommand
|
from .init import InitCommand
|
||||||
from .show import ShowCommand
|
from .show import ShowCommand
|
||||||
|
from .logs import LogsCommand
|
||||||
|
|
||||||
__all__ = ['SubCommand', 'InitCommand', 'ShowCommand']
|
__all__ = [
|
||||||
|
'SubCommand',
|
||||||
|
'InitCommand',
|
||||||
|
'ShowCommand',
|
||||||
|
'LogsCommand'
|
||||||
|
]
|
53
src/kiwi/subcommands/_utils.py
Normal file
53
src/kiwi/subcommands/_utils.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from ..config import LoadedConfig
|
||||||
|
|
||||||
|
|
||||||
|
class SubCommand:
|
||||||
|
@classmethod
|
||||||
|
def get_cmd(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Docker:
|
||||||
|
__requires_root = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __check_requires_root(cls):
|
||||||
|
if cls.__requires_root is None:
|
||||||
|
try:
|
||||||
|
config = LoadedConfig.get()
|
||||||
|
subprocess.run(
|
||||||
|
[config['executables:docker'], 'ps'],
|
||||||
|
check=True,
|
||||||
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
||||||
|
)
|
||||||
|
cls.__requires_root = False
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
cls.__requires_root = True
|
||||||
|
|
||||||
|
return cls.__requires_root
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run_command(cls, program, args, cwd=None, env=None):
|
||||||
|
config = LoadedConfig.get()
|
||||||
|
cmd = [config['executables:' + program], *args]
|
||||||
|
|
||||||
|
if cls.__check_requires_root():
|
||||||
|
cmd = [config['executables:sudo'], *cmd]
|
||||||
|
|
||||||
|
print(cmd)
|
||||||
|
return subprocess.run(
|
||||||
|
cmd,
|
||||||
|
# stdout=subprocess.PIPE,
|
||||||
|
# stderr=subprocess.PIPE,
|
||||||
|
cwd=cwd, env=env
|
||||||
|
)
|
|
@ -1,10 +1,10 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from kiwi.core import KIWI_CONF_NAME, Parser
|
from ..core import KIWI_CONF_NAME, Parser
|
||||||
from kiwi.config import Config
|
from ..config import DefaultConfig
|
||||||
|
|
||||||
from .subcommand import SubCommand
|
from ._utils import SubCommand
|
||||||
|
|
||||||
|
|
||||||
def user_input(config, key, prompt):
|
def user_input(config, key, prompt):
|
||||||
|
@ -16,6 +16,25 @@ def user_input(config, key, prompt):
|
||||||
config[key] = result
|
config[key] = result
|
||||||
|
|
||||||
|
|
||||||
|
def find_exe(program_name):
|
||||||
|
for path in os.environ["PATH"].split(os.pathsep):
|
||||||
|
exe_file = os.path.join(path, program_name)
|
||||||
|
if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK):
|
||||||
|
return exe_file
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def user_input_exe(config, program_name):
|
||||||
|
exe_file = find_exe(program_name)
|
||||||
|
key = 'executables:' + program_name
|
||||||
|
|
||||||
|
if exe_file is not None:
|
||||||
|
config[key] = exe_file
|
||||||
|
else:
|
||||||
|
user_input(config, key, "Enter path to '{}' executable".format(program_name))
|
||||||
|
|
||||||
|
|
||||||
class InitCommand(SubCommand):
|
class InitCommand(SubCommand):
|
||||||
__parser = None
|
__parser = None
|
||||||
|
|
||||||
|
@ -30,19 +49,23 @@ class InitCommand(SubCommand):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls):
|
def run(cls):
|
||||||
config = Config.default()
|
config = DefaultConfig.get()
|
||||||
|
|
||||||
if os.path.isfile(KIWI_CONF_NAME):
|
if os.path.isfile(KIWI_CONF_NAME):
|
||||||
logging.warning("Overwriting existing '%s'!", KIWI_CONF_NAME)
|
logging.warning("Overwriting existing '%s'!", KIWI_CONF_NAME)
|
||||||
|
|
||||||
user_input(config, 'version', "Choose kiwi-config version")
|
user_input(config, 'version', "Choose kiwi-config version")
|
||||||
|
|
||||||
|
user_input(config, 'runtime:storage', "Enter main directory for local data")
|
||||||
|
|
||||||
user_input(config, 'markers:project', "Enter marker string for project directories")
|
user_input(config, 'markers:project', "Enter marker string for project directories")
|
||||||
user_input(config, 'markers:down', "Enter marker string for disabled projects")
|
user_input(config, 'markers:down', "Enter marker string for disabled projects")
|
||||||
|
|
||||||
user_input(config, 'network:name', "Enter name for local docker network")
|
user_input(config, 'network:name', "Enter name for local docker network")
|
||||||
user_input(config, 'network:cidr', "Enter CIDR block for local docker network")
|
user_input(config, 'network:cidr', "Enter CIDR block for local docker network")
|
||||||
|
|
||||||
user_input(config, 'runtime:storage', "Enter main directory for local data")
|
user_input_exe(config, 'docker')
|
||||||
|
user_input_exe(config, 'docker-compose')
|
||||||
|
user_input_exe(config, 'sudo')
|
||||||
|
|
||||||
config.save()
|
config.save()
|
||||||
|
|
19
src/kiwi/subcommands/logs.py
Normal file
19
src/kiwi/subcommands/logs.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from ..core import Parser
|
||||||
|
|
||||||
|
from ._utils import SubCommand, Docker
|
||||||
|
|
||||||
|
|
||||||
|
class LogsCommand(SubCommand):
|
||||||
|
__parser = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_cmd(cls):
|
||||||
|
return 'logs'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup(cls):
|
||||||
|
cls.__parser = Parser.get_subparsers().add_parser(cls.get_cmd(), help="Show logs of a project")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls):
|
||||||
|
print(Docker.run_command('docker-compose', ['logs', '-tf', '--tail=10'], cwd='hello-world.project', env={'COMPOSE_PROJECT_NAME': 'hello-world'}))
|
|
@ -1,7 +1,7 @@
|
||||||
from kiwi.config import Config
|
from ..config import LoadedConfig
|
||||||
from kiwi.core import Parser
|
from ..core import Parser
|
||||||
|
|
||||||
from .subcommand import SubCommand
|
from ._utils import SubCommand
|
||||||
|
|
||||||
|
|
||||||
class ShowCommand(SubCommand):
|
class ShowCommand(SubCommand):
|
||||||
|
@ -17,5 +17,5 @@ class ShowCommand(SubCommand):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls):
|
def run(cls):
|
||||||
config = Config.load()
|
config = LoadedConfig.get()
|
||||||
print(config)
|
print(config)
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
class SubCommand:
|
|
||||||
@classmethod
|
|
||||||
def get_cmd(cls):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setup(cls):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def run(cls):
|
|
||||||
pass
|
|
Loading…
Reference in a new issue