mirror of
https://github.com/yavook/kiwi-scp.git
synced 2024-11-21 20:33:00 +00:00
basic "kiwi list" command
This commit is contained in:
parent
1dcf542c6d
commit
a5a0ca9a63
5 changed files with 65 additions and 33 deletions
|
@ -12,7 +12,7 @@
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
<option name="SCRIPT_NAME" value="kiwi_scp.scripts.kiwi_next" />
|
<option name="SCRIPT_NAME" value="kiwi_scp.scripts.kiwi_next" />
|
||||||
<option name="PARAMETERS" value="list" />
|
<option name="PARAMETERS" value="list hello-world.project web" />
|
||||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
<option name="EMULATE_TERMINAL" value="false" />
|
<option name="EMULATE_TERMINAL" value="false" />
|
||||||
<option name="MODULE_MODE" value="true" />
|
<option name="MODULE_MODE" value="true" />
|
||||||
|
|
|
@ -10,20 +10,20 @@ networks:
|
||||||
name: ${KIWI_HUB_NAME}
|
name: ${KIWI_HUB_NAME}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# simple loop producing (rather boring) logs
|
|
||||||
greeter:
|
greeter:
|
||||||
|
# simple loop producing (rather boring) logs
|
||||||
image: alpine:latest
|
image: alpine:latest
|
||||||
command: sh -c 'LOOP=1; while :; do echo Hello World "$$LOOP"; LOOP=$$(($$LOOP + 1)); sleep 10; done'
|
command: sh -c 'LOOP=1; while :; do echo Hello World "$$LOOP"; LOOP=$$(($$LOOP + 1)); sleep 10; done'
|
||||||
|
|
||||||
# basic webserver listening on localhost:8080
|
|
||||||
web:
|
web:
|
||||||
|
# basic webserver listening on localhost:8080
|
||||||
build: web
|
build: web
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:80"
|
- "8080:80"
|
||||||
|
|
||||||
# internal mariadb (mysql) instance with persistent storage
|
|
||||||
db:
|
db:
|
||||||
|
# internal mariadb (mysql) instance with persistent storage
|
||||||
image: mariadb:10
|
image: mariadb:10
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
|
@ -33,8 +33,8 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- "${TARGETDIR}/db:/var/lib/mysql"
|
- "${TARGETDIR}/db:/var/lib/mysql"
|
||||||
|
|
||||||
# admin interface for databases
|
|
||||||
adminer:
|
adminer:
|
||||||
|
# admin interface for databases
|
||||||
image: adminer:standalone
|
image: adminer:standalone
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
|
@ -45,8 +45,8 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "8081:8080"
|
- "8081:8080"
|
||||||
|
|
||||||
# Another webserver just to show off the ${CONFDIR} variable
|
|
||||||
another-web:
|
another-web:
|
||||||
|
# Another webserver just to show off the ${CONFDIR} variable
|
||||||
image: nginx:stable-alpine
|
image: nginx:stable-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from kiwi_scp.misc import service_command
|
from ..instance import Instance, pass_instance
|
||||||
|
from ..misc import service_command
|
||||||
|
|
||||||
|
|
||||||
@click.command(
|
@click.command(
|
||||||
"list",
|
"list",
|
||||||
short_help="Inspect a kiwi-scp instance",
|
short_help="Inspect a kiwi-scp instance",
|
||||||
)
|
)
|
||||||
|
@pass_instance
|
||||||
@service_command
|
@service_command
|
||||||
def cmd(project: str, service: str):
|
def cmd(ctx: Instance, project: str, service: str):
|
||||||
"""List projects in this instance, services inside a project or service(s) inside a project"""
|
"""List projects in this instance, services inside a project or service(s) inside a project"""
|
||||||
print(f"project: {project!r}, service: {service!r}")
|
if project is not None:
|
||||||
|
if service is not None:
|
||||||
|
print(f"{ctx.get_service(project, service)}")
|
||||||
|
else:
|
||||||
|
print(f"services: {ctx.get_services(project)}")
|
||||||
|
else:
|
||||||
|
print(f"projects: {ctx.config.projects}")
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import functools
|
import functools
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Dict, Any, Generator
|
from typing import Generator, List
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
import click
|
import click
|
||||||
|
from ruamel.yaml.comments import CommentedMap
|
||||||
|
|
||||||
from ._constants import COMPOSE_FILE_NAME
|
from ._constants import COMPOSE_FILE_NAME
|
||||||
from .config import KiwiConfig
|
from .config import KiwiConfig
|
||||||
|
@ -16,27 +17,40 @@ _RE_CONFDIR = re.compile(r"^\s*\$(?:CONFDIR|{CONFDIR})/+(.*)$", flags=re.UNICODE
|
||||||
@attr.s
|
@attr.s
|
||||||
class Service:
|
class Service:
|
||||||
name: str = attr.ib()
|
name: str = attr.ib()
|
||||||
configs: List[Path] = attr.ib()
|
description: CommentedMap = attr.ib()
|
||||||
|
|
||||||
@classmethod
|
def __str__(self) -> str:
|
||||||
def from_description(cls, name: str, description: Dict[str, Any]):
|
return YAML().dump({
|
||||||
configs: List[Path] = []
|
"service": {
|
||||||
|
self.name: self.description
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if "volumes" in description:
|
@property
|
||||||
volumes: List[str] = description["volumes"]
|
def configs(self) -> Generator[Path, None, None]:
|
||||||
|
if "volumes" not in self.description:
|
||||||
|
return
|
||||||
|
|
||||||
for volume in volumes:
|
for volume in self.description["volumes"]:
|
||||||
host_part = volume.split(":")[0]
|
host_part = volume.split(":")[0]
|
||||||
confdir = _RE_CONFDIR.match(host_part)
|
cd_match = _RE_CONFDIR.match(host_part)
|
||||||
|
|
||||||
if confdir:
|
if cd_match:
|
||||||
configs.append(Path(confdir.group(1)))
|
yield cd_match.group(1)
|
||||||
|
|
||||||
return cls(
|
|
||||||
name=name,
|
|
||||||
configs=configs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
@attr.s
|
||||||
|
class Services:
|
||||||
|
project_name: str = attr.ib()
|
||||||
|
content: List[Service] = attr.ib()
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return YAML().dump({
|
||||||
|
"services": {
|
||||||
|
service.name: service.description
|
||||||
|
for service in self.content
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
class Instance:
|
class Instance:
|
||||||
|
@ -48,19 +62,24 @@ class Instance:
|
||||||
|
|
||||||
return KiwiConfig.from_directory(self.directory)
|
return KiwiConfig.from_directory(self.directory)
|
||||||
|
|
||||||
@classmethod
|
@staticmethod
|
||||||
@functools.lru_cache(maxsize=10)
|
@functools.lru_cache(maxsize=10)
|
||||||
def _parse_compose_file(cls, directory: Path):
|
def _parse_compose_file(directory: Path):
|
||||||
with open(directory.joinpath(COMPOSE_FILE_NAME), "r") as cf:
|
with open(directory.joinpath(COMPOSE_FILE_NAME), "r") as cf:
|
||||||
return YAML().load(cf)
|
return YAML().load(cf)
|
||||||
|
|
||||||
def get_services(self, project_name: str) -> Generator[Service, None, None]:
|
def get_services(self, project_name: str) -> Services:
|
||||||
yml = Instance._parse_compose_file(self.directory.joinpath(project_name))
|
yml = Instance._parse_compose_file(self.directory.joinpath(project_name))
|
||||||
|
|
||||||
return (
|
return Services(project_name, [
|
||||||
Service.from_description(name, description)
|
Service(name, description)
|
||||||
for name, description in yml["services"].items()
|
for name, description in yml["services"].items()
|
||||||
)
|
])
|
||||||
|
|
||||||
|
def get_service(self, project_name: str, service_name: str) -> Service:
|
||||||
|
yml = Instance._parse_compose_file(self.directory.joinpath(project_name))
|
||||||
|
|
||||||
|
return Service(service_name, yml["services"][service_name])
|
||||||
|
|
||||||
|
|
||||||
pass_instance = click.make_pass_decorator(Instance, ensure=True)
|
pass_instance = click.make_pass_decorator(Instance, ensure=True)
|
||||||
|
|
|
@ -14,9 +14,14 @@ class TestDefault:
|
||||||
|
|
||||||
assert p.name == "hello-world.project"
|
assert p.name == "hello-world.project"
|
||||||
|
|
||||||
s = list(i.get_services(p.name))
|
ss = list(i.get_services(p.name))
|
||||||
|
|
||||||
assert len(s) == 5
|
assert len(ss) == 5
|
||||||
|
|
||||||
|
s = ss[0]
|
||||||
|
|
||||||
|
assert s.name == "greeter"
|
||||||
|
assert s == i.get_service(p.name, s.name)
|
||||||
|
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
i = Instance()
|
i = Instance()
|
||||||
|
|
Loading…
Reference in a new issue