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)



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/osctld/console/console.rb', line 104

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 !ct.ephemeral? && !ctrc.destroy_dataset_on_stop? && Daemon.get.config.writeout_dirtied_pages?
    # Force write-out of dirtied pages
    ct.unmount(force: true)
    ct.mount
  end

  if ctrc.destroy_dataset_on_stop?
    GarbageCollector.free_container_run_dataset(ctrc, ctrc.dataset)
  end

  ctrc.fulfil_exit

  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)



98
99
100
101
102
# File 'lib/osctld/console/console.rb', line 98

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

def on_close
  # The current thread is used to handle the console and has to exit.
  # Manipulation must happen from another thread.
  t = Thread.new { on_ct_stop }
  ThreadReaper.add(t, nil)
end

#on_ct_stopObject (protected)



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
91
92
93
94
95
96
# File 'lib/osctld/console/console.rb', line 49

def on_ct_stop
  # The TTY may have closed due to an unforeseen error, check if the
  # container is actually stopped.
  60.times do
    break if ct.state == :stopped

    log(:info, ct, 'Console closed, waiting for stopped state')
    sleep(1)
  end

  unless ct.state == :stopped
    log(:fatal, ct, 'Console closed, but container is not stopped')
    return
  end

  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

  # Send events about halt/reboot from the inside
  if !ctrc.aborted? && !ct.is_being_manipulated?
    Eventd.report(
      :ct_exit,
      pool: ct.pool.name,
      id: ct.id,
      exit_type: ctrc.reboot? ? 'reboot' : 'halt'
    )
  end

  handle_ct_stop(ctrc)

  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)



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/osctld/console/console.rb', line 140

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,
      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