Class: OsCtld::CGroup::Params

Inherits:
Object
  • Object
show all
Includes:
OsCtl::Lib::Utils::Log, Lockable
Defined in:
lib/osctld/cgroup/params.rb

Direct Known Subclasses

ContainerParams

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Lockable

#exclusively, included, #inclusively, #init_lock, #lock, #unlock

Constructor Details

#initialize(owner, params: []) ⇒ Params

Returns a new instance of Params.

Parameters:



16
17
18
19
20
# File 'lib/osctld/cgroup/params.rb', line 16

def initialize(owner, params: [])
  init_lock
  @owner = owner
  @params = params
end

Instance Attribute Details

#ownerObject (readonly, protected)

Returns the value of attribute owner.



286
287
288
# File 'lib/osctld/cgroup/params.rb', line 286

def owner
  @owner
end

#paramsObject (readonly, protected)

Returns the value of attribute params.



286
287
288
# File 'lib/osctld/cgroup/params.rb', line 286

def params
  @params
end

Class Method Details

.load(owner, cfg) ⇒ Object

Load CGroup parameters from config



10
11
12
# File 'lib/osctld/cgroup/params.rb', line 10

def self.load(owner, cfg)
  new(owner, params: (cfg || []).map { |v| CGroup::Param.load(v) })
end

Instance Method Details

#apply(keep_going: false) {|subsystem| ... } ⇒ Object

Apply configured cgroup parameters into the system

Parameters:

  • keep_going (Boolean) (defaults to: false)

    skip parameters that do not exist

Yield Parameters:

  • subsystem (String)

    cgroup subsystem

Yield Returns:

  • (String)

    absolute path to the cgroup directory



118
119
120
# File 'lib/osctld/cgroup/params.rb', line 118

def apply(keep_going: false, &block)
  apply_params_and_retry(usable_params, keep_going: keep_going, &block)
end

#apply_params(param_list, keep_going: false) ⇒ Array<CGroup::Param> (protected)

Returns parameters that failed to set.

Parameters:

  • param_list (Array<CGroup::Param>)
  • keep_going (Boolean) (defaults to: false)

Returns:



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/osctld/cgroup/params.rb', line 295

def apply_params(param_list, keep_going: false)
  failed = []

  param_list.each do |p|
    path = File.join(yield(p.subsystem), p.name)

    begin
      failed << p unless CGroup.set_param(path, p.value)

    rescue CGroupFileNotFound
      raise unless keep_going

      log(
        :info,
        :cgroup,
        "Skip #{path}, group or parameter does not exist"
      )
      next
    end
  end

  failed
end

#apply_params_and_retry(param_list, keep_going: false, &block) ⇒ Object (protected)



319
320
321
322
323
324
325
326
327
328
329
# File 'lib/osctld/cgroup/params.rb', line 319

def apply_params_and_retry(param_list, keep_going: false, &block)
  failed = apply_params(
    param_list,
    keep_going: keep_going,
    &block
  ).select { |p| p.name.start_with?('memory.') }

  if failed.any?
    apply_params(failed, keep_going: keep_going, &block)
  end
end

#detect(&block) ⇒ Object



110
111
112
# File 'lib/osctld/cgroup/params.rb', line 110

def detect(&block)
  params.detect(&block)
end

#dumpObject

Dump params to config



273
274
275
# File 'lib/osctld/cgroup/params.rb', line 273

def dump
  params.select(&:persistent).map(&:dump)
end

#dup(new_owner) ⇒ Object



277
278
279
280
281
282
283
# File 'lib/osctld/cgroup/params.rb', line 277

def dup(new_owner)
  ret = super()
  ret.init_lock
  ret.instance_variable_set('@owner', new_owner)
  ret.instance_variable_set('@params', params.map(&:clone))
  ret
end

#each(&block) ⇒ Object



97
98
99
# File 'lib/osctld/cgroup/params.rb', line 97

def each(&block)
  params.each(&block)
end

#each_usable(&block) ⇒ Object



106
107
108
# File 'lib/osctld/cgroup/params.rb', line 106

def each_usable(&block)
  each_version(CGroup.version, &block)
end

#each_version(version, &block) ⇒ Object

Parameters:

  • version (1, 2)


102
103
104
# File 'lib/osctld/cgroup/params.rb', line 102

def each_version(version, &block)
  params.select { |p| p.version == version }.each(&block)
end

#find_cpu_limitInteger?

Find CPU limit

Returns:

  • (Integer, nil)

    CPU limit in percent (100 % for one CPU)



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/osctld/cgroup/params.rb', line 236

def find_cpu_limit
  if CGroup.v2?
    each_usable do |p|
      next if p.name != 'cpu.max'

      quota, period = p.value.last.split

      if quota == 'max'
        return nil
      else
        return (quota.to_i / period.to_i) * 100
      end
    end

    return nil
  end

  quota = nil
  period = nil

  each_usable do |p|
    if p.name == 'cpu.cfs_quota_us'
      quota = p.value.last.to_i
      return nil if quota == -1
    elsif p.name == 'cpu.cfs_period_us'
      period = p.value.last.to_i
    end

    if quota && period
      return (quota / period) * 100
    end
  end

  nil
end

#find_memory_limitInteger?

Find memory limit

Returns:

  • (Integer, nil)

    memory limit in bytes



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/osctld/cgroup/params.rb', line 164

def find_memory_limit
  if CGroup.v2?
    each_usable do |p|
      next if p.name != 'memory.max'

      v = p.value.last.to_i
      return v > 0 ? v : nil
    end

    return nil
  end

  mem_limit = 0
  memsw_limit = 0

  each_usable do |p|
    if p.name == 'memory.limit_in_bytes'
      mem_limit = p.value.last.to_i
    elsif p.name == 'memory.memsw.limit_in_bytes'
      memsw_limit = p.value.last.to_i
    end

    break if mem_limit > 0 && memsw_limit > 0
  end

  if memsw_limit > 0 && memsw_limit < mem_limit
    memsw_limit
  elsif mem_limit > 0
    mem_limit
  else
    nil
  end
end

#find_swap_limitInteger?

Find swap limit

Returns:

  • (Integer, nil)

    swap limit in bytes



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/osctld/cgroup/params.rb', line 200

def find_swap_limit
  if CGroup.v2?
    each_usable do |p|
      next if p.name != 'memory.swap.max'

      v = p.value.last.to_i
      return v > 0 ? v : nil
    end

    return nil
  end

  mem_limit = 0
  memsw_limit = 0

  each_usable do |p|
    if p.name == 'memory.limit_in_bytes'
      mem_limit = p.value.last.to_i
    elsif p.name == 'memory.memsw.limit_in_bytes'
      memsw_limit = p.value.last.to_i
    end

    break if mem_limit > 0 && memsw_limit > 0
  end

  if memsw_limit > 0 && memsw_limit < mem_limit
    memsw_limit
  elsif mem_limit > 0
    memsw_limit - mem_limit
  else
    nil
  end
end

#import(new_params) ⇒ Object

Process params from the client and return internal representation. Invalid parameters raise an exception.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/osctld/cgroup/params.rb', line 24

def import(new_params)
  new_params.map do |hash|
    p = CGroup::Param.import(hash)

    # Check parameter. We can verify it only when the same cgroup version
    # is used.
    if p.version == CGroup.version
      subsys = CGroup.real_subsystem(p.subsystem)
      path = CGroup.abs_cgroup_path(subsys)

      param = File.join(path, 'osctl', p.name)

      unless File.exist?(param)
        raise CGroupParameterNotFound, "CGroup parameter '#{param}' not found"
      end
    end

    p
  end
end

#replace(new_params, save: true, &block) ⇒ Object

Replace all parameters by a new list of parameters

Parameters:

  • new_params (Array<CGroup::Param>)
  • save (Boolean) (defaults to: true)

    update the owner's config file



125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/osctld/cgroup/params.rb', line 125

def replace(new_params, save: true, &block)
  @params.each do |p|
    found = new_params.detect do |n|
      n.version == p.version && n.subsystem == p.subsystem && n.name == p.name
    end

    reset(p, true, &block) unless found
  end

  @params = new_params
  owner.save_config if save
end

#reset(param, keep_going) {|subsystem| ... } ⇒ Object

Reset cgroup parameter to its initial/unlimited value.

Only a limited subset of cgroup parameters is supported.

Parameters:

Yield Parameters:

  • subsystem (String)

    cgroup subsystem

Yield Returns:

  • (String)

    absolute path to the cgroup directory



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/osctld/cgroup/params.rb', line 146

def reset(param, keep_going)
  v = reset_value(param)
  return unless v

  path = File.join(yield(param.subsystem), param.name)
  CGroup.set_param(path, v)

rescue CGroupFileNotFound
  raise unless keep_going
  log(
    :info,
    :cgroup,
    "Skip #{path}, group or parameter does not exist"
  )
end

#reset_value(param) ⇒ Object (protected)



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/osctld/cgroup/params.rb', line 331

def reset_value(param)
  case param.name
  when 'cpu.cfs_quota_us'
    [-1]

  when 'cpu.max'
    ['max']

  when 'memory.limit_in_bytes', 'memory.memsw.limit_in_bytes'
    [-1]

  when 'memory.min', 'memory.low'
    [0]

  when 'memory.high', 'memory.max'
    ['max']

  else
    nil
  end
end

#set(new_params, append: false, save: true) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/osctld/cgroup/params.rb', line 45

def set(new_params, append: false, save: true)
  exclusively do
    new_params.each do |new_p|
      replaced = false

      params.map! do |p|
        if p.version == new_p.version \
           && p.subsystem == new_p.subsystem \
           && p.name == new_p.name
          replaced = true

          new_p.value = p.value + new_p.value if append
          new_p

        else
          p
        end
      end

      next if replaced

      params << new_p
    end
  end

  owner.save_config if save
end

#unset(del_params, save: true, reset: true, keep_going: false) {|subsystem| ... } ⇒ Object

Parameters:

  • save (Boolean) (defaults to: true)

    save config file

  • reset (Boolean) (defaults to: true)

    reset cgroup parameter value

  • keep_going (Boolean) (defaults to: false)

    skip parameters that do not exist

Yield Parameters:

  • subsystem (String)

    cgroup subsystem

Yield Returns:

  • (String)

    absolute path to the cgroup directory



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/osctld/cgroup/params.rb', line 78

def unset(del_params, save: true, reset: true, keep_going: false, &block)
  exclusively do
    del_params.each do |del_h|
      del_p = CGroup::Param.import(del_h)

      params.delete_if do |p|
        del = p.version == del_p.version \
              && p.subsystem == del_p.subsystem \
              && p.name == del_p.name
        next(del) if !del
        reset(p, keep_going, &block) if reset && p.version == CGroup.version
        true
      end
    end
  end

  owner.save_config if save
end

#usable_paramsObject (protected)



288
289
290
# File 'lib/osctld/cgroup/params.rb', line 288

def usable_params
  params.select { |p| p.version == CGroup.version }
end