Devops 0.0.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.
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +33 -0
- data/README.md +54 -0
- data/autocomplete +5 -0
- data/bin/ops +34 -0
- data/devops.gemspec +23 -0
- data/lib/host/default.rb +123 -0
- data/lib/host/e_c_2.rb +11 -0
- data/lib/host/list.rb +11 -0
- data/lib/ops.rb +31 -0
- data/lib/ops/common.rb +52 -0
- data/lib/ops/console.rb +45 -0
- data/lib/tasks/ec2.rb +50 -0
- data/lib/tasks/hosts.rb +48 -0
- data/lib/tasks/init.rb +4 -0
- data/lib/tasks/ops.rb +33 -0
- data/lib/tasks/ssh.rb +22 -0
- data/lib/version.rb +6 -0
- data/pkg/.gitfile +0 -0
- data/res/samples/default/config.json +7 -0
- data/res/strings/strings.yml +14 -0
- data/res/strings/tasks/hosts.yml +15 -0
- data/spec/lib/host/default.rb +32 -0
- data/spec/lib/host/list.rb +36 -0
- data/spec/spec_helper.rb +1 -0
- metadata +92 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
aws-sdk (1.8.3)
|
5
|
+
json (~> 1.4)
|
6
|
+
nokogiri (>= 1.4.4)
|
7
|
+
uuidtools (~> 2.1)
|
8
|
+
diff-lcs (1.1.3)
|
9
|
+
i18n (0.6.1)
|
10
|
+
json (1.7.7)
|
11
|
+
net-ssh (2.6.5)
|
12
|
+
nokogiri (1.5.6)
|
13
|
+
rake (10.0.3)
|
14
|
+
rspec (2.11.0)
|
15
|
+
rspec-core (~> 2.11.0)
|
16
|
+
rspec-expectations (~> 2.11.0)
|
17
|
+
rspec-mocks (~> 2.11.0)
|
18
|
+
rspec-core (2.11.1)
|
19
|
+
rspec-expectations (2.11.2)
|
20
|
+
diff-lcs (~> 1.1.3)
|
21
|
+
rspec-mocks (2.11.2)
|
22
|
+
uuidtools (2.1.3)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
aws-sdk
|
29
|
+
i18n
|
30
|
+
json
|
31
|
+
net-ssh
|
32
|
+
rake
|
33
|
+
rspec
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Ops
|
2
|
+
|
3
|
+
This repo serves as a container for utilitys and apps related
|
4
|
+
to Operations tasks.
|
5
|
+
|
6
|
+
## Using Ops tools:
|
7
|
+
|
8
|
+
### Requirements
|
9
|
+
|
10
|
+
ruby 1.8.7
|
11
|
+
openssh
|
12
|
+
|
13
|
+
### Getting Started
|
14
|
+
|
15
|
+
Add the following to your .bashrc or .bash_profile_
|
16
|
+
|
17
|
+
export $OPS_HOME="/path to your ops repo"
|
18
|
+
source $OPS_HOME/autocomplete
|
19
|
+
|
20
|
+
Add the following symbolic link so you can use this from any directory
|
21
|
+
|
22
|
+
# ln -s this somewhere else if you're using a shared computer
|
23
|
+
# maybe create a local bin folder in ~/ and add it to your path
|
24
|
+
|
25
|
+
ln -s $OPS_HOME /usr/local/bin/ops
|
26
|
+
|
27
|
+
run the following command
|
28
|
+
|
29
|
+
bundle install
|
30
|
+
|
31
|
+
create a config.json file with the following contents:
|
32
|
+
|
33
|
+
{
|
34
|
+
"IdentityLocations" : [ "~/.ssh", ... ],
|
35
|
+
"AWS" : {
|
36
|
+
"AccessKeyId" : "Your Access Key",
|
37
|
+
"SecretAccessKey" : "Your Secret Access Key"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
### Connecting to a host:
|
42
|
+
|
43
|
+
usage: ops [ host ]:ssh
|
44
|
+
|
45
|
+
### Other commands:
|
46
|
+
|
47
|
+
ops -T - List all tasks available
|
48
|
+
|
49
|
+
ops hosts:list - List all the hosts
|
50
|
+
|
51
|
+
ops hosts:sync - Sync hosts.json with EC2 instance list
|
52
|
+
|
53
|
+
ops hosts:add host=[ alias name ] hostname=[ ip address or hostname ] \
|
54
|
+
identity=[ private key name ] user=[ user ]
|
data/autocomplete
ADDED
data/bin/ops
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'Ops'
|
4
|
+
|
5
|
+
def exit_failure( reason="", code=1 )
|
6
|
+
puts reason; exit
|
7
|
+
end
|
8
|
+
|
9
|
+
bootstrap_files = [
|
10
|
+
File.join( 'tasks', 'init.rb' ) ]
|
11
|
+
|
12
|
+
Rake.application.init( File.basename( $0 ) )
|
13
|
+
|
14
|
+
begin
|
15
|
+
bootstrap_files.each do | f |
|
16
|
+
File.join Ops::root_dir, f
|
17
|
+
require f
|
18
|
+
end
|
19
|
+
rescue => e
|
20
|
+
puts e
|
21
|
+
end
|
22
|
+
|
23
|
+
bootstrap_files.each do | f |
|
24
|
+
f = File.join Ops::pwd_dir, f
|
25
|
+
require f if File.exists? f
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
Rake.application.top_level
|
30
|
+
rescue => e
|
31
|
+
puts "Failed to call task: #{ e.message }"
|
32
|
+
end
|
33
|
+
|
34
|
+
exit
|
data/devops.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'lib/version.rb'
|
2
|
+
|
3
|
+
files = `git ls-files`.split("\n")
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'Devops'
|
7
|
+
|
8
|
+
s.version = Ops::version
|
9
|
+
|
10
|
+
s.date = Time.new
|
11
|
+
|
12
|
+
s.summary = "Ops tool for remote servers"
|
13
|
+
s.description = "Ops tool for remote servers"
|
14
|
+
|
15
|
+
s.authors = [ "Hardeep Shoker", "Ryan Willoughby" ]
|
16
|
+
s.email = 'hardeepshoker@gmail.com'
|
17
|
+
s.homepage = 'https://github.com/hardeep/ops'
|
18
|
+
|
19
|
+
s.files = files
|
20
|
+
|
21
|
+
s.bindir = 'bin'
|
22
|
+
s.executables = [ 'ops' ]
|
23
|
+
end
|
data/lib/host/default.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
module Host
|
2
|
+
class Default
|
3
|
+
|
4
|
+
attr_reader :alias, :host_name, :ssh_pem, :user, :tags
|
5
|
+
|
6
|
+
def initialize( host = 'unspecified', info = {}, opts = {} )
|
7
|
+
@alias = host
|
8
|
+
|
9
|
+
@host_name = info[ "HostName" ] || nil
|
10
|
+
@user = info[ "User" ] || Etc.getlogin
|
11
|
+
@ssh_pem = info[ "IdentityFile" ] || nil
|
12
|
+
@ssh_port = info[ "Port" ] || nil
|
13
|
+
@type = info[ "Type" ] || :default
|
14
|
+
@tags = info[ "Tags" ] || {}
|
15
|
+
@pem_dirs = opts[ "IdentityLocations" ] || nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def type
|
19
|
+
@type.to_sym
|
20
|
+
end
|
21
|
+
|
22
|
+
def tags=( tags )
|
23
|
+
raise IOError, "tags must be a hash" unless tags.kind_of?( Hash )
|
24
|
+
@tags = tags
|
25
|
+
end
|
26
|
+
|
27
|
+
def matches?( tags )
|
28
|
+
tags.each do | tag, value |
|
29
|
+
is_regex = value.match( /^\/(.*)\/$/ )
|
30
|
+
|
31
|
+
if is_regex
|
32
|
+
regex = Regexp.new( is_regex[ 1 ] )
|
33
|
+
|
34
|
+
unless @tags.has_key?( tag ) && @tags[ tag ].match( regex )
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
else
|
38
|
+
unless @tags.has_key?( tag ) && @tags[ tag ] == value
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def ssh_pem
|
48
|
+
ssh_pem = nil
|
49
|
+
|
50
|
+
unless @ssh_pem.nil?
|
51
|
+
unless @pem_dirs.nil?
|
52
|
+
@pem_dirs.each do | dir |
|
53
|
+
f = File.expand_path File.join( dir, "#{ @ssh_pem }*" )
|
54
|
+
glob = Dir.glob( f )
|
55
|
+
ssh_pem = glob.first unless glob.empty?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
raise( IOError,
|
60
|
+
"Error: pem - #{ ssh_pem } not found or not accessable." ) unless
|
61
|
+
File.stat( ssh_pem )
|
62
|
+
end
|
63
|
+
|
64
|
+
ssh_pem
|
65
|
+
end
|
66
|
+
|
67
|
+
def shell!( opts = nil )
|
68
|
+
ssh_cmd = [ "ssh" ]
|
69
|
+
|
70
|
+
raise( IOError, "Error: HostName invalid." ) if @host_name.nil?
|
71
|
+
|
72
|
+
ssh_cmd << [ "-l", @user ]
|
73
|
+
ssh_cmd << @host_name
|
74
|
+
|
75
|
+
pem = ssh_pem
|
76
|
+
ssh_cmd << [ "-i", pem ] unless pem.nil?
|
77
|
+
|
78
|
+
begin
|
79
|
+
exec( ssh_cmd.join(" ") )
|
80
|
+
rescue => e
|
81
|
+
raise( IOError, "Could not call ssh." )
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def shell_exec! command
|
86
|
+
ssh_pem
|
87
|
+
|
88
|
+
options = { :keys => ssh_pem }
|
89
|
+
|
90
|
+
color = Color.random_color
|
91
|
+
|
92
|
+
Net::SSH.start( host_name, user, options ) do | s |
|
93
|
+
|
94
|
+
channel = s.open_channel do |ch|
|
95
|
+
ch.exec( command ) do | ch, success |
|
96
|
+
raise( IOError,
|
97
|
+
"#{ host_name } > could not execute command" ) unless
|
98
|
+
success
|
99
|
+
|
100
|
+
ch.on_data do | c, data |
|
101
|
+
data.split("\n").each do | line |
|
102
|
+
puts "#{ Color.print(
|
103
|
+
self.alias, [ :bold, color ] ) } > #{ line }"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
ch.on_extended_data do |c, type, data|
|
108
|
+
data.split("\n").each do | line |
|
109
|
+
puts "#{ Color.print(
|
110
|
+
self.alias, [ :bold, color ] ) } > #{ line }"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
ch.on_close do
|
115
|
+
puts "#{ Color.print(
|
116
|
+
self.alias, [ :bold, color ] ) } > COMMAND finished"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/host/e_c_2.rb
ADDED
data/lib/host/list.rb
ADDED
data/lib/ops.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
end
|
7
|
+
|
8
|
+
# standard gems
|
9
|
+
require 'json'
|
10
|
+
require 'etc'
|
11
|
+
require 'pathname'
|
12
|
+
require 'pp'
|
13
|
+
|
14
|
+
# external gems
|
15
|
+
require 'net/ssh'
|
16
|
+
require 'i18n'
|
17
|
+
require 'rake'
|
18
|
+
require 'aws-sdk'
|
19
|
+
|
20
|
+
# local includes
|
21
|
+
require 'version'
|
22
|
+
require 'host/list'
|
23
|
+
require 'host/default'
|
24
|
+
require 'host/e_c_2'
|
25
|
+
require 'ops/common'
|
26
|
+
require 'ops/console'
|
27
|
+
|
28
|
+
# load all i18n strings
|
29
|
+
string_search = File.join( Ops::root_dir, "res", "strings/**/*.yml" )
|
30
|
+
string_files = Dir[ string_search ]
|
31
|
+
I18n.load_path << string_files
|
data/lib/ops/common.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Ops
|
2
|
+
|
3
|
+
def self.root_dir
|
4
|
+
File.expand_path(
|
5
|
+
File.join( File.dirname( __FILE__ ), "..", ".." ) )
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.pwd_dir
|
9
|
+
Dir.pwd
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.has_bash?
|
13
|
+
`which bash`
|
14
|
+
( $? == 0 ) ? true : false
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.read_config
|
18
|
+
config_file = File.join( self.pwd_dir, "config.json" )
|
19
|
+
|
20
|
+
begin
|
21
|
+
config = JSON.parse File.read( config_file )
|
22
|
+
rescue JSON::ParserError
|
23
|
+
raise IOError, "Error parsing config file: #{ config_file }."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.read_hosts
|
28
|
+
config = read_config
|
29
|
+
|
30
|
+
hosts = {}
|
31
|
+
|
32
|
+
hosts_files = [
|
33
|
+
File.join( self.pwd_dir, "hosts.json" ),
|
34
|
+
File.join( self.pwd_dir, 'tmp' ,"hosts.json" ), ]
|
35
|
+
|
36
|
+
hosts_files.each do | file |
|
37
|
+
if File.exists? file
|
38
|
+
begin
|
39
|
+
json = JSON.parse File.read( file )
|
40
|
+
json.each do | n, i |
|
41
|
+
hosts[ n ] = Host::Default.new( n, i, config )
|
42
|
+
end
|
43
|
+
rescue JSON::ParserError => e
|
44
|
+
raise( IOError,
|
45
|
+
"Error parsing hosts file: #{ file }. #{ e.message }" )
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
hosts
|
51
|
+
end
|
52
|
+
end
|
data/lib/ops/console.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Ops
|
2
|
+
module Console
|
3
|
+
OPTIONS = { :bold => 1, :underline => 4 }
|
4
|
+
|
5
|
+
COLORS = { :black => 30,
|
6
|
+
:red => 31, :green => 32, :yellow => 33, :blue => 34,
|
7
|
+
:magenta => 35, :cyan => 36, :white => 37 }
|
8
|
+
|
9
|
+
BG_COLORS = { :black => 40, :red => 41, :green => 42,
|
10
|
+
:yellow => 43, :blue => 44, :magenta => 45, :cyan => 46,
|
11
|
+
:white => 47 }
|
12
|
+
|
13
|
+
def self.reload!
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.is_bash?
|
18
|
+
`which bash`
|
19
|
+
( $? == 0 ) ? true : false
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.bash_exec!( cmd )
|
23
|
+
bash = `which bash`.strip
|
24
|
+
`#{ bash } -c #{ cmd }"`
|
25
|
+
end
|
26
|
+
|
27
|
+
def print( string, opts = [] )
|
28
|
+
c = []
|
29
|
+
opts.each { | o | c << COLORS[ o ] if COLORS.has_key?( o ) }
|
30
|
+
opts.each { | o | c << OPTIONS[ o ] if OPTIONS.has_key?( o ) }
|
31
|
+
|
32
|
+
"\033[#{ c.join( ";" ) }m#{ string }\033[0m"
|
33
|
+
end
|
34
|
+
|
35
|
+
def random_color
|
36
|
+
colors = COLORS.keys + BG_COLORS.keys
|
37
|
+
colors.reject!{ | c | [ :white, :black ].include? c }
|
38
|
+
colors.choice
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Color
|
44
|
+
extend Ops::Console
|
45
|
+
end
|
data/lib/tasks/ec2.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
namespace "hosts" do
|
2
|
+
|
3
|
+
namespace "ec2" do
|
4
|
+
|
5
|
+
## Sync EC2 Hosts
|
6
|
+
desc "hosts.sync"
|
7
|
+
task "sync" do
|
8
|
+
ec2 = AWS::EC2.new(
|
9
|
+
:access_key_id => $config[ "AWS" ][ "AccessKeyId" ],
|
10
|
+
:secret_access_key => $config[ "AWS" ][ "SecretAccessKey" ] )
|
11
|
+
|
12
|
+
hosts = {}
|
13
|
+
|
14
|
+
# used if no name is given
|
15
|
+
count = 0
|
16
|
+
|
17
|
+
ec2.instances.each do | h |
|
18
|
+
name = h.tags[ "Name" ]
|
19
|
+
|
20
|
+
if name.nil? || name.empty?
|
21
|
+
name = "noname-#{ count }"
|
22
|
+
count += 1
|
23
|
+
end
|
24
|
+
|
25
|
+
ip = h.dns_name || "stopped"
|
26
|
+
|
27
|
+
puts "Discovered: #{ name } -> #{ ip }"
|
28
|
+
|
29
|
+
hosts[ name ] = {
|
30
|
+
"HostName" => ip,
|
31
|
+
"User" => h.tags[ "User" ],
|
32
|
+
"IdentityFile" => h.key_name,
|
33
|
+
"Tags" => h.tags.to_h.to_hash,
|
34
|
+
"Type" => "EC2" }
|
35
|
+
end
|
36
|
+
|
37
|
+
tmp_dir = File.join( Ops::pwd_dir, 'tmp' )
|
38
|
+
Dir.mkdir( tmp_dir ) unless File.directory? tmp_dir
|
39
|
+
|
40
|
+
host_file = File.join( tmp_dir, 'hosts.json' )
|
41
|
+
File.open( host_file, 'w' ) { | f | f.write( hosts.to_json ) }
|
42
|
+
|
43
|
+
if Ops::has_bash?
|
44
|
+
bash = `which bash`.strip
|
45
|
+
`#{ bash } -c "source #{
|
46
|
+
File.join( Ops::root_dir, 'autocomplete' ) }"`
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/tasks/hosts.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
namespace "hosts" do
|
2
|
+
|
3
|
+
desc I18n.t( "hosts.list.desc" )
|
4
|
+
task "list" do
|
5
|
+
hosts = Ops::read_hosts
|
6
|
+
hosts.each do | i, h |
|
7
|
+
puts "#{ h.alias }"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
desc I18n.t( "hosts.add.desc" )
|
12
|
+
task "add" do
|
13
|
+
required = [ 'hostname', 'host', 'user' ]
|
14
|
+
|
15
|
+
required.each do | p |
|
16
|
+
fail I18n.t( "hosts.add.no_#{ p }" ) if ENV[ p ].nil? ||
|
17
|
+
ENV[ p ].empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
hostname = ENV[ 'hostname' ]
|
21
|
+
host = ENV[ 'host' ]
|
22
|
+
user = ENV[ 'user' ]
|
23
|
+
type = ENV[ 'type' ] || "default"
|
24
|
+
identity = File.basename( ENV[ 'identity' ] )
|
25
|
+
|
26
|
+
|
27
|
+
puts "Adding host: #{ host }"
|
28
|
+
puts " => #{ hostname }"
|
29
|
+
puts " => using #{ identity }" unless identity.nil?
|
30
|
+
|
31
|
+
hosts = {}
|
32
|
+
hosts_file = File.join( pwd, "hosts.json" )
|
33
|
+
|
34
|
+
hosts = Ops::read_hosts
|
35
|
+
|
36
|
+
exit_failure( "Error: #{ host } is already defined" ) if
|
37
|
+
hosts.has_key? host
|
38
|
+
|
39
|
+
hosts[ host ] = {
|
40
|
+
'HostName' => hostname,
|
41
|
+
'User' => user,
|
42
|
+
'IdentityFile' => identity,
|
43
|
+
"Type" => "type"
|
44
|
+
}
|
45
|
+
|
46
|
+
File.open( hosts_file, 'w' ) { | f | f.write( hosts.to_json ) }
|
47
|
+
end
|
48
|
+
end
|
data/lib/tasks/init.rb
ADDED
data/lib/tasks/ops.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
task "default" do
|
2
|
+
Rake.application.options.show_task_pattern = //
|
3
|
+
Rake.application.display_tasks_and_comments()
|
4
|
+
end
|
5
|
+
|
6
|
+
desc I18n.t( "ops.version.desc" )
|
7
|
+
task "version" do
|
8
|
+
puts "Version: #{ Ops.version }"
|
9
|
+
end
|
10
|
+
|
11
|
+
## Project Initialization
|
12
|
+
|
13
|
+
desc I18n.t( "ops.init.desc" )
|
14
|
+
task "init" do
|
15
|
+
|
16
|
+
name = ENV[ 'name' ]
|
17
|
+
fail I18n.t( "ops.init.no_name" ) if name.nil? || name.empty?
|
18
|
+
|
19
|
+
FileUtils.cp_r( File.join( Ops::root_dir, "res", "samples", "default" ),
|
20
|
+
File.join( Ops::pwd_dir, name ) )
|
21
|
+
end
|
22
|
+
|
23
|
+
begin
|
24
|
+
$hosts = Ops::read_hosts
|
25
|
+
rescue
|
26
|
+
$hosts = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
$config = Ops::read_config
|
31
|
+
rescue
|
32
|
+
$config = {}
|
33
|
+
end
|
data/lib/tasks/ssh.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
namespace "hosts" do
|
2
|
+
|
3
|
+
$hosts.each do | i, host |
|
4
|
+
|
5
|
+
namespace host.alias do
|
6
|
+
|
7
|
+
desc I18n.t( "host.ssh", :host => host.alias )
|
8
|
+
task "ssh" do
|
9
|
+
host.shell!
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Execute a command over ssh"
|
13
|
+
task "ssh:exec" do
|
14
|
+
command = ENV[ "command" ]
|
15
|
+
raise IOError, "Command not specified" if command.nil? ||
|
16
|
+
command.empty?
|
17
|
+
|
18
|
+
host.shell_exec! command
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/version.rb
ADDED
data/pkg/.gitfile
ADDED
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
en:
|
2
|
+
messages:
|
3
|
+
reload_bash: "To have autocompletion for new/modified hosts reload
|
4
|
+
your bash profile/configs. Use `$ source [ location to
|
5
|
+
.bashrc or .bash_profile ]` on most machines."
|
6
|
+
ops:
|
7
|
+
init:
|
8
|
+
desc: "Initialize a new project"
|
9
|
+
no_name: "project name not provided"
|
10
|
+
version:
|
11
|
+
desc: "Print version number"
|
12
|
+
|
13
|
+
host:
|
14
|
+
ssh: "SSH into %{host}"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
en:
|
2
|
+
hosts:
|
3
|
+
|
4
|
+
list:
|
5
|
+
desc: "List all hosts form hosts config file."
|
6
|
+
|
7
|
+
sync:
|
8
|
+
desc: "Syncronize local hosts file with instances from EC2."
|
9
|
+
in_progress: "Syncing hosts.json with EC2..."
|
10
|
+
|
11
|
+
add:
|
12
|
+
desc: "Add a host to the hosts file"
|
13
|
+
no_hostname: "No hostname was provided."
|
14
|
+
no_host: "No host was provided."
|
15
|
+
no_user: "No use was provided."
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Host::Default do
|
4
|
+
|
5
|
+
context "with tags" do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@host = Host::Default.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should allow you to add tags" do
|
12
|
+
@host.tags = { "Platform" => "Windows" }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ".matches?" do
|
16
|
+
|
17
|
+
before :each do
|
18
|
+
@host.tags = { "Platform" => "Windows" }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return true if all tags match" do
|
22
|
+
@host.matches?( { "Platform" => "Windows" } ).should == true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return true if all tags match" do
|
26
|
+
@host.matches?( {
|
27
|
+
"Platform" => "Windows",
|
28
|
+
"Role" => "Worker" } ).should == false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Host::List do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@list = Host::List.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be an extenstion of the array class" do
|
10
|
+
@list.kind_of?( Array ).should == true
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".filter" do
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
@host = Host::Default.new( "host1" )
|
17
|
+
@host.tags = { "Platform" => "Windows" }
|
18
|
+
@list << @host
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should iterate through the items and call .matches?" do
|
22
|
+
@host.should_receive( :matches? )
|
23
|
+
@list.filter( { "Platform" => "Windows" } )
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return the matched host" do
|
27
|
+
hosts = @list.filter( { "Platform" => "Windows" } )
|
28
|
+
hosts.length.should == 1
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return a empty list" do
|
32
|
+
hosts = @list.filter( { "Platform" => "Linux" } )
|
33
|
+
hosts.length.should == 0
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'ops.rb'
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Devops
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Hardeep Shoker
|
14
|
+
- Ryan Willoughby
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2013-03-25 00:00:00 Z
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Ops tool for remote servers
|
23
|
+
email: hardeepshoker@gmail.com
|
24
|
+
executables:
|
25
|
+
- ops
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- .rspec
|
33
|
+
- Gemfile
|
34
|
+
- Gemfile.lock
|
35
|
+
- README.md
|
36
|
+
- autocomplete
|
37
|
+
- bin/ops
|
38
|
+
- devops.gemspec
|
39
|
+
- lib/host/default.rb
|
40
|
+
- lib/host/e_c_2.rb
|
41
|
+
- lib/host/list.rb
|
42
|
+
- lib/ops.rb
|
43
|
+
- lib/ops/common.rb
|
44
|
+
- lib/ops/console.rb
|
45
|
+
- lib/tasks/ec2.rb
|
46
|
+
- lib/tasks/hosts.rb
|
47
|
+
- lib/tasks/init.rb
|
48
|
+
- lib/tasks/ops.rb
|
49
|
+
- lib/tasks/ssh.rb
|
50
|
+
- lib/version.rb
|
51
|
+
- pkg/.gitfile
|
52
|
+
- res/samples/default/config.json
|
53
|
+
- res/strings/strings.yml
|
54
|
+
- res/strings/tasks/hosts.yml
|
55
|
+
- spec/lib/host/default.rb
|
56
|
+
- spec/lib/host/list.rb
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
homepage: https://github.com/hardeep/ops
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.8.24
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Ops tool for remote servers
|
91
|
+
test_files: []
|
92
|
+
|