Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Install packages
run: sudo apt install podman golang-github-containernetworking-plugin-dnsname sqlite3 jq
run: sudo apt-get update && sudo apt-get install podman golang-github-containernetworking-plugin-dnsname sqlite3 jq
- name: Create virtualenv
run: python3 -m venv venv
- name: Install
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install tox
run: pip install tox
- name: Install pipx
run: pip install pipx
- name: Install uv
run: pipx install uv
- name: Run pipx ensurepath
run: pipx ensurepath
- name: Run unit tests
run: tox -e py3
run: uv run --extra test tox
46 changes: 23 additions & 23 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
exclude: 'ceph_devstack/ceph_devstack\.(te|pp)'

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.11
hooks:
- id: ruff-check
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
exclude: ^docs/conf.py
additional_dependencies:
- types-dataclasses >= 0.1.3
- types-PyYAML
- tomli >= 0.2.6, < 2.0.0
- types-typed-ast >= 1.4.1
- click >= 8.1.0
- platformdirs >= 2.1.0
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.11
hooks:
- id: ruff-check
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.20.1
hooks:
- id: mypy
exclude: ^docs/conf.py
additional_dependencies:
- types-dataclasses >= 0.1.3
- types-PyYAML
- tomli >= 0.2.6, < 2.0.0
- types-typed-ast >= 1.4.1
- click >= 8.1.0
- platformdirs >= 2.1.0
22 changes: 11 additions & 11 deletions ceph_devstack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import tomlkit.exceptions

from pathlib import Path
from typing import List, Optional, Union
from typing import List


VERBOSE = 15
Expand Down Expand Up @@ -117,8 +117,8 @@ def parse_args(args: List[str]) -> argparse.Namespace:

def deep_merge(*maps):
result = {}
for map in maps:
for k, v in map.items():
for mapping in maps:
for k, v in mapping.items():
if isinstance(v, dict):
v = deep_merge(result.get(k, {}), v)
result[k] = v
Expand All @@ -128,7 +128,7 @@ def deep_merge(*maps):
class Config(dict):
__slots__ = ["user_obj", "user_path"]

def load(self, config_path: Optional[Path] = None):
def load(self, config_path: Path | None = None):
parsed = tomlkit.parse((Path(__file__).parent / "config.toml").read_text())
self.update(parsed)
if config_path:
Expand Down Expand Up @@ -160,18 +160,18 @@ def get_value(self, name: str) -> str:
return str(obj)
return tomlkit.dumps(obj).strip()

def set_value(self, name: str, value: str):
def set_value(self, name: str, value: str) -> None:
path = name.split(".")
obj = self.user_obj
i = 0
last_index = len(path) - 1
item: Union[tomlkit.items.Item, str] = value
try:
item = tomlkit.value(item)
except tomlkit.exceptions.UnexpectedCharError:
pass
except tomlkit.exceptions.InternalParserError:
pass
item = tomlkit.value(value)
except (
tomlkit.exceptions.UnexpectedCharError,
tomlkit.exceptions.InternalParserError,
):
item = tomlkit.item(value)
while i <= last_index:
if i < last_index:
obj = obj.setdefault(path[i], {})
Expand Down
Binary file modified ceph_devstack/ceph_devstack.pp
Binary file not shown.
9 changes: 9 additions & 0 deletions ceph_devstack/ceph_devstack.te
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
module ceph_devstack 1.0;

require {
type unconfined_t;
type container_t;
type container_init_t;
type proc_t;
type sysfs_t;
type tmpfs_t;
type user_tmp_t;
type devpts_t;
class filesystem mount;
class filesystem unmount;
Expand Down Expand Up @@ -74,6 +77,9 @@ require {
type fuse_device_t;

type tun_tap_device_t;

class sock_file write;
class unix_stream_socket connectto;
}

#============= container_init_t ==============
Expand Down Expand Up @@ -116,3 +122,6 @@ allow container_init_t lvm_control_t:chr_file mounton;
allow container_init_t fuse_device_t:chr_file mounton;
allow container_init_t fixed_disk_device_t:blk_file mounton;
allow container_init_t tun_tap_device_t:chr_file mounton;

allow container_t user_tmp_t:sock_file write;
allow container_t unconfined_t:unix_stream_socket connectto;
50 changes: 30 additions & 20 deletions ceph_devstack/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,39 @@
from ceph_devstack.requirements import check_requirements
from ceph_devstack.resources.ceph import CephDevStack

CONFIG_HANDLERS = {
"dump": lambda config, args: print(config.dump()),
"get": lambda config, args: print(config.get_value(args.name)),
"set": lambda config, args: print(config.set_value(args.name, args.value)),
}

def main(): # noqa: C901
COMMAND_HANDLERS = {
"doctor": None,
"apply": lambda args, obj: obj.apply(args.command),
"pull": lambda _, obj: obj.pull(),
"build": lambda _, obj: obj.build(),
"create": lambda _, obj: obj.create(),
"remove": lambda _, obj: obj.remove(),
"start": lambda _, obj: obj.start(),
"stop": lambda _, obj: obj.stop(),
"watch": lambda _, obj: obj.watch(),
"wait": lambda args, obj: obj.wait(container_name=args.container),
"logs": lambda args, obj: obj.logs(
run_name=args.run_name, job_id=args.job_id, locate=args.locate
),
}


def main() -> int:
args = parse_args(sys.argv[1:])
config.load(args.config_file)
if args.verbose:
for handler in logging.getLogger("root").handlers:
if not isinstance(handler, logging.FileHandler):
handler.setLevel(VERBOSE)
if args.command == "config":
if args.config_op == "dump":
print(config.dump())
if args.config_op == "get":
print(config.get_value(args.name))
elif args.config_op == "set":
config.set_value(args.name, args.value)
return
CONFIG_HANDLERS[args.config_op](config, args)
return 0
config["args"] = vars(args)
data_path = Path(config["data_dir"]).expanduser()
data_path.mkdir(parents=True, exist_ok=True)
Expand All @@ -35,20 +52,13 @@ async def run():
obj.check_requirements(),
):
logger.error("Requirements not met!")
sys.exit(1)
if args.command == "doctor":
return
elif args.command == "wait":
return await obj.wait(container_name=args.container)
elif args.command == "logs":
return await obj.logs(
run_name=args.run_name, job_id=args.job_id, locate=args.locate
)
else:
await obj.apply(args.command)
return 0
return 1
handler = COMMAND_HANDLERS.get(args.command)
if handler:
return await handler(args, obj)

try:
sys.exit(asyncio.run(run()))
except KeyboardInterrupt:
logger.debug("Exiting!")
return 130 # 128 + SIGINT
5 changes: 4 additions & 1 deletion ceph_devstack/exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ def run(self) -> subprocess.Popen:
async def arun(self) -> asyncio.subprocess.Process:
logger.log(VERBOSE, self._make_log_msg())
loop = asyncio.get_running_loop()
protocol_factory: functools.partial[SubprocessStreamProtocol]
protocol_factory: (
functools.partial[SubprocessStreamProtocol]
| functools.partial[LoggingStreamProtocol]
)
if self.stream_output:
protocol_factory = functools.partial(
LoggingStreamProtocol,
Expand Down
5 changes: 4 additions & 1 deletion ceph_devstack/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ async def get_sysctl_value(self, name: str) -> int:
return int(out.decode().strip())

async def apparmor_enabled(self) -> bool:
proc = await host.arun(["aa-enabled", "-q"])
try:
proc = await host.arun(["aa-enabled", "-q"])
except FileNotFoundError:
return False
return await proc.wait() == 0


Expand Down
5 changes: 3 additions & 2 deletions ceph_devstack/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@ class PodmanResource:
stop_cmd: List[str] = []
cmd_vars: List[str] = ["name"]
log: Dict[str, Set[str]] = {}
_name: str | None = None

def __init__(self, name: str = ""):
if name:
self._name = name

@property
def name(self) -> str:
if hasattr(self, "_name"):
if self._name is not None:
return self._name
return self.__class__.__name__.lower()

Expand Down Expand Up @@ -110,5 +111,5 @@ async def remove(self):
await self.cmd(self.format_cmd(self.remove_cmd))

def __repr__(self):
param_str = "" if not hasattr(self, "_name") else f'name="{self._name}"'
param_str = "" if self._name is None else f'name="{self._name}"'
return f"{self.__class__.__name__}({param_str})"
6 changes: 4 additions & 2 deletions ceph_devstack/resources/ceph/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import asyncio
import contextlib
import os
import pathlib
import tempfile

from subprocess import CalledProcessError
Expand Down Expand Up @@ -67,12 +68,13 @@ async def _get_ssh_keys(self):
privkey_path = os.environ.get("SSH_PRIVKEY_PATH")
self.pubkey_path = "/dev/null"
if not privkey_path:
privkey_path = tempfile.mktemp(
temp_dir = tempfile.mkdtemp(
prefix="teuthology-ssh-key-",
dir="/tmp",
)
privkey_path = pathlib.Path(temp_dir) / self.__class__.privkey_path
await self.cmd(
["ssh-keygen", "-t", "rsa", "-N", "", "-f", privkey_path],
["ssh-keygen", "-t", "rsa", "-N", "", "-f", str(privkey_path)],
check=True,
force_local=True,
)
Expand Down
7 changes: 4 additions & 3 deletions ceph_devstack/resources/ceph/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Paddles(Container):


class Archive(Container):
cmd_vars: List[str] = ["name", "image", "archive_dir"]
cmd_vars = Container.cmd_vars + ["archive_dir"]
create_cmd = [
"podman",
"container",
Expand Down Expand Up @@ -150,11 +150,12 @@ class Pulpito(Container):
]
env_vars = {
"PULPITO_PADDLES_ADDRESS": "http://paddles:8080",
"VITE_MACHINE_TYPE": "testnode",
}


class TestNode(Container):
cmd_vars: List[str] = ["name", "image"]
_image_name = "teuthology-testnode"
capabilities = [
"SYS_ADMIN",
"NET_ADMIN",
Expand Down Expand Up @@ -367,7 +368,7 @@ def create_cmd(self):
f"{ansible_inv}/secrets:/etc/ansible/secrets",
]
ssh_auth_socket = os.environ.get("SSH_AUTH_SOCK")
if ssh_auth_socket:
if ssh_auth_socket and Path(ssh_auth_socket).exists():
cmd += [
"-v",
f"{ssh_auth_socket}:{ssh_auth_socket}",
Expand Down
13 changes: 10 additions & 3 deletions ceph_devstack/resources/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
class Container(PodmanResource):
network: str
secret: List[str]
cmd_vars: List[str] = ["name", "image", "image_tag"]
cmd_vars: List[str] = ["name", "image", "image_name", "image_tag"]
build_cmd: List[str] = [
"podman",
"build",
"-t",
"{name}:{image_tag}",
"{image_name}:{image_tag}",
".",
]
create_cmd: List[str] = ["podman", "container", "create", "{name}"]
Expand All @@ -27,6 +27,7 @@ class Container(PodmanResource):
pull_cmd: List[str] = ["podman", "pull", "{image}"]
wait_cmd: List[str] = ["podman", "wait", "{name}"]
env_vars: Dict[str, Optional[str]] = {}
_image_name: str | None = None

def __init__(self, name: str = ""):
super().__init__(name)
Expand All @@ -48,10 +49,16 @@ def add_env_to_args(self, args: List):
def config(self):
return config["containers"].get(self.__class__.__name__.lower(), {})

@property
def image_name(self) -> str:
if self._image_name is not None:
return self._image_name
return self.__class__.__name__.lower()

@property
def image(self):
if self.repo:
return f"localhost/{self.name}"
return f"localhost/{self.image_name}"
return self.config["image"]

@property
Expand Down
Loading
Loading