diff --git a/Gemfile b/Gemfile index 50d1cf9..96aa959 100644 --- a/Gemfile +++ b/Gemfile @@ -3,3 +3,4 @@ gem 'ruby-lxc', git: 'https://git.denkn.at/deac/ruby-lxc' gem 'prometheus-client' gem 'puma' gem 'rack' +gem 'cbor' diff --git a/lib/cborio.rb b/lib/cborio.rb new file mode 100644 index 0000000..0354c4f --- /dev/null +++ b/lib/cborio.rb @@ -0,0 +1,54 @@ +require 'cbor' + +class CBORIO + include Enumerable + def orig_io() @io end + def unpacker() @un end + def close() @io.close end + def write( obj) @io.write CBOR.pack( obj) end + def sync() @io.sync end + def sync( v) @io.sync = v end + def self.pipe() IO.pipe.map &self.method(:new) end + def self.popen &exe + rd, wr = self.pipe + pid = + fork do + rd.close + yield wr + exit 0 + end + wr.close + [pid, rd] + end + + def initialize io + @io, @un = io, CBOR::Unpacker.new + @io.sync = true + end + + def self.open io, &exe + if block_given? + s = self.new io + begin yield s + ensure s.close + end + else self.new io + end + end + + def read + return @un.read rescue EOFError + loop do + @un.feed @io.readpartial( 1024) + return @un.read rescue EOFError + end + end + + def each &exe + return to_enum __method__ unless block_given? + loop { yield read } + self + rescue EOFError + self + end +end diff --git a/lib/lxc_collector.rb b/lib/lxc_collector.rb index 9d48244..c605e4f 100755 --- a/lib/lxc_collector.rb +++ b/lib/lxc_collector.rb @@ -1,35 +1,20 @@ #!/usr/bin/env ruby require 'pathname' -require 'json' require 'prometheus/client' require 'lxc' require_relative 'ns' require_relative 'file-statfs' +require_relative 'cborio' +require_relative 'lxc_extend' require_relative 'lxc-exporter/os_release' require_relative 'lxc-exporter/mount_info' -require_relative 'lxc_extend' - -=begin -class LXC::CT - def initialize name - extend Fiddle::Importer - dlload Fiddle.dlopen( nil) - - extern 'lxc_container *lxc_container_new( const char* name, const char* config_path)' - - def initialize name, config = nil - lxc_container_new name, config - end - end -end -=end class LxcCollector include Prometheus::Client - CTStates = { aborting: -1, stopped: 0, starting: 1, stopping: 2, running: 3 } + CTStates = { aborting: -1, stopped: 0, starting: 0.75, stopping: 0.25, running: 1 } def statfs ct, mis mis.each do |mi| @@ -81,32 +66,38 @@ class LxcCollector mis = MountInfo.of pid NS.change pid, :pid, :mnt do name = ct.config_item( 'lxc.uts.name') + + # Filesystems statfs ct, mis do |ct, mp, st| next unless st.fstypename and 0 < st.blocks st = st.to_h.merge mp: mp, id: ct.name, name: name - wr.puts [:mountpoint, st].to_json + wr.write [:mountpoint, st] end + + # OS / Distribution osr = OsRelease.read if osr - wr.puts [:os_release, { + wr.write [:os_release, { id: ct.name, name: name, os_id: osr[:id], os_name: osr[:name], os_pretty_name: osr[:pretty_name], os_version_id: osr[:version_id].to_i, os_version_codename: osr[:version_codename] - }].to_json + }] + case osr[:id].to_sym + # Special things for Debian(-based) distributions when :debian upgradable = nil pid = IO.popen %w[apt list --upgradable], err: "/dev/null" do |apt| upgradable = apt.readlines.length - 1 end - wr.puts [:pkgs, { + wr.write [:pkgs, { id: ct.name, name: name, upgradable: upgradable, last_update: AptLastUpdateFile.stat.mtime.to_f, - }].to_json + }] end end end @@ -116,19 +107,13 @@ class LxcCollector end def collect - rd, wr = IO.pipe - pid = fork do - rd.close - forked wr - end - wr.close LXC.containers do |ct| labels = { id: ct.name, name: ct.config_item( 'lxc.uts.name') } @up.set ct.running? ? 1 : 0, labels: labels @state.set CTStates[ct.state], labels: labels end - rd.each_line do |l| - l = JSON.parse l, symbolize_names: true + pid, rd = CBORIO.popen( &method( :forked)) + rd.each do |l| case l[0].to_sym when :mountpoint @@ -155,7 +140,7 @@ class LxcCollector when :pkgs as = OpenStruct.new l[1] @pkgs_last_update.set as.last_update, labels: { id: as.id } - @pkgs_upgradable.set as.upgradable, labels: { id: as.id } + @pkgs_upgradable.set as.upgradable, labels: { id: as.id } end end rd.close