Class: OsCtld::Console::Console

Inherits:
TTY
  • Object
show all
Includes:
OsCtl::Lib::Utils::Exception
Defined in:
lib/osctld/console/console.rb

Overview

Special case for tty0 (/dev/console)

tty0 is opened on container start, at least when it’s started by osctld. The tty is accessed using unix server socket created by the osctld container wrapper.

Instance Attribute Summary

Attributes inherited from TTY

#ct, #n, #tty_in_io, #tty_out_io, #tty_pid

Instance Method Summary collapse

Methods inherited from TTY

#add_client, #client_read, #close, #initialize, #opened?, #remove_client, #start, #sync, #tty_read, #tty_write, #wake, #watch_ios

Methods included from Utils::SwitchUser

#ct_attach, #ct_syscmd

Constructor Details

This class inherits a constructor from OsCtld::Console::TTY

Instance Method Details

#connect(pid, socket) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/osctld/console/console.rb', line 18

def connect(pid, socket)
  tries = 0

  begin
    c = UNIXSocket.new(socket)
  rescue Errno::ENOENT
    raise if tries >= (0.2 * 50 * 10) # try for 10 seconds

    tries += 1
    sleep(0.2)
    retry
  end

  sync do
    @opened = true
    self.tty_pid = pid
    self.tty_in_io = c
    self.tty_out_io = c
    wake
  end
end

#handle_ct_stop(ctrc) ⇒ Object (protected)



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/osctld/console/console.rb', line 87

def handle_ct_stop(ctrc)
  if ctrc.aborted?
    log(:info, ctrc, 'Container was aborted, performing cleanup')
    recovery = Container::Recovery.new(ctrc.ct)
    recovery.cleanup_or_taint
  end

  if ctrc.destroy_dataset_on_stop?
    begin
      TrashBin.add_dataset(ctrc.pool, ctrc.dataset)
    rescue SystemCommandFailed => e
      log(:warn, ctrc, "Unable to trash dataset '#{ctrc.dataset}': #{e.message}")
    end
  end

  if ctrc.reboot?
    sleep(1)
    reboot_ct

  elsif ctrc.aborted?
    nil

  elsif ct.ephemeral? && !ct.is_being_manipulated?
    Commands::Container::Delete.run(
      pool: ct.pool.name,
      id: ct.id,
      force: true,
      manipulation_lock: 'wait'
    )
  end
end

#handle_improper_ct_stopObject (protected)



81
82
83
84
85
# File 'lib/osctld/console/console.rb', line 81

def handle_improper_ct_stop
  # In this scenario, it is possible that the veth-down hooks weren't
  # run either. Cleanup interfaces that may have been left behind.
  ct.netifs.take_down
end

#on_closeObject (protected)



42
43
44
45
46
# File 'lib/osctld/console/console.rb', line 42

def on_close
  return unless ct.state == :stopped

  on_ct_stop
end

#on_ct_stopObject (protected)



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
# File 'lib/osctld/console/console.rb', line 48

def on_ct_stop
  ctrc = ct.get_past_run_conf

  CpuScheduler.unschedule_ct(ct)

  begin
    ct.update_hints
  rescue Exception => e # rubocop:disable Lint/RescueException
    log(:warn, ct, "Unable to update hints: #{e.message} (#{e.class})")
    log(:warn, ct, denixstorify(e.backtrace))
  end

  if ctrc.nil?
    # This means that {UserControl::Commands::CtPostStop} hasn't run for some
    # reason.
    log(:fatal, ct, 'Unable to properly handle container stop')
    handle_improper_ct_stop
    return
  end

  if ctrc.aborted? \
     || ctrc.reboot? \
     || (ct.ephemeral? && !ct.is_being_manipulated?) \
     || (ctrc && ctrc.destroy_dataset_on_stop?)
    # The current thread is used to handle the console and has to exit.
    # Manipulation must happen from another thread.
    t = Thread.new { handle_ct_stop(ctrc) }
    ThreadReaper.add(t, nil)
  end

  ct.forget_past_run_conf
end

#openObject



14
15
16
# File 'lib/osctld/console/console.rb', line 14

def open
  # Does nothing for tty0, it is opened automatically on ct start
end

#reboot_ctObject (protected)



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/osctld/console/console.rb', line 119

def reboot_ct
  ct.pool.request_reboot(ct)

  until ct.pool.imported?
    log(:info, ct, 'Waiting for pool import to reboot')
    sleep(1)
  end

  begin
    ret = Commands::Container::Start.run(
      pool: ct.pool.name,
      id: ct.id,
      force: true,
      manipulation_lock: 'wait'
    )
  rescue CommandFailed => e
    log(:warn, ct, "Reboot failed: #{e.message}")
  else
    if !ret.is_a?(Hash)
      log(:warn, ct, 'Reboot failed: reason unknown')
    elsif !ret[:status]
      log(:warn, ct, "Reboot failed: #{ret[:message]}")
    end
  end
end