Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / lxc / lxc_guests @ b5f95726

Historique | Voir | Annoter | Télécharger (11 ko)

1
#!/bin/sh
2
# -*- sh -*-
3

    
4
: << =cut
5

    
6
=head1 NAME
7

    
8
lxc_guests - collect statistics about containers virtualized via LXC
9

    
10
=head1 CONFIGURATION
11

    
12
  [lxc_guests]
13
    user root
14

    
15
    # The memory usage of containers are by default drawn as stacked area
16
    # charts.  Alternatively a non-stacked graph with lines can be configured.
17
    # Default: true
18
    #env.ram_display_stacked true
19

    
20
    # lxc container path, default below
21
    #env.lxcpath /var/lib/lxc
22

    
23
    # exclude the following containers
24
    # (default none excluded)
25
    #env.exclude container1 container2
26

    
27
    # path where tasks sysfs files are stored,
28
    # set this if the various attempts in the
29
    # code don't work
30
    # (default none)
31
    #env.cgrouppath /sys/fs/cgroup/cpuacct/lxc/
32

    
33
=head1 INTERPRETATION
34

    
35
This plugin needs root privilege.
36

    
37
This plugin has been tested with lxc 3 and
38
lx2 (on Debian buster and Debian jessie,
39
respectively).
40

    
41
For the network graphs to work, you need
42
to have in every container's config file
43
a line defining the virtual network interface
44
path (else lxc will use a random name at
45
each container's start); see the lxc_netdev()
46
function below.
47

    
48
If using lxc 2, make sure you do not have cruft
49
in your container config files, you can test
50
it with:
51
   lxc-cgroup -o /dev/stdout -l INFO -n 104 cpuacct.usage
52
-- with 104 a valid lxc instance), if you
53
get a warning, fix the config file.
54

    
55
For the logins graph, the "users" command is required in each
56
container.
57

    
58
Tested on Debian buster and Debian jessie.
59

    
60

    
61
=head1 AUTHOR
62

    
63
vajtsz vajtsz@gmail.com
64
mitty  mitty@mitty.jp
65
alphanet schaefer@alphanet.ch (many changes and multigraph)
66
Lars Kruse <devel@sumpfralle.de>
67

    
68
=head1 LICENSE
69

    
70
2-clause BSD License
71
or GPLv3 license or later, at your option
72

    
73
=head1 MAGIC MARKERS
74

    
75
 #%# family=auto
76
 #%# capabilities=autoconf
77

    
78
=cut
79

    
80
set -eu
81

    
82

    
83
. "$MUNIN_LIBDIR/plugins/plugin.sh"
84

    
85

    
86
lxcpath=${lxcpath:-/var/lib/lxc}
87
# containers to be ignored
88
exclude=${exclude:-}
89
ram_display_stacked=${ram_display_stacked:-true}
90
# try to guess the location, if empty
91
cgrouppath=${cgrouppath:-}
92

    
93

    
94
# --- FUNCTIONS
95

    
96
get_active_guests() {
97
   local excludes="$1"
98
   local guest_name
99
   for guest_name in $(lxc-ls)
100
   do
101
      # handle optional exclude list in $1
102
      if ! echo "$excludes" | grep -qwF "$guest_name"; then
103
         if lxc-info -n "$guest_name" --state 2>/dev/null | grep -qw RUNNING; then
104
            echo "$guest_name"
105
         fi
106
      fi
107
   done
108
}
109

    
110

    
111
get_lxc_cgroup_info() {
112
   local guest_name="$1"
113
   local field="$2"
114
   # lxc3 (lxc < 3: may output some warnings if there is cruft in your config dir)
115
   lxc-cgroup -o /dev/stdout -l INFO -n "$guest_name" "$field" | sed 's/^.*lxc_cgroup.c:main:[0-9][0-9]* - //' | grep -v set_config_idmaps
116
}
117

    
118

    
119
lxc_netdev() {
120
   local guest_name="$1"
121

    
122
   if [ -f "$lxcpath/$guest_name/config" ]; then
123
      # lxc 3 vs < 3
124
      (grep -E '^lxc.net.0.veth.pair' "$lxcpath/$guest_name/config" 2>/dev/null \
125
         || grep -E '^lxc.network.veth.pair' "$lxcpath/$guest_name/config"
126
      ) | awk '{print $NF;}'
127
   fi
128
}
129

    
130

    
131
# find proper sysfs and count it
132
# Debian 6.0: /sys/fs/cgroup/<container>/tasks
133
# Ubuntu 12.04 with fstab: /sys/fs/cgroup/lxc/<container>/tasks
134
# Ubuntu 12.04 with cgroup-lite: /sys/fs/cgroup/cpuacct/lxc/<container>/tasks
135
# Ubuntu 12.04 with cgroup-bin: /sys/fs/cgroup/cpuacct/sysdefault/lxc/<container>/tasks
136
# Ubuntu 14.04 /sys/fs/cgroup/systemd/lxc/<container>/tasks
137
# and with cgmanager on jessie
138
lxc_count_processes () {
139
   local guest_name="$1"
140
   local SYSFS
141

    
142
   [ -z "$guest_name" ] && return 0
143

    
144
   if [ -n "$cgrouppath" ]; then
145
      SYSFS="$cgrouppath/$guest_name/tasks"
146
      if [ -e "$SYSFS" ]; then
147
         wc -l <"$SYSFS"
148
         return
149
      fi
150
   fi
151

    
152
   for SYSFS in \
153
      "/sys/fs/cgroup/$guest_name/tasks" \
154
      "/sys/fs/cgroup/lxc/$guest_name/tasks" \
155
      "/sys/fs/cgroup/cpuacct/lxc/$guest_name/tasks" \
156
      "/sys/fs/cgroup/systemd/lxc/$guest_name/tasks" \
157
      "/sys/fs/cgroup/cpuacct/sysdefault/lxc/$guest_name/tasks"
158
   do
159
      if [ -e "$SYSFS" ]; then
160
         wc -l <"$SYSFS"
161
         return
162
      fi
163
   done
164

    
165
   if [ -e /usr/bin/cgm ]; then
166
      cgm getvalue cpu "lxc/$guest_name" tasks 2>/dev/null | wc -l
167
   else
168
      get_lxc_cgroup_info "$guest_name" "tasks" | wc -l
169
   fi
170
}
171

    
172

    
173
# change the first character of a string to upper case
174
title_case() {
175
   local text="$1"
176
   printf "%s%s" "$(echo "$text" | cut -c 1 | tr "[:lower:]" "[:upper:]")" "$(echo "$text" | cut -c 2-)"
177
}
178

    
179

    
180
do_autoconf() {
181
   if [ ! -r /proc/net/dev ]; then
182
      echo "no (/proc/net/dev cannot be read)"
183
   elif [ ! -e "$lxcpath" ]; then
184
      echo "no ($lxcpath is not present)"
185
   elif [ -z "$(which lxc-ls)" ]; then
186
      echo "no ('lxc-ls' is not available in PATH)"
187
   else
188
      echo yes
189
   fi
190
}
191

    
192

    
193
do_config() {
194
   local active_guests guest_name draw_style
195
   active_guests=$(get_active_guests "$exclude")
196

    
197
   cat <<EOF
198
multigraph lxc_cpu
199
graph_title CPU Usage
200
graph_args -l 0 --base 1000
201
graph_vlabel USER_HZ
202
graph_category virtualization
203
EOF
204

    
205
   for guest_name in $active_guests
206
   do
207
      for cpu_usage in user system
208
      do
209
         cat <<EOF
210
$(clean_fieldname "cpu_${cpu_usage}_${guest_name}").label $guest_name: $(title_case "$cpu_usage")
211
$(clean_fieldname "cpu_${cpu_usage}_${guest_name}").type DERIVE
212
$(clean_fieldname "cpu_${cpu_usage}_${guest_name}").min 0
213
EOF
214
      done
215
   done
216

    
217
   cat <<EOF
218

    
219
multigraph lxc_cpu_time
220
graph_title CPU time
221
graph_args -l 0 --base 1000
222
graph_vlabel nanosec
223
graph_category virtualization
224
EOF
225

    
226
   for guest_name in $active_guests
227
   do
228
      cat <<EOF
229
$(clean_fieldname "cpu_time_${guest_name}").label $guest_name: CPU time
230
$(clean_fieldname "cpu_time_${guest_name}").type DERIVE
231
$(clean_fieldname "cpu_time_${guest_name}").min 0
232
EOF
233
   done
234

    
235
   cat <<EOF
236

    
237
multigraph lxc_logins
238
graph_title Logins
239
graph_category virtualization
240
EOF
241

    
242
   for guest_name in $active_guests
243
   do
244
      cat <<EOF
245
$(clean_fieldname "logins_${guest_name}").label $guest_name: logins
246
$(clean_fieldname "logins_${guest_name}").type GAUGE
247
EOF
248
   done
249

    
250
   cat <<EOF
251

    
252
multigraph lxc_net
253
graph_title Network traffic
254
graph_args --base 1000
255
graph_vlabel bits in (-) / out (+) per \${graph_period}
256
graph_category virtualization
257
graph_info This graph shows the traffic of active LXC containers.
258
EOF
259

    
260
   for guest_name in $active_guests
261
   do
262
      device=$(lxc_netdev "$guest_name")
263
      if [ -z "$device" ]; then
264
         continue
265
      fi
266
      cat <<EOF
267
$(clean_fieldname "net_${guest_name}_down").label $guest_name
268
$(clean_fieldname "net_${guest_name}_down").type DERIVE
269
$(clean_fieldname "net_${guest_name}_down").graph no
270
$(clean_fieldname "net_${guest_name}_down").cdef $(clean_fieldname "net_${guest_name}_down"),8,*
271
$(clean_fieldname "net_${guest_name}_down").min 0
272
$(clean_fieldname "net_${guest_name}_up").label $guest_name
273
$(clean_fieldname "net_${guest_name}_up").type DERIVE
274
$(clean_fieldname "net_${guest_name}_up").negative $(clean_fieldname "net_${guest_name}_down")
275
$(clean_fieldname "net_${guest_name}_up").cdef $(clean_fieldname "net_${guest_name}_up"),8,*
276
$(clean_fieldname "net_${guest_name}_up").min 0
277
EOF
278
      if [ -r "/sys/class/net/$device/speed" ]; then
279
         megabit_per_second=$(cat "/sys/class/net/$device/speed")
280
         bps=$((megabit_per_second * 1000 * 1000))
281
         cat <<EOF
282
$(clean_fieldname "net_${guest_name}_down").max $bps
283
$(clean_fieldname "net_${guest_name}_up").max $bps
284
EOF
285
      fi
286
   done
287

    
288
   cat <<EOF
289

    
290
multigraph lxc_proc
291
graph_title Processes
292
graph_args -l 0 --base 1000
293
graph_vlabel Number of processes
294
graph_category virtualization
295
EOF
296
   for guest_name in $active_guests
297
   do
298
      cat <<EOF
299
$(clean_fieldname "lxc_proc_${guest_name}").label $guest_name: processes
300
$(clean_fieldname "lxc_proc_${guest_name}").type GAUGE
301
$(clean_fieldname "lxc_proc_${guest_name}").min 0
302
EOF
303
   done
304

    
305
   cat <<EOF
306

    
307
multigraph lxc_ram
308
graph_title Memory
309
graph_args -l 0 --base 1024
310
graph_vlabel byte
311
graph_category virtualization
312
EOF
313

    
314
   for guest_name in $active_guests
315
   do
316
      if [ "$ram_display_stacked" != "true" ]; then
317
         draw_style="LINE1"
318
      else
319
         draw_style="AREASTACK"
320
      fi
321

    
322
      cat <<EOF
323
$(clean_fieldname "mem_usage_${guest_name}").label ${guest_name}: Mem usage
324
$(clean_fieldname "mem_usage_${guest_name}").type GAUGE
325
$(clean_fieldname "mem_usage_${guest_name}").draw $draw_style
326
$(clean_fieldname "mem_cache_${guest_name}").label ${guest_name}: Cache
327
$(clean_fieldname "mem_cache_${guest_name}").type GAUGE
328
$(clean_fieldname "mem_active_${guest_name}").label ${guest_name}: Active
329
$(clean_fieldname "mem_active_${guest_name}").type GAUGE
330
$(clean_fieldname "mem_inactive_${guest_name}").label ${guest_name}: Inactive
331
$(clean_fieldname "mem_inactive_${guest_name}").type GAUGE
332
EOF
333
   done
334
}
335

    
336

    
337
do_fetch() {
338
   local active_guests cpu_usage device value_up value_down
339
   active_guests=$(get_active_guests "$exclude")
340

    
341
   echo "multigraph lxc_cpu"
342
   for guest_name in $active_guests
343
   do
344
      for cpu_usage in user system
345
      do
346
         echo "$(clean_fieldname "cpu_${cpu_usage}_${guest_name}").value $(get_lxc_cgroup_info "$guest_name" "cpuacct.stat" | grep "$cpu_usage" | awk '{ print $2; }')"
347
      done
348
   done
349

    
350
   echo "multigraph lxc_cpu_time"
351
   for guest_name in $active_guests
352
   do
353
      echo "$(clean_fieldname "cpu_time_${guest_name}").value $(get_lxc_cgroup_info "$guest_name" "cpuacct.usage")"
354
   done
355

    
356
   echo "multigraph lxc_logins"
357
   for guest_name in $active_guests
358
   do
359
      echo "$(clean_fieldname "logins_${guest_name}").value $(lxc-attach -n "$guest_name" users | wc -w)"
360
   done
361

    
362
   echo "multigraph lxc_net"
363
   for guest_name in $active_guests
364
   do
365
      device=$(lxc_netdev "$guest_name")
366
      if [ -z "$device" ]; then
367
         value_up="U"
368
         value_down="U"
369
      else
370
         value_up=$(grep -E "^ *${device}:" /proc/net/dev | awk '{print $10;}')
371
         value_down=$(grep -E "^ *${device}:" /proc/net/dev | awk '{print $2;}')
372
      fi
373

    
374
      cat <<EOF
375
$(clean_fieldname "net_${guest_name}_up").value $value_up
376
$(clean_fieldname "net_${guest_name}_down").value $value_down
377
EOF
378
   done
379

    
380
   echo "multigraph lxc_proc"
381
   for guest_name in $active_guests
382
   do
383
      echo "$(clean_fieldname "lxc_proc_${guest_name}").value $(lxc_count_processes "$guest_name")"
384
   done
385

    
386
   echo "multigraph lxc_ram"
387
   for guest_name in $active_guests
388
   do
389
      cat <<EOF
390
$(clean_fieldname "mem_usage_${guest_name}").value $(get_lxc_cgroup_info "$guest_name" "memory.usage_in_bytes")
391
$(clean_fieldname "mem_cache_${guest_name}").value $(get_lxc_cgroup_info "$guest_name" "memory.stat" | grep total_cache | awk '{print $2;}')
392
$(clean_fieldname "mem_active_${guest_name}").value $(get_lxc_cgroup_info "$guest_name" "memory.stat" | grep total_active_anon | awk '{print $2;}')
393
$(clean_fieldname "mem_inactive_${guest_name}").value $(get_lxc_cgroup_info "$guest_name" "memory.stat" | grep total_inactive_anon | awk '{print $2;}')
394
EOF
395
   done
396
}
397

    
398

    
399
case "${1:-}" in
400
   autoconf)
401
      do_autoconf
402
      exit 0
403
      ;;
404
   config)
405
      do_config
406
      if [ "${MUNIN_CAP_DIRTYCONFIG:-0}" = 1 ]; then do_fetch; fi
407
      exit 0
408
      ;;
409
   "")
410
      do_fetch
411
      exit 0
412
      ;;
413
   *)
414
      echo >&2 "Invalid action requested (none of: autoconf / config / '')"
415
      exit 1
416
esac