Class: Tem::MultiUpdater::Updater

Inherits:
Object
  • Object
show all
Defined in:
lib/tem_multi_updater/updater.rb

Overview

Updates the TEM firmware in all the smartcards on tem_multi_proxy server.

Instance Method Summary collapse

Constructor Details

#initialize(logger, multiproxy_server_addr, options = {}) ⇒ Updater

Creates a multi-proxy firmware updater.

Args:

logger:: receives update progress notifications
multiproxy_server_addr:: the address (host or host:port) of the
                         tem_multi_proxy RPC port


21
22
23
24
25
26
27
# File 'lib/tem_multi_updater/updater.rb', line 21

def initialize(logger, multiproxy_server_addr, options = {})
  @logger = logger
  @server_addr = multiproxy_server_addr
  @options = options
  @pending = nil
  @pending_mx, @pending_cv = Mutex.new, ConditionVariable.new
end

Instance Method Details

#needs_update?(transport) ⇒ Boolean

Checks if the a smart-card needs a TEM firmware upload.

Args:

transport_config:: smart-card transport connecting to the TEM card

Returns:

  • (Boolean)


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/tem_multi_updater/updater.rb', line 140

def needs_update?(transport)
  return true if @options[:force]
  
  begin
    tem = Tem::Session.new transport
    tem_version = tem.fw_version
    local_version = Tem::Firmware::Uploader.fw_version
    if local_version[:major] != tem_version[:major]
      return local_version[:major] > tem_version[:major]
    end
    return local_version[:minor] > tem_version[:minor]
  rescue Smartcard::Iso::ApduError
    # An APDU error here means the TEM firmware was not installed.
    return true       
  end
end

#runObject

Runs the multi-proxy update.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/tem_multi_updater/updater.rb', line 30

def run
  return unless @pending.nil?
  
  @logger.info "Querying tem_multi_proxy at #{@server_addr}"
  @transport_configs = Tem::MultiProxy::Client.query_tems @server_addr
  if @transport_configs.nil? || @transport_configs.empty?
    @logger.error "No response from tem_multi_proxy at #{@server_addr}"
    return false
  end
  
  spawn_threads
  wait_for_threads
  return true
end

#spawn_threadsObject

Spawns one updating thread for each smart-card transport configuration.



46
47
48
49
50
51
52
53
# File 'lib/tem_multi_updater/updater.rb', line 46

def spawn_threads
  @pending = @transport_configs.length
  @transport_configs.each do |transport_config|
    Thread.new(transport_config) do |config|
      update_thread config
    end
  end
end

#transport_for_config(transport_config) ⇒ Object

Creates a ISO smart-card transport out of a configuration.

Args:

transport_config:: configuration for the TEM's smart-card transport

Returns a transport.



93
94
95
# File 'lib/tem_multi_updater/updater.rb', line 93

def transport_for_config(transport_config)
  Smartcard::Iso::AutoConfigurator.try_transport transport_config    
end

#update_thread(transport_config) ⇒ Object

Main method for a TEM firmware updating thread.

Args:

transport_config:: configuration for the TEM's smart-card transport


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/tem_multi_updater/updater.rb', line 69

def update_thread(transport_config)
  begin
    transport = transport_for_config transport_config
    if transport
      @logger.info "Connected to #{transport.inspect}"
      update_transport transport
      transport.disconnect
    else
      @logger.warn "Failed connecting to #{transport_config.inspect}"
    end
  ensure    
    @pending_mx.synchronize do
      @pending -= 1
      @pending_cv.signal
    end
  end
end

#update_transport(transport) ⇒ Object

Installs or updates TEM firmware on a smart-card.

No firmware will be uploaded if the smart-card already has the latest version of the TEM software.

Args:

transport_config:: smart-card transport connecting to the TEM card

Returns



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
# File 'lib/tem_multi_updater/updater.rb', line 106

def update_transport(transport)
  if !needs_update? transport
    @logger.info "No update needed at #{transport.inspect}"
    return false
  end
  
  @logger.info "Uploading TEM firmware to #{transport.inspect}"
  begin
    Tem::Firmware::Uploader.upload_cap transport
  rescue Exception => e
    @logger.error "Error while uploading TEM firmware to " +
                  "#{transport.inspect} - #{e.class.name}: #{e.message}"
    @logger.info e.backtrace.join("\n")
    return false
  end

  @logger.info "Emitting TEM at #{transport.inspect}"
  begin
    tem = Tem::Session.new transport
    tem.activate
    tem.emit
    return true
  rescue Exception => e
    @logger.error "Error while emitting TEM at " +
                  "#{transport.inspect} - #{e.class.name}: #{e.message}"
    @logger.info e.backtrace.join("\n")
    return false
  end
end

#wait_for_threadsObject

Waits for all the updating threads to complete.



56
57
58
59
60
61
62
63
# File 'lib/tem_multi_updater/updater.rb', line 56

def wait_for_threads
  @pending_mx.synchronize do
    loop do
      break if @pending == 0
      @pending_cv.wait @pending_mx
    end
  end
end