blower 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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: []