1use super::{command_mechanism, ActionSpec};
9use sysknife_types::RiskLevel;
10
11const HELPER: &str = "/usr/lib/sysknife/log-edit";
12
13pub fn specs() -> Vec<ActionSpec> {
14 vec![
15 get_logrotate_status(None),
16 configure_log_rotation("nginx", "/var/log/nginx/*.log", "daily", 14, true),
17 remove_log_rotation("nginx"),
18 configure_remote_syslog("logs.example.com", 514, "tcp"),
19 remove_remote_syslog(),
20 ]
21}
22
23pub fn get_logrotate_status(config: Option<&str>) -> ActionSpec {
26 let conf = config.unwrap_or("/etc/logrotate.conf");
27 ActionSpec {
28 action_name: "GetLogrotateStatus",
29 mechanism: command_mechanism("logrotate", ["-d", conf]),
30 risk_level: RiskLevel::Low,
31 reboot_required: false,
32 rollback_available: false,
33 }
34}
35
36pub fn configure_log_rotation(
38 name: &str,
39 path: &str,
40 frequency: &str,
41 rotate: u32,
42 compress: bool,
43) -> ActionSpec {
44 let rot = rotate.to_string();
45 let mut args = vec![
46 HELPER.to_string(),
47 "--op".to_string(),
48 "logrotate".to_string(),
49 "--name".to_string(),
50 name.to_string(),
51 "--path".to_string(),
52 path.to_string(),
53 "--frequency".to_string(),
54 frequency.to_string(),
55 "--rotate".to_string(),
56 rot,
57 ];
58 if compress {
59 args.push("--compress".to_string());
60 }
61 ActionSpec {
62 action_name: "ConfigureLogRotation",
63 mechanism: command_mechanism("sudo", args),
64 risk_level: RiskLevel::Medium,
65 reboot_required: false,
66 rollback_available: false,
67 }
68}
69
70pub fn remove_log_rotation(name: &str) -> ActionSpec {
72 ActionSpec {
73 action_name: "RemoveLogRotation",
74 mechanism: command_mechanism("sudo", [HELPER, "--op", "rm-logrotate", "--name", name]),
75 risk_level: RiskLevel::Medium,
76 reboot_required: false,
77 rollback_available: false,
78 }
79}
80
81pub fn configure_remote_syslog(host: &str, port: u16, protocol: &str) -> ActionSpec {
83 let p = port.to_string();
84 ActionSpec {
85 action_name: "ConfigureRemoteSyslog",
86 mechanism: command_mechanism(
87 "sudo",
88 [
89 HELPER,
90 "--op",
91 "rsyslog-forward",
92 "--host",
93 host,
94 "--port",
95 &p,
96 "--protocol",
97 protocol,
98 ],
99 ),
100 risk_level: RiskLevel::High,
101 reboot_required: false,
102 rollback_available: false,
103 }
104}
105
106pub fn remove_remote_syslog() -> ActionSpec {
108 ActionSpec {
109 action_name: "RemoveRemoteSyslog",
110 mechanism: command_mechanism("sudo", [HELPER, "--op", "rm-forward"]),
111 risk_level: RiskLevel::High,
112 reboot_required: false,
113 rollback_available: false,
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120 use crate::actions::ActionMechanism;
121
122 fn args_of(spec: &ActionSpec) -> (&'static str, Vec<String>) {
123 match &spec.mechanism {
124 ActionMechanism::Command { program, args } => (program, args.clone()),
125 other => panic!("expected Command, got {other:?}"),
126 }
127 }
128
129 #[test]
130 fn logrotate_status_dry_run() {
131 let (program, args) = args_of(&get_logrotate_status(None));
132 assert_eq!(program, "logrotate");
133 assert_eq!(args, vec!["-d", "/etc/logrotate.conf"]);
134 assert_eq!(get_logrotate_status(None).risk_level, RiskLevel::Low);
135 }
136
137 #[test]
138 fn configure_rotation_with_compress() {
139 let (program, args) = args_of(&configure_log_rotation(
140 "nginx",
141 "/var/log/nginx/*.log",
142 "daily",
143 14,
144 true,
145 ));
146 assert_eq!(program, "sudo");
147 assert_eq!(
148 args,
149 vec![
150 HELPER,
151 "--op",
152 "logrotate",
153 "--name",
154 "nginx",
155 "--path",
156 "/var/log/nginx/*.log",
157 "--frequency",
158 "daily",
159 "--rotate",
160 "14",
161 "--compress"
162 ]
163 );
164 let (_, no_comp) = args_of(&configure_log_rotation(
165 "n",
166 "/var/log/x",
167 "weekly",
168 4,
169 false,
170 ));
171 assert!(!no_comp.iter().any(|a| a == "--compress"));
172 }
173
174 #[test]
175 fn syslog_forward_tcp_and_removes() {
176 let (_, fwd) = args_of(&configure_remote_syslog("logs.example.com", 514, "tcp"));
177 assert_eq!(
178 fwd,
179 vec![
180 HELPER,
181 "--op",
182 "rsyslog-forward",
183 "--host",
184 "logs.example.com",
185 "--port",
186 "514",
187 "--protocol",
188 "tcp"
189 ]
190 );
191 assert_eq!(
192 configure_remote_syslog("h", 1, "udp").risk_level,
193 RiskLevel::High
194 );
195 let (_, rm) = args_of(&remove_remote_syslog());
196 assert_eq!(rm, vec![HELPER, "--op", "rm-forward"]);
197 }
198}