Class: OsCtl::Cli::Bisect

Inherits:
Object
  • Object
show all
Defined in:
lib/osctl/cli/bisect.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cts, suspend_action: nil, cols: nil) ⇒ Bisect

Returns a new instance of Bisect.

Parameters:

  • cts (Array)
  • suspend_action (:freeze, :stop) (defaults to: nil)
  • cols (Array) (defaults to: nil)


8
9
10
11
12
13
# File 'lib/osctl/cli/bisect.rb', line 8

def initialize(cts, suspend_action: nil, cols: nil)
  @cts = cts
  @suspend_action = suspend_action
  @cols = cols
  @mutex = Mutex.new
end

Instance Attribute Details

#colsObject (readonly, protected)

Returns the value of attribute cols.



39
40
41
# File 'lib/osctl/cli/bisect.rb', line 39

def cols
  @cols
end

#ctsObject (readonly, protected)

Returns the value of attribute cts.



39
40
41
# File 'lib/osctl/cli/bisect.rb', line 39

def cts
  @cts
end

#mutexObject (readonly, protected)

Returns the value of attribute mutex.



39
40
41
# File 'lib/osctl/cli/bisect.rb', line 39

def mutex
  @mutex
end

#suspend_actionObject (readonly, protected)

Returns the value of attribute suspend_action.



39
40
41
# File 'lib/osctl/cli/bisect.rb', line 39

def suspend_action
  @suspend_action
end

Instance Method Details

#action_reverse(action) ⇒ Object (protected)

Parameters:

  • action (:suspend, :resume)


171
172
173
# File 'lib/osctl/cli/bisect.rb', line 171

def action_reverse(action)
  action == :suspend ? :resume : :suspend
end

#action_str(action) ⇒ Object (protected)



175
176
177
178
179
180
181
182
183
# File 'lib/osctl/cli/bisect.rb', line 175

def action_str(action)
  if suspend_action == :freeze
    action == :suspend ? 'freeze' : 'thaw'
  elsif suspend_action == :stop
    action == :suspend ? 'stop' : 'start'
  else
    raise "invalid action '#{suspend_action}'"
  end
end

#ask_confirmation!Object (protected)



96
97
98
99
100
101
102
103
104
105
# File 'lib/osctl/cli/bisect.rb', line 96

def ask_confirmation!
  $stdout.write('Continue? [y/N]: ')
  $stdout.flush

  unless %w[y yes].include?($stdin.readline.strip.downcase)
    raise 'Aborted'
  end

  puts
end

#ask_success?Boolean (protected)

Returns:

  • (Boolean)


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/osctl/cli/bisect.rb', line 107

def ask_success?
  loop do
    $stdout.write('Has the situation changed? [y/n]: ')
    $stdout.flush

    s = $stdin.readline.strip.downcase
    ret = nil

    if %w[y yes].include?(s)
      ret = true
    elsif %w[n no].include?(s)
      ret = false
    end

    puts

    return ret unless ret.nil?
  end
end

#bisectObject (protected)



41
42
43
44
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/osctl/cli/bisect.rb', line 41

def bisect
  ct_set = @cts.clone
  action = :suspend

  loop do
    if ct_set.size == 1
      execute_action_set(ct_set, :resume) if action == :resume

      ct = ct_set.first
      puts
      puts "Container identified: #{ct[:pool]}:#{ct[:id]}"
      break
    end

    left, right = ct_set.each_slice((ct_set.size / 2.0).round).to_a

    execute_action_set(left, action)
    puts

    if action == :suspend
      if ask_success?
        ct_set = left
        action = :resume
        execute_action_set(right, :resume)
      else
        ct_set = right
        action = :suspend
        execute_action_set(left, :resume)
        puts
      end

    elsif action == :resume
      if ask_success?
        ct_set = left
        action = :suspend
        execute_action_set(right, :resume)
      else
        ct_set = right
        action = :resume
        execute_action_set(left, :resume)
        puts
      end

    else
      raise 'programming error'
    end

    puts "Narrowed down to #{ct_set.size} containers"
  end
end

#execute_action_set(ct_set, action) ⇒ Object (protected)

Parameters:

  • ct_set (Array)
  • action (:suspend, :resume)


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/osctl/cli/bisect.rb', line 129

def execute_action_set(ct_set, action)
  queue = Queue.new
  ct_set.each_with_index { |ct, i| queue << [i + 1, ct] }
  n = ct_set.length

  osctl_action =
    if suspend_action == :freeze
      action == :suspend ? :ct_freeze : :ct_unfreeze
    elsif suspend_action == :stop
      action == :suspend ? :ct_stop : :ct_start
    else
      raise "invalid action '#{suspend_action}'"
    end

  threads = Etc.nprocessors.times.map do
    Thread.new do
      c = OsCtl::Client.new
      c.open

      loop do
        begin
          i, ct = queue.pop(true)
        rescue ThreadError
          break
        end

        resp = c.cmd_response(osctl_action, pool: ct[:pool], id: ct[:id])

        mutex.synchronize do
          puts "[#{i}/#{n}] #{action_str(action)} #{ct[:pool]}:#{ct[:id]} " \
               "... #{resp.ok? ? 'ok' : "error: #{resp.message}"}"
        end
      end

      c.close
    end
  end

  threads.each(&:join)
end


92
93
94
# File 'lib/osctl/cli/bisect.rb', line 92

def print_set(ct_set)
  OsCtl::Lib::Cli::OutputFormatter.print(ct_set, cols:, layout: :columns)
end

#resetObject



33
34
35
# File 'lib/osctl/cli/bisect.rb', line 33

def reset
  execute_action_set(cts, :resume)
end

#runObject



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/osctl/cli/bisect.rb', line 15

def run
  print_set(cts)
  puts
  puts "Selected containers: #{cts.length}"
  puts "Suspend action: #{suspend_action}"
  puts
  ask_confirmation!

  begin
    bisect
  rescue StandardError, Interrupt
    puts
    puts 'Resuming all affected containers...'
    reset
    raise
  end
end