added initial beginnings to actions

This commit is contained in:
Paul Wilde 2024-08-18 18:45:37 +01:00
parent ec6c9a7a46
commit 3a9294dcf1
9 changed files with 172 additions and 55 deletions

View file

@ -1,27 +1,29 @@
import ../model/config_type import ../model/config_type
import ../model/state_type import ../model/state_type
import ../model/borg_type
import ../notifier/notifier import ../notifier/notifier
import strutils, sequtils import ../utils/actions
import strutils
import strformat
import sequtils
import osproc import osproc
import times import times
import os import os
import nativesockets import nativesockets
const BORG_BIN = "borg"
proc genArchiveName(): string = proc genArchiveName(): string =
let hostname = getHostname() let hostname = getHostname()
let ts = getTime().format("yyyy-MM-dd'T'HH:mm:ss'.'ffffff") let ts = getTime().format("yyyy-MM-dd'T'HH:mm:ss'.'ffffff")
return hostname & "-" & ts return fmt"{hostname}-{ts}"
proc genCommand(cmd: string, repo: string, others: seq[string]): string = proc genCommand(cmd: string, repo: string, others: seq[string]): string =
var str = BORG_BIN & " " & cmd & " " let args = others.join(" ")
str &= " " & repo & " " let cmd = fmt"{BORG_BIN} {cmd} {repo} {args}"
str &= others.join(" ") return cmd
return str
proc run(cmd: string): int = proc run(cmd: string): int =
echo "Trying to run : ", cmd echo fmt"Trying to run : {cmd}"
try: try:
let res = execProcess(cmd) let res = execProcess(cmd)
echo res echo res
@ -29,7 +31,7 @@ proc run(cmd: string): int =
echo getCurrentExceptionMsg() echo getCurrentExceptionMsg()
proc runDiscard(cmd: string): int = proc runDiscard(cmd: string): int =
echo "Trying to run : ", cmd echo fmt"Trying to run : {cmd}"
try: try:
let res = execCmd(cmd) let res = execCmd(cmd)
return res return res
@ -40,13 +42,23 @@ proc runDiscard(cmd: string): int =
proc initRepo(nc: NorgConfig, repo: Repository): int = proc initRepo(nc: NorgConfig, repo: Repository): int =
return runDiscard genCommand(cmd = "init", repo = repo.path, others = nc.args.others) return runDiscard genCommand(cmd = "init", repo = repo.path, others = nc.args.others)
proc createArchive(nc: NorgConfig, repo: Repository, archivename: string, retry: int = 0): int =
let others = concat(nc.source_directories, nc.args.others)
let res = run genCommand(cmd = "create", repo = archivename, others = others)
if res == 1:
sleep 15 * 1000 # 15 seconds
if retry == nc.retries:
return 1
else:
return createArchive(nc, repo, archivename, retry + 1)
return res
proc backupSources(nc: NorgConfig, repo: Repository): int = proc backupSources(nc: NorgConfig, repo: Repository): int =
let start_time = now() let start_time = now()
notify(nc.notifiers, state=Running) notify(nc.notifiers, state=Running)
let others = concat(nc.source_dirs, nc.args.others)
let archivename = repo.path & "::" & genArchiveName()
let res = run genCommand(cmd = "create", repo = archivename, others = others)
let end_time = now() let end_time = now()
let archivename = repo.path & "::" & genArchiveName()
let res = createArchive(nc, repo, archivename)
let total = (end_time - start_time).inMilliSeconds() let total = (end_time - start_time).inMilliSeconds()
case res case res
of 0: of 0:
@ -55,6 +67,7 @@ proc backupSources(nc: NorgConfig, repo: Repository): int =
notify(nc.notifiers, state=Failure, runtime=total) notify(nc.notifiers, state=Failure, runtime=total)
else: else:
notify(nc.notifiers, state=Failure, runtime=total) notify(nc.notifiers, state=Failure, runtime=total)
return res
proc listArchives(nc: NorgConfig, repo: Repository): int = proc listArchives(nc: NorgConfig, repo: Repository): int =
@ -65,7 +78,7 @@ proc mountArchive(nc: NorgConfig, repo: Repository): int =
let others = nc.args.others[1..^1] let others = nc.args.others[1..^1]
let ok = runDiscard genCommand(cmd = "mount", repo = archive, others = others) let ok = runDiscard genCommand(cmd = "mount", repo = archive, others = others)
if ok == 0: if ok == 0:
echo "Mounted ", archive, " at ", others[0] echo fmt"Mounted {archive} at {others[0]}"
else: else:
echo "Failed to mount ", archive echo "Failed to mount ", archive
@ -83,7 +96,7 @@ proc isEmpty(dir: string): bool =
return count == 0 return count == 0
proc extractArchive(nc: NorgConfig, repo: Repository): int = proc extractArchive(nc: NorgConfig, repo: Repository): int =
let archive = repo.path & "::" & nc.args.others[0] let archive = fmt"{repo.path}::{nc.args.others[0]}"
var others = nc.args.others[1..^1] var others = nc.args.others[1..^1]
if nc.args.extract_destination != "": if nc.args.extract_destination != "":
discard existsOrCreateDir(nc.args.extract_destination) discard existsOrCreateDir(nc.args.extract_destination)
@ -96,22 +109,51 @@ proc extractArchive(nc: NorgConfig, repo: Repository): int =
else: else:
echo "Not restoring to non-empty destination\r\nPlease use the --destination flag" echo "Not restoring to non-empty destination\r\nPlease use the --destination flag"
proc pruneRepo(nc: NorgConfig, repo: Repository): int =
echo "Not Yet Implemented."
discard
proc compactRepo(nc: NorgConfig, repo: Repository): int =
echo "Not Yet Implemented."
discard
proc checkRepo(nc: NorgConfig, repo: Repository): int =
echo "Not Yet Implemented."
discard
proc execute*(nc: NorgConfig) = proc execute*(nc: NorgConfig) =
putEnv("BORG_PASSPHRASE", nc.getEncryptionPassword()) run_actions(norg_config.actions.before_everything)
for repo in nc.repositories: for repo in nc.repositories:
run_actions(norg_config.actions.before_actions)
case nc.args.borg_cmd case nc.args.borg_cmd
of "init": of INIT:
discard initRepo(nc, repo) discard initRepo(nc, repo)
of "backup": of CREATE:
run_actions(norg_config.actions.before_backup)
discard backupSources(nc, repo) discard backupSources(nc, repo)
of "create": run_actions(norg_config.actions.after_backup)
discard backupSources(nc, repo) of LIST:
of "list":
discard listArchives(nc, repo) discard listArchives(nc, repo)
of "mount": of MOUNT:
discard mountArchive(nc, repo) discard mountArchive(nc, repo)
of "umount": of UMOUNT:
discard unmountArchive(nc) discard unmountArchive(nc)
of "extract": of EXTRACT:
run_actions(norg_config.actions.before_extract)
discard extractArchive(nc, repo) discard extractArchive(nc, repo)
delEnv("BORG_PASSPHRASE") run_actions(norg_config.actions.after_extract)
of PRUNE:
run_actions(norg_config.actions.before_prune)
discard pruneRepo(nc, repo)
run_actions(norg_config.actions.after_prune)
of COMPACT:
run_actions(norg_config.actions.before_compact)
discard compactRepo(nc, repo)
run_actions(norg_config.actions.after_compact)
of CHECK:
run_actions(norg_config.actions.before_check)
discard checkRepo(nc, repo)
run_actions(norg_config.actions.after_check)
run_actions(norg_config.actions.after_actions)
delEncryptionPassphraseInfo()
run_actions(norg_config.actions.after_everything)

View file

@ -1,10 +1,11 @@
import argparse import argparse
import ../model/borg_type
type type
NorgArgs* = object NorgArgs* = object
config_file*: string config_file*: string
extract_destination*: string extract_destination*: string
borg_cmd*: string borg_cmd*: BorgCommand
others*: seq[string] others*: seq[string]
var norg_args*: NorgArgs = NorgArgs() var norg_args*: NorgArgs = NorgArgs()
@ -20,7 +21,7 @@ proc parseArgs*() =
var opts = p.parse(commandLineParams()) var opts = p.parse(commandLineParams())
norg_args.config_file = opts.config norg_args.config_file = opts.config
norg_args.extract_destination = opts.destination norg_args.extract_destination = opts.destination
norg_args.borg_cmd = opts.borg_cmd norg_args.borg_cmd = opts.borg_cmd.toBorgCommand()
norg_args.others = opts.others norg_args.others = opts.others
except ShortCircuit as err: except ShortCircuit as err:

View file

@ -4,18 +4,34 @@ import ../model/config_type
import notifier_config import notifier_config
export config_type export config_type
proc parseConfigFile*(file: string): NorgConfig = proc parseSourceDirectories*(in_conf: TomlValueRef): seq[string] =
norg_config = newNorgConfig() var src_dirs: seq[string] = @[]
let in_conf = parsetoml.parseFile(file) for dir in in_conf{"source_directories"}.getElems():
src_dirs.add(dir.getStr())
# this is here for backwards compatibiliy
for dir in in_conf{"source_dirs"}.getElems(): for dir in in_conf{"source_dirs"}.getElems():
norg_config.source_dirs.add(dir.getStr()) norg_config.source_directories.add(dir.getStr())
for r in in_conf{"repositories"}.getElems(): return src_dirs
proc parseEncryption*(enc_conf: TomlValueRef) =
norg_config.setEncryptionPassphrase(enc_conf{"encryption_passphrase"}.getStr(""))
proc parseRepositories*(rep_conf: TomlValueRef): seq[Repository] =
var repos: seq[Repository] = @[]
for r in rep_conf.getElems():
let rtable = r.getTable() let rtable = r.getTable()
var repo = Repository() var repo = Repository()
repo.path = rtable["path"].getStr() repo.path = rtable["path"].getStr()
repo.label = rtable["label"].getStr() repo.label = rtable["label"].getStr()
norg_config.repositories.add(repo) repos.add(repo)
norg_config.setEncryptionPassword(in_conf{"encryption_password"}.getStr("")) return repos
proc parseConfigFile*(file: string): NorgConfig =
norg_config = newNorgConfig()
let in_conf = parsetoml.parseFile(file)
norg_config.source_directories = parseSourceDirectories(in_conf)
parseEncryption(in_conf{"encryption"})
norg_config.repositories = parseRepositories(in_conf{"repositories"})
norg_config.notifiers = parseNotifiers(in_conf) norg_config.notifiers = parseNotifiers(in_conf)
return norg_config return norg_config

View file

@ -18,5 +18,4 @@ proc parseNotifiers*(in_conf: TomlValueRef): Notifiers =
if in_conf.hasKey("uptimekuma"): if in_conf.hasKey("uptimekuma"):
let u = parseUptimeKumaConf(in_conf["uptimekuma"]) let u = parseUptimeKumaConf(in_conf["uptimekuma"])
notifiers.uptimekuma = u notifiers.uptimekuma = u
echo notifiers
return notifiers return notifiers

View file

@ -0,0 +1,24 @@
type
Actions* = object
# Before and after everything for all repositories
before_everything*: seq[string]
after_everything*: seq[string]
# before and after each reposistory
before_actions*: seq[string]
after_actions*: seq[string]
# before and after a backup per respository
before_backup*: seq[string]
after_backup*: seq[string]
# before and after a prune per repository
before_prune*: seq[string]
after_prune*: seq[string]
# before and after an extract per repository
before_extract*: seq[string]
after_extract*: seq[string]
# before and after an compact per repository
before_compact*: seq[string]
after_compact*: seq[string]
# before and after an check per repository
before_check*: seq[string]
after_check*: seq[string]

19
norg/model/borg_type.nim Normal file
View file

@ -0,0 +1,19 @@
const BORG_BIN* = "borg"
type
BorgCommand* = enum
LIST = "list"
INIT = "init",
CREATE = "create",
EXTRACT = "extract",
MOUNT = "mount",
UMOUNT = "umount",
PRUNE = "prune",
CHECK = "check",
COMPACT = "compact"
proc toBorgCommand*(str: string): BorgCommand =
for cmd in BorgCommand.items:
if str == $cmd: return cmd

View file

@ -1,44 +1,54 @@
import repository_type import repository_type
import notifier_types import notifier_types
import actions_type
import ../config/args import ../config/args
import os
export repository_type export repository_type
export notifier_types export notifier_types
export actions_type
type type
NorgConfig* = ref object NorgConfig* = ref object
source_dirs*: seq[string] retries*: int
source_directories*: seq[string]
repositories*: seq[Repository] repositories*: seq[Repository]
maintenance*: Maintenance
#checks*: Check - see borgmatic
notifiers*: Notifiers
actions*: Actions
args*: NorgArgs
Maintenance* = object
keep_daily*: int keep_daily*: int
keep_weekly*: int keep_weekly*: int
keep_monthly*: int keep_monthly*: int
#checks*: Check - see borgmatic
notifiers*: Notifiers
args*: NorgArgs
encryption_password: string
var norg_config*: NorgConfig var norg_config*: NorgConfig
proc newMaintenance*(): Maintenance =
var m = Maintenance()
m.keep_daily = 7
m.keep_weekly = 4
m.keep_monthly = 6
return m
proc newNorgConfig*(): NorgConfig = proc newNorgConfig*(): NorgConfig =
var nc = NorgConfig() var nc = NorgConfig()
nc.keep_daily = 7 nc.maintenance = newMaintenance()
nc.keep_weekly = 4
nc.keep_monthly = 6
return nc return nc
proc `$`*(c: NorgConfig): string = #proc `$`*(c: NorgConfig): string =
var msg: string = "Source Dirs: " & $c.source_dirs & "\r\n" # var msg: string = "Source Dirs: " & $c.source_directories & "\r\n"
msg &= "Repositories: " & $c.repositories & "\r\n" # msg &= "Repositories: " & $c.repositories & "\r\n"
msg &= "Keep Daily: " & $c.keep_daily & "\r\n" # msg &= "Notifiers: " & $c.notifiers & "\r\n"
msg &= "Keep Weekly: " & $c.keep_weekly & "\r\n" # return msg
msg &= "Keep Monthly: " & $c.keep_monthly & "\r\n"
msg &= "Notifiers: " & $c.notifiers & "\r\n" proc setEncryptionPassphrase*(nc: var NorgConfig, pw: string) =
return msg putEnv("BORG_PASSPHRASE", pw)
proc delEncryptionPassphraseInfo*() =
delEnv("BORG_PASSPHRASE")
proc setEncryptionPassword*(nc: var NorgConfig, pw: string) =
nc.encryption_password = pw
proc getEncryptionPassword*(nc: NorgConfig): string =
return nc.encryption_password

View file

@ -6,7 +6,7 @@ proc start() =
parseArgs() parseArgs()
norg_config = parseConfigFile(norg_args.config_file) norg_config = parseConfigFile(norg_args.config_file)
norg_config.args = norg_args norg_config.args = norg_args
if norg_config.source_dirs.len > 0 and norg_config.repositories.len > 0: if norg_config.source_directories.len > 0 and norg_config.repositories.len > 0:
borg.execute(norg_config) borg.execute(norg_config)
when isMainModule: when isMainModule:

6
norg/utils/actions.nim Normal file
View file

@ -0,0 +1,6 @@
import osproc
proc run_actions*(actions: seq[string]): int {.discardable.} =
for action in actions:
echo execCmd(action)