/
repl.clj
307 lines (267 loc) · 9.28 KB
/
repl.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
(ns re-mote.repl
"Main remote workflow functions of Re-mote, it includes functions for performing a range of operations from updating packages to running an Nmap scan and collecting metrics.
For more info check https://re-ops.github.io/re-ops/"
(:refer-clojure :exclude [update])
(:require
[me.raynes.fs :as fs]
[clojure.core.strint :refer (<<)]
[re-mote.validate :refer (check-entropy check-jce)]
[clojure.pprint :refer (pprint)]
[taoensso.timbre :refer (refer-timbre)]
[re-mote.repl.base :refer (refer-base)]
[re-mote.persist.es :refer (refer-es-persist)]
[re-mote.repl.desktop :refer (refer-desktop)]
[re-mote.repl.zfs :refer (refer-zfs)]
[re-mote.repl.stress :refer (refer-stress)]
[re-mote.repl.output :refer (refer-out)]
[re-mote.repl.publish :refer (refer-publish)]
[re-mote.repl.puppet :refer (refer-puppet)]
[re-mote.repl.re-conf :refer (refer-reconf)]
[re-mote.repl.spec :refer (refer-spec)]
[re-mote.repl.octo :refer (refer-octo)]
[re-mote.repl.restic :refer (refer-restic)]
[re-mote.zero.stats :refer (refer-stats)]
[re-mote.zero.security :refer (refer-security)]
[re-mote.repl.sensors :refer (refer-sensors)]
[re-mote.zero.sensors :refer (refer-zero-sensors)]
[re-mote.repl.re-gent :refer (refer-regent)]
[re-share.schedule :refer (watch seconds)]
[re-mote.zero.facts :refer (refer-facts)]
[re-mote.zero.process :refer (refer-process)]
[re-mote.zero.git :refer (refer-git)]
[re-mote.zero.test :as tst]
[re-mote.zero.pkg :refer (refer-zero-pkg)]
[re-mote.repl.pkg :refer (refer-pkg)]
[re-mote.log :refer (setup-logging)]
[clojure.java.io :refer (file)])
(:import [re_mote.repl.base Hosts]))
(refer-timbre)
(refer-facts)
(refer-process)
(refer-base)
(refer-out)
(refer-stats)
(refer-security)
(refer-sensors)
(refer-zero-sensors)
(refer-pkg)
(refer-zero-pkg)
(refer-reconf)
(refer-puppet)
(refer-spec)
(refer-zfs)
(refer-publish)
(refer-octo)
(refer-restic)
(refer-regent)
(refer-git)
(refer-es-persist)
(refer-desktop)
(refer-stress)
(defn setup
"Setup Re-mote environment as a part of the Reload workflow"
[]
(check-entropy 200)
(check-jce)
(setup-logging)
(setup-stats 10 10))
(defn single
"Create a single hosts instance"
[h & m]
(Hosts. (merge {:user "re-ops"} (first m)) [h]))
; security
(defn ^{:category :security} ports-persist
"Scan for open ports and persist into ES:
(ports-persist hs \"192.168.1.0/24\")"
[hs network]
(run (open-ports hs "-T5" network) | (enrich "nmap-scan") | (split by-hosts) | (split nested) | (persist)))
(defn ^{:category :security} port-scan
"Scan for running open ports on the network:
(port-scan hs \"192.168.1.0/24\")"
[hs network]
(run> (open-ports hs "-T5" network) | (pretty "ports scan")))
(defn ^{:category :security} host-scan
"Scan for running hosts on the network:
(host-scan hs \"192.168.1.0/24\")"
[hs network]
(run> (security/hosts hs "-sP" network) | (pretty "hosts scan")))
(defn ^{:category :security} inactive-firewall
"Find hosts with inactive firewall:
(inactive-firewall hs)"
[hs]
(run> (rules hs) | (pick (fn [success failure hosts] (mapv :host (failure 1))))))
; persistent stats
(defn ^{:category :stats} du-persist
"Collect disk usage with persist (metrics collection):
(du-persist hs)"
[hs]
(run> (du hs) | (enrich "du") | (persist) | (riemann)))
(defn ^{:category :stats} cpu-persist
"Collect CPU and idle usage with persistence (metrics collection):
(cpu-persist hs)
"
[hs]
(run> (cpu hs) | (enrich "cpu") | (persist) | (riemann)))
(defn ^{:category :stats} ram-persist
"Collect free and used RAM usage with persistence (metrics collection):
(ram-persist hs)
"
[hs]
(run> (free hs) | (enrich "free") | (persist) | (riemann)))
(defn ^{:category :stats} net-persist
"Collect networking in/out kbps and persist (metric collection):
(net-persist hs)
"
[hs]
(run> (net hs) | (enrich "net") | (persist) | (riemann)))
(defn ^{:category :stats} temperature-persist
"Collect CPU temperature (using lm-sensors) and persist (metric collection):
(temperature-persist hs)
"
[hs]
(run> (zsens/temperature hs) | (enrich "temperature") | (persist) | (riemann)))
(defn ^{:category :stats} load-persist
"Read average load and persist is (metrics collection):
(load-persist hs)
"
[hs]
(run> (load-avg hs) | (enrich "load") | (persist) | (riemann)))
(defn tofrom
"Email configuration used to send emails"
[desc]
{:to "narkisr@gmail.com" :from "gookup@gmail.com" :subject (<< "Running ~{desc} results")})
; Packaging
(defn- update-
"Update with downgrading"
[hs]
(run> (zpkg/update hs) | (downgrade pkg/update) | (pretty "update")))
(defn- upgrade-
"Run upgrade with downgrading (private)"
[hs m]
(run> (zpkg/upgrade hs) | (downgrade pkg/upgrade)))
(defn ^{:category :packaging} update
"Update the package repository of the hosts:
(update hs)
"
[hs]
(run (update- hs) | (email (tofrom "package update")) | (enrich "update") | (persist)))
(defn ^{:category :packaging} upgrade
"Run package update followed by an upgrade on hosts that were updated successfully:
(upgrade hs)
"
[hs]
(run (update- hs) | (pick successful) | (upgrade-) | (pretty "upgrade") | (email (tofrom "package upgrade")) | (enrich "upgrade") | (persist)))
(defn ^{:category :packaging} install
"Install a package on hosts:
(install hs \"openjdk8-jre\")
"
[hs pkg]
(run (zpkg/install hs pkg) | (downgrade pkg/install [pkg]) | (pretty "package install")))
(defn ^{:category :packaging} pakage-fix
"Attempt to fix a broken package provider (like apt) by applying common known fixes.
(package-fix hs)
"
[hs]
(run (zpkg/fix hs) | (zpkg/kill) | (pretty "package provider fix")))
; Reconf
(defn ^{:category :reconf} provision
"Sync Reconf source code into the remote machine and apply it:
(provision hs {:src \"base-sandbox\"})
"
[hs {:keys [src args]}]
{:pre [src]}
(let [dest (<< "/tmp/~(fs/base-name src)")]
(run (rm hs dest "-rf") | (sync- src dest) | (pick successful) | (apply-recipes dest (or args "")) | (pretty "provision"))))
(defn ^{:category :puppet} puppet-run
"Sync Puppet source code into the remote machine and apply it:
(provision hs {:src \"base-sandbox\"})
"
[hs {:keys [src args]}]
{:pre [src]}
(let [dest (<< "/tmp/~(fs/base-name src)")]
(run (rm hs dest "-rf") | (sync- src dest) | (pick successful) | (apply-module dest (or args "")) | (pretty "provision"))))
(defn ^{:category :serverspec} spec
"Run spec test against hosts
(spec hs \"/home/foo/base-sandbox\" \"minimal\")
"
[hs src target]
{:pre [src]}
(run (spc/spec hs src target) | (pretty "spec")))
; Re-gent
(defn ^{:category :re-gent} deploy
"Deploy re-gent and setup .curve remotely:
(deploy hs \"re-gent/target/re-gent\")"
[{:keys [auth] :as hs} bin]
(let [{:keys [user]} auth home (<< "/home/~{user}") dest (<< "~{home}/.curve")]
(run (mkdir hs dest "-p") | (scp ".curve/server-public.key" dest) | (pretty "curve copy"))
(run (kill-agent hs) | (pretty "kill agent"))
(run> (scp hs bin home) | (pick successful) | (start-agent home) | (pretty "scp"))))
(defn ^{:category :re-gent} kill
"Kill a re-gent process on all of the hosts:
(kill hs)"
[hs]
(run (kill-agent hs) | (pretty "kill agent")))
(defn ^{:category :re-gent} launch
"Start a re-gent process on hosts:
(launch hs)
"
[{:keys [auth] :as hs}]
(let [{:keys [user]} auth home (<< "/home/~{user}")]
(run (start-agent hs home) | (pretty "launch agent"))))
(defn pull
"Pull latest git repository changes:
(pull hs {:repo \"re-core\" :branch \"master\" :remote \"git://github.com/re-ops/re-mote.git\"})"
[hs {:keys [repo remote branch]}]
(run (git/pull hs repo remote branch) | (pretty "git pull")))
(defn filter-hosts
"Filter a sub group out of the provided hosts, the filtering function gets OS information:
(filter-hosts hs (fn [os] TODO ))"
[hs f]
(run (os-info hs) | (pick (partial results-filter f)) | (pretty "filter hosts")))
(defn host-os-info
"Hosts information using oshi:
(host-info hs)"
[hs]
(run> (os-info hs) | (pretty "filter hosts")))
(defn host-hardware-info
"Hosts information using oshi:
(host-info hs)"
[hs]
(run> (hardware-info hs) | (pretty "filter hosts")))
; sanity testing
(defn failing
"A workflow that always fail:
(failing hs)"
[hs]
(run (tst/listdir hs "/") | (pick successful) | (tst/fail) | (pretty "failing")))
(defn ^{:category :shell} listing
"List directories under / on the remote hosts:
(listing hs)"
[hs]
(run (ls hs "/" "-la") | (pretty "listing")))
; basic tasks
(defn copy-file
"Copy a local file to hosts"
[hs src dest]
(run (scp hs src dest) | (pretty "file opened")))
; desktop
(defn browse-to
"Open a browser url:
(browse-to hs \"github.com\")
"
[hs url]
(run (browse hs url) | (pretty "opened browser")))
(defn open-file
"Open a file using a remote browser:
(open-file hs \"/home/foo/bar.pdf\")
"
[hs src]
(let [dest (<< "/tmp/~(fs/base-name src)")]
(run (scp hs src dest) | (browse dest) | (pretty "file opened"))))
; process management
(defn process-matching
"Find processes matching target name:
(process-matching hs \"ssh\"); find all ssh processes
"
[hs target]
(run> (processes hs target) | (pretty "process-matching")))