Browse Source

fix diskspace plugin in Docker (#18035)

* fix diskspace in Docker

* freez mount_point_stat_path
Ilya Mashchenko 8 months ago
parent
commit
f8350a705c

+ 8 - 0
packaging/docker/README.md

@@ -50,6 +50,7 @@ along with their descriptions.
 |       Component        |           Mounts           | Description                                                                                                                                | 
 |:----------------------:|:--------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
 |        netdata         |      /etc/os-release       | Host info detection.                                                                                                                       |
+|    diskspace.plugin    |             /              | Host mount points monitoring.                                                                                                              |
 |     cgroups.plugin     | /sys, /var/run/docker.sock | Docker containers monitoring and name resolution.                                                                                          |
 |      go.d.plugin       |    /var/run/docker.sock    | Docker Engine and containers monitoring. See [docker](https://github.com/netdata/go.d.plugin/tree/master/modules/docker#readme) collector. |
 |      go.d.plugin       |          /var/log          | Web servers logs tailing. See [weblog](https://github.com/netdata/go.d.plugin/tree/master/modules/weblog#readme) collector.                |
@@ -80,6 +81,7 @@ docker run -d --name=netdata \
   -v netdataconfig:/etc/netdata \
   -v netdatalib:/var/lib/netdata \
   -v netdatacache:/var/cache/netdata \
+  -v /:/host/root:ro,rslave \
   -v /etc/passwd:/host/etc/passwd:ro \
   -v /etc/group:/host/etc/group:ro \
   -v /etc/localtime:/etc/localtime:ro \
@@ -121,6 +123,7 @@ services:
       - netdataconfig:/etc/netdata
       - netdatalib:/var/lib/netdata
       - netdatacache:/var/cache/netdata
+      - /:/host/root:ro,rslave
       - /etc/passwd:/host/etc/passwd:ro
       - /etc/group:/host/etc/group:ro
       - /etc/localtime:/etc/localtime:ro
@@ -233,6 +236,7 @@ docker run -d --name=netdata \
   -v $(pwd)/netdataconfig/netdata:/etc/netdata \
   -v netdatalib:/var/lib/netdata \
   -v netdatacache:/var/cache/netdata \
+  -v /:/host/root:ro,rslave \
   -v /etc/passwd:/host/etc/passwd:ro \
   -v /etc/group:/host/etc/group:ro \
   -v /etc/localtime:/etc/localtime:ro \
@@ -274,6 +278,7 @@ services:
       - ./netdataconfig/netdata:/etc/netdata
       - netdatalib:/var/lib/netdata
       - netdatacache:/var/cache/netdata
+      - /:/host/root:ro,rslave
       - /etc/passwd:/host/etc/passwd:ro
       - /etc/group:/host/etc/group:ro
       - /etc/localtime:/etc/localtime:ro
@@ -349,6 +354,7 @@ services:
       - netdataconfig:/etc/netdata
       - netdatalib:/var/lib/netdata
       - netdatacache:/var/cache/netdata
+      - /:/host/root:ro,rslave
       - /etc/passwd:/host/etc/passwd:ro
       - /etc/group:/host/etc/group:ro
       - /etc/localtime:/etc/localtime:ro
@@ -402,6 +408,7 @@ services:
       - netdataconfig:/etc/netdata
       - netdatalib:/var/lib/netdata
       - netdatacache:/var/cache/netdata
+      - /:/host/root:ro,rslave
       - /etc/passwd:/host/etc/passwd:ro
       - /etc/group:/host/etc/group:ro
       - /etc/localtime:/etc/localtime:ro
@@ -449,6 +456,7 @@ services:
       - netdataconfig:/etc/netdata
       - netdatalib:/var/lib/netdata
       - netdatacache:/var/cache/netdata
+      - /:/host/root:ro,rslave
       - /etc/passwd:/host/etc/passwd:ro
       - /etc/group:/host/etc/group:ro
       - /etc/localtime:/etc/localtime:ro

+ 14 - 11
src/collectors/diskspace.plugin/plugin_diskspace.c

@@ -111,6 +111,7 @@ void mountpoint_delete_cb(const DICTIONARY_ITEM *item __maybe_unused, void *entr
 struct basic_mountinfo {
     char *persistent_id;    
     char *root;             
+    char *mount_point_stat_path;
     char *mount_point;      
     char *filesystem;       
 
@@ -123,12 +124,13 @@ static netdata_mutex_t slow_mountinfo_mutex;
 static struct basic_mountinfo *basic_mountinfo_create_and_copy(struct mountinfo* mi)
 {
     struct basic_mountinfo *bmi = callocz(1, sizeof(struct basic_mountinfo));
-    
+
     if (mi) {
         bmi->persistent_id = strdupz(mi->persistent_id);
-        bmi->root          = strdupz(mi->root);
-        bmi->mount_point   = strdupz(mi->mount_point);
-        bmi->filesystem    = strdupz(mi->filesystem);
+        bmi->root = strdupz(mi->root);
+        bmi->mount_point_stat_path = strdupz(mi->mount_point_stat_path);
+        bmi->mount_point = strdupz(mi->mount_point);
+        bmi->filesystem = strdupz(mi->filesystem);
     }
 
     return bmi;
@@ -150,6 +152,7 @@ static void free_basic_mountinfo(struct basic_mountinfo *bmi)
     if (bmi) {
         freez(bmi->persistent_id);
         freez(bmi->root);
+        freez(bmi->mount_point_stat_path);
         freez(bmi->mount_point);
         freez(bmi->filesystem);
 
@@ -359,9 +362,9 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
             usec_t start_time = now_monotonic_high_precision_usec();
             struct stat bs;
 
-            if(stat(mi->mount_point, &bs) == -1) {
+            if(stat(mi->mount_point_stat_path, &bs) == -1) {
                 collector_error("DISKSPACE: Cannot stat() mount point '%s' (disk '%s', filesystem '%s', root '%s')."
-                               , mi->mount_point
+                               , mi->mount_point_stat_path
                                , disk
                                , mi->filesystem?mi->filesystem:""
                                , mi->root?mi->root:""
@@ -372,7 +375,7 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
             else {
                 if((bs.st_mode & S_IFMT) != S_IFDIR) {
                     collector_error("DISKSPACE: Mount point '%s' (disk '%s', filesystem '%s', root '%s') is not a directory."
-                                   , mi->mount_point
+                                   , mi->mount_point_stat_path
                                    , disk
                                    , mi->filesystem?mi->filesystem:""
                                    , mi->root?mi->root:""
@@ -451,10 +454,10 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
     usec_t start_time = now_monotonic_high_precision_usec();
     struct statvfs buff_statvfs;
 
-    if (statvfs(mi->mount_point, &buff_statvfs) < 0) {
+    if (statvfs(mi->mount_point_stat_path, &buff_statvfs) < 0) {
         if(!m->shown_error) {
             collector_error("DISKSPACE: failed to statvfs() mount point '%s' (disk '%s', filesystem '%s', root '%s')"
-                            , mi->mount_point
+                            , mi->mount_point_stat_path
                             , disk
                             , mi->filesystem?mi->filesystem:""
                             , mi->root?mi->root:""
@@ -489,10 +492,10 @@ static inline void do_slow_disk_space_stats(struct basic_mountinfo *mi, int upda
     m->updated = true;
 
     struct statvfs buff_statvfs;
-    if (statvfs(mi->mount_point, &buff_statvfs) < 0) {
+    if (statvfs(mi->mount_point_stat_path, &buff_statvfs) < 0) {
         if(!m->shown_error) {
             collector_error("DISKSPACE: failed to statvfs() mount point '%s' (disk '%s', filesystem '%s', root '%s')"
-                            , mi->mount_point
+                            , mi->mount_point_stat_path
                             , mi->persistent_id
                             , mi->filesystem?mi->filesystem:""
                             , mi->root?mi->root:""

+ 25 - 7
src/collectors/proc.plugin/proc_self_mountinfo.c

@@ -113,6 +113,7 @@ struct mountinfo *mountinfo_find_by_filesystem_super_option(struct mountinfo *ro
 
 static void mountinfo_free(struct mountinfo *mi) {
     freez(mi->root);
+    freez(mi->mount_point_stat_path);
     freez(mi->mount_point);
     freez(mi->mount_options);
     freez(mi->persistent_id);
@@ -212,13 +213,23 @@ static inline int mount_point_is_protected(char *mount_point)
 // read the whole mountinfo into a linked list
 struct mountinfo *mountinfo_read(int do_statvfs) {
     char filename[FILENAME_MAX + 1];
-    snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", netdata_configured_host_prefix);
-    procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
-    if(unlikely(!ff)) {
+
+    snprintfz(filename, FILENAME_MAX, "%s/root/proc/1/mountinfo", netdata_configured_host_prefix);
+    procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+
+    // Inside docker with '-v "/:/host/root:ro'
+    bool host_root_prefix = ff != NULL;
+
+    if (!ff) {
+        snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", netdata_configured_host_prefix);
+        ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
+    }
+    if (!ff) {
         snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", netdata_configured_host_prefix);
         ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
-        if(unlikely(!ff)) return NULL;
     }
+    if (!ff)
+        return NULL;
 
     ff = procfile_readall(ff);
     if(unlikely(!ff))
@@ -269,9 +280,16 @@ struct mountinfo *mountinfo_read(int do_statvfs) {
         mi->root = strdupz(procfile_lineword(ff, l, w)); w++;
         mi->root_hash = simple_hash(mi->root);
 
-        mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++;
+        mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w));w++;
         mi->mount_point_hash = simple_hash(mi->mount_point);
 
+        if (host_root_prefix) {
+            snprintfz(filename, FILENAME_MAX, "%s/root%s", netdata_configured_host_prefix, mi->mount_point);
+            mi->mount_point_stat_path = strdupz(filename);
+        } else {
+            mi->mount_point_stat_path = strdupz(mi->mount_point);
+        }
+
         mi->persistent_id = strdupz(mi->mount_point);
         netdata_fix_chart_id(mi->persistent_id);
         mi->persistent_id_hash = simple_hash(mi->persistent_id);
@@ -339,7 +357,7 @@ struct mountinfo *mountinfo_read(int do_statvfs) {
             // mark as BIND the duplicates (i.e. same filesystem + same source)
             if(do_statvfs) {
                 struct stat buf;
-                if(unlikely(stat(mi->mount_point, &buf) == -1)) {
+                if(unlikely(stat(mi->mount_point_stat_path, &buf) == -1)) {
                     mi->st_dev = 0;
                     mi->flags |= MOUNTINFO_NO_STAT;
                 }
@@ -391,7 +409,7 @@ struct mountinfo *mountinfo_read(int do_statvfs) {
         // check if it has size
         if(do_statvfs && !(mi->flags & MOUNTINFO_IS_DUMMY)) {
             struct statvfs buff_statvfs;
-            if(unlikely(statvfs(mi->mount_point, &buff_statvfs) < 0)) {
+            if(unlikely(statvfs(mi->mount_point_stat_path, &buff_statvfs) < 0)) {
                 mi->flags |= MOUNTINFO_NO_STAT;
             }
             else if(unlikely(!buff_statvfs.f_blocks /* || !buff_statvfs.f_files */)) {

+ 2 - 1
src/collectors/proc.plugin/proc_self_mountinfo.h

@@ -24,7 +24,8 @@ struct mountinfo {
     char *root;             // root: root of the mount within the filesystem.
     uint32_t root_hash;
 
-    char *mount_point;      // mount point: mount point relative to the process's root.
+    char *mount_point_stat_path; // the actual pathname of the mount point (may differ in Docker)
+    char *mount_point;           // mount point: mount point relative to the process's root.
     uint32_t mount_point_hash;
 
     char *mount_options;    // mount options: per-mount options.