1 /** 2 Copyright: Copyright (c) 2019, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module dsnapshot.cmdgroup.admin; 7 8 import logger = std.experimental.logger; 9 import std.algorithm; 10 import std.array : empty, array; 11 import std.exception : collectException; 12 import std.stdio : writeln; 13 14 import dsnapshot.backend; 15 import dsnapshot.config : Config; 16 import dsnapshot.exception; 17 import dsnapshot.process; 18 import dsnapshot.types; 19 20 @safe: 21 22 int cmdAdmin(SnapshotConfig[] snapshots, const Config.Admin conf) nothrow { 23 auto operateOn = () { 24 if (conf.names.empty) { 25 return snapshots; 26 } 27 28 import dsnapshot.set : Set, toSet; 29 30 Set!string pick = conf.names.map!(a => a.value).toSet; 31 return snapshots.filter!(a => pick.contains(a.name)).array; 32 }(); 33 34 foreach (snapshot; operateOn) { 35 try { 36 auto backend = makeSyncBackend(snapshot); 37 38 auto crypt = makeCrypBackend(snapshot.crypt); 39 open(crypt, backend.flow); 40 scope (exit) 41 crypt.close; 42 43 final switch (conf.cmd) with (Config.Admin) { 44 case Cmd.list: 45 cmdList(snapshot, backend.flow); 46 break; 47 case Cmd.diskusage: 48 cmdDiskUsage(snapshot, backend.flow); 49 break; 50 } 51 } catch (SnapshotException e) { 52 e.errMsg.match!(a => a.print).collectException; 53 logger.error(e.msg).collectException; 54 } catch (Exception e) { 55 logger.error(e.msg).collectException; 56 break; 57 } 58 } 59 60 return 0; 61 } 62 63 private: 64 65 void cmdList(SnapshotConfig snapshot, Flow flow) { 66 import dsnapshot.layout_utils; 67 68 auto layout = snapshot.syncCmd.match!((None a) => snapshot.layout, 69 (RsyncConfig a) => fillLayout(snapshot.layout, a.flow, snapshot.remoteCmd)); 70 71 writeln("Snapshot config: ", snapshot.name); 72 writeln(layout); 73 } 74 75 void cmdDiskUsage(SnapshotConfig snapshot, Flow flow) { 76 import dsnapshot.layout; 77 import dsnapshot.layout_utils; 78 79 writeln("Snapshot config: ", snapshot.name); 80 81 const cmdDu = snapshot.syncCmd.match!((None a) => null, (RsyncConfig a) => a.cmdDiskUsage); 82 if (cmdDu.empty) { 83 logger.errorf("cmd_du is not set for snapshot %s", snapshot.name).collectException; 84 return; 85 } 86 87 // dfmt off 88 flow.match!((None a) => 1, 89 (FlowRsyncToLocal a) => localDiskUsage(cmdDu, a.dst.value.Path), 90 (FlowLocal a) => localDiskUsage(cmdDu, a.dst.value.Path), 91 (FlowLocalToRsync a) => remoteDiskUsage(a.dst, snapshot.remoteCmd, cmdDu) 92 ); 93 // dfmt on 94 } 95 96 int localDiskUsage(const string[] cmdDu, Path p) { 97 return spawnProcessLog(cmdDu ~ p.toString).wait; 98 } 99 100 int remoteDiskUsage(RemoteHost host, RemoteCmd remote, const string[] cmdDu) { 101 auto cmd = remote.match!((SshRemoteCmd a) => a.rsh); 102 cmd ~= host.addr ~ cmdDu ~ host.path; 103 return spawnProcessLog(cmd).wait; 104 }