blower 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 52e337abe103b677ac90233cfd4f38121585fe0b
4
+ data.tar.gz: 47e87f53486d3b7ec27e2abc78d24098b5759e0d
5
+ SHA512:
6
+ metadata.gz: 6f250fa25824a1e5c003cadb0102f90305fd6e536b7a4602021a7222ddf7d3259e2870e4dc5d4efd5d1f617367474f541be6ec1f1d784b164c6f621a00bbec87
7
+ data.tar.gz: 518c595f5587dc82b6ef0b2fb831c095e237c407c614807e56e7e126d72d58a66c7a530552fd4ca1f3bf61ad990e271c472445a3c5bcfe944ae152d37f8edbda
data/bin/blow ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'blower'
4
+
5
+ huff = Blower::Huff.new
6
+
7
+ args = ARGV
8
+ args = ["main"] if args.empty? && (File.exist?("main") || !Dir["main.*"].empty?)
9
+
10
+ if args.empty?
11
+ huff.log.fail "Usage: blow TASK..."
12
+ exit 1
13
+ end
14
+
15
+ args = ["hosts.ini", *args] if File.exist?("hosts.ini")
16
+
17
+ begin
18
+ args.each do |arg|
19
+ huff.run arg
20
+ end
21
+ rescue RuntimeError => e
22
+ huff.log.fail e.message
23
+ exit 1
24
+ end
@@ -0,0 +1,56 @@
1
+ module Blower
2
+ class Huff
3
+
4
+ attr_accessor :hosts, :log, :puffs, :env
5
+
6
+ def initialize ()
7
+ @hosts = ["127.0.0.1"]
8
+ @log = Logger.new
9
+ @logdent = 0
10
+ @puffs = Hash.new { |h, k| h[k] = Puff.new(self, k) }
11
+ @env = {}
12
+ end
13
+
14
+ def hosts (hosts)
15
+ log.info "new hosts: #{hosts.join(", ")}"
16
+ @hosts = hosts
17
+ end
18
+
19
+ def ruby (task)
20
+ instance_eval(File.read(task), task)
21
+ end
22
+
23
+ def shell (task)
24
+ @hosts.each do |host|
25
+ log.info "running #{task} on #{host}" do
26
+ puffs[host].shell(task)
27
+ end
28
+ end
29
+ end
30
+
31
+ def inventory (task)
32
+ hosts File.read(task).split
33
+ end
34
+
35
+ def run (name)
36
+ name = name.to_s
37
+ task = File.exist?(name) ? name : Dir[name + ".*"].first
38
+ if !task
39
+ fail "Can't find #{name}"
40
+ elsif File.directory?(task)
41
+ Dir.chdir(task) do
42
+ run("main")
43
+ end
44
+ elsif task =~ /\.rb$/
45
+ ruby(task)
46
+ elsif task =~ /\.sh$/
47
+ shell(task)
48
+ elsif task =~ /\.ini$/
49
+ inventory(task)
50
+ else
51
+ fail "Don't know what to do with #{task}"
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,44 @@
1
+ require "colorize"
2
+
3
+ module Blower
4
+ class Logger
5
+
6
+ def initialize ()
7
+ @logdent = 0
8
+ end
9
+
10
+ def info (message, **keys, &block)
11
+ log(message, :blue, **keys, &block)
12
+ end
13
+
14
+ def warn (message, **keys, &block)
15
+ log(message, :yellow, STDERR, **keys, &block)
16
+ end
17
+
18
+ def fail (message, **keys, &block)
19
+ log(message, :red, STDERR, **keys, &block)
20
+ end
21
+
22
+ def win (message, **keys, &block)
23
+ log(message, :green, **keys, &block)
24
+ end
25
+
26
+ def log (message, color=nil, to=STDOUT, prefix: "", &block)
27
+ message.to_s.scan(/(?:[^\n\r]*[\n\r])|(?:[^\n\r]+$)/) do |line|
28
+ case line[-1]
29
+ when "\n", "\r"
30
+ else
31
+ line = line + "\n"
32
+ end
33
+ STDOUT.write " " * @logdent + prefix + (color ? line.colorize(color) : line)
34
+ end
35
+ begin
36
+ @logdent +=1
37
+ block.()
38
+ ensure
39
+ @logdent -= 1
40
+ end if block
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,57 @@
1
+ require "net/ssh"
2
+ require "shellwords"
3
+
4
+ module Blower
5
+ class Puff
6
+
7
+ attr_accessor :huff, :host, :log, :env
8
+
9
+ def initialize (huff, host)
10
+ @huff = huff
11
+ @log = huff.log
12
+ @host = host
13
+ @env = {}
14
+ end
15
+
16
+ def env2shell ()
17
+ huff.env.merge(@env).map do |name, value|
18
+ next unless name =~ /\A[A-Za-z\d_]+\z/
19
+ "#{name}=#{value.shellescape}"
20
+ end.join("\n") + "\n"
21
+ end
22
+
23
+ def shell (task)
24
+ Net::SSH.start(host, "root") do |ssh|
25
+ command = File.read(task)
26
+ status, signal = nil, nil
27
+ ssh.open_channel do |ch|
28
+ stdout, stderr = "", ""
29
+ ch.exec(env2shell + command) do |_, success|
30
+ fail "failed to execute command" unless success
31
+ ch.on_data do |_, data|
32
+ stdout << data
33
+ if i = stdout.rindex(/[\n\r]/)
34
+ data, stdout = stdout[0..i], (stdout[(i + 1)..-1] || "")
35
+ log.log data
36
+ end
37
+ end
38
+ ch.on_extended_data do |_, _, data|
39
+ stderr << data
40
+ if i = stderr.rindex(/[\n\r]/)
41
+ data, stderr = stderr[0..i], (stderr[(i + 1)..-1] || "")
42
+ log.fail data
43
+ end
44
+ end
45
+ ch.on_request("exit-status") { |_, data| status = data.read_long }
46
+ ch.on_request("exit-signal") { |_, data| signal = data.read_long }
47
+ end
48
+ end
49
+ ssh.loop
50
+ if status != 0
51
+ fail "exit status #{status}"
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module Blower
2
+ VERSION = "0.2.3"
3
+ end
data/lib/blower.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'blower/logger'
2
+ require 'blower/huff'
3
+ require 'blower/puff'
4
+ require 'blower/version'
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blower
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.3
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Baum
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-ssh
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.7'
41
+ description: Really simple server orchestration
42
+ email: n@p12a.org.uk
43
+ executables:
44
+ - blow
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - bin/blow
49
+ - lib/blower.rb
50
+ - lib/blower/huff.rb
51
+ - lib/blower/logger.rb
52
+ - lib/blower/puff.rb
53
+ - lib/blower/version.rb
54
+ homepage: http://www.github.org/nbaum/blower
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.4.5.1
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Really simple server orchestration
78
+ test_files: []