Unpackerr is a companion software for your download clients, that can automatically unpack any archives it finds to ensure that Sonarr and Radarr are able to find the media files and import them into your library.
You can create a Terraform module to deploy Unpackerr on Kubernetes, and mount the configuration file as well as host paths to your download folders, so it can automatically unpack archives and notify Sonarr and Radarr.
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "2.13.1"
}
}
}
resource "kubernetes_deployment" "unpackerr" {
metadata {
name = "unpackerr"
namespace = var.namespace
labels = {
"servarr.app" = "unpackerr"
}
}
spec {
replicas = 1
selector {
match_labels = {
"servarr.app" = "unpackerr"
}
}
template {
metadata {
labels = {
"servarr.app" = "unpackerr"
}
annotations = {
"ravianand.me/config-hash" = sha1(jsonencode(merge(
kubernetes_config_map.unpackerr_conf.data,
)))
}
}
spec {
init_container {
name = "copy-config"
image = "busybox"
command = ["sh", "-c", "cp /tmp/unpackerr.conf /config/unpackerr.conf"]
volume_mount {
name = "config"
mount_path = "/tmp"
}
volume_mount {
name = "data"
mount_path = "/config"
}
}
container {
image = "golift/unpackerr"
name = "unpackerr"
volume_mount {
name = "data"
mount_path = "/config"
}
volume_mount {
name = "downloads"
mount_path = "/downloads"
}
resources {
limits = {
cpu = 2
}
}
}
volume {
name = "downloads"
host_path {
path = "/mnt/media/torrents/downloads"
type = "Directory"
}
}
volume {
name = "data"
persistent_volume_claim {
claim_name = "unpackerr-data"
}
}
volume {
name = "config"
config_map {
name = kubernetes_config_map.unpackerr_conf.metadata.0.name
items {
key = "unpackerr.conf"
path = "unpackerr.conf"
}
}
}
}
}
}
}
resource "kubernetes_persistent_volume_claim" "unmanic_data" {
metadata {
name = "unpackerr-data"
namespace = var.namespace
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = "10Gi"
}
}
storage_class_name = "local-path"
}
}
resource "kubernetes_config_map" "unpackerr_conf" {
metadata {
name = "unpackerr-conf"
namespace = var.namespace
}
data = {
"unpackerr.conf" = <<EOT
# [true/false] Turn on debug messages in the output. Do not wrap this in quotes.
# Recommend trying this so you know what it looks like. I personally leave it on.
debug = false
# Disable writing messages to stdout. This silences the app. You should set a log
# file below if you set this to true. Recommended when starting with systemctl.
quiet = false
# Setting activity to true will silence all app queue log lines with only zeros.
# Set this to true when you want less log spam.
activity = false
# The application queue data is logged on an interval. Adjust that interval with this setting.
# Default is a minute. 2m, 5m, 10m, 30m, 1h are also perfectly acceptable.
log_queues = "1m"
# Write messages to a log file. This is the same data that is normally output to stdout.
# This setting is great for Docker users that want to export their logs to a file.
# The alternative is to use syslog to log the output of the application to a file.
# Default is no log file; this is unset. log_files=0 turns off auto-rotation.
# Default files is 10 and size(mb) is 10 Megabytes; both doubled if debug is true.
#log_file = '/downloads/unpackerr.log'
log_files = 10
log_file_mb = 10
# How often to poll sonarr and radarr.
# Recommend 1m-5m. Uses Go Duration.
interval = "2m"
# How long an item must be queued (download complete) before extraction will start.
# One minute is the historic default and works well. Set higher if your downloads
# take longer to finalize (or transfer locally). Uses Go Duration.
start_delay = "1m"
# How long to wait before removing the history for a failed extraction.
# Once the history is deleted the item will be recognized as new and
# extraction will start again. Uses Go Duration.
retry_delay = "5m"
# How many files may be extracted in parallel. 1 works fine.
# Do not wrap the number in quotes. Raise this only if you have fast disks and CPU.
parallel = 1
# Use these configurations to control the file modes used for newly extracted
# files and folders. Recommend 0644/0755 or 0666/0777.
file_mode = "0644"
dir_mode = "0755"
##-Notes-#######-READ THIS!!!-##################################################
## The following sections can be repeated if you have more than one Sonarr, ##
## Radarr or Lidarr, Readarr, Folder, Webhook, or Command Hook. ##
## You MUST uncomment the [[header]] and api_key at a minimum for Starr apps. ##
## ALL LINES BEGINNING WITH A HASH # ARE IGNORED ##
## REMOVE THE HASH # FROM CONFIG LINES YOU WANT TO CHANGE ##
################################################################################
[[sonarr]]
url = "http://sonarr.servarr:8989"
api_key = "${var.sonarr_api_key}"
# File system path where downloaded Sonarr items are located.
paths = ['/downloads']
# Default protocols is torrent. Alternative: "torrent,usenet"
protocols = "torrent"
# How long to wait for a reply from the backend.
timeout = "10s"
# If you use this app with NZB you may wish to delete archives after extraction.
# General recommendation is: do not enable this for torrent use.
# Setting this to true deletes the entire original download folder after import.
delete_orig = false
# If you use Syncthing, setting this to true will make unpackerr wait for syncs to finish.
syncthing = false
[[radarr]]
url = "http://radarr.servarr:7878"
api_key = "${var.radarr_api_key}"
# File system path where downloaded Radarr items are located.
paths = ['/downloads']
# Default protocols is torrents. Alternative: "torrent,usenet"
protocols = "torrent"
# How long to wait for a reply from the backend.
timeout = "10s"
# If you use this app with NZB you may wish to delete archives after extraction.
# General recommendation is: do not enable this for torrent use.
# Setting this to true deletes the entire original download folder after import.
delete_orig = false
# If you use Syncthing, setting this to true will make unpackerr wait for syncs to finish.
syncthing = false
EOT
}
}
This module relies on sensitive variables to set the Sonarr and Radarr API keys. Create a variables.tf
and add this content:
variable "namespace" {
description = "Kubernetes namespace to deploy workloads and services"
type = string
}
variable "sonarr_api_key" {
description = "API key to access Sonarr API"
type = string
sensitive = true
}
variable "radarr_api_key" {
description = "API key to access Radarr API"
type = string
sensitive = true
}
When calling this module from a parent module, you can provide the variables as args. If you're directly supplying the variables, create a terraform.tfvars.json
and add the following content:
{
"namespace": "servarr",
"sonarr_api_key": "<Sonarr API Key>",
"radarr_api_key": "<Radarr API Key>"
}
Never share the
.tfvars
and.tfvars.json
files with anyone, and make sure to include them in.gitignore
if you're using VCS. They most likely contain secrets and other sensitive values.