ArchiveBox v1 REST API Machine 模块详解Machine 与 Binary 资源端点全解析【免费下载链接】ArchiveBox Open source self-hosted web archiving. Takes URLs/browser history/bookmarks/Pocket/Pinboard/etc., saves HTML, JS, PDFs, media, and more...项目地址: https://gitcode.com/gh_mirrors/ar/ArchiveBox本篇技术文章基于 ArchiveBox 仓库中的 API 参考文档 docs/apidocs/archivebox/archivebox.api.v1_machine.md围绕其对应的实现源码 archivebox/api/v1_machine.py 展开系统讲解 ArchiveBox v1 REST API 中“机器与依赖Machine and Dependencies”这一资源组的四个 SchemaMachineSchema、MachineFilterSchema、BinarySchema、BinaryFilterSchema和六个只读查询端点。读完后你将能够通过 HTTP API 查询当前归档主机及其操作系统/硬件指纹、列出并定位主机上已安装的归档依赖二进制如python3、wget并理解这些字段在 archivebox/machine/models.py 中的真实来源与缓存/刷新机制。1. 模块定位与路由挂载archivebox.api.v1_machine是 ArchiveBox v1 API 的机器资源路由模块。整个 API 基于django-ninja构建archivebox/api/v1_api.py 中的register_urls()将该模块的router挂载到/machine/前缀下与/core/、/crawls/、/cli/、/auth/、/personas/等路由组并列最终对外暴露的完整路径为/api/v1/machine/...# archivebox/api/v1_api.py def register_urls(api: NinjaAPI) - NinjaAPI: api.add_router(/auth/, archivebox.api.v1_auth.router) api.add_router(/core/, archivebox.api.v1_core.router) api.add_router(/crawls/, archivebox.api.v1_crawls.router) api.add_router(/cli/, archivebox.api.v1_cli.router) api.add_router(/machine/, archivebox.api.v1_machine.router) # 本模块 api.add_router(/personas/, archivebox.api.v1_personas.router) return api源码中路由器声明为router Router(tags[Machine and Dependencies])archivebox/api/v1_machine.py该标签会出现在 Swagger 文档分组中。两个关键实现细节值得注意统一鉴权NinjaAPIWithIOCapture实例在创建时传入authAPI_AUTH_METHODSarchivebox/api/v1_api.py因此本模块所有端点都需要携带 API 凭证。API Token 可在管理界面/admin/api/中创建API 首页由 archivebox/api/v1_api.py 的html_description生成也明确提示 API 仍处 v1 ALPHA 阶段接口可能变更。响应增强该 API 类重写了create_temporal_response()会为每个响应附加X-ArchiveBox-Stdout、X-ArchiveBox-Stderr、X-ArchiveBox-Auth-Method、X-ArchiveBox-Auth-Token-Id等调试头并设置Cache-Control: no-store禁用缓存。异常约定通用异常处理器把ObjectDoesNotExist、EmptyResultSet、PermissionDenied统一映射为 404其余异常映射为 503archivebox/api/v1_api.py。因此本文各端点在“ID 不存在”时均返回 404 且响应体为{succeeded: false, message: ..., errors: [...]}。2. MachineSchema机器资源的数据结构API 文档中的MachineSchema对应源码 archivebox/api/v1_machine.pyclass MachineSchema(Schema): Schema for Machine model. TYPE: str machine.Machine id: UUID created_at: datetime modified_at: datetime guid: str hostname: str hw_in_docker: bool hw_in_vm: bool hw_manufacturer: str hw_product: str hw_uuid: str os_arch: str os_family: str os_platform: str os_release: str os_kernel: str stats: dict num_uses_succeeded: int num_uses_failed: int各字段与 Django 模型 Machine 一一对应完整字段语义如下字段类型对应模型字段含义TYPEstr常量固定为machine.Machine用于标识资源类型与 BinarySchema.TYPE 的machine.Binary呼应iduuid.UUIDCompactUUIDField(primary_keyTrue, defaultuuid7)UUIDv7 主键时间有序created_at/modified_atdatetimeDateTimeField创建/修改时间modified_at为auto_nowTrueguidstrguidmax_length64unique主机 GUID由get_host_guid()探测用于跨重启识别“同一台机器”hostnamestrhostnamemax_length63主机名默认取socket.gethostname()hw_in_docker/hw_in_vmbool同名 BooleanField是否运行在 Docker 容器 / 虚拟机内由get_vm_info()探测hw_manufacturer/hw_product/hw_uuidstr同名 CharField硬件厂商、产品型号、硬件 UUIDos_arch/os_family/os_platform/os_release/os_kernelstr同名 CharFieldCPU 架构、操作系统族、平台、发行版、内核版本由get_os_info()填充statsdictJSONJSONField主机实时状态快照get_host_stats()采集如 CPU/内存指标num_uses_succeeded/num_uses_failedintPositiveIntegerField该机器上任务执行的成功/失败计数继承自ModelWithHealthStats的健康统计基类从源码结构看Machine模型还持有一个 API Schema 未直接暴露的configJSON 字段archivebox/machine/models.py用于保存机器级配置覆盖并会与ArchiveBox.conf文件做双向镜像见 Machine.save。2.1 数据从哪来Machine.current() 的缓存与刷新机制端点GET /machine/current的返回值直接来自Machine.current()archivebox/api/v1_machine.py。该方法的实现archivebox/machine/models.py包含几个值得了解的行为进程级缓存模块变量_CURRENT_MACHINE缓存当前机器实例MACHINE_RECHECK_INTERVAL 7 * 24 * 60 * 607 天内直接返回缓存避免重复探测硬件信息。按 guid 定位机器首次调用时先以get_host_guid()得到的guid查询已有记录查不到则创建一条新记录hostname、os_info、vm_info、stats 一并写入。7 天定期重检若modified_at超过 7 天则重新采集 hostname、OS/VM 信息与 stats并以update_fields做窄字段更新。每次 save 失效缓存Machine.save()会主动置空_CURRENT_MACHINE并通过mirror_machine_config_to_file()把config变更同步回配置文件保证 Admin 界面、API、命令行三种入口的修改在同一进程内即时生效archivebox/machine/models.py。因此通过 API 读到的hostname、os_*、stats等字段其新鲜度上限是“上次 save 或 7 天重检”而不是请求时刻的实时探测——这在诊断环境变化类问题时是需要知道的适用前提。3. MachineFilterSchema/machines 列表的过滤参数MachineFilterSchemaarchivebox/api/v1_machine.py继承ninja.FilterSchema每个字段通过Annotated[..., FilterLookup(...)]声明了对应的 Django ORM 查询语义查询参数匹配方式FilterLookup说明idid__startswith按主键前缀匹配允许用 ID 片段定位hostnamehostname__icontains主机名不区分大小写的模糊匹配os_platformos_platform__icontains操作系统平台模糊匹配os_archos_archCPU 架构精确匹配hw_in_dockerhw_in_docker布尔精确匹配hw_in_vmhw_in_vm布尔精确匹配bin_providersbin_providers__icontains按机器上二进制安装渠道串模糊匹配所有参数均可选默认None表示不参与过滤。例如查询某台 Linux 容器内机器curl -s -H Authorization: Bearer $API_TOKEN \ https://host/api/v1/machine/machines?hw_in_dockertrueos_platformlinux请求需携带在 Admin 的/admin/api/创建的 API Token具体鉴权头格式以部署环境的API_AUTH_METHODS配置为准。4. BinarySchema二进制依赖资源的数据结构BinarySchemaarchivebox/api/v1_machine.py描述“某台机器上某次探测到的一个可执行依赖”字段类型含义TYPEstr常量machine.Binaryiduuid.UUIDBinary 主键UUIDv7created_at/modified_atdatetime记录创建/修改时间machine_iduuid.UUID所属机器 ID模型中的外键machinemachine_hostnamestr所属机器的主机名由下面讲到的resolve_machine_hostname从外键解析而来namestr二进制名称如python3、wgetmax_length63binprovidersstr允许的安装渠道列表逗号分隔如apt,brew,pip,npm,envmax_length127binproviderstr实际成功安装该二进制的渠道max_length31abspathstr安装后的绝对路径max_length255为空表示尚未安装versionstr版本号max_length32sha256str文件 SHA256max_length64用于校验安装产物statusstr生命周期状态queued待安装或installed已安装is_validbool是否为可用二进制由resolve_is_valid从模型属性解析num_uses_succeeded/num_uses_failedint该二进制的健康统计计数Schema 上有两个staticmethod解析器是 django-ninja 将 Django 模型字段映射到输出字段的标准手段staticmethod def resolve_machine_hostname(obj) - str: return obj.machine.hostname staticmethod def resolve_is_valid(obj) - bool: return obj.is_valid对应的模型侧逻辑在 archivebox/machine/models.pyproperty def is_valid(self) - bool: A binary is valid if it has a resolved path and is marked installed. return bool(self.abspath) and self.status self.StatusChoices.INSTALLED即只有“已解析出绝对路径且状态为installed”的二进制才算有效。这与模型的文档字符串描述的两态队列生命周期一致queued→ 安装成功填齐abspath/version/sha256后进入installed安装失败则保持queued并设置retry_at重试见 Binary。此外模型通过unique_together ((machine, name, abspath, version, sha256),)保证同一机器上同一二进制不会产生重复记录archivebox/machine/models.py。5. BinaryFilterSchema/binaries 列表的过滤参数BinaryFilterSchemaarchivebox/api/v1_machine.py的查询参数如下查询参数匹配方式说明idid__startswith主键前缀匹配namename__icontains二进制名模糊匹配binproviderbinprovider实际安装渠道精确匹配statusstatusqueued/installed精确匹配machine_idmachine_id__startswith按机器 ID 前缀过滤versionversion__icontains版本号模糊匹配实用示例——列出某台机器上所有已安装的依赖curl -s -H Authorization: Bearer $API_TOKEN \ https://host/api/v1/machine/binaries?statusinstalledmachine_idmachine_uuid_prefix6. 六个端点逐一解析以下按源码中 Machine Endpoints 与 Binary Endpoints 的顺序给出每个端点的路由装饰器、实现要点与对应测试。6.1 GET /api/v1/machine/machines — 列出所有机器router.get(/machines, responselist[MachineSchema], url_nameget_machines) paginate(CustomPagination) def get_machines(request: HttpRequest, filters: Query[MachineFilterSchema]): List all machines. from archivebox.machine.models import Machine return filters.filter(Machine.objects.all()).distinct()实现要点用MachineFilterSchema过滤Machine.objects.all()distinct()去重paginate(CustomPagination)来自 archivebox/api/v1_core.py使响应体为分页结构{count, items: [...]}。测试佐证archivebox/tests/test_api_v1_machine_machines.py 先调用Machine.current(refreshTrue)确保本机记录存在再断言GET /api/v1/machine/machines返回 200archivebox/tests/test_api_v1_machine_binaries.py 还验证了分页响应中payload[count]与payload[items][0][id]、abspath、version的字段取值。6.2 GET /api/v1/machine/machine/current — 获取当前机器router.get(/machine/current, responseMachineSchema, url_nameget_current_machine) def get_current_machine(request: HttpRequest): Get the current machine. from archivebox.machine.models import Machine return Machine.current()实现要点无路径参数、无过滤直接返回Machine.current()的单机对象不分页。注意路由常量是字符串字面量/machine/current而非函数动态拼接Machine.current()的 7 天重检与配置镜像行为见本文第 2.1 节。测试佐证archivebox/tests/test_api_v1_machine_machine_current.py 请求/api/v1/machine/machine/machine/current测试中的完整 URL 见该文件断言并断言 200。该端点是运维侧确认“API 所在服务器指纹”的常用入口。6.3 GET /api/v1/machine/machine/{machine_id} — 按 ID 或主机名取单台机器router.get(/machine/{machine_id}, responseMachineSchema, url_nameget_machine) def get_machine(request: HttpRequest, machine_id: str): Get a specific machine by ID. from archivebox.machine.models import Machine from django.db.models import Q return Machine.objects.get(Q(id__startswithmachine_id) | Q(hostname__iexactmachine_id))实现要点路径参数machine_id支持两种写法——UUID 前缀id__startswith或主机名精确匹配hostname__iexact不区分大小写。两者都命中或都不命中时分别由 Django 的MultipleObjectsReturned/DoesNotExist抛出经第 1 节的通用异常处理器转为 503 / 404 响应。测试佐证archivebox/tests/test_api_v1_machine_machine_machine_id.py 用完整machine.id请求并断言 200。6.4 GET /api/v1/machine/binaries — 列出所有二进制router.get(/binaries, responselist[BinarySchema], url_nameget_binaries) paginate(CustomPagination) def get_binaries(request: HttpRequest, filters: Query[BinaryFilterSchema]): List all binaries. from archivebox.machine.models import Binary return filters.filter(Binary.objects.all().select_related(machine)).distinct()实现要点select_related(machine)预先 JOIN 机器表避免序列化machine_hostname时逐行回表配合MachineFilterSchema/BinaryFilterSchema的参数实现服务端过滤。测试佐证archivebox/tests/test_api_v1_machine_binaries.py 通过install_real_binary(python3, machinemachine)辅助函数定义于 archivebox/tests/conftest.py先落库一条真实二进制再断言列表接口的count 1且items[0]的id、abspath、version与模型一致。6.5 GET /api/v1/machine/binary/{binary_id} — 按 ID 取单个二进制router.get(/binary/{binary_id}, responseBinarySchema, url_nameget_binary) def get_binary(request: HttpRequest, binary_id: str): Get a specific binary by ID. from archivebox.machine.models import Binary return Binary.objects.select_related(machine).get(id__startswithbinary_id)实现要点与 6.3 一致采用前缀匹配id__startswith可用 UUID 片段查询select_related(machine)同样保证machine_hostname零额外查询。测试佐证archivebox/tests/test_api_v1_machine_binary_binary_id.py 断言响应 JSON 的id、abspath、version与落库记录完全一致。6.6 GET /api/v1/machine/binary/by-name/{name} — 按名称批量取二进制router.get(/binary/by-name/{name}, responselist[BinarySchema], url_nameget_binaries_by_name) def get_binaries_by_name(request: HttpRequest, name: str): Get all binaries with the given name. from archivebox.machine.models import Binary return list(Binary.objects.filter(name__iexactname).select_related(machine))实现要点这是六个端点中唯一的“按名称”入口name__iexact为不区分大小写的精确匹配由于同一机器上同名二进制可能对应多个历史安装记录不同abspath/version/sha256返回类型是列表且不分页序列化时同样带出machine_hostname。测试佐证archivebox/tests/test_api_v1_machine_binary_by_name_name.py 安装名为python3的二进制后请求/api/v1/machine/binary/by-name/python3断言返回列表长度恰为 1 且字段匹配。7. 与 CLI / 内部服务的协作关系从源码结构看Machine/Binary 数据不只服务于 REST API而是整个运行时的共享事实源CLI 侧archivebox/cli/archivebox_machine.py、archivebox/cli/archivebox_binary.py 提供archivebox machine/archivebox binary子命令与 API 读取同一套模型内部消费BinaryManager.get_from_db_or_cache()archivebox/machine/models.py在 30 分钟窗口BINARY_RECHECK_INTERVAL内优先命中进程内缓存_CURRENT_BINARIES否则update_or_create落库Binary.install()安装失败后会把retry_at设为 5 分钟后并递增num_uses_failedarchivebox/machine/models.py——这解释了 API 中num_uses_succeeded/num_uses_failed两个健康计数为何持续增长安装产物外联安装成功后symlink_to_lib_bin_after_commit()会在事务提交后把二进制软链到ABXPKG_LIB_DIR/bin便捷目录archivebox/machine/models.py即通过 API 查到abspath后本地 shell 通常也能在派生lib/bin目录找到同名入口。8. 参考文件索引类型路径说明API 参考文档docs/apidocs/archivebox/archivebox.api.v1_machine.md本文的原始骨架模块全部类、函数、数据项的 autodoc 参考API 实现archivebox/api/v1_machine.py4 个 Schema 6 个端点的完整源码API 装配archivebox/api/v1_api.py路由注册、鉴权、异常与响应头约定数据模型archivebox/machine/models.pyMachine、NetworkInterface、Binary、Process模型与Machine.current()缓存机制端点测试archivebox/tests/test_api_v1_machine_machines.py、test_api_v1_machine_machine_current.py、test_api_v1_machine_machine_machine_id.py、test_api_v1_machine_binaries.py、test_api_v1_machine_binary_binary_id.py、test_api_v1_machine_binary_by_name_name.py六个端点各自的 200 路径行为验证需要再次强调的是适用前提API 首页自述 v1 API 处于ALPHA 阶段见 archivebox/api/v1_api.py 的描述文案字段与路由可能随版本调整本文所有路径、字段与行为均以当前仓库代码为准升级前建议重新核对 docs/apidocs/archivebox/archivebox.api.v1_machine.md 的最新版生成内容。【免费下载链接】ArchiveBox Open source self-hosted web archiving. Takes URLs/browser history/bookmarks/Pocket/Pinboard/etc., saves HTML, JS, PDFs, media, and more...项目地址: https://gitcode.com/gh_mirrors/ar/ArchiveBox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
