octo 0.0.2
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.
- data/.gitignore +2 -0
- data/bin/octo +90 -0
- data/lib/octo.rb +34 -0
- data/lib/octo/profile.rb +41 -0
- data/octo.gemspec +16 -0
- metadata +99 -0
data/.gitignore
ADDED
data/bin/octo
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'gli'
|
4
|
+
require 'octo'
|
5
|
+
|
6
|
+
# Install signal handlers
|
7
|
+
Signal.trap('SIGINT') do
|
8
|
+
exit
|
9
|
+
end
|
10
|
+
|
11
|
+
Signal.trap('SIGKILL') do
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
Signal.trap('SIGTERM') do
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
|
19
|
+
include GLI::App
|
20
|
+
|
21
|
+
program_desc 'Run commands on multiple hosts'
|
22
|
+
|
23
|
+
flag [:t,:tasklist], :default_value => File.join(ENV['HOME'],'.todolist')
|
24
|
+
|
25
|
+
octo = nil
|
26
|
+
pre do |global_opts, command, opts, args|
|
27
|
+
octo = Octo.new(opts)
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Manage profiles'
|
32
|
+
long_desc 'Manage profile that will be used to run commands. Each profile consists of a set of servers.'
|
33
|
+
command :profile do |profile|
|
34
|
+
profile.desc 'List all profiles'
|
35
|
+
profile.long_desc 'List all the profiles that have been previously configured along with their server.'
|
36
|
+
profile.arg_name '[profile]'
|
37
|
+
profile.command :list do |list|
|
38
|
+
list.action do |global_opts, opts, args|
|
39
|
+
if args.empty?
|
40
|
+
octo.list.each do |profile|
|
41
|
+
puts "#{profile}:"
|
42
|
+
octo.config[profile].each do |server|
|
43
|
+
puts "- #{server}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else
|
47
|
+
exit_now!("#{args.first} is not a defined profile") unless octo.config.keys.include? args.first
|
48
|
+
|
49
|
+
puts "#{args.first}:"
|
50
|
+
octo.config[args.first].each do |server|
|
51
|
+
puts "- #{server}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
profile.desc 'Add a host to a profile'
|
58
|
+
profile.arg_name 'profile server'
|
59
|
+
profile.long_desc 'Add a host to a profile, the host should be specified using the form user@hostname, eg. nan@nine27.com.'
|
60
|
+
profile.command :add do |add|
|
61
|
+
add.action do |global_opts, opts, args|
|
62
|
+
octo.add args[0], args[1]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
profile.desc 'Remove a host from a profile'
|
67
|
+
profile.long_desc 'Remove a host from a profile, the host should be specified using the form user@hostname, eg. nan@nine27.com.'
|
68
|
+
profile.arg_name 'profile server'
|
69
|
+
profile.command :rm do |rm|
|
70
|
+
rm.action do |global_opts, opts, args|
|
71
|
+
octo.rm args[0], args[1]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
desc 'Run a command'
|
77
|
+
long_desc 'Run a command in parallel on all configured hosts in the profile, eg.
|
78
|
+
octo run cluster_1 \'tail -f /var/log/httpd/error_log\'.'
|
79
|
+
command :run do |cmd|
|
80
|
+
cmd.action do |global_opts, tops, args|
|
81
|
+
octo.run args[0], args[1]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
post do |global_opts, command, opts, args|
|
86
|
+
octo.save
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
exit run(ARGV)
|
data/lib/octo.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'net/ssh/multi'
|
3
|
+
require 'term/ansicolor'
|
4
|
+
|
5
|
+
class Octo
|
6
|
+
require 'octo/profile'
|
7
|
+
include Octo::Profile
|
8
|
+
include Term::ANSIColor
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options.merge({
|
12
|
+
file: false,
|
13
|
+
multi: false
|
14
|
+
})
|
15
|
+
|
16
|
+
self.load
|
17
|
+
end
|
18
|
+
|
19
|
+
def run(profile, command)
|
20
|
+
Net::SSH::Multi.start do |session|
|
21
|
+
@config[profile].each do |server|
|
22
|
+
session.use server
|
23
|
+
end
|
24
|
+
|
25
|
+
session.exec command do |ch, stream, data|
|
26
|
+
data.lines.each do |line|
|
27
|
+
stream = stream == :stderr ? $stderr : $stdout
|
28
|
+
stream.puts "[#{green(ch.properties[:server].to_s)}] #{line}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
session.loop
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/octo/profile.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'octo'
|
2
|
+
|
3
|
+
module Octo::Profile
|
4
|
+
attr_reader :config
|
5
|
+
|
6
|
+
def config_file
|
7
|
+
"#{Dir.home}/.octorc"
|
8
|
+
end
|
9
|
+
|
10
|
+
def list(profile = nil)
|
11
|
+
if profile.nil?
|
12
|
+
@config.keys
|
13
|
+
else
|
14
|
+
@config[profile]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(profile, server)
|
19
|
+
@config[profile] = [] if @config[profile].nil?
|
20
|
+
@config[profile] << server
|
21
|
+
end
|
22
|
+
|
23
|
+
def rm(profile, server)
|
24
|
+
@config[profile].delete(server)
|
25
|
+
@config.delete(profile) if @config[profile].empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def load
|
29
|
+
if File.exists?(config_file)
|
30
|
+
@config = YAML.load_file(config_file)
|
31
|
+
else
|
32
|
+
@config = {}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def save
|
37
|
+
File.open(config_file, 'w') do |f|
|
38
|
+
f.write YAML.dump(@config)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/octo.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'octo'
|
3
|
+
s.summary = 'Run commands in parallel on multiple hosts'
|
4
|
+
s.description = 'A lightweight script that allows you to run commands in parallel on multiple hosts'
|
5
|
+
s.version = '0.0.2'
|
6
|
+
s.author = 'Nan Zhong'
|
7
|
+
s.email = 'nan@nine27.com'
|
8
|
+
s.homepage = 'https://github.com/nanzhong/octo'
|
9
|
+
s.files = `git ls-files`.split($\)
|
10
|
+
|
11
|
+
s.executables << 'octo'
|
12
|
+
|
13
|
+
s.add_dependency 'net-ssh-multi'
|
14
|
+
s.add_dependency 'gli'
|
15
|
+
s.add_dependency 'term-ansicolor'
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: octo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nan Zhong
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: net-ssh-multi
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: gli
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: term-ansicolor
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: A lightweight script that allows you to run commands in parallel on multiple
|
63
|
+
hosts
|
64
|
+
email: nan@nine27.com
|
65
|
+
executables:
|
66
|
+
- octo
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- bin/octo
|
72
|
+
- lib/octo.rb
|
73
|
+
- lib/octo/profile.rb
|
74
|
+
- octo.gemspec
|
75
|
+
homepage: https://github.com/nanzhong/octo
|
76
|
+
licenses: []
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 1.8.24
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Run commands in parallel on multiple hosts
|
99
|
+
test_files: []
|