Skip to content
Open
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ logs
bin
.build
.dist
dist/

# python
**/__pycache__/
Expand Down
29 changes: 29 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# DEVELOPMENT

This guide helps through the development process

## Contribution

Read the [CONTRIBUTING.md guide](CONTRIBUTING.md).

## Development environment

We recommend you to create a dedicated environment for your developments with Pyenv.

```sh
pyenv install 3.9
pyenv virtualenv 3.9 freyja
pyenv activate freyja
pip install --upgrade pip
```

## Running

While you develop, stick to the Poetry usage to leverage your development environment :

```sh
poetry update
poetry install
# use poetry to run freyja development version
poetry run freyja --help
```
Binary file modified dist/freyja-0.1.0-py3-none-any.whl
Binary file not shown.
23 changes: 22 additions & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,33 @@ freyja machine usage vm1 vm2 --watch
freyja machine usage vm1
```

Opens a console in a specific machine :

```sh
freyja machine console vm1
```

List mac addresses already in use :

```sh
freyja machine info | grep mac
```

Create a snapshot of a machine :
```sh
freyja machine snapshot vm1 snaphost_name
```

Restore a snapshot of a machine :
```sh
freyja machine restore vm1 snaphost_name
```

List the snapshots of a machine :
```sh
freyja machine list-snapshots vm1
```

List networks:

```sh
Expand All @@ -77,4 +98,4 @@ Describe networks :
freyja network info
# filter by name
freyja network info net1 net2
```
```
3 changes: 2 additions & 1 deletion freyja/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

import typer

from freyja.cli import machine, network
from freyja.cli import machine, network, snapshot
from freyja.environment import FreyjaEnvironment
from freyja.logger import FreyjaLogger

app = typer.Typer(help=f"Manage virtual machine and network using QEMU and KVM",
no_args_is_help=True)
app.add_typer(machine.app, name="machine")
app.add_typer(network.app, name="network")
app.add_typer(snapshot.app, name="snapshot")

logger = logging.getLogger(FreyjaLogger.name)

Expand Down
10 changes: 9 additions & 1 deletion freyja/cli/machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from freyja.core.services.machine_service import create_machines, delete_machines, info_machines, \
list_machines, \
restart_machines, start_machines, \
stop_machines, usage_machine
stop_machines, usage_machine, open_console_machine
from freyja.lib.exceptions.configuration_exceptions import ConfigurationContentError, \
ConfigurationFileNotFoundException, \
ConfigurationFormatError
Expand Down Expand Up @@ -126,3 +126,11 @@ def usage(names: Optional[List[str]] = typer.Argument(None, help="VM names list
Display the virtual machines cpu and memory usage.
"""
usage_machine(names, watch)


@app.command()
def console(name: str = typer.Argument(..., help="VM name in which a console should be opened")):
"""
Opens a console in the specified machine
"""
open_console_machine(name)
57 changes: 57 additions & 0 deletions freyja/cli/snapshot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import logging

import typer

from freyja.core.services.snapshot_service import restore_snapshot, create_snapshot, list_snapshot, delete_snapshot
from freyja.lib.utils.subprocess_utils import yes_no_question
from freyja.logger import FreyjaLogger

app = typer.Typer(help="Manage snapshots of virtual machines")

logger: logging.Logger = logging.getLogger(FreyjaLogger.name)


@app.command()
def restore(name: str = typer.Argument(..., help="VM name to restore"),
snapshot: str = typer.Argument(..., help="Name of the snapshot")):
"""
Restore a VM from a snapshot
"""
restore_snapshot(name, snapshot)
logger.warning(f"The machine {name} will be restore to snapshot {snapshot}")
if yes_no_question("Are you sure ? (Y/n)[default: n]", False):
restore_snapshot(name, snapshot)
logger.info("OK")
else:
logger.info("Aborted")


@app.command()
def create(name: str = typer.Argument(..., help="VM name to snapshot"),
snapshot: str = typer.Argument(..., help="Name of the snapshot")):
"""
Create a snapshot of a VM
"""
create_snapshot(name, snapshot)
logger.info(f"Created snapshot {snapshot}")


@app.command()
def delete(name: str = typer.Argument(..., help="VM name concerned by the snapshot deletion"),
snapshot: str = typer.Argument(..., help="Name of the snapshot to delete")):
"""
Delete a snapshot of a VM
"""
if yes_no_question(f"Are you sure to delete snapshot {snapshot} ? (Y/n)[default: n]", False):
delete_snapshot(name, snapshot)
logger.info(f"Deleted snapshot {snapshot}")
else:
logger.info("Aborted")


@app.command(name="list")
def list_(name: str = typer.Argument(..., help="The name of the VM concerned by the snapshots")):
"""
List snapshots of a VM
"""
list_snapshot(name)
13 changes: 12 additions & 1 deletion freyja/core/services/machine_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from freyja.lib.exceptions.machine_exceptions import MachineAlreadyExists
from freyja.lib.utils.bytes_utils import convert_size
from freyja.lib.utils.error_utils import check_message
from freyja.lib.utils.subprocess_utils import execute
from freyja.lib.utils.subprocess_utils import execute, execute_interactive
from freyja.lib.utils.virsh_utils import parse_info, parse_list, parse_stats
from freyja.logger import FreyjaLogger
from freyja.models import machine_info
Expand Down Expand Up @@ -342,3 +342,14 @@ def usage_machine(names: List[str], watch: bool = False):
curses.nocbreak()
curses.echo()
curses.endwin()


def open_console_machine(domain: str):
"""
Opens a console for the provided machine
:param name: name of the machine in which the console will be opened
"""
try:
execute_interactive(["virsh", "console", domain])
except ChildProcessError as e:
logger.warning(f"Skip {domain}: Machine not found")
39 changes: 39 additions & 0 deletions freyja/core/services/snapshot_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import logging

from freyja.lib.utils.error_utils import check_message
from freyja.lib.utils.subprocess_utils import execute
from freyja.logger import FreyjaLogger

logger: logging.Logger = logging.getLogger(FreyjaLogger.name)


def create_snapshot(domain: str, name: str):
try:
execute(["virsh", "snapshot-create-as", domain, "--name", name])
except ChildProcessError as e:
logger.warning(f"Skip {domain}: Machine not found")


def delete_snapshot(domain: str, name: str):
try:
execute(["virsh", "snapshot-delete", domain, "--snapshotname", name])
except ChildProcessError as e:
logger.warning(f"Skip {domain}: Machine not found")


def restore_snapshot(domain: str, name: str):
try:
execute(["virsh", "snapshot-revert", domain, "--snapshotname", name])
except ChildProcessError as e:
if check_message(e, "snapshot"):
logger.warning(f"Skip {domain}: snapshot {name} not found")
else:
logger.warning(f"Skip {domain}: Machine not found")


def list_snapshot(domain: str):
try:
execute(["virsh", "snapshot-list", domain], stream_stdout=True)

except ChildProcessError as e:
logger.warning(f"Skip {domain}: Machine not found")
7 changes: 7 additions & 0 deletions freyja/lib/utils/subprocess_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,10 @@ def yes_no_question(question: str, default: bool):
return valid[choice]
else:
pass


def execute_interactive(command: List[str]):
try:
subprocess.check_call(command)
except subprocess.CalledProcessError as e:
raise ChildProcessError(str(e))