Module: LeapCli::Remote::LeapPlugin
- Defined in:
- lib/leap_cli/remote/leap_plugin.rb
Instance Method Summary collapse
-
#assert_initialized ⇒ Object
echos “ok” if the node has been initialized and the required packages are installed, bails out otherwise.
-
#capture(cmd, &block) ⇒ Object
like stream, but capture all the output before returning.
-
#check_for_no_deploy ⇒ Object
bails out the deploy if the file /etc/leap/no-deploy exists.
- #log(*args, &block) ⇒ Object
- #mark_initialized ⇒ Object
-
#mkdirs(*dirs) ⇒ Object
creates directories that are owned by root and 700 permissions.
- #required_packages ⇒ Object
-
#run_with_progress(cmd, &block) ⇒ Object
Run a command, with a nice status report and progress indicator.
-
#stream(cmd, &block) ⇒ Object
similar to run(cmd, &block), but with:.
-
#with_task(name) ⇒ Object
This is a hairy ugly hack, exactly the kind of stuff that makes ruby dangerous and too much fun for its own good.
Instance Method Details
#assert_initialized ⇒ Object
echos “ok” if the node has been initialized and the required packages are installed, bails out otherwise.
27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 27 def assert_initialized begin test_initialized_file = "test -f #{INITIALIZED_FILE}" check_required_packages = "! dpkg-query -W --showformat='${Status}\n' #{required_packages} 2>&1 | grep -q -E '(deinstall|no packages)'" run "#{test_initialized_file} && #{check_required_packages} && echo ok" rescue Capistrano::CommandError => exc LeapCli::Util.bail! do exc.hosts.each do |host| LeapCli::Util.log :error, "running deploy: node not initialized. Run 'leap node init #{host}'", :host => host end end end end |
#capture(cmd, &block) ⇒ Object
like stream, but capture all the output before returning
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 111 def capture(cmd, &block) command = '%s 2>&1; echo "exitcode=$?" 2>&1;' % cmd host_data = {} run(command) do |channel, stream, data| host_data[channel[:host]] ||= "" if data =~ /exitcode=(\d+)\n/ exitcode = $1.to_i data.sub!(/exitcode=(\d+)\n/,'') host_data[channel[:host]] += data yield({:host => channel[:host], :data => host_data[channel[:host]], :exitcode => exitcode}) else host_data[channel[:host]] += data end end end |
#check_for_no_deploy ⇒ Object
bails out the deploy if the file /etc/leap/no-deploy exists. This kind of sucks, because it would be better to skip over nodes that have no-deploy set instead halting the entire deploy. As far as I know, with capistrano, there is no way to close one of the ssh connections in the pool and make sure it gets no further commands.
47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 47 def check_for_no_deploy begin run "test ! -f /etc/leap/no-deploy" rescue Capistrano::CommandError => exc LeapCli::Util.bail! do exc.hosts.each do |host| LeapCli::Util.log "Can't continue because file /etc/leap/no-deploy exists", :host => host end end end end |
#log(*args, &block) ⇒ Object
12 13 14 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 12 def log(*args, &block) LeapCli::Util::log(*args, &block) end |
#mark_initialized ⇒ Object
59 60 61 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 59 def mark_initialized run "touch #{INITIALIZED_FILE}" end |
#mkdirs(*dirs) ⇒ Object
creates directories that are owned by root and 700 permissions
19 20 21 22 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 19 def mkdirs(*dirs) raise ArgumentError.new('illegal dir name') if dirs.grep(/[\' ]/).any? run dirs.collect{|dir| "mkdir -m 700 -p #{dir}; "}.join end |
#required_packages ⇒ Object
8 9 10 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 8 def required_packages "puppet ruby-hiera-puppet rsync lsb-release locales" end |
#run_with_progress(cmd, &block) ⇒ Object
Run a command, with a nice status report and progress indicator. Only successful results are returned, errors are printed.
For each successful run on each host, block is yielded with a hash like so:
=> ‘bluejay’, :exitcode => 0, :data => ‘shell output’
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 169 170 171 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 135 def run_with_progress(cmd, &block) ssh_failures = [] exitcode_failures = [] succeeded = [] task = LeapCli.log_level > 1 ? :standard_task : :skip_errors_task with_task(task) do log :querying, 'facts' do progress " " call_on_failure do |host| ssh_failures << host progress 'F' end capture(cmd) do |response| if response[:exitcode] == 0 progress '.' yield response else exitcode_failures << response progress 'F' end end end end puts "done" if ssh_failures.any? log :failed, 'to connect to nodes: ' + ssh_failures.join(' ') end if exitcode_failures.any? log :failed, 'to run successfully:' do exitcode_failures.each do |response| log "[%s] exit %s - %s" % [response[:host], response[:exitcode], response[:data].strip] end end end rescue Capistrano::RemoteError => err log :error, err.to_s end |
#stream(cmd, &block) ⇒ Object
similar to run(cmd, &block), but with:
-
exit codes
-
stdout and stderr are combined
96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 96 def stream(cmd, &block) command = '%s 2>&1; echo "exitcode=$?"' % cmd run(command) do |channel, stream, data| exitcode = nil if data =~ /exitcode=(\d+)\n/ exitcode = $1.to_i data.sub!(/exitcode=(\d+)\n/,'') end yield({:host => channel[:host], :data => data, :exitcode => exitcode}) end end |
#with_task(name) ⇒ Object
This is a hairy ugly hack, exactly the kind of stuff that makes ruby dangerous and too much fun for its own good.
In most places, we run remote ssh without a current ‘task’. This works fine, except that in a few places, the behavior of capistrano ssh is controlled by the options of the current task.
We don’t want to create an actual current task, because tasks are no fun and can’t take arguments or return values. So, when we need to configure things that can only be configured in a task, we use this handy hack to fake the current task.
This is NOT thread safe, but could be made to be so with some extra work.
78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/leap_cli/remote/leap_plugin.rb', line 78 def with_task(name) task = @config.tasks[name] @config.class.send(:alias_method, :original_current_task, :current_task) @config.class.send(:define_method, :current_task, Proc.new(){ task }) begin yield ensure @config.class.send(:remove_method, :current_task) @config.class.send(:alias_method, :current_task, :original_current_task) end end |