Class: Makitzo::Application

Inherits:
Object
  • Object
show all
Includes:
SSH::Multi
Defined in:
lib/makitzo/application.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SSH::Multi

#multi_connect, #multi_session, #multi_ssh, #ssh_context_class

Constructor Details

#initializeApplication

Returns a new instance of Application.



10
11
12
13
14
# File 'lib/makitzo/application.rb', line 10

def initialize
  @config = Config.new(self)
  @logger = Logging::Collector.new
  @root_directory = '.'
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



5
6
7
# File 'lib/makitzo/application.rb', line 5

def config
  @config
end

#loggerObject (readonly)

Returns the value of attribute logger.



6
7
8
# File 'lib/makitzo/application.rb', line 6

def logger
  @logger
end

#queryObject

Returns the value of attribute query.



7
8
9
# File 'lib/makitzo/application.rb', line 7

def query
  @query
end

#root_directoryObject

Returns the value of attribute root_directory.



8
9
10
# File 'lib/makitzo/application.rb', line 8

def root_directory
  @root_directory
end

Instance Method Details

#compare(*command) ⇒ Object

Run a shell command on hosts and compare output



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/makitzo/application.rb', line 121

def compare(*command)
  command = command.join(' ')
  sessions = nil
  results, mutex = Hash.new { |h,k| h[k] = [] }, Mutex.new
  
  logger.silence do
    sessions = multi_session(target_hosts) do |session, host|
      result = session.exec(command)
      mutex.synchronize { results[result] << host }
    end
  end
  
  logger.log_command_line(command)
  
  sessions.each do |s|
    if s.connection_error
      logger.error "connection to #{s.host.name} failed: #{s.connection_error.class} (#{s.connection_error.message})"
    end
  end
  
  logger.info("#{results.length} unique response(s)")
  
  results.each do |result, hosts|
    hosts.each do |h|
      logger.info(h.name + ":")
    end
    logger.log_command_status(result)
  end
end

#create_migration(name) ⇒ Object



59
60
61
62
# File 'lib/makitzo/application.rb', line 59

def create_migration(name)
  generator = Migrations::Generator.new(self)
  generator.create_migration(name)
end

#exec(*command) ⇒ Object

Execute an aribtrary helper method on all target systems



45
46
47
48
49
# File 'lib/makitzo/application.rb', line 45

def exec(*command)
  config.store.open do
    multi_session(target_hosts) { |session, host| session.send(*command) }
  end
end

#installObject



41
# File 'lib/makitzo/application.rb', line 41

def install;      exec(:makitzo_install);   end

#invoke(command, *args) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/makitzo/application.rb', line 25

def invoke(command, *args)
  raise ArgumentError, "unknown command: #{command}" unless valid_commands.include?(command)
  success = false

  old_wd = Dir.getwd
  Dir.chdir(@root_directory)
  success = send(command.to_sym, *args)

  result = @logger.result
  puts @logger.result unless result.length == 0
  
  success
ensure
  Dir.chdir(old_wd)
end

#listObject

List the hosts which would be affected, taking into account any query parameters.



66
67
68
# File 'lib/makitzo/application.rb', line 66

def list
  target_hosts.map { |h| h.name }.sort.each { |h| puts h }
end

#migrateObject

Migrate all target systems



52
53
54
55
56
57
# File 'lib/makitzo/application.rb', line 52

def migrate
  config.store.open do
    migrator = Migrations::Migrator.new(self)
    migrator.migrate(target_hosts)
  end
end

#shell(*command) ⇒ Object

Run a shell command on hosts



71
72
73
# File 'lib/makitzo/application.rb', line 71

def shell(*command)
  multi_session(target_hosts) { |session, host| session.exec(command.join(' ')) }
end

#stream(io) ⇒ Object

read from IO and send commands to target hosts this is intended to be used non-interactively (e.g. with a pipe) TODO: other system operations should be rewritten to use the “shell” service as it remembers state such as working directory etc TODO: how to we specify which shell to open?! TODO: this should probably be extracted



81
82
83
84
85
86
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
# File 'lib/makitzo/application.rb', line 81

def stream(io)
  reader = MultiplexedReader.new(io)
  multi_ssh(target_hosts) do |host, conn, error|
    logger.with_host(host) do
      if error
        logger.error("could not connect to host: #{error.message} (#{error.class})")
      else
        conn.open_channel do |ch|
          ch.send_channel_request("shell") do |ch, success|
            if success
              logger.info "shell opened"
              
              ch.on_data { |ch, data| }
              ch.on_close { logger.info "shell closed" }
              
              while line = reader.gets
                line.strip!
                logger.log_command_line(line)
                line += "\n"
                ch.send_data(line)
              end
              ch.send_data("exit\n")
            else
              logger.error "shell could not be opened"
            end
          end
        end
        
        conn.loop
      end
    end
  end
end

#sudo(*command) ⇒ Object

Run a shell command on hosts using sudo



116
117
118
# File 'lib/makitzo/application.rb', line 116

def sudo(*command)
  multi_session(target_hosts) { |session, host| session.sudo { session.exec(command.join(' ')) } }
end

#target_hostsObject



16
17
18
19
# File 'lib/makitzo/application.rb', line 16

def target_hosts
  query = @query || World::Query.all
  query.exec(config)
end

#uninstallObject



42
# File 'lib/makitzo/application.rb', line 42

def uninstall;    exec(:makitzo_uninstall); end

#valid_commandsObject



21
22
23
# File 'lib/makitzo/application.rb', line 21

def valid_commands
  %w(install uninstall exec migrate create_migration list compare shell stream sudo)
end