Skip to content

Commit

Permalink
Merge pull request #46 from MrMatAP/bugfix/build
Browse files Browse the repository at this point in the history
Dependency version bump
  • Loading branch information
MrMatAP authored Nov 26, 2023
2 parents 3674eae + 449d75f commit 03e3483
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
- name: Build
run: |
pip install --user -r dev-requirements.txt
pylint --rcfile ${GITHUB_WORKSPACE}/.pylintrc ${GITHUB_WORKSPACE}/src/mrmat_python_cli --exit-zero
pylint --rcfile ${GITHUB_WORKSPACE}/.pylintrc ${GITHUB_WORKSPACE}/src/kaso_mashin --exit-zero
python -m build --wheel -n
PYTHONPATH=${GITHUB_WORKSPACE}/src python -m pytest
Expand Down
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 17 additions & 17 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@

# Build/Test requirements

setuptools>=42.0.0
build>=0.9.0 # MIT
wheel>=0.36.0 # MIT
pylint~=2.17.5 # MIT
pytest~=7.4.2 # GPL-2.0-or-later
pytest-cov~=4.1.0 # MIT
setuptools==69.0.2
build==0.9.0 # MIT
wheel==0.41.3 # MIT
pylint==3.0.2 # MIT
pytest==7.4.3 # GPL-2.0-or-later
pytest-cov==4.1.0 # MIT

# Runtime requirements

rich~=13.5.3 # MIT
requests~=2.31.0 # Apache 2.0
pyyaml~=6.0 # MIT
netifaces~=0.11.0 # MIT
sqlalchemy~=2.0.20 # MIT
fastapi~=0.103.1 # MIT
uvicorn~=0.23.2 # BSD 3-Clause
httpx~=0.25.0 # BSD 3-Clause
aiofiles~=23.2.1 # Apache 2.0
qemu.qmp~=0.0.3 # ?
passlib~=1.7.4 # BSD
rich==13.7.0 # MIT
requests==2.31.0 # Apache 2.0
pyyaml==6.0 # MIT
netifaces==0.11.0 # MIT
sqlalchemy==2.0.23 # MIT
fastapi==0.104.1 # MIT
uvicorn==0.23.2 # BSD 3-Clause
httpx==0.24.1 # BSD 3-Clause
aiofiles==23.2.1 # Apache 2.0
qemu.qmp==0.0.3 # ?
passlib==1.7.4 # BSD
28 changes: 14 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
[build-system]
requires = [
'setuptools>=42.0.0',
'wheel >= 0.36.0'
'setuptools==69.0.2',
'wheel==0.41.3'
]
build-backend = 'setuptools.build_meta'

[project]
name = "kaso-mashin"
description = "Building a mini-cloud as a playground"
urls = { "Sources" = "https://github.com/MrMatAP/kaso-mashin" }
keywords = ["experimental"]
keywords = ["mac", "virtualization", "virtualisation", "arm64"]
readme = "README.md"
license = { text = "MIT" }
authors = [
Expand All @@ -25,17 +25,17 @@ classifiers = [
]
requires-python = ">=3.10"
dependencies = [
"rich~=13.5.2", # MIT
"requests~=2.31.0", # Apache 2.0
"pyyaml~=6.0", # MIT
"netifaces~=0.11.0", # MIT
"sqlalchemy~=2.0.20", # MIT
"fastapi~=0.103.1", # MIT
"uvicorn~=0.23.2", # BSD 3-Clause
"httpx~=0.25.0", # BSD 3-Clause
"aiofiles~=23.2.1", # Apache 2.0
"qemu.qmp~=0.0.3", # ?
"passlib~=1.7.4" # BSD
"rich==13.7.0", # MIT
"requests==2.31.0", # Apache 2.0
"pyyaml==6.0", # MIT
"netifaces==0.11.0", # MIT
"sqlalchemy==2.0.23", # MIT
"fastapi==0.104.1", # MIT
"uvicorn==0.23.2", # BSD 3-Clause
"httpx==0.24.1", # BSD 3-Clause
"aiofiles==23.2.1", # Apache 2.0
"qemu.qmp==0.0.3", # ?
"passlib==1.7.4" # BSD
]
dynamic = ["version"]

Expand Down
2 changes: 1 addition & 1 deletion src/kaso_mashin/cli/commands/identity_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def create(self, args: argparse.Namespace) -> int:
homedir=args.homedir,
shell=args.shell)
if not args.pubkey and not args.passwd:
console.print(f'[red]ERROR[/red]: You must either provide the path to a public key or a password')
console.print('[red]ERROR[/red]: You must either provide the path to a public key or a password')
return 1
if args.pubkey:
schema.kind = IdentityKind.PUBKEY
Expand Down
8 changes: 4 additions & 4 deletions src/kaso_mashin/common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def load(self, config_file: pathlib.Path):
if not config_file.exists():
self._logger.debug('No configuration file exists, using defaults')
return
self._logger.debug(f'Loading config file at {config_file}')
self._logger.debug('Loading config file at %s', config_file)
configurable = {field.name: field.type for field in dataclasses.fields(self)}
try:
with open(config_file, 'r', encoding='UTF-8') as c:
Expand All @@ -53,7 +53,7 @@ def load(self, config_file: pathlib.Path):
setattr(self, key, pathlib.Path(value))
else:
setattr(self, key, value)
self._logger.debug(f'Config file overrides {key} to {value}')
self._logger.debug('Config file overrides %s to %s', key, value)
except yaml.YAMLError as exc:
raise KasoMashinException(status=400, msg='Invalid config file') from exc

Expand All @@ -69,10 +69,10 @@ def cli_override(self, args: argparse.Namespace):
value = configured.get(key)
if value != getattr(self, key):
setattr(self, key, value)
self._logger.debug(f'CLI overrides {key} to {value}')
self._logger.debug('CLI overrides %s to %s', key, value)

def save(self, config_file: pathlib.Path):
self._logger.debug(f'Saving configuration at {config_file}')
self._logger.debug('Saving configuration at %s', config_file)
configured = {field.name: getattr(self, field.name) for field in dataclasses.fields(self)}
try:
with open(config_file, 'w+', encoding='UTF-8') as c:
Expand Down
4 changes: 3 additions & 1 deletion src/kaso_mashin/common/model/instance_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ class InstanceCreateSchema(pydantic.BaseModel):
image_id: int = pydantic.Field(description='Image ID to use as the backing OS disk', examples=[1])
network_id: int = pydantic.Field(description='Network ID to connect the instance to', examples=[1])
os_disk_size: str = pydantic.Field(description='The OS disk size in GB', default='5G', examples=['5G'])
identities: list = pydantic.Field(description='The identities on that instance', default_factory=list, examples=['1'])
identities: list = pydantic.Field(description='The identities on that instance',
default_factory=list,
examples=['1'])


class InstanceModifySchema(pydantic.BaseModel):
Expand Down
21 changes: 13 additions & 8 deletions src/kaso_mashin/common/model/qemu_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,16 @@ def __init__(self, model: InstanceModel):
self._cmd = self._generate_cmd()
self._process: subprocess.Popen | None = None
self._logger = logging.getLogger(f'{self.__class__.__module__}.{self.__class__.__name__}')
self._logger.info(f'Initialised for {model.name}')
self._logger.info('Initialised for %s', model.name)

def _generate_cmd(self) -> str:
cmd = (f'{self.emulator} -name {self.model.name} -machine virt -cpu host -accel hvf -smp {self.model.vcpu} -m {self.model.ram} '
cmd = (f'{self.emulator} -name {self.model.name} -machine virt -cpu host -accel hvf '
f'-smp {self.model.vcpu} -m {self.model.ram} '
f'-bios /opt/homebrew/share/qemu/edk2-aarch64-code.fd '
'-device virtio-rng-pci -device nec-usb-xhci,id=usb-bus -device usb-kbd,bus=usb-bus.0 '
f'-drive if=virtio,file={self.model.os_disk_path},format=qcow2,cache=writethrough '
f'-smbios type=3,manufacturer=MrMat,version=0,serial=instance_{self.model.instance_id},asset={self.model.name},sku=MrMat '
f'-smbios type=3,manufacturer=MrMat,version=0,serial=instance_{self.model.instance_id},'
f'asset={self.model.name},sku=MrMat '
f'-chardev socket,id=char0,server=on,wait=off,path={self.model.console_path} '
f'-qmp unix:{self.model.qmp_path},server=on,wait=off ')
match self.model.display:
Expand Down Expand Up @@ -120,7 +122,8 @@ def _generate_cmd(self) -> str:
def generate_script(self):
with open(self.model.vm_script_path, mode='w', encoding='UTF-8') as v:
v.write(f'#!/bin/bash\n# '
f'This script can be used to manually start the instance it is located in\n\n{self._generate_cmd()}')
f'This script can be used to manually start the instance it is located in'
f'\n\n{self._generate_cmd()}')
self.model.vm_script_path.chmod(0o755)

def _wait_for_bridge(self) -> bool | None:
Expand All @@ -137,24 +140,26 @@ def _wait_for_bridge(self) -> bool | None:
return self.model.network.host_ip4 in addr2if

def start(self):
# pylint: disable=consider-using-with
self.process = subprocess.Popen(args=shlex.split(self._generate_cmd()), encoding='UTF-8')
self._logger.info('Started QEmu process')
# TODO: Cloud-init will only ever phone home once per instance, unless we make it a runcmd
# Wait for the bridge to come up
attempt = 0
while attempt < 15 and not self._wait_for_bridge():
self._logger.info(f'Waiting for bridge to come up ({attempt}/15)')
self._logger.info('Waiting for bridge to come up (%s/15)', attempt)
attempt += 1
time.sleep(1)
if attempt == 9:
raise KasoMashinException(status=500, msg='Bridge never came up')
self._logger.info('Bridge has come up')

def _instance_phoned_home(actual_ip: str):
self._logger.info(f'Instance has phoned home. Actual IP: ${actual_ip}')
self._logger.info('Instance has phoned home. Actual IP: %s', actual_ip)

self._logger.info(f'Starting phone home server on host {self.model.network.host_ip4}')
httpd = PhoneHomeServer(server_address=(str(self.model.network.host_ip4), self.model.network.host_phone_home_port),
self._logger.info('Starting phone home server on host %s', self.model.network.host_ip4)
httpd = PhoneHomeServer(server_address=(str(self.model.network.host_ip4),
self.model.network.host_phone_home_port),
callback=_instance_phoned_home,
RequestHandlerClass=PhoneHomeHandler)
httpd.timeout = 60
Expand Down
2 changes: 1 addition & 1 deletion src/kaso_mashin/common/model/relation_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
Base.metadata,
Column('instance_id', ForeignKey('instances.instance_id')),
Column('identity_id', ForeignKey('identities.identity_id'))
)
)
6 changes: 3 additions & 3 deletions src/kaso_mashin/server/controllers/identity_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def create(self, model: IdentityModel) -> IdentityModel:
return model
except sqlalchemy.exc.SQLAlchemyError as sae:
self.db.session.rollback()
raise KasoMashinException(status=500, msg=f'Database exception: {sae}')
raise KasoMashinException(status=500, msg=f'Database exception: {sae}') from sae

def modify(self, identity_id: int, update: IdentityModel) -> IdentityModel:
try:
Expand All @@ -69,7 +69,7 @@ def modify(self, identity_id: int, update: IdentityModel) -> IdentityModel:
return current
except sqlalchemy.exc.SQLAlchemyError as sae:
self.db.session.rollback()
raise KasoMashinException(status=500, msg=f'Database exception: {sae}')
raise KasoMashinException(status=500, msg=f'Database exception: {sae}') from sae

def remove(self, identity_id: int):
try:
Expand All @@ -87,4 +87,4 @@ def remove(self, identity_id: int):
return False
except sqlalchemy.exc.SQLAlchemyError as sae:
self.db.session.rollback()
raise KasoMashinException(status=500, msg=f'Database exception: {sae}')
raise KasoMashinException(status=500, msg=f'Database exception: {sae}') from sae
8 changes: 4 additions & 4 deletions src/kaso_mashin/server/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ def create_server(runtime: Runtime) -> fastapi.applications.FastAPI:
@app.exception_handler(KasoMashinException)
# pylint: disable=unused-argument
async def kaso_mashin_exception_handler(request: fastapi.Request, exc: KasoMashinException):
logging.getLogger('kaso_mashin.server').error(f'({exc.status}) {exc.msg}')
logging.getLogger('kaso_mashin.server').error('(%s) %s', exc.status, exc.msg)
return fastapi.responses.JSONResponse(status_code=exc.status,
content=ExceptionSchema(status=exc.status, msg=exc.msg)
.model_dump())

@app.exception_handler(sqlalchemy.exc.SQLAlchemyError)
# pylint: disable=unused-argument
async def sqlalchemy_exception_handler(request: fastapi.Request, exc: sqlalchemy.exc.SQLAlchemyError):
logging.getLogger('kaso_mashin.server').error(f'(500) Database exception {exc}')
logging.getLogger('kaso_mashin.server').error('(500) Database exception %s', str(exc))
return fastapi.responses.JSONResponse(status_code=500,
content=ExceptionSchema(status=500, msg=f'Database exception {exc}')
.model_dump())
Expand Down Expand Up @@ -87,8 +87,8 @@ def main(args: typing.Optional[typing.List] = None) -> int:
# TODO: We should move this into config
runtime.late_init(server=True)
try:
logger.info(f'Effective user {runtime.effective_user}')
logger.info(f'Owning user {runtime.owning_user}')
logger.info('Effective user %s', runtime.effective_user)
logger.info('Owning user %s', runtime.owning_user)
app = create_server(runtime)
uvicorn.run(app, host=config.default_server_host, port=config.default_server_port)
return 0
Expand Down

0 comments on commit 03e3483

Please sign in to comment.