diff --git a/config.ru b/config.ru index d7e04c2..1cefb2b 100644 --- a/config.ru +++ b/config.ru @@ -1,13 +1,20 @@ require 'rack' -require_relative 'lxc-exporter' +require_relative 'lib/lxc_collector' +require_relative 'lib/authorized_keys_collector' require 'prometheus/client/formats/text' run lambda {|env| req = Rack::Request.new env case req.path - when "/metrics" + + when '/authorized_keys' + collector = AuthorizedKeysCollector.new + [200, {"Content-Type" => "text/javascript"}, [collector.collect.to_json]}] + + when '/metrics' collector = LxcCollector.new [200, {"Content-Type" => "text/plain"}, [Prometheus::Client::Formats::Text.marshal( collector.collect)]] + else [404, {"Content-Type" => "text/plain"}, ["Not found\nYou want to try /metrics?\n"]] end diff --git a/lib/file-statfs.rb b/lib/file-statfs.rb new file mode 100644 index 0000000..a1cdc6f --- /dev/null +++ b/lib/file-statfs.rb @@ -0,0 +1,140 @@ +require 'fiddle' +require 'fiddle/import' + +class File + module Statfs + Magics = {} + Line = <<~EOF + ADFS 0xadf5 + AFFS 0xadff + AFS 0x5346414F + AUTOFS 0x0187 + CODA 0x73757245 + CRAMFS 0x28cd3d45 + CRAMFS_WEND 0x453dcd28 + DEBUGFS 0x64626720 + SECURITYFS 0x73636673 + SELINUX 0xf97cff8c + SMACK 0x43415d53 + RAMFS 0x858458f6 + TMPFS 0x01021994 + HUGETLBFS 0x958458f6 + SQUASHFS 0x73717368 + ECRYPTFS 0xf15f + EFS 0x414A53 + EROFS_V1 0xE0F5E1E2 + EXT2 0xEF53 + EXT3 0xEF53 + XENFS 0xabba1974 + EXT4 0xEF53 + BTRFS 0x9123683E + NILFS 0x3434 + F2FS 0xF2F52010 + HPFS 0xf995e849 + ISOFS 0x9660 + JFFS2 0x72b6 + XFS 0x58465342 + PSTOREFS 0x6165676C + EFIVARFS 0xde5e81e4 + HOSTFS 0x00c0ffee + OVERLAYFS 0x794c7630 + MINIX 0x137F + MINIX2 0x138F + MINIX2 0x2468 + MINIX22 0x2478 + MINIX3 0x4d5a + MSDOS 0x4d44 + NCP 0x564c + NFS 0x6969 + OCFS2 0x7461636f + OPENPROM 0x9fa1 + QNX4 0x002f + QNX6 0x68191122 + AFS_FS 0x6B414653 + REISERFS 0x52654973 + REISERFS "ReIsErFs" + REISER2FS "ReIsEr2Fs" + REISER2FS_JR "ReIsEr3Fs" + SMB 0x517B + CGROUP 0x27e0eb + CGROUP2 0x63677270 + RDTGROUP 0x7655821 + STACK_END 0x57AC6E9D + TRACEFS 0x74726163 + V9FS 0x01021997 + BDEVFS 0x62646576 + DAXFS 0x64646178 + BINFMTFS 0x42494e4d + DEVPTS 0x1cd1 + BINDERFS 0x6c6f6f70 + FUTEXFS 0xBAD1DEA + PIPEFS 0x50495045 + PROC 0x9fa0 + SOCKFS 0x534F434B + SYSFS 0x62656572 + USBDEVICE 0x9fa2 + MTD_INODE_FS 0x11307854 + ANON_INODE_FS 0x09041934 + BTRFS_TEST 0x73727279 + NSFS 0x6e736673 + BPF_FS 0xcafe4a11 + AAFS 0x5a3c69f0 + ZONEFS 0x5a4f4653 + UDF 0x15013346 + BALLOON_KVM 0x13661366 + ZSMALLOC 0x58295829 + DMA_BUF 0x444d4142 + DEVMEM 0x454d444d + Z3FOLD 0x33 + PPC_CMM 0xc7571590 + EOF + Line.each_line do |l| + n, v = l.split(/\s+/)[0..1] + v = + case v + when /^0x(\h+)$/ then $1.to_i 16 + when /^"([^"]+)"$/ then $1 + else raise "Unknown value: #$1" + end + Magics[v] = n.downcase.to_sym + end + + extend Fiddle::Importer + dlload Fiddle.dlopen( nil) + + Struct_statfs = struct <<~EOS + long type, + long bsize, + unsigned long blocks, + unsigned long bfree, + unsigned long bavail, + unsigned long files, + unsigned long ffree, + int fsid[2], + long namelen, + long frsize, + long flags, + long spare[4] + EOS + + class Struct_statfs + def fstypename + Magics[type] + end + + def to_h + {type: type, fstypename: fstypename, bsize: bsize, blocks: blocks, bfree: bfree, bavail: bavail, files: files, ffree: ffree, fsid: fsid, namelen: namelen, frsize: frsize, flags: flags, spare: spare} + end + end + + StatfsFun = Fiddle::Function.new handler['statfs'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT + #extern 'int statfs( const char *__file, struct statfs *__buf)' + + def self.new file + buf = Struct_statfs.malloc + val = StatfsFun.call file, buf + raise SystemCallError.new( "statfs(#{file.inspect})", Fiddle.last_error) unless val == 0 + buf + end + end +end diff --git a/lib/lxc-exporter/mount_info.rb b/lib/lxc-exporter/mount_info.rb new file mode 100644 index 0000000..5d50e51 --- /dev/null +++ b/lib/lxc-exporter/mount_info.rb @@ -0,0 +1,25 @@ +require 'pathname' + +class MountInfo + attr_reader :major, :minor, :mp, :dev, :type, :opts + + # 4979 4977 0:213 / /proc rw,nosuid,nodev,noexec,relatime shared:2416 - proc proc rw + + def initialize *args + i = args.find_index {|x| '-' == x } + args2 = args[(i+1)..-1] + ma, mi = args[2].split ':' + @major, @minor, @mp, @dev, @type, @opts = + ma.to_i, mi.to_i, args[4], args2[1], args2[0], args2[2].split( ',') + end + + class << self + def parse line + new *line.split( ' ') + end + + def of pid + Pathname.new( "/proc/#{pid}/mountinfo").readlines.map {|l| parse l } + end + end +end diff --git a/lib/lxc-exporter/os_release.rb b/lib/lxc-exporter/os_release.rb new file mode 100644 index 0000000..765df03 --- /dev/null +++ b/lib/lxc-exporter/os_release.rb @@ -0,0 +1,38 @@ +require 'pathname' + +class OsRelease + Path = Pathname.new '/etc/os-release' + + class <