paratele 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Michel Martens and Damian Janowski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,106 @@
1
+ TELE(1)
2
+
3
+ NAME
4
+ tele -- Provisioning at a distance.
5
+
6
+ SYNOPSIS
7
+ tele [-h] [-d path] (init|status|install)
8
+
9
+ DESCRIPTION
10
+ Tele is a small provisioning framework that allows you to run bash
11
+ scripts on remote servers over SSH. It uses your own SSH, not a Ruby
12
+ version, so you can profit from your settings and public/private keys.
13
+
14
+ It uses the following directory structure to store the recipes and
15
+ configuration files:
16
+
17
+ .tele/layout.json
18
+ .tele/ssh_config
19
+ .tele/recipes/redis/status.sh
20
+ .tele/recipes/redis/install.sh
21
+ .tele/recipes/unicorn/status.sh
22
+ .tele/recipes/unicorn/install.sh
23
+
24
+ In the example, there are recipes for Redis and Unicorn. Please note that you are in
25
+ charge of creating them.
26
+
27
+ layout.json
28
+ The server layout, with the available roles and servers. Example:
29
+
30
+ {
31
+ "servers": {
32
+ "app-1": ["redis"],
33
+ "app-2": ["ruby", "unicorn"],
34
+ "app-3": ["ruby", "resque"]
35
+ }
36
+ }
37
+
38
+ The key "servers" stores a map of servers to roles. The keys can be
39
+ either hostnames declared in .tele/ssh_config or IP addresses.
40
+
41
+ ssh_config
42
+ Configuration file for the SSH connection. Check the SSH_CONFIG man
43
+ page for more information.
44
+
45
+ The following options are available:
46
+
47
+ -h
48
+ Display this help message.
49
+
50
+ -d path
51
+ Sets path as the directory where tele will search for scripts and
52
+ configuration files. You can also use the environment variable
53
+ TELE_HOME.
54
+
55
+ -v
56
+ Print output from servers for all roles, whether they succeed or
57
+ not. The default is to print output from servers only if a recipe
58
+ fails.
59
+
60
+ -q
61
+ Don't print output from servers locally.
62
+
63
+ init
64
+ Copies a .tele template to the current directory.
65
+
66
+ run command
67
+ Runs every <recipe>/<command>.sh script on the servers declared
68
+ in layout.json, in the specified order. The scripts must have an
69
+ exit status of 0 on success, otherwise it will be counted as failed.
70
+ If a recipe fails, no more recipes for that server will be executed.
71
+
72
+
73
+ USAGE
74
+ To provision two servers called `server1` and `server2` with Redis,
75
+ starting from scratch:
76
+
77
+ # Create the .tele directory.
78
+ $ tele init
79
+
80
+ # Create directories for the recipes.
81
+ $ mkdir -p .tele/recipes/redis
82
+
83
+ # Create install.sh script (ommited).
84
+
85
+ # Edit .tele/layout.json as follows:
86
+
87
+ {
88
+ "servers": {
89
+ "server1": ["redis"],
90
+ "server2": ["redis"]
91
+ }
92
+ }
93
+
94
+ # Edit .tele/ssh_config:
95
+
96
+ Host server1
97
+ Hostname 10.0.0.1
98
+
99
+ Host server2
100
+ Hostname 10.0.0.2
101
+
102
+ # Run tele install
103
+ $ tele run install
104
+
105
+ INSTALLATION
106
+ $ gem install tele
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ task :test do
2
+ require "cutest"
3
+
4
+ Cutest.run(Dir["test/tele.rb"])
5
+ end
6
+
7
+ task :default => :test
data/bin/tele ADDED
@@ -0,0 +1,140 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ help = File.expand_path(File.join("..", "README"), File.dirname(__FILE__))
4
+
5
+ if ARGV.empty?
6
+ exec "less #{help}"
7
+ end
8
+
9
+ require "clap"
10
+ require "json"
11
+ require "open3"
12
+
13
+ def path(*parts)
14
+ File.expand_path(File.join(*parts), ENV["TELE_HOME"])
15
+ end
16
+
17
+ def ssh(server, script)
18
+ out, status = Open3.capture2e("ssh -T -F #{path("ssh_config")} #{server} < #{script}")
19
+ [out, status.exitstatus]
20
+ end
21
+
22
+ def layout
23
+ $layout ||= JSON.parse(File.read(path("layout.json")))
24
+ end
25
+
26
+ def servers
27
+ layout["servers"]
28
+ end
29
+
30
+ def recipe_script(recipe, command)
31
+ path("recipes", recipe, "#{command}.sh")
32
+ end
33
+
34
+ def run(server, recipe, command)
35
+ script = recipe_script(recipe, command)
36
+
37
+ if File.exist?(script)
38
+ ssh(server, script)
39
+ end
40
+ end
41
+
42
+ out = Module.new do
43
+ def self.server(name)
44
+ puts name
45
+ end
46
+
47
+ def self.error
48
+ puts "\033[01;31mERROR\033[00m"
49
+ end
50
+
51
+ def self.ok
52
+ puts "\033[01;32mOK\033[00m"
53
+ end
54
+
55
+ def self.missing
56
+ puts "\033[01;33mMISSING\033[00m"
57
+ end
58
+
59
+ def self.done
60
+ puts "\033[01;32mDONE\033[00m"
61
+ end
62
+
63
+ def self.unknown
64
+ puts "?"
65
+ end
66
+ end
67
+
68
+ ###
69
+
70
+ ENV["TELE_HOME"] ||= File.join(Dir.pwd, ".tele")
71
+
72
+ verbosity = 1
73
+
74
+ commands = Clap.run ARGV,
75
+ "-h" => lambda {
76
+ exec "less #{help}"
77
+ },
78
+ "-q" => lambda {
79
+ verbosity = 0
80
+ },
81
+ "-v" => lambda {
82
+ verbosity = 2
83
+ },
84
+ "-d" => lambda {|path|
85
+ ENV["TELE_HOME"] = File.join(Dir.pwd, path)
86
+ }
87
+
88
+ Clap.run commands,
89
+ "init" => lambda {
90
+ source = File.expand_path("../templates/.tele", File.dirname(__FILE__))
91
+ target = File.expand_path(Dir.pwd)
92
+
93
+ %x{cp -r #{source} #{target}}
94
+ out.done
95
+ }
96
+
97
+ unless File.directory?(path)
98
+ $stderr.puts "Couldn't find a .tele directory"
99
+ exit 1
100
+ end
101
+
102
+ Clap.run commands,
103
+ "run" => lambda {|command|
104
+ if commands.size == 3
105
+ selected = commands.last.split(",")
106
+ servers.select! {|server| selected.include?(server)}
107
+ end
108
+
109
+ exit_status = 0
110
+
111
+ servers.each do |server, recipes|
112
+ out.server(server)
113
+
114
+ recipes.each do |recipe|
115
+ print " #{recipe}: "
116
+
117
+ if File.exists?(path("recipes", recipe))
118
+ stdout, status = run(server, recipe, command)
119
+
120
+ case status
121
+ when nil
122
+ out.unknown
123
+ when 0
124
+ out.ok
125
+ $stderr.print stdout if verbosity >= 2
126
+ else
127
+ out.error
128
+ $stderr.print stdout if verbosity >= 1
129
+ exit_status = 1
130
+ break
131
+ end
132
+ else
133
+ out.unknown
134
+ exit 1
135
+ end
136
+ end
137
+ end
138
+
139
+ exit exit_status
140
+ }
data/paratele.gemspec ADDED
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "paratele"
3
+ s.version = "0.0.1"
4
+ s.summary = "Provisioning at a distance"
5
+ s.description = "Tele is a small provisioning framework that allows you to run bash scripts on remote servers over SSH."
6
+ s.authors = ["Damian Janowski", "Michel Martens"]
7
+ s.email = ["djanowski@dimaion.com", "michel@soveran.com"]
8
+ s.homepage = "http://github.com/djanowski/tele"
9
+
10
+ s.executables.push("tele")
11
+
12
+ s.add_dependency("clap")
13
+
14
+ s.files = ["LICENSE", "README", "Rakefile", "bin/tele", "templates/.tele/layout.json", "templates/.tele/ssh_config", "paratele.gemspec", "tele.gemspec", "test/tele.rb"]
15
+ end
data/tele.gemspec ADDED
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "tele"
3
+ s.version = "0.0.1"
4
+ s.summary = "Provisioning at a distance"
5
+ s.description = "Tele is a small provisioning framework that allows you to run bash scripts on remote servers over SSH."
6
+ s.authors = ["Damian Janowski", "Michel Martens"]
7
+ s.email = ["djanowski@dimaion.com", "michel@soveran.com"]
8
+ s.homepage = "http://github.com/djanowski/tele"
9
+
10
+ s.executables.push("tele")
11
+
12
+ s.add_dependency("clap")
13
+
14
+ s.files = ["LICENSE", "README", "Rakefile", "bin/tele", "templates/.tele/layout.json", "templates/.tele/ssh_config", "tele.gemspec", "test/tele.rb"]
15
+ end
@@ -0,0 +1,9 @@
1
+ {
2
+ "roles": {
3
+
4
+ },
5
+
6
+ "servers": {
7
+
8
+ }
9
+ }
File without changes
data/test/tele.rb ADDED
@@ -0,0 +1,126 @@
1
+ require "shellwords"
2
+ require "open3"
3
+
4
+ ROOT = File.expand_path(File.join(File.dirname(__FILE__), ".."))
5
+
6
+ def root(*args)
7
+ File.join(ROOT, *args)
8
+ end
9
+
10
+ def tele(*args)
11
+ sh("ruby #{root "bin/tele"} #{Shellwords.join args}")
12
+ end
13
+
14
+ def sh(cmd)
15
+ Open3.capture3(cmd)
16
+ end
17
+
18
+ prepare do
19
+ `rm -rf /tmp/tele`
20
+ `mkdir /tmp/tele`
21
+ end
22
+
23
+ test "`tele run` without a config" do
24
+ out, err, status = tele("run", "install")
25
+
26
+ assert err =~ /Couldn't find/
27
+ assert_equal 1, status.exitstatus
28
+ end
29
+
30
+ test "`tele run` with missing recipes" do
31
+ out, err, status = tele("run", "deploy", "-d", "test/.tele.missing-recipes")
32
+
33
+ assert_equal 1, status.exitstatus
34
+ assert out =~ /db-1/
35
+ assert out =~ /redis: .*\?/
36
+ assert out !~ /cassandra: .*\?/
37
+ end
38
+
39
+ test "`tele run` successful" do
40
+ out, err, status = tele("run", "install", "-d", "test/.tele.simple")
41
+
42
+ assert_equal 0, status.exitstatus
43
+ assert out =~ /db-1/
44
+ assert out =~ /db-2/
45
+ assert out =~ /redis: .*OK/
46
+ assert out =~ /cdb: .*OK/
47
+ assert out =~ /cassandra: .*OK/
48
+ end
49
+
50
+ test "`tele run` with recipes missing a command" do
51
+ out, err, status = tele("run", "status", "-d", "test/.tele.simple")
52
+
53
+ assert_equal 0, status.exitstatus
54
+ assert out =~ /cassandra: .*\?/
55
+ assert out =~ /cdb: .*OK/
56
+ assert out =~ /redis: .*OK/
57
+ end
58
+
59
+ test "`tele run` with errors" do
60
+ out, err, status = tele("run", "update", "-d", "test/.tele.simple")
61
+
62
+ assert_equal 1, status.exitstatus
63
+
64
+ assert out =~ /db-1/
65
+ assert out =~ /cassandra: .*ERROR/
66
+ assert err =~ /Updating Cassandra failed/
67
+ assert out !~ /cdb:/
68
+
69
+ assert out =~ /db-2/
70
+ assert out =~ /redis: .*OK/
71
+ end
72
+
73
+ test "`tele run` with specific server" do
74
+ out, err, status = tele("run", "install", "db-2", "-d", "test/.tele.simple")
75
+
76
+ assert_equal 0, status.exitstatus
77
+ assert out !~ /db-1/
78
+ assert out !~ /cassandra/
79
+ assert out !~ /cdb/
80
+ assert out =~ /db-2/
81
+ assert out =~ /redis/
82
+ end
83
+
84
+ test "`tele run` with multiple server" do
85
+ out, err, status = tele("run", "install", "db-2,db-1", "-d", "test/.tele.simple")
86
+
87
+ assert_equal 0, status.exitstatus
88
+ assert out =~ /db-1/
89
+ assert out =~ /db-2/
90
+ end
91
+
92
+ test "`tele run -v`" do
93
+ out, err, status = tele("run", "update", "-v", "-d", "test/.tele.simple")
94
+
95
+ assert err =~ /Redis succesfully updated/
96
+ assert err =~ /Updating Cassandra failed/
97
+ assert out !~ /Redis succesfully updated/
98
+ assert out !~ /Updating Cassandra failed/
99
+ end
100
+
101
+ test "`tele run -q`" do
102
+ out, err, status = tele("run", "update", "-q", "-d", "test/.tele.simple")
103
+
104
+ assert err !~ /Redis succesfully updated/
105
+ assert err !~ /Updating Cassandra failed/
106
+ assert out !~ /Redis succesfully updated/
107
+ assert out !~ /Updating Cassandra failed/
108
+ end
109
+
110
+ __END__
111
+
112
+ test "`tele init`" do
113
+ `rm -rf test/tmp`
114
+ `mkdir test/tmp`
115
+
116
+ assert !File.exists?("test/tmp/.tele")
117
+
118
+ Dir.chdir("test/tmp") do
119
+ out, err = tele("init")
120
+
121
+ assert File.exists?(".tele")
122
+
123
+ out, err, status = tele("status")
124
+ assert status.exitstatus == 0
125
+ end
126
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paratele
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Damian Janowski
13
+ - Michel Martens
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-09 00:00:00 -03:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: clap
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: Tele is a small provisioning framework that allows you to run bash scripts on remote servers over SSH.
35
+ email:
36
+ - djanowski@dimaion.com
37
+ - michel@soveran.com
38
+ executables:
39
+ - tele
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - LICENSE
46
+ - README
47
+ - Rakefile
48
+ - bin/tele
49
+ - templates/.tele/layout.json
50
+ - templates/.tele/ssh_config
51
+ - paratele.gemspec
52
+ - tele.gemspec
53
+ - test/tele.rb
54
+ has_rdoc: true
55
+ homepage: http://github.com/djanowski/tele
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.7
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Provisioning at a distance
86
+ test_files: []
87
+