-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
009e0b1
commit 34b3139
Showing
16 changed files
with
439 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,10 +5,13 @@ Maintainer: Vladimir Vinogradenko <[email protected]> | |
Build-Depends: debhelper-compat (= 12), | ||
dh-python, | ||
python3-all, | ||
python3-aiohttp-rpc, | ||
python3-ixhardware, | ||
python3-jsonschema, | ||
python3-licenselib, | ||
python3-humanfriendly, | ||
python3-psutil, | ||
python3-pyroute2, | ||
python3-setuptools | ||
Standards-Version: 4.4.0 | ||
|
||
|
@@ -20,10 +23,13 @@ Depends: ${misc:Depends}, | |
gdisk, | ||
openzfs, | ||
parted, | ||
python3-aiohttp-rpc, | ||
python3-ixhardware, | ||
python3-jsonschema, | ||
python3-licenselib, | ||
python3-humanfriendly, | ||
python3-psutil, | ||
python3-pyroute2, | ||
setserial, | ||
squashfs-tools, | ||
util-linux | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[Unit] | ||
Description=TrueNAS Installer | ||
|
||
[Service] | ||
ExecStart=/usr/bin/python3 -m truenas_installer --server | ||
|
||
[Install] | ||
WantedBy=multi-user.target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,40 @@ | ||
import argparse | ||
import asyncio | ||
|
||
from aiohttp import web | ||
|
||
from ixhardware import parse_dmi | ||
|
||
from .installer import Installer | ||
from .installer_menu import InstallerMenu | ||
from .server import InstallerRPCServer | ||
|
||
|
||
if __name__ == "__main__": | ||
def main(): | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("--server", action="store_true") | ||
args = parser.parse_args() | ||
|
||
with open("/etc/version") as f: | ||
version = f.read().strip() | ||
|
||
dmi = parse_dmi() | ||
|
||
installer = Installer(version, dmi) | ||
installer.run() | ||
|
||
if args.server: | ||
rpc_server = InstallerRPCServer(installer) | ||
app = web.Application() | ||
app.router.add_routes([ | ||
web.get("/", rpc_server.handle_http_request), | ||
]) | ||
app.on_shutdown.append(rpc_server.on_shutdown) | ||
web.run_app(app, port=80) | ||
else: | ||
loop = asyncio.get_event_loop() | ||
loop.create_task(InstallerMenu(installer).run()) | ||
loop.run_forever() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,8 @@ | ||
import asyncio | ||
|
||
from .installer_menu import InstallerMenu | ||
import os | ||
|
||
|
||
class Installer: | ||
def __init__(self, version, dmi): | ||
self.version = version | ||
self.dmi = dmi | ||
|
||
def run(self): | ||
loop = asyncio.get_event_loop() | ||
|
||
loop.create_task(InstallerMenu(self).run()) | ||
|
||
loop.run_forever() | ||
self.efi = os.path.exists("/sys/firmware/efi") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from dataclasses import dataclass | ||
|
||
from pyroute2 import IPRoute, NetlinkDumpInterrupted | ||
|
||
__all__ = ["list_network_interfaces"] | ||
|
||
|
||
@dataclass | ||
class NetworkInterface: | ||
name: str | ||
|
||
|
||
async def list_network_interfaces(): | ||
max_retries = 3 | ||
for attempt in range(1, max_retries + 1): | ||
try: | ||
with IPRoute() as ipr: | ||
interfaces = [NetworkInterface(dev.get_attr("IFLA_IFNAME")) for dev in ipr.get_links()] | ||
except NetlinkDumpInterrupted: | ||
if attempt < max_retries: | ||
# When the kernel is producing a dump of a kernel structure | ||
# over multiple netlink messages, and the structure changes | ||
# mid-way, NLM_F_DUMP_INTR is added to the header flags. | ||
# This an indication that the requested dump contains | ||
# inconsistent data and must be re-requested. See function | ||
# nl_dump_check_consistent() in include/net/netlink.h. The | ||
# pyroute2 library raises this specific exception for this | ||
# scenario, so we'll try again (up to a max of 3 times). | ||
continue | ||
else: | ||
raise | ||
|
||
return [ | ||
interface for interface in interfaces | ||
if interface.name not in ["lo"] | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import aiohttp_rpc | ||
|
||
import truenas_installer.server.api | ||
from truenas_installer.server.api.adoption import adoption_middleware | ||
from .error import exception_middleware | ||
from .method import methods | ||
|
||
__all__ = ["InstallerRPCServer"] | ||
|
||
|
||
class InstallerRPCServer(aiohttp_rpc.WsJsonRpcServer): | ||
def __init__(self, installer): | ||
self.installer = installer | ||
super().__init__( | ||
middlewares=( | ||
adoption_middleware, | ||
exception_middleware, | ||
aiohttp_rpc.middlewares.extra_args_middleware, | ||
), | ||
) | ||
|
||
for method in methods.values(): | ||
method.server = self | ||
self.add_method(aiohttp_rpc.protocol.JsonRpcMethod(method.call, name=method.name)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import truenas_installer.server.api.adoption | ||
import truenas_installer.server.api.info | ||
import truenas_installer.server.api.install | ||
import truenas_installer.server.api.power |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import errno | ||
import secrets | ||
import typing | ||
|
||
from aiohttp_rpc import errors, protocol | ||
|
||
from truenas_installer.server.error import Error | ||
from truenas_installer.server.method import method | ||
|
||
__all__ = ["is_adopted", "adopt", "authenticate"] | ||
|
||
access_key = None | ||
|
||
|
||
@method(None, {"type": "boolean"}) | ||
async def is_adopted(context): | ||
return access_key is not None | ||
|
||
|
||
@method(None, {"type": "string"}) | ||
async def adopt(context): | ||
global access_key | ||
|
||
if access_key is not None: | ||
raise Error("System is already adopted") | ||
|
||
access_key = secrets.token_urlsafe(32) | ||
|
||
setattr(context.rpc_request.context["http_request"], "_authenticated", True) | ||
|
||
return access_key | ||
|
||
|
||
@method({"type": "string"}, None) | ||
async def authenticate(context, key): | ||
global access_key | ||
|
||
if access_key is None: | ||
raise Error("The system is not adopted") | ||
|
||
if key != access_key: | ||
raise Error("Invalid access key", errno.EINVAL) | ||
|
||
setattr(context.rpc_request.context["http_request"], "_authenticated", True) | ||
|
||
|
||
async def adoption_middleware(request: protocol.JsonRpcRequest, handler: typing.Callable) -> protocol.JsonRpcResponse: | ||
if access_key is not None: | ||
if not ( | ||
request.method_name in ["is_adopted", "authenticate"] or | ||
getattr(request.context["http_request"], "_authenticated", False) | ||
): | ||
return protocol.JsonRpcResponse( | ||
id=request.id, | ||
jsonrpc=request.jsonrpc, | ||
error=errors.InvalidParams("You must authenticate before making this call", data={"errno": errno.EACCES}), | ||
) | ||
|
||
return await handler(request) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
from dataclasses import asdict | ||
|
||
from truenas_installer.disks import list_disks as _list_disks | ||
from truenas_installer.network_interfaces import list_network_interfaces as _list_network_interfaces | ||
from truenas_installer.lock import installation_lock | ||
from truenas_installer.server.method import method | ||
|
||
__all__ = ["system_info", "list_disks", "list_network_interfaces"] | ||
|
||
|
||
@method(None, { | ||
"type": "object", | ||
"properties": { | ||
"running": {"type": "boolean"}, | ||
"version": {"type": "string"}, | ||
"efi": {"type": "boolean"}, | ||
}, | ||
}) | ||
async def system_info(context): | ||
return { | ||
"running": installation_lock.locked(), | ||
"version": context.installer.version, | ||
"efi": context.installer.efi, | ||
} | ||
|
||
|
||
@method(None, { | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": { | ||
"name": {"type": "string"}, | ||
"size": {"type": "number"}, | ||
"model": {"type": "string"}, | ||
"label": {"type": "string"}, | ||
"removable": {"type": "boolean"}, | ||
}, | ||
}, | ||
}) | ||
async def list_disks(context): | ||
return [asdict(disk) for disk in await _list_disks()] | ||
|
||
|
||
@method(None, { | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": { | ||
"name": {"type": "string"}, | ||
}, | ||
}, | ||
}) | ||
async def list_network_interfaces(context): | ||
return [asdict(interface) for interface in await _list_network_interfaces()] |
Oops, something went wrong.