paratele 0.0.1

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/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
+