zool 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +96 -0
- data/Rakefile +57 -0
- data/Readme.md +96 -0
- data/bin/zool +156 -0
- data/features/config_parser.feature +67 -0
- data/features/fetching_ssh_keys.feature +72 -0
- data/features/step_definitions/ssh_keys_steps.rb +136 -0
- data/features/store_ssh_keys.feature +62 -0
- data/features/support/env.rb +39 -0
- data/lib/py_config_parser/py_config_parser.tt +85 -0
- data/lib/zool.rb +24 -0
- data/lib/zool/configuration.rb +151 -0
- data/lib/zool/key_file_writer.rb +48 -0
- data/lib/zool/server.rb +116 -0
- data/lib/zool/server_pool.rb +74 -0
- data/spec/py_config_parser_spec.rb +55 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/zool.rb +4 -0
- data/spec/zool/configuration_spec.rb +170 -0
- data/spec/zool/key_file_writer_spec.rb +82 -0
- data/spec/zool/server_pool_spec.rb +133 -0
- data/spec/zool/server_spec.rb +178 -0
- metadata +266 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
module Zool
|
4
|
+
describe KeyfileWriter do
|
5
|
+
context "dumping keys to files" do
|
6
|
+
before :each do
|
7
|
+
@writer = KeyfileWriter.new
|
8
|
+
end
|
9
|
+
|
10
|
+
context "#write" do
|
11
|
+
context "with no filename provided" do
|
12
|
+
before :each do
|
13
|
+
sorted_keys = [
|
14
|
+
key_fixtures[:pascal],
|
15
|
+
key_fixtures[:pascal_private],
|
16
|
+
key_fixtures[:pascal_laptop],
|
17
|
+
key_fixtures[:bob],
|
18
|
+
key_fixtures[:upcase],
|
19
|
+
]
|
20
|
+
sorted_keys.each do |key|
|
21
|
+
@writer.write key
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should replace special characters with underscores in filename" do
|
26
|
+
it_should_generate_keyfile 'bob_schneider.pub'
|
27
|
+
it_should_generate_keyfile 'pascal_friederich.pub'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not fail if keyfile name is not parsable" do
|
31
|
+
key_without_host = "ssh-dsa asdfkasdlfjasdlfkjsdf="
|
32
|
+
@writer.write key_without_host
|
33
|
+
it_should_generate_keyfile '1__not_parsable.pub'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not fail if the name in the keyfile is unusual" do
|
37
|
+
key_with_only_username = "ssh-dsa asdfasdfasdfkjkj= Peter"
|
38
|
+
@writer.write key_with_only_username
|
39
|
+
it_should_generate_keyfile "peter.pub"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should write the ssh key in the appropriate keyfile" do
|
43
|
+
File.read('keys/bob_schneider.pub').chomp.should == key_fixtures[:bob]
|
44
|
+
File.read('keys/pascal_friederich.pub').chomp.should == key_fixtures[:pascal]
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should turn the filenames to underscores" do
|
48
|
+
it_should_generate_keyfile 'upcase_van.pub'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should number dublicate keynames" do
|
52
|
+
it_should_generate_keyfile 'pascal_friederich_2.pub'
|
53
|
+
it_should_generate_keyfile 'pascal_friederich_3.pub'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with a filename provided" do
|
58
|
+
it "should write the ssh key to the file named as given (with .pub added to the name)" do
|
59
|
+
@writer.write('a key', 'customname')
|
60
|
+
it_should_generate_keyfile('customname.pub')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "#write_keys" do
|
66
|
+
it "should write every key" do
|
67
|
+
@writer.should_receive(:write).exactly(3).times
|
68
|
+
keys = [
|
69
|
+
key_fixtures[:pascal],
|
70
|
+
key_fixtures[:pascal_private],
|
71
|
+
key_fixtures[:pascal_laptop]
|
72
|
+
]
|
73
|
+
@writer.write_keys(keys)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def it_should_generate_keyfile(keyfile)
|
81
|
+
Dir['keys/*.pub'].map {|path| path.split('/').last }.should include keyfile
|
82
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
module Zool
|
4
|
+
describe ServerPool do
|
5
|
+
context "parsing from a hosts file" do
|
6
|
+
context "with a user argument and/or password" do
|
7
|
+
before :each do
|
8
|
+
hostsfile = <<-HOSTS
|
9
|
+
12.21.4.1 servername
|
10
|
+
HOSTS
|
11
|
+
@server = ServerPool.from_hostfile(hostsfile, :user => 'peter', :password => 'peters1234').servers.first
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should pass the user argument to the servers" do
|
15
|
+
@server.user.should == 'peter'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should pass the password argument to the servers" do
|
19
|
+
@server.send(:instance_variable_get, :@options)[:password].should == 'peters1234'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when given a String" do
|
24
|
+
it "should return a Serverpool object with the servers from the hosts file" do
|
25
|
+
hostsfile = StringIO.new <<-HOSTS
|
26
|
+
12.21.4.1 servername
|
27
|
+
12.21.4.2 servername2
|
28
|
+
12.21.4.3 servername3
|
29
|
+
12.21.4.4 servername4
|
30
|
+
HOSTS
|
31
|
+
pool = ServerPool.from_hostfile(hostsfile)
|
32
|
+
pool.servers.map {|server| server.hostname }.should == ['12.21.4.1', '12.21.4.2', '12.21.4.3', '12.21.4.4']
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should remove duplicates from the list of servers" do
|
36
|
+
hostsfile = StringIO.new <<-HOSTS
|
37
|
+
12.21.4.1 servername1
|
38
|
+
12.21.4.2 servername2
|
39
|
+
12.21.4.2 fancy_alias
|
40
|
+
HOSTS
|
41
|
+
pool = ServerPool.from_hostfile(hostsfile)
|
42
|
+
pool.servers.map {|server| server.hostname }.should == ['12.21.4.1', '12.21.4.2']
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should remove localhost and networks from the list of servers" do
|
46
|
+
hostfile = StringIO.new <<-HOSTS
|
47
|
+
12.34.45.56 validserver
|
48
|
+
localhost localhost
|
49
|
+
127.0.0.1 localhost
|
50
|
+
255.255.255.255 network
|
51
|
+
::1 localhost
|
52
|
+
HOSTS
|
53
|
+
pool = ServerPool.from_hostfile(hostfile)
|
54
|
+
pool.servers.map {|server| server.hostname }.should == ['12.34.45.56']
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should ignore malformed lines" do
|
58
|
+
hostsfile = StringIO.new <<-HOSTS
|
59
|
+
# asdfasdfasdf comment
|
60
|
+
19023912u0194h odd_line
|
61
|
+
12.21.4.1 servername1
|
62
|
+
|
63
|
+
10.257.2.1 invalid_ip
|
64
|
+
12.21.4.2 servername2
|
65
|
+
myhost.de
|
66
|
+
HOSTS
|
67
|
+
pool = ServerPool.from_hostfile(hostsfile)
|
68
|
+
pool.servers.map {|server| server.hostname }.should == ['12.21.4.1', '12.21.4.2', 'myhost.de']
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
before :each do
|
73
|
+
@pool = ServerPool.new
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should only take Server objects" do
|
77
|
+
lambda { @pool << Object.new }.should raise_error TypeError
|
78
|
+
lambda { @pool.add Object.new }.should raise_error TypeError
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should delegate methods to the server objects" do
|
82
|
+
server = mock('server')
|
83
|
+
server.should_receive(:keys)
|
84
|
+
server.should_receive(:fetch_keys)
|
85
|
+
server.should_receive(:upload_keys)
|
86
|
+
@pool.push server
|
87
|
+
|
88
|
+
@pool.keys
|
89
|
+
@pool.fetch_keys
|
90
|
+
@pool.upload_keys
|
91
|
+
end
|
92
|
+
|
93
|
+
context "delegating methods to the servers" do
|
94
|
+
it "should aggregated values as an hash" do
|
95
|
+
server1 = stub
|
96
|
+
server1_keys = ['first key', 'second key']
|
97
|
+
server1.stub!(:keys).and_return(server1_keys)
|
98
|
+
|
99
|
+
server2 = stub
|
100
|
+
server2_keys = ['third key', 'forth key']
|
101
|
+
server2.stub!(:keys).and_return(server2_keys)
|
102
|
+
|
103
|
+
@pool.push server1
|
104
|
+
@pool.push server2
|
105
|
+
|
106
|
+
@pool.keys.should == server1_keys + server2_keys
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "dumping the servers keys to files" do
|
111
|
+
it "should write a keyfile for every key" do
|
112
|
+
FileUtils.rm_r 'keys' # cleanup old keyfiles
|
113
|
+
@pool.stub!(:keys).and_return(key_fixtures.values.join("\n"))
|
114
|
+
@pool.dump_keyfiles
|
115
|
+
Dir['keys/*'].should have(key_fixtures.size).keys
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "adding a key to the serverpool" do
|
120
|
+
it "should add the key to every server in the pool" do
|
121
|
+
new_key = 'a key'
|
122
|
+
keys = mock('keys')
|
123
|
+
server1 = mock('server1', :keys => keys)
|
124
|
+
server2 = mock('server2', :keys => keys)
|
125
|
+
@pool.push server1
|
126
|
+
@pool.push server2
|
127
|
+
|
128
|
+
keys.should_receive(:<<).twice.with(new_key)
|
129
|
+
@pool.keys << new_key
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'ruby-debug'
|
3
|
+
Debugger.start
|
4
|
+
|
5
|
+
module Zool
|
6
|
+
describe Server do
|
7
|
+
before :each do
|
8
|
+
@server = Server.new("somehost")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have a getter for the user attribute" do
|
12
|
+
@server.user.should == @server.send(:instance_variable_get, :@options)[:user]
|
13
|
+
end
|
14
|
+
|
15
|
+
context "fetching a servers keys" do
|
16
|
+
it "should use a password if provided" do
|
17
|
+
server = Server.new('somehost', :user => 'root', :password => 'a password')
|
18
|
+
Net::SCP.should_receive(:download!).with(anything, anything, anything, anything, :ssh => {:password => 'a password'})
|
19
|
+
server.keys
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should use the default server location" do
|
23
|
+
Server.new('somehost').keyfile_location.should == '~/.ssh/authorized_keys'
|
24
|
+
Server.new('somehost', :user => 'peter').keyfile_location.should == '~/.ssh/authorized_keys'
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with a custom keyfile location set" do
|
28
|
+
it "should use the custom keyfile location" do
|
29
|
+
@server = Server.new('somehost')
|
30
|
+
custom_keyfile_location = '/some/custom/path'
|
31
|
+
@server.keyfile_location = custom_keyfile_location
|
32
|
+
Net::SCP.should_receive(:download!).with(anything, anything, custom_keyfile_location, anything, anything)
|
33
|
+
|
34
|
+
@server.fetch_keys
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when the keyfile is not presetn" do
|
39
|
+
it "should return an empty list of keys" do
|
40
|
+
Net::SCP.should_receive(:download!).and_raise(Net::SCP::Error)
|
41
|
+
@server.keys.should be_empty
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should load the authorized_keys file from the server" do
|
46
|
+
@server = Server.new('somehost')
|
47
|
+
Net::SCP.should_receive(:download!).with(anything, anything, @server.keyfile_location, anything, anything)
|
48
|
+
|
49
|
+
@server.fetch_keys
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should make the keys available through a keys array" do
|
53
|
+
@server.stub!(:load_remote_file).and_return("#{key_fixtures[:pascal]}\n#{key_fixtures[:bob]}")
|
54
|
+
@server.keys.should == [key_fixtures[:pascal], key_fixtures[:bob]]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should remove unneccasarry whitespace from the output" do
|
58
|
+
@server = Server.new('somehost')
|
59
|
+
@server.stub!(:load_remote_file).and_return(" #{key_fixtures[:pascal]} ")
|
60
|
+
@server.keys.should == [key_fixtures[:pascal]]
|
61
|
+
@server.keys.should have(1).key
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should remove blank lines" do
|
65
|
+
@server = Server.new('somehost')
|
66
|
+
@server.stub!(:load_remote_file).and_return(" #{key_fixtures[:pascal]} \n ")
|
67
|
+
@server.keys.should == [key_fixtures[:pascal]]
|
68
|
+
@server.keys.should have(1).key
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should remove duplicate keys from the list" do
|
72
|
+
@server = Server.new('somehost')
|
73
|
+
@server.stub!(:load_remote_file).and_return("#{key_fixtures[:pascal]}\n#{key_fixtures[:pascal]}")
|
74
|
+
@server.keys.should have(1).key
|
75
|
+
@server.keys.should == [key_fixtures[:pascal]]
|
76
|
+
end
|
77
|
+
|
78
|
+
context "requesting the keys several times" do
|
79
|
+
it "should not fetch the keys again" do
|
80
|
+
@server = Server.new('somehost')
|
81
|
+
@server.should_receive(:load_remote_file).once.and_return("n#{key_fixtures[:pascal]}")
|
82
|
+
@server.keys
|
83
|
+
@server.keys
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "fetching the keys again after they have already been fetched" do
|
88
|
+
it "should return the new list of keys" do
|
89
|
+
@server = Server.new('somehost')
|
90
|
+
@server.should_receive(:load_remote_file).ordered.and_return("#{key_fixtures[:pascal]}")
|
91
|
+
@server.should_receive(:load_remote_file).ordered.and_return("#{key_fixtures[:bob]}")
|
92
|
+
@server.keys
|
93
|
+
@server.keys.should == [key_fixtures[:pascal]]
|
94
|
+
@server.fetch_keys
|
95
|
+
@server.keys.should == [key_fixtures[:bob]]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "dumping the keys to files" do
|
101
|
+
it "should write a keyfile for every key" do
|
102
|
+
FileUtils.rm_r 'keys' # cleanup old keyfiles
|
103
|
+
@server.stub!(:load_remote_file).and_return(key_fixtures.values.join("\n"))
|
104
|
+
@server.dump_keyfiles
|
105
|
+
Dir['keys/*'].should have(key_fixtures.size).keys
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "setting a servers keys" do
|
110
|
+
before :each do
|
111
|
+
@server = Server.new('somehost')
|
112
|
+
@server.stub!(:load_remote_file).and_return("")
|
113
|
+
end
|
114
|
+
|
115
|
+
context "by replacing all of them" do
|
116
|
+
it "should take a array of keys" do
|
117
|
+
@server.keys = [key_fixtures[:pascal], key_fixtures[:bob]]
|
118
|
+
@server.keys.should == [key_fixtures[:pascal], key_fixtures[:bob]]
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not fetch the servers existing keys" do
|
122
|
+
@server.should_not_receive(:load_remote_file)
|
123
|
+
@server.keys = [key_fixtures[:pascal]]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "by adding keys to the existing keys" do
|
128
|
+
it "should fetch the servers current keys if not done before" do
|
129
|
+
@server.should_receive(:load_remote_file)
|
130
|
+
@server.keys << "asdf"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "and uploading them" do
|
135
|
+
before :each do
|
136
|
+
@server.keys = [key_fixtures[:pascal], key_fixtures[:bob]]
|
137
|
+
@backup_keys = 'original keys'
|
138
|
+
@server.stub!(:load_remote_file).and_return(@backup_keys)
|
139
|
+
|
140
|
+
Net::SCP.stub(:download!)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should write a authorized_keys file with all the keys" do
|
144
|
+
channel_stub = stub('ssh channel stub', :null_object => true)
|
145
|
+
Net::SSH.stub!(:start).and_return(channel_stub)
|
146
|
+
Net::SCP.stub!(:upload!) # the backup
|
147
|
+
channel_stub.stub(:scp).and_return(channel_stub)
|
148
|
+
|
149
|
+
channel_stub.should_receive(:upload!).with(stringbuffer_with(@server.keys.join("\n")), @server.keyfile_location).ordered
|
150
|
+
@server.upload_keys
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should backup the existing authorized_keys file" do
|
154
|
+
@server.should_receive(:load_remote_file).and_return(@backup_keys)
|
155
|
+
Net::SSH.stub!(:start).and_return(stub('ssh channel stub', :null_object => true))
|
156
|
+
|
157
|
+
Net::SCP.should_receive(:upload!).with('somehost', 'root', stringbuffer_with(@backup_keys), /authorized_keys_\d+$/, anything)
|
158
|
+
@server.upload_keys
|
159
|
+
end
|
160
|
+
|
161
|
+
context "with an exception during backup of the original keys" do
|
162
|
+
before :each do
|
163
|
+
Net::SCP.stub!(:download!).and_raise(Exception)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should not upload the new keys" do
|
167
|
+
Net::SCP.should_not_receive(:upload!)
|
168
|
+
lambda { @server.upload_keys }.should raise_error
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "providing a fallback if something goes wrong" do
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
metadata
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pascal Friederich
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-06 00:00:00 +01:00
|
13
|
+
default_executable: zool
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: net-scp
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.0.2
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: net-ssh
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.17
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: net-scp
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.0.2
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: net-ssh
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.0.17
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: treetop
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.4.3
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: polyglot
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.2.9
|
74
|
+
version:
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: highline
|
77
|
+
type: :runtime
|
78
|
+
version_requirement:
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 1.5.1
|
84
|
+
version:
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: builder
|
87
|
+
type: :development
|
88
|
+
version_requirement:
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 2.1.2
|
94
|
+
version:
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: columnize
|
97
|
+
type: :development
|
98
|
+
version_requirement:
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.3.1
|
104
|
+
version:
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: cucumber
|
107
|
+
type: :development
|
108
|
+
version_requirement:
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 0.5.3
|
114
|
+
version:
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: diff-lcs
|
117
|
+
type: :development
|
118
|
+
version_requirement:
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 1.1.2
|
124
|
+
version:
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: fakefs
|
127
|
+
type: :development
|
128
|
+
version_requirement:
|
129
|
+
version_requirements: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.2.1
|
134
|
+
version:
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: json_pure
|
137
|
+
type: :development
|
138
|
+
version_requirement:
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: 1.2.0
|
144
|
+
version:
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: linecache
|
147
|
+
type: :development
|
148
|
+
version_requirement:
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: "0.43"
|
154
|
+
version:
|
155
|
+
- !ruby/object:Gem::Dependency
|
156
|
+
name: rake
|
157
|
+
type: :development
|
158
|
+
version_requirement:
|
159
|
+
version_requirements: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: 0.8.7
|
164
|
+
version:
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: rspec
|
167
|
+
type: :development
|
168
|
+
version_requirement:
|
169
|
+
version_requirements: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 1.2.9
|
174
|
+
version:
|
175
|
+
- !ruby/object:Gem::Dependency
|
176
|
+
name: ruby-debug
|
177
|
+
type: :development
|
178
|
+
version_requirement:
|
179
|
+
version_requirements: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - ">="
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: 0.10.3
|
184
|
+
version:
|
185
|
+
- !ruby/object:Gem::Dependency
|
186
|
+
name: ruby-debug-base
|
187
|
+
type: :development
|
188
|
+
version_requirement:
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: 0.10.3
|
194
|
+
version:
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: term-ansicolor
|
197
|
+
type: :development
|
198
|
+
version_requirement:
|
199
|
+
version_requirements: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - ">="
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: 1.0.4
|
204
|
+
version:
|
205
|
+
description: Zool allows you to manage authorized_keys files on servers. It comes with a command-line client 'zool'. The configuration can be done in a pyconfig/gitosis like configuration file. See README.md for further details
|
206
|
+
email: paukul@gmail.com
|
207
|
+
executables:
|
208
|
+
- zool
|
209
|
+
extensions: []
|
210
|
+
|
211
|
+
extra_rdoc_files:
|
212
|
+
- LICENSE
|
213
|
+
- README.md
|
214
|
+
files:
|
215
|
+
- LICENSE
|
216
|
+
- Rakefile
|
217
|
+
- Readme.md
|
218
|
+
- bin/zool
|
219
|
+
- lib/py_config_parser/py_config_parser.tt
|
220
|
+
- lib/zool.rb
|
221
|
+
- lib/zool/configuration.rb
|
222
|
+
- lib/zool/key_file_writer.rb
|
223
|
+
- lib/zool/server.rb
|
224
|
+
- lib/zool/server_pool.rb
|
225
|
+
- README.md
|
226
|
+
has_rdoc: true
|
227
|
+
homepage: http://github.com/paukul/zool
|
228
|
+
licenses: []
|
229
|
+
|
230
|
+
post_install_message:
|
231
|
+
rdoc_options:
|
232
|
+
- --charset=UTF-8
|
233
|
+
require_paths:
|
234
|
+
- lib
|
235
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
236
|
+
requirements:
|
237
|
+
- - ">="
|
238
|
+
- !ruby/object:Gem::Version
|
239
|
+
version: "0"
|
240
|
+
version:
|
241
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
242
|
+
requirements:
|
243
|
+
- - ">="
|
244
|
+
- !ruby/object:Gem::Version
|
245
|
+
version: "0"
|
246
|
+
version:
|
247
|
+
requirements: []
|
248
|
+
|
249
|
+
rubyforge_project:
|
250
|
+
rubygems_version: 1.3.5
|
251
|
+
signing_key:
|
252
|
+
specification_version: 3
|
253
|
+
summary: Library and command-line client to manage authorized_keys files
|
254
|
+
test_files:
|
255
|
+
- spec/py_config_parser_spec.rb
|
256
|
+
- spec/spec_helper.rb
|
257
|
+
- spec/zool/configuration_spec.rb
|
258
|
+
- spec/zool/key_file_writer_spec.rb
|
259
|
+
- spec/zool/server_pool_spec.rb
|
260
|
+
- spec/zool/server_spec.rb
|
261
|
+
- spec/zool.rb
|
262
|
+
- features/config_parser.feature
|
263
|
+
- features/fetching_ssh_keys.feature
|
264
|
+
- features/step_definitions/ssh_keys_steps.rb
|
265
|
+
- features/store_ssh_keys.feature
|
266
|
+
- features/support/env.rb
|