Parent

Class/Module Index [+]

Quicksearch

OpenShift::Runtime::Utils::Cgroups::Libcgroup

Public Class Methods

cgroup_mounts() click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 75
def self.cgroup_mounts
  if not @@cgroup_mounts_cache
    @@cgroup_mounts_cache = {}
    File.open("/proc/mounts") do |mounts|
      mounts.each do |mntpt|
        fs_spec, fs_file, fs_vtype, fs_mntops, fs_freq, fs_passno = mntpt.split
        fs_mntops = fs_mntops.split(',')
        if fs_vtype == "cgroup"
          subsystems.each do |subsys|
            @@cgroup_mounts_cache[subsys]=fs_file if fs_mntops.include?(subsys)
          end
        end
      end
    end
    @@cgroup_mounts_cache.freeze
  end
  @@cgroup_mounts_cache
end
cgroup_paths() click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 94
def self.cgroup_paths
  if not @@cgroup_paths_cache
    @@cgroup_paths_cache = {}
    cgroup_mounts.each do |subsys, mntpt|
      p = File.join(mntpt, cgroup_root)
      Dir.mkdir(p, 0755) unless File.exist?(p)
      @@cgroup_paths_cache[subsys]=p
    end
    @@cgroup_paths_cache.freeze
  end
  @@cgroup_paths_cache
end
cgroup_root() click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 57
def self.cgroup_root
  if not @@cgroup_root_cache
    @@cgroup_root_cache = (OpenShift::Config.new.get("OPENSHIFT_CGROUP_ROOT") or @@DEFAULT_CGROUP_ROOT)
  end
  @@cgroup_root_cache
end
new(uuid) click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 46
def initialize(uuid)
  raise ArgumentError, "Invalid uuid" if uuid.to_s == ""

  @uuid = uuid

  @cgroup_root = self.class.cgroup_root
  @cgroup_path = "#{@cgroup_root}/#{@uuid}"
  @config      = OpenShift::Config.new
  @wrap_around_uid = (@config.get("WRAPAROUND_UID") || 65536).to_i
end
parameters() click to toggle source

Public: List the available parameters for the implementation

and their default values.

Note: This will only list parameters that have a specific

controller associated with them and will not list
general cgroups parameters.
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 117
def self.parameters
  if not @@parameters_cache
    @@parameters_cache = {}
    cgroup_paths.each do |subsys, path|
      Dir.entries(path).select { |p|
        p.start_with?("#{subsys}.")
      }.sort { |a,b|
        a.count('.') <=> b.count('.')   # "memory.foo" must be set before "memory.memsw.foo"
      }.each do |p|
        begin
          @@parameters_cache[p]=parse_cgparam(File.read(File.join(path, p)))
        rescue
        end
      end
    end
    @@parameters_cache.freeze
  end
  @@parameters_cache
end
parse_usage(info) click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 163
def self.parse_usage(info)
  info.lines.to_a.inject(Hash.new{|h,k| h[k] = {}} ) do |h,line|
    (uuid, key, val) = line.split(/\W/).values_at(0,-2,-1)
    h[uuid][key.to_sym] = val.to_i
    h
  end
end
subsystems() click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 64
def self.subsystems
  if not @@subsystems_cache
    @@subsystems_cache = (OpenShift::Config.new.get("OPENSHIFT_CGROUP_SUBSYSTEMS") or @@DEFAULT_CGROUP_SUBSYSTEMS).strip.split(',').freeze
  end
  @@subsystems_cache
end
usage() click to toggle source

TODO: These could potentially be replaced by cgsnapshot if we can determine if its fast enough (str, err, rc = ::OpenShift::Runtime::Utils::oo_spawn('cgsnapshot 2> /dev/null') keys = %w(cpu.cfs_period_us cpu.cfs_quota_us cpuacct.usage) Hash[str.scan(/^groupsopenshift/(.*?)s(.*?)^}/m).map{|mg| [mg, Hash[mg.scan(/s*(#{keys.join('|')})s*=s*"(.*)";/).map{|k,v| [k,v.to_i]}]] }]

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 149
def self.usage
  # Retrieve cgroup counters: cpu.stat, cpuacct.usage, cpu.cfs_quota_us
  expression     = '/cgroup/*/openshift/*/cpu*'
  cmd            = %(set -e -o pipefail; grep -H ^ #{expression} |sed 's|^/cgroup/[^/]*/openshift/||')
  (out, err, rc) = ::OpenShift::Runtime::Utils::oo_spawn(cmd, :quiet => true)
  if 1 < rc
    (count, _, _) = ::OpenShift::Runtime::Utils::oo_spawn(%(ls #{expression} |wc -l), :quiet => true)
    unless count.chomp == '0'
      NodeLogger.logger.error %(Failed to read cgroups counters from #{expression}: #{err} (#{rc}))
    end
  end
  parse_usage(out)
end

Protected Class Methods

parse_cgparam(val) click to toggle source

Private: Parse the contents of a cgroups entry

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 337
def self.parse_cgparam(val)
  pval = val.split(/\n/).map { |v| [*v.split] }
  if pval.flatten.length == 1
    pval.flatten.first
  elsif pval.flatten.first.length == 1
    pval.flatten
  else
    Hash[*(pval.map { |l| [l.shift, l.join(' ')] }.flatten)]
  end
end

Public Instance Methods

cgroup_paths() click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 107
def cgroup_paths
  Hash[ *(self.class.cgroup_paths.map { |subsys, path| [ subsys, File.join(path, @uuid) ] }.flatten ) ]
end
classify_processes() click to toggle source

Public: Distribute this user's processes into their cgroup

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 276
def classify_processes
  errors = {}

  threads = []
  threads_foreach do |tid, pid, name, puid, pgid|
    if puid == uid
      threads << tid
    end
  end

  cgroup_paths.each do |subsys, path|
    begin
      File.open(File.join(path, "tasks"), File::WRONLY | File::SYNC) do |t|
        threads.each do |pid|
          begin
            t.syswrite "#{pid}\n"
          rescue Errno::ESRCH       # The thread went away or is a zombie
          rescue Errno::ENOMEM => e # Cannot allocate memory (cgroup is full)
            errors[pid]="The cgroup is full"
            NodeLogger.logger.error("Error classifying #{@uuid} #{pid}: The cgroup is full")
          rescue => e
            errors[pid]=e.message
            NodeLogger.logger.error("Error classifying #{@uuid} #{pid}: #{e.message}")
          end
        end
      end
    rescue Errno::ENOENT
    end
  end
  errors
end
create(defaults={}) click to toggle source

Public: Create a cgroup namespace for the gear

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 172
def create(defaults={})
  newcfg = Hash["perm", {}, *(subsystems.map { |s| [s,{}] }.flatten)]
  to_store = Hash.new

  newcfg["perm"] = {
    "task" => {   # These must be numeric to avoid confusion in libcgroup.
      "uid" => uid,
      "gid" => uid,
    },
    "admin" => {  # These must be "root", as "0" confuses libcgroup.
      "uid" => "root",
      "gid" => "root",
    }
  }

  newcfg["net_cls"]["net_cls.classid"] = net_cls
  to_store["net_cls.classid"] = newcfg["net_cls"]["net_cls.classid"]

  # Parameter order matters and its implicitly defined in
  # parameters
  parameters.each_key do |k|
    v = defaults[k]
    if v
      subsys = k.split('.')[0]
      if subsystems.include?(subsys)
        newcfg[subsys][k]=v
        to_store[k]=v
      end
    end
  end

  with_cgroups_lock do
    cgcreate
    update_cgconfig(newcfg)
    update_cgrules(true)
  end

  store(to_store)
  classify_processes
end
delete() click to toggle source

Public: Delete a cgroup namespace for the gear

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 214
def delete
  with_cgroups_lock do
    update_cgconfig(nil)
    update_cgrules(false)
    cgdelete
  end
end
exists?() click to toggle source

Public: Return true if a cgroup exists for this uuid

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 224
def exists?
  begin
    fetch
  rescue ArgumentError
    return false
  end
  true
end
fetch(*args) click to toggle source

Public: Fetch parameters for a specific uuid, or a hash of key=>value for all parametetrs for the gear.

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 235
def fetch(*args)
  keys = [*args].flatten.flatten
  vals = {}

  # Parameter order matters and is implicitly defined in the
  # parameters variable.
  parameters.select { |k,v| keys.include?(k) }.each do |param, defval|
    path = cgroup_paths[param.split('.')[0]]
    raise RuntimeError, "User does not exist in cgroups: #{@uuid}" unless (path and File.exist?(path))
    begin
      val = File.read(File.join(path, param))
      vals[param] = parse_cgparam(val)
    rescue Errno::ENOENT
      raise KeyError, "Cgroups parameter not found: #{param}"
    end
  end
  vals
end
parameters() click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 137
def parameters
  self.class.parameters
end
processes() click to toggle source

Public: List processes in a cgroup regardless of what UID owns them

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 309
def processes
  pids = []
  cgroup_paths.each do |subsys, path|
    begin
      pids << File.read(File.join(path, "tasks")).split.map { |pid| pid.to_i }
    rescue Errno::ENOENT
    end
  end
  pids.flatten.uniq
end
store(*args) click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 254
def store(*args)
  vals = Hash[*args]

  # Parameter order matters and is implicitly defined in the
  # parameters variable.
  parameters.map { |k, v| [k, vals[k]] }.select { |ent| ent[1] }.each do |param, val|
    path = cgroup_paths[param.split('.')[0]]
    raise RuntimeError, "User does not exist in cgroups: #{@uuid}" unless (path and File.exist?(path))
    begin
      File.open(File.join(path, param), File::WRONLY | File::SYNC) do |t|
        t.syswrite("#{val}\n")
      end
    rescue Errno::ENOENT
      raise KeyError, "Cgroups controller or parameter not found for: #{param}"
    rescue Errno::EINVAL, Errno::EIO
      raise KeyError, "Cgroups parameter cannot be set to value: #{param} = #{val}"
    end
  end
  vals
end
subsystems() click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 71
def subsystems
  self.class.subsystems
end
uid() click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 141
def uid
  @uid_cache ||= Etc.getpwnam(@uuid).uid
end

Protected Instance Methods

cgcreate() click to toggle source

Private: Call the low level cgroups creation

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 353
def cgcreate
  cgroup_paths.each do |subsys, path|
    Dir.mkdir(path, 0755) unless File.exist?(path)
    File.chown(uid, uid, File.join(path, "tasks"))
  end
end
cgdelete() click to toggle source

Private: Call the low level cgroups deletion

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 403
def cgdelete
  cgroup_paths.each do |subsys, path|
    while File.exist?(path)
      begin
        Dir.rmdir(path)
      rescue Errno::EBUSY
        File.open(File.join(path, "..", "tasks"), File::WRONLY | File::SYNC) do |t|
          File.read(File.join(path, "tasks")).split.each do |pid|
            t.syswrite("#{pid}\n")
          end
        end
      end
    end
  end
  nil
end
gen_cgconfig(data) click to toggle source

Private: Generate configuration stanzas for cgconfig.conf from a hash.

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 457
def gen_cgconfig(data)
  rbuf = ""
  if data.respond_to? :each_pair
    rbuf << "{"
    data.each_pair do |k,v|
      rbuf << " #{k} "
      rbuf << gen_cgconfig(v)
    end
    rbuf << "}"
  else
    rbuf << "= #{data}; "
  end
  rbuf
end
net_cls() click to toggle source

Compute the network class id Major = 1 Minor = UID Caveat: 0 <= Minor

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 327
def net_cls
  major = 1
  if (uid < 1)
    raise RuntimeError, "Cannot assign network class id for: #{uid}"
  end
  (major << 16) + (uid % @wrap_around_uid)
end
overwrite_with_safe_swap(filename) click to toggle source

Private: Open and safely swap the file if it changed

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 495
def overwrite_with_safe_swap(filename)
  r=nil

  begin
    f_in=File.open(filename, File::RDONLY)
  rescue Errno::ENOENT
    f_in=File.open('/dev/null', File::RDONLY)
  end

  begin
    File.open(filename+"-", File::RDWR|File::CREAT|File::TRUNC, 0o0644) do |f_out|
      if block_given?
        r=yield(f_in, f_out)
      end
      f_out.fsync()
    end
  ensure
    f_in.close
  end

  FileUtils.mv(filename+"-", filename, :force => true)
  SelinuxContext.instance.chcon(filename)

  r
end
parse_cgparam(*args) click to toggle source
# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 348
def parse_cgparam(*args)
  self.class.parse_cgparam(*args)
end
processes_foreach() click to toggle source

Private: List of processes on the system

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 375
def processes_foreach
  Dir.foreach('/proc') do |procent|
    begin
      pid = procent.to_i
      uid = 0
      gid = 0
      name = ""

      File.open(File.join('/proc', procent, "status")) do |f|
        f.each do |l|
          token, values = l.split(':')
          case token
          when 'Name'
            name = values.strip
          when 'Uid'
            uid = values.strip.split[0].to_i
          when 'Gid'
            gid = values.strip.split[0].to_i
          end
        end
      end
      yield(pid, name, uid, gid)
    rescue
    end
  end
end
threads_foreach() click to toggle source

Private: List of threads on the system

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 361
def threads_foreach
  processes_foreach do |pid, name, uid, gid|
    begin
      Dir.foreach("/proc/#{pid}/task") do |tid|
        if not tid.start_with?('.')
          yield(tid, pid, name, uid, gid)
        end
      end
    rescue
    end
  end
end
update_cgconfig(newconfig=nil) click to toggle source

Private: Update the cgconfig.conf file. This removes the requested path and re-adds it at the end if a new configuration is provided.

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 440
def update_cgconfig(newconfig=nil)
  overwrite_with_safe_swap(@@CGCONFIG) do |f_in, f_out|
    f_in.each do |l|
      if not l=~/^group #{@cgroup_path}\s/
        f_out.puts(l)
      end
    end
    if newconfig
      f_out.write("group #{@cgroup_path} ")
      f_out.write(gen_cgconfig(newconfig))
      f_out.write("\n")
    end
  end
end
update_cgrules(recreate=true) click to toggle source

Private: Update the cgrules.conf file. This removes the requested uuid and re-adds it at the end if a new path is provided.

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 423
def update_cgrules(recreate=true)
  overwrite_with_safe_swap(@@CGRULES) do |f_in, f_out|
    f_in.each do |l|
      if not l=~/^#{@uuid}\s/
        f_out.puts(l)
      end
    end
    if recreate
      f_out.puts("#{@uuid}\t#{subsystems.join(',')}\t#{@cgroup_path}")
    end
  end
  processes_foreach { |pid, name| Process.kill("USR2", pid) if name == "cgrulesengd" }
end
with_cgroups_lock() click to toggle source

Private: Serialize for editing the cgroups config files

# File lib/openshift-origin-node/utils/cgroups/libcgroup.rb, line 473
def with_cgroups_lock
  r = nil
  @@MUTEX.synchronize do
    File.open(@@LOCKFILE, File::RDWR|File::CREAT|File::TRUNC|File::SYNC, 0o0600) do |lockfile|
      lockfile.sync=true
      lockfile.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
      lockfile.flock(File::LOCK_EX)
      lockfile.write("#{Process::pid}\n")
      begin
        if block_given?
          r = yield
        end
      ensure
        lockfile.flock(File::LOCK_UN)
      end
    end
  end
  r
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.