Skip to content

Commit 8f5e213

Browse files
committed
implement restish wrapper
1 parent f84ba9f commit 8f5e213

10 files changed

Lines changed: 225 additions & 133 deletions

modules/arr-common/downloadClientsService.nix

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
{
22
lib,
33
pkgs,
4+
restishPackage,
45
}: serviceName: serviceConfig:
56
with lib; let
6-
mkWaitForApiScript = import ./mkWaitForApiScript.nix {inherit lib pkgs;};
7+
mkWaitForApiScript = import ./mkWaitForApiScript.nix {
8+
inherit lib pkgs restishPackage;
9+
};
710
capitalizedName = lib.toUpper (builtins.substring 0 1 serviceName) + builtins.substring 1 (-1) serviceName;
811
in {
912
description = "Configure ${serviceName} download clients via API";
1013
after = ["${serviceName}-config.service"];
1114
requires = ["${serviceName}-config.service"];
1215
wantedBy = ["multi-user.target"];
1316

17+
path = [restishPackage pkgs.jq];
18+
1419
serviceConfig = {
1520
Type = "oneshot";
1621
RemainAfterExit = true;
@@ -20,18 +25,13 @@ in {
2025
script = ''
2126
set -eu
2227
23-
# Read API key secret
24-
API_KEY=$(cat ${serviceConfig.apiKeyPath})
25-
26-
BASE_URL="http://127.0.0.1:${builtins.toString serviceConfig.hostConfig.port}${serviceConfig.hostConfig.urlBase}/api/${serviceConfig.apiVersion}"
27-
2828
# Fetch all download client schemas
2929
echo "Fetching download client schemas..."
30-
SCHEMAS=$(${pkgs.curl}/bin/curl -sS -H "X-Api-Key: $API_KEY" "$BASE_URL/downloadclient/schema")
30+
SCHEMAS=$(restish -o json ${serviceName}/downloadclient/schema)
3131
3232
# Fetch existing download clients
3333
echo "Fetching existing download clients..."
34-
DOWNLOAD_CLIENTS=$(${pkgs.curl}/bin/curl -sS -H "X-Api-Key: $API_KEY" "$BASE_URL/downloadclient")
34+
DOWNLOAD_CLIENTS=$(restish -o json ${serviceName}/downloadclient)
3535
3636
# Build list of configured download client names
3737
CONFIGURED_NAMES=$(cat <<'EOF'
@@ -47,9 +47,8 @@ in {
4747
4848
if ! echo "$CONFIGURED_NAMES" | ${pkgs.jq}/bin/jq -e --arg name "$CLIENT_NAME" 'index($name)' >/dev/null 2>&1; then
4949
echo "Deleting download client not in config: $CLIENT_NAME (ID: $CLIENT_ID)"
50-
${pkgs.curl}/bin/curl -sSf -X DELETE \
51-
-H "X-Api-Key: $API_KEY" \
52-
"$BASE_URL/downloadclient/$CLIENT_ID" >/dev/null || echo "Warning: Failed to delete download client $CLIENT_NAME"
50+
restish delete ${serviceName}/downloadclient/$CLIENT_ID > /dev/null \
51+
|| echo "Warning: Failed to delete download client $CLIENT_NAME"
5352
fi
5453
done
5554
@@ -95,11 +94,7 @@ in {
9594
9695
UPDATED_CLIENT=$(apply_field_overrides "$EXISTING_CLIENT" "$CLIENT_API_KEY" "$FIELD_OVERRIDES")
9796
98-
${pkgs.curl}/bin/curl -sSf -X PUT \
99-
-H "X-Api-Key: $API_KEY" \
100-
-H "Content-Type: application/json" \
101-
-d "$UPDATED_CLIENT" \
102-
"$BASE_URL/downloadclient/$CLIENT_ID" >/dev/null
97+
echo "$UPDATED_CLIENT" | restish put ${serviceName}/downloadclient/$CLIENT_ID > /dev/null
10398
10499
echo "Download client ${clientName} updated"
105100
else
@@ -114,11 +109,7 @@ in {
114109
115110
NEW_CLIENT=$(apply_field_overrides "$SCHEMA" "$CLIENT_API_KEY" "$FIELD_OVERRIDES")
116111
117-
${pkgs.curl}/bin/curl -sSf -X POST \
118-
-H "X-Api-Key: $API_KEY" \
119-
-H "Content-Type: application/json" \
120-
-d "$NEW_CLIENT" \
121-
"$BASE_URL/downloadclient" >/dev/null
112+
echo "$NEW_CLIENT" | restish post ${serviceName}/downloadclient > /dev/null
122113
123114
echo "Download client ${clientName} created"
124115
fi

modules/arr-common/hostConfigService.nix

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
{
22
lib,
33
pkgs,
4+
restishPackage,
45
}:
56
# Helper function to create a systemd service that configures *arr basic settings via API
67
serviceName: serviceConfig:
78
with lib; let
8-
mkWaitForApiScript = import ./mkWaitForApiScript.nix {inherit lib pkgs;};
9+
mkWaitForApiScript = import ./mkWaitForApiScript.nix {
10+
inherit lib pkgs restishPackage;
11+
};
912
capitalizedName = lib.toUpper (builtins.substring 0 1 serviceName) + builtins.substring 1 (-1) serviceName;
1013
in {
1114
description = "Configure ${serviceName} via API";
1215
after = ["${serviceName}.service"];
1316
wantedBy = ["multi-user.target"];
1417

18+
path = [restishPackage pkgs.jq];
19+
1520
serviceConfig = {
1621
Type = "oneshot";
1722
RemainAfterExit = true;
@@ -21,15 +26,12 @@ in {
2126
script = ''
2227
set -eu
2328
24-
# Read secrets
25-
API_KEY=$(cat ${serviceConfig.apiKeyPath})
29+
# Read password secret
2630
AUTH_PASSWORD=$(cat ${serviceConfig.hostConfig.passwordPath})
2731
28-
BASE_URL="http://127.0.0.1:${builtins.toString serviceConfig.hostConfig.port}${serviceConfig.hostConfig.urlBase}/api/${serviceConfig.apiVersion}"
29-
3032
# Get current host configuration
3133
echo "Fetching current host configuration..."
32-
HOST_CONFIG=$(${pkgs.curl}/bin/curl -s -f -H "X-Api-Key: $API_KEY" "$BASE_URL/config/host" 2>/dev/null)
34+
HOST_CONFIG=$(restish -o json ${serviceName}/config/host)
3335
3436
if [ -z "$HOST_CONFIG" ]; then
3537
echo "Failed to fetch host configuration"
@@ -39,6 +41,9 @@ in {
3941
# Extract the ID from the host config (needed for PUT request)
4042
CONFIG_ID=$(echo "$HOST_CONFIG" | ${pkgs.jq}/bin/jq -r '.id')
4143
44+
# Read API key for config JSON
45+
API_KEY=$(cat ${serviceConfig.apiKeyPath})
46+
4247
# Build the complete configuration JSON
4348
echo "Building configuration..."
4449
NEW_CONFIG=$(${pkgs.jq}/bin/jq -n \
@@ -88,11 +93,7 @@ in {
8893
8994
# Update host configuration
9095
echo "Updating ${capitalizedName} configuration via API..."
91-
${pkgs.curl}/bin/curl -s -f -X PUT \
92-
-H "X-Api-Key: $API_KEY" \
93-
-H "Content-Type: application/json" \
94-
-d "$NEW_CONFIG" \
95-
"$BASE_URL/config/host/$CONFIG_ID" > /dev/null
96+
echo "$NEW_CONFIG" | restish put ${serviceName}/config/host/$CONFIG_ID > /dev/null
9697
9798
echo "Configuration updated successfully"
9899

modules/arr-common/mkArrServiceModule.nix

Lines changed: 66 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,18 @@ with lib; let
1111
stateDir = "${nixflix.stateDir}/${serviceName}";
1212

1313
arrConfigModule = import ./configModule.nix {inherit lib;};
14-
mkArrHostConfigService = import ./hostConfigService.nix {inherit lib pkgs;};
15-
mkArrRootFoldersService = import ./rootFoldersService.nix {inherit lib pkgs;};
16-
mkArrDownloadClientsService = import ./downloadClientsService.nix {inherit lib pkgs;};
14+
mkArrHostConfigService = import ./hostConfigService.nix {
15+
inherit lib pkgs;
16+
restishPackage = nixflix.restish.package;
17+
};
18+
mkArrRootFoldersService = import ./rootFoldersService.nix {
19+
inherit lib pkgs;
20+
restishPackage = nixflix.restish.package;
21+
};
22+
mkArrDownloadClientsService = import ./downloadClientsService.nix {
23+
inherit lib pkgs;
24+
restishPackage = nixflix.restish.package;
25+
};
1726
capitalizedName = toUpper (substring 0 1 serviceName) + substring 1 (-1) serviceName;
1827
usesMediaDirs = !(elem serviceName ["prowlarr"]);
1928
serviceSupportsUserGroup = !(elem serviceName ["prowlarr"]);
@@ -131,45 +140,66 @@ in {
131140
}
132141
];
133142

134-
nixflix.${serviceName}.config = {
135-
apiKeyPath = mkDefault null;
136-
hostConfig = {
137-
username = mkDefault serviceName;
138-
passwordPath = mkDefault null;
139-
instanceName = mkDefault capitalizedName;
140-
urlBase = mkDefault (
141-
if nixflix.serviceNameIsUrlBase
142-
then "/${serviceName}"
143-
else ""
143+
nixflix = {
144+
${serviceName}.config = {
145+
apiKeyPath = mkDefault null;
146+
hostConfig = {
147+
username = mkDefault serviceName;
148+
passwordPath = mkDefault null;
149+
instanceName = mkDefault capitalizedName;
150+
urlBase = mkDefault (
151+
if nixflix.serviceNameIsUrlBase
152+
then "/${serviceName}"
153+
else ""
154+
);
155+
};
156+
downloadClients = mkDefault (
157+
optionals (config.nixflix.sabnzbd.enable or false) [
158+
{
159+
name = "SABnzbd";
160+
implementationName = "SABnzbd";
161+
inherit (config.nixflix.sabnzbd) apiKeyPath;
162+
inherit (config.nixflix.sabnzbd.settings) host;
163+
inherit (config.nixflix.sabnzbd.settings) port;
164+
urlBase = config.nixflix.sabnzbd.settings.url_base;
165+
}
166+
]
144167
);
145168
};
146-
downloadClients = mkDefault (
147-
optionals (config.nixflix.sabnzbd.enable or false) [
169+
170+
dirRegistrations =
171+
[
148172
{
149-
name = "SABnzbd";
150-
implementationName = "SABnzbd";
151-
inherit (config.nixflix.sabnzbd) apiKeyPath;
152-
inherit (config.nixflix.sabnzbd.settings) host;
153-
inherit (config.nixflix.sabnzbd.settings) port;
154-
urlBase = config.nixflix.sabnzbd.settings.url_base;
173+
inherit (cfg) group;
174+
dir = stateDir;
175+
owner = cfg.user;
155176
}
156177
]
157-
);
158-
};
178+
++ optionals usesMediaDirs (map (mediaDir: {
179+
inherit (cfg) group;
180+
inherit (mediaDir) dir owner;
181+
})
182+
cfg.mediaDirs);
159183

160-
nixflix.dirRegistrations =
161-
[
162-
{
163-
inherit (cfg) group;
164-
dir = stateDir;
165-
owner = cfg.user;
166-
}
167-
]
168-
++ optionals usesMediaDirs (map (mediaDir: {
169-
inherit (cfg) group;
170-
inherit (mediaDir) dir owner;
171-
})
172-
cfg.mediaDirs);
184+
restish.services = mkIf (cfg.config.apiKeyPath != null) {
185+
${serviceName} = let
186+
host =
187+
if cfg.config.hostConfig ? bindAddress && cfg.config.hostConfig.bindAddress != null
188+
then
189+
if cfg.config.hostConfig.bindAddress == "*"
190+
then "127.0.0.1"
191+
else cfg.config.hostConfig.bindAddress
192+
else "127.0.0.1";
193+
urlBase =
194+
if cfg.config.hostConfig ? urlBase && cfg.config.hostConfig.urlBase != null
195+
then cfg.config.hostConfig.urlBase
196+
else "";
197+
in {
198+
baseUrl = "http://${host}:${toString cfg.config.hostConfig.port}${urlBase}/api/${cfg.config.apiVersion}";
199+
inherit (cfg.config) apiKeyPath;
200+
};
201+
};
202+
};
173203

174204
services = {
175205
${serviceName} =

modules/arr-common/mkWaitForApiScript.nix

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
{
22
lib,
33
pkgs,
4+
restishPackage,
45
}:
56
# Helper function to create a script that waits for an *arr service API to be ready
67
serviceName: serviceConfig:
78
pkgs.writeShellScript "${serviceName}-wait-for-api" (let
89
capitalizedName = lib.toUpper (builtins.substring 0 1 serviceName) + builtins.substring 1 (-1) serviceName;
910
in ''
10-
API_KEY=$(cat ${serviceConfig.apiKeyPath})
11-
BASE_URL="http://127.0.0.1:${builtins.toString serviceConfig.hostConfig.port}${serviceConfig.hostConfig.urlBase}/api/${serviceConfig.apiVersion}"
11+
export PATH="${restishPackage}/bin:$PATH"
1212
1313
echo "Waiting for ${capitalizedName} API to be available..."
1414
for i in {1..90}; do
15-
if ${pkgs.curl}/bin/curl -s -f "$BASE_URL/system/status?apiKey=$API_KEY" >/dev/null 2>&1; then
15+
if restish -o json ${serviceName}/system/status >/dev/null 2>&1; then
1616
echo "${capitalizedName} API is available"
1717
exit 0
1818
fi

modules/arr-common/rootFoldersService.nix

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
{
22
lib,
33
pkgs,
4+
restishPackage,
45
}:
56
# Helper function to create a systemd service that configures *arr root folders via API
67
serviceName: serviceConfig:
78
with lib; let
8-
mkWaitForApiScript = import ./mkWaitForApiScript.nix {inherit lib pkgs;};
9+
mkWaitForApiScript = import ./mkWaitForApiScript.nix {
10+
inherit lib pkgs restishPackage;
11+
};
912
capitalizedName = lib.toUpper (builtins.substring 0 1 serviceName) + builtins.substring 1 (-1) serviceName;
1013
in {
1114
description = "Configure ${serviceName} root folders via API";
1215
after = ["${serviceName}-config.service"];
1316
wantedBy = ["multi-user.target"];
1417

18+
path = [restishPackage pkgs.jq];
19+
1520
serviceConfig = {
1621
Type = "oneshot";
1722
RemainAfterExit = true;
@@ -21,14 +26,8 @@ in {
2126
script = ''
2227
set -eu
2328
24-
# Read API key secret
25-
API_KEY=$(cat ${serviceConfig.apiKeyPath})
26-
27-
BASE_URL="http://127.0.0.1:${builtins.toString serviceConfig.hostConfig.port}${serviceConfig.hostConfig.urlBase}/api/${serviceConfig.apiVersion}"
28-
29-
# Create root folders if they don't exist
3029
echo "Checking for root folders..."
31-
ROOT_FOLDERS=$(${pkgs.curl}/bin/curl -sSf -H "X-Api-Key: $API_KEY" "$BASE_URL/rootfolder" 2>/dev/null)
30+
ROOT_FOLDERS=$(restish -o json ${serviceName}/rootfolder)
3231
3332
# Build list of configured paths
3433
CONFIGURED_PATHS=$(cat <<'EOF'
@@ -44,25 +43,18 @@ in {
4443
4544
if ! echo "$CONFIGURED_PATHS" | ${pkgs.jq}/bin/jq -e --arg path "$FOLDER_PATH" 'index($path)' >/dev/null 2>&1; then
4645
echo "Deleting root folder not in config: $FOLDER_PATH (ID: $FOLDER_ID)"
47-
${pkgs.curl}/bin/curl -sSf -X DELETE \
48-
-H "X-Api-Key: $API_KEY" \
49-
"$BASE_URL/rootfolder/$FOLDER_ID" >/dev/null 2>&1 || echo "Warning: Failed to delete root folder $FOLDER_PATH"
46+
restish delete ${serviceName}/rootfolder/$FOLDER_ID > /dev/null \
47+
|| echo "Warning: Failed to delete root folder $FOLDER_PATH"
5048
fi
5149
done
5250
5351
${concatMapStringsSep "\n" (folderConfig: let
54-
# Convert the Nix attr set to a JSON string
5552
folderJson = builtins.toJSON folderConfig;
56-
# Extract the path for checking existence
5753
folderPath = folderConfig.path;
5854
in ''
5955
if ! echo "$ROOT_FOLDERS" | ${pkgs.jq}/bin/jq -e '.[] | select(.path == "${folderPath}")' >/dev/null 2>&1; then
6056
echo "Creating root folder: ${folderPath}"
61-
${pkgs.curl}/bin/curl -sSf -X POST \
62-
-H "X-Api-Key: $API_KEY" \
63-
-H "Content-Type: application/json" \
64-
-d '${folderJson}' \
65-
"$BASE_URL/rootfolder" > /dev/null
57+
echo '${folderJson}' | restish post ${serviceName}/rootfolder > /dev/null
6658
echo "Root folder created: ${folderPath}"
6759
else
6860
echo "Root folder already exists: ${folderPath}"

modules/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
./postgres.nix
88
./prowlarr
99
./radarr
10+
./restish-wrapper
1011
./sabnzbd
1112
./sonarr
1213
];

0 commit comments

Comments
 (0)