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.
Files changed (6) hide show
  1. data/.gitignore +2 -0
  2. data/bin/octo +90 -0
  3. data/lib/octo.rb +34 -0
  4. data/lib/octo/profile.rb +41 -0
  5. data/octo.gemspec +16 -0
  6. metadata +99 -0
@@ -0,0 +1,2 @@
1
+ *.swp
2
+ *.swo
@@ -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)
@@ -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
@@ -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
@@ -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: []