inventory: Add roles.<name>.description option and a warning if it is not set
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
# TODO: a client can only be in one instance, add constraint
|
# TODO: a client can only be in one instance, add constraint
|
||||||
|
|
||||||
roles.server = {
|
roles.server = {
|
||||||
|
description = "A borgbackup server that stores the backups of clients.";
|
||||||
interface =
|
interface =
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
{
|
{
|
||||||
@@ -62,6 +62,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
roles.client = {
|
roles.client = {
|
||||||
|
description = "A borgbackup client that backs up to one or more borgbackup servers.";
|
||||||
interface =
|
interface =
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
|
|||||||
@@ -140,6 +140,12 @@
|
|||||||
imports = [
|
imports = [
|
||||||
# Import the resolved module.
|
# Import the resolved module.
|
||||||
# i.e. clan.modules.admin
|
# i.e. clan.modules.admin
|
||||||
|
{
|
||||||
|
options.module = lib.mkOption {
|
||||||
|
type = lib.types.raw;
|
||||||
|
default = (builtins.head instances).instance.module;
|
||||||
|
};
|
||||||
|
}
|
||||||
(builtins.head instances).instance.resolvedModule
|
(builtins.head instances).instance.resolvedModule
|
||||||
] # Include all the instances that correlate to the resolved module
|
] # Include all the instances that correlate to the resolved module
|
||||||
++ (builtins.map (v: {
|
++ (builtins.map (v: {
|
||||||
|
|||||||
@@ -381,6 +381,13 @@ in
|
|||||||
roleName = name;
|
roleName = name;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
options.description = mkOption {
|
||||||
|
type = lib.types.nullOr types.str;
|
||||||
|
description = "A short description of the role '${name}', explaining it's effect on the supplied machine.";
|
||||||
|
example = "Connects the supplied machine as a '${name}' to the 'example' service.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
options.interface = mkOption {
|
options.interface = mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Abstract interface of the role.
|
Abstract interface of the role.
|
||||||
@@ -959,8 +966,21 @@ in
|
|||||||
(
|
(
|
||||||
let
|
let
|
||||||
failedAssertions = (lib.filterAttrs (_: v: !v.assertion) config.result.assertions);
|
failedAssertions = (lib.filterAttrs (_: v: !v.assertion) config.result.assertions);
|
||||||
|
formatModule =
|
||||||
|
if config.module.input != null then
|
||||||
|
"${config.module.input}/${config.module.name}"
|
||||||
|
else
|
||||||
|
"<clan-core>/${config.module.name}";
|
||||||
|
warningsWithNull = lib.mapAttrsToList (
|
||||||
|
roleName: roleConfig:
|
||||||
|
if (roleConfig.description == null) then
|
||||||
|
"Missing description for role '${roleName}' of clanService '${formatModule}'"
|
||||||
|
else
|
||||||
|
null
|
||||||
|
) config.roles;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
warnings = (lib.filter (v: v != null) warningsWithNull);
|
||||||
assertions = lib.attrValues failedAssertions;
|
assertions = lib.attrValues failedAssertions;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
manifest = eval.config.manifest;
|
manifest = eval.config.manifest;
|
||||||
roles = lib.mapAttrs (_n: _v: { }) eval.config.roles;
|
roles = lib.mapAttrs (_n: v: { inherit (v) description; }) eval.config.roles;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,8 +37,14 @@ const mockFetcher: Fetcher = <K extends OperationNames>(
|
|||||||
description: "This is module A",
|
description: "This is module A",
|
||||||
},
|
},
|
||||||
roles: {
|
roles: {
|
||||||
client: null,
|
client: {
|
||||||
server: null,
|
name: "client",
|
||||||
|
description: null,
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
name: "server",
|
||||||
|
description: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -52,9 +58,18 @@ const mockFetcher: Fetcher = <K extends OperationNames>(
|
|||||||
description: "This is module B",
|
description: "This is module B",
|
||||||
},
|
},
|
||||||
roles: {
|
roles: {
|
||||||
peer: null,
|
peer: {
|
||||||
moon: null,
|
name: "peer",
|
||||||
controller: null,
|
description: null,
|
||||||
|
},
|
||||||
|
moon: {
|
||||||
|
name: "moon",
|
||||||
|
description: null,
|
||||||
|
},
|
||||||
|
controller: {
|
||||||
|
name: "controller",
|
||||||
|
description: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -147,10 +147,16 @@ def extract_frontmatter[T](
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, eq=True)
|
||||||
|
class Role:
|
||||||
|
name: str
|
||||||
|
description: str | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ModuleInfo:
|
class ModuleInfo:
|
||||||
manifest: ModuleManifest
|
manifest: ModuleManifest
|
||||||
roles: dict[str, None]
|
roles: dict[str, Role]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -242,6 +248,9 @@ def list_service_modules(flake: Flake) -> ClanModules:
|
|||||||
"input": None if input_name == clan_input_name else input_name,
|
"input": None if input_name == clan_input_name else input_name,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
roles = module_info.get("roles", {})
|
||||||
|
|
||||||
res.append(
|
res.append(
|
||||||
Module(
|
Module(
|
||||||
instance_refs=find_instance_refs_for_module(
|
instance_refs=find_instance_refs_for_module(
|
||||||
@@ -249,7 +258,13 @@ def list_service_modules(flake: Flake) -> ClanModules:
|
|||||||
),
|
),
|
||||||
usage_ref=module_ref,
|
usage_ref=module_ref,
|
||||||
info=ModuleInfo(
|
info=ModuleInfo(
|
||||||
roles=module_info.get("roles", {}),
|
roles={
|
||||||
|
rname: Role(
|
||||||
|
name=rname,
|
||||||
|
description=roles[rname].get("description", None),
|
||||||
|
)
|
||||||
|
for rname in roles
|
||||||
|
},
|
||||||
manifest=ModuleManifest.from_dict(module_info["manifest"]),
|
manifest=ModuleManifest.from_dict(module_info["manifest"]),
|
||||||
),
|
),
|
||||||
native=(input_name == clan_input_name),
|
native=(input_name == clan_input_name),
|
||||||
@@ -462,7 +477,8 @@ def set_service_instance(
|
|||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
|
|
||||||
module = resolve_service_module_ref(flake, module_ref)
|
module = resolve_service_module_ref(flake, module_ref)
|
||||||
allowed_roles = module.info.roles.keys()
|
|
||||||
|
allowed_roles = list(module.info.roles)
|
||||||
|
|
||||||
for role_name in roles:
|
for role_name in roles:
|
||||||
if role_name not in allowed_roles:
|
if role_name not in allowed_roles:
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ def test_list_service_instances(
|
|||||||
assert instances["baz"].resolved.usage_ref.get("input") is None
|
assert instances["baz"].resolved.usage_ref.get("input") is None
|
||||||
assert instances["baz"].resolved.usage_ref.get("name") == "sshd"
|
assert instances["baz"].resolved.usage_ref.get("name") == "sshd"
|
||||||
|
|
||||||
|
borgbackup_service = next(
|
||||||
|
m for m in service_modules.modules if m.usage_ref.get("name") == "borgbackup"
|
||||||
|
)
|
||||||
|
# Module has roles with descriptions
|
||||||
|
assert borgbackup_service.info.roles["client"].description is not None
|
||||||
|
assert borgbackup_service.info.roles["server"].description is not None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_core
|
@pytest.mark.with_core
|
||||||
def test_list_service_modules(
|
def test_list_service_modules(
|
||||||
|
|||||||
Reference in New Issue
Block a user