kytoon 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.document +5 -0
  2. data/Gemfile +15 -0
  3. data/Gemfile.lock +29 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +81 -0
  6. data/Rakefile +35 -0
  7. data/VERSION +1 -0
  8. data/config/server_group_vpc.json +14 -0
  9. data/config/server_group_xen.json +24 -0
  10. data/lib/kytoon.rb +8 -0
  11. data/lib/kytoon/providers/cloud_servers_vpc.rb +6 -0
  12. data/lib/kytoon/providers/cloud_servers_vpc/client.rb +197 -0
  13. data/lib/kytoon/providers/cloud_servers_vpc/connection.rb +148 -0
  14. data/lib/kytoon/providers/cloud_servers_vpc/server.rb +121 -0
  15. data/lib/kytoon/providers/cloud_servers_vpc/server_group.rb +401 -0
  16. data/lib/kytoon/providers/cloud_servers_vpc/ssh_public_key.rb +29 -0
  17. data/lib/kytoon/providers/cloud_servers_vpc/vpn_network_interface.rb +33 -0
  18. data/lib/kytoon/providers/xenserver.rb +1 -0
  19. data/lib/kytoon/providers/xenserver/server_group.rb +371 -0
  20. data/lib/kytoon/server_group.rb +46 -0
  21. data/lib/kytoon/ssh_util.rb +23 -0
  22. data/lib/kytoon/util.rb +118 -0
  23. data/lib/kytoon/version.rb +8 -0
  24. data/lib/kytoon/vpn/vpn_connection.rb +46 -0
  25. data/lib/kytoon/vpn/vpn_network_manager.rb +237 -0
  26. data/lib/kytoon/vpn/vpn_openvpn.rb +112 -0
  27. data/lib/kytoon/xml_util.rb +15 -0
  28. data/rake/kytoon.rake +115 -0
  29. data/test/client_test.rb +111 -0
  30. data/test/helper.rb +18 -0
  31. data/test/server_group_test.rb +253 -0
  32. data/test/server_test.rb +69 -0
  33. data/test/ssh_util_test.rb +22 -0
  34. data/test/test_helper.rb +194 -0
  35. data/test/test_kytoon.rb +7 -0
  36. data/test/util_test.rb +23 -0
  37. data/test/vpn_network_manager_test.rb +40 -0
  38. metadata +247 -0
@@ -0,0 +1,15 @@
1
+ module Kytoon
2
+
3
+ module XMLUtil
4
+
5
+ def self.element_text(dom, name)
6
+ if dom.elements[name]
7
+ return dom.elements[name].text
8
+ else
9
+ return nil
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,115 @@
1
+ include Kytoon
2
+
3
+ namespace :group do
4
+ TMP_SG=File.join(KYTOON_PROJECT, 'tmp', 'server_groups')
5
+
6
+ directory TMP_SG
7
+
8
+ task :init => [TMP_SG] do
9
+ ServerGroup.init
10
+ end
11
+
12
+ desc "Create a new group of cloud servers"
13
+ task :create => [ "init" ] do
14
+ sg = ServerGroup.create
15
+ puts "Server group ID #{sg.id} created."
16
+ end
17
+
18
+ desc "List existing cloud server groups."
19
+ task :list => "init" do
20
+
21
+ server_groups=nil
22
+ server_groups=ServerGroup.index(:source => "cache")
23
+ if server_groups.size > 0
24
+ puts "Server groups:"
25
+ server_groups.sort { |a,b| b.id <=> a.id }.each do |sg|
26
+ gw=sg.gateway_ip.nil? ? "" : " (#{sg.gateway_ip})"
27
+ puts "\t :id => #{sg.id}, :name => #{sg.name} #{gw}"
28
+ end
29
+ else
30
+ puts "No server groups."
31
+ end
32
+
33
+ end
34
+
35
+ desc "Print information for a cloud server group"
36
+ task :show => [ "init" ] do
37
+ sg = ServerGroup.get
38
+ sg.pretty_print
39
+ end
40
+
41
+ desc "Delete a cloud server group"
42
+ task :delete => ["init"] do
43
+
44
+ sg = ServerGroup.get
45
+ puts "Deleting cloud server group ID: #{sg.id}."
46
+ sg.delete
47
+ SshUtil.remove_known_hosts_ip(sg.gateway_ip)
48
+
49
+ end
50
+
51
+ desc "Print the VPN gateway IP address"
52
+ task :gateway_ip do
53
+ group = ServerGroup.get
54
+ puts group.gateway_ip
55
+ end
56
+
57
+ end
58
+
59
+ desc "SSH into the most recently created VPN gateway server."
60
+ task :ssh => 'group:init' do
61
+
62
+ sg=ServerGroup.get
63
+ args=ARGV[1, ARGV.length].join(" ")
64
+ if (ARGV[1] and ARGV[1] =~ /^GROUP_.*/) and (ARGV[2] and ARGV[2] =~ /^GROUP_.*/)
65
+ args=ARGV[3, ARGV.length].join(" ")
66
+ elsif ARGV[1] and ARGV[1] =~ /^GROUP_.*/
67
+ args=ARGV[2, ARGV.length].join(" ")
68
+ end
69
+ exec("ssh -o \"StrictHostKeyChecking no\" root@#{sg.gateway_ip} #{args}")
70
+ end
71
+
72
+ desc "Print help and usage information"
73
+ task :usage do
74
+
75
+ puts ""
76
+ puts "Kytoon Toolkit Version: #{Kytoon::Version::VERSION}"
77
+ puts ""
78
+ puts "The following tasks are available:"
79
+
80
+ puts %x{cd #{KYTOON_PROJECT} && rake -T}
81
+ puts "----"
82
+ puts "Example commands:"
83
+ puts ""
84
+ puts "\t- Create a new server group."
85
+ puts ""
86
+ puts "\t\t$ rake group:create"
87
+
88
+ puts ""
89
+ puts "\t- List your currently running server groups."
90
+ puts ""
91
+ puts "\t\t$ rake group:list"
92
+
93
+ puts ""
94
+ puts "\t- List all remote groups using a common Cloud Servers VPC account."
95
+ puts ""
96
+ puts "\t\t$ rake group:list"
97
+
98
+ puts ""
99
+ puts "\t- SSH into the current (most recently created) server group."
100
+ puts ""
101
+ puts "\t\t$ rake ssh"
102
+
103
+ puts ""
104
+ puts "\t- SSH into a server group with an ID of 3."
105
+ puts ""
106
+ puts "\t\t$ rake ssh GROUP_ID=3"
107
+
108
+ puts ""
109
+ puts "\t- Delete the server group with an ID of 3."
110
+ puts ""
111
+ puts "\t\t$ rake group:delete GROUP_ID=3"
112
+
113
+ end
114
+
115
+ task :default => 'usage'
@@ -0,0 +1,111 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'test_helper'
3
+
4
+ module Kytoon
5
+ module Providers
6
+ module CloudServersVPC
7
+
8
+ class ClientTest < Test::Unit::TestCase
9
+
10
+ include Kytoon::Providers::CloudServersVPC
11
+
12
+ def setup
13
+ @tmp_dir=TmpDir.new_tmp_dir
14
+ Client.data_dir=@tmp_dir
15
+ end
16
+
17
+ def teardown
18
+ FileUtils.rm_rf(@tmp_dir)
19
+ end
20
+
21
+ def test_new
22
+ client=Client.new(:name => "test", :description => "zz", :status => "Pending")
23
+ assert_equal "test", client.name
24
+ assert_equal "zz", client.description
25
+ assert_equal 0, client.vpn_network_interfaces.size
26
+ end
27
+
28
+ def test_from_xml
29
+ client=Client.from_xml(CLIENT_XML)
30
+ assert_equal "local", client.name
31
+ assert_equal "Toolkit Client: local", client.description
32
+ assert_equal 5, client.id
33
+ assert_equal 11, client.server_group_id
34
+ vni=client.vpn_network_interfaces[0]
35
+ assert_not_nil vni.client_key
36
+ assert_not_nil vni.client_cert
37
+ assert_not_nil vni.ca_cert
38
+ end
39
+
40
+ def test_client_to_and_from_xml
41
+ client=Client.from_xml(CLIENT_XML)
42
+ xml=client.to_xml
43
+ assert_not_nil xml
44
+ client=Client.from_xml(xml)
45
+ assert_equal "local", client.name
46
+ assert_equal "Toolkit Client: local", client.description
47
+ assert_equal 5, client.id
48
+ assert_equal 11, client.server_group_id
49
+ vni=client.vpn_network_interfaces[0]
50
+ assert_not_nil vni.client_key
51
+ assert_not_nil vni.client_cert
52
+ assert_not_nil vni.ca_cert
53
+ end
54
+
55
+ def test_get
56
+
57
+ tmp_dir=TmpDir.new_tmp_dir
58
+ File.open("#{tmp_dir}/5.xml", 'w') do |f|
59
+ f.write(CLIENT_XML)
60
+ end
61
+ Client.data_dir=tmp_dir
62
+
63
+ Connection.stubs(:get).returns(CLIENT_XML)
64
+
65
+ # should raise exception if no ID is set and doing a remote lookup
66
+ assert_raises(RuntimeError) do
67
+ Client.get
68
+ end
69
+
70
+ client=Client.get(:id => "1234")
71
+ assert_not_nil client
72
+ assert_equal "Toolkit Client: local", client.description
73
+
74
+ client=Client.get(:id => "5", :source => "cache")
75
+ assert_not_nil client
76
+ assert_equal "Toolkit Client: local", client.description
77
+
78
+ #nonexistent group from cache
79
+ ENV['GROUP_ID']="1234"
80
+ assert_raises(RuntimeError) do
81
+ Client.get(:source => "cache")
82
+ end
83
+
84
+ #invalid get source
85
+ assert_raises(RuntimeError) do
86
+ Client.get(:id => "5", :source => "asdf")
87
+ end
88
+
89
+ end
90
+
91
+ def test_delete
92
+
93
+ client=Client.from_xml(CLIENT_XML)
94
+ client.delete
95
+ assert_equal false, File.exists?(File.join(Client.data_dir, "#{client.id}.xml"))
96
+
97
+ end
98
+
99
+ def test_create
100
+
101
+ Connection.stubs(:post).returns(CLIENT_XML)
102
+ client=Client.create(ServerGroup.from_xml(SERVER_GROUP_XML), "local")
103
+ assert_equal "local", client.name
104
+
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'kytoon'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,253 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'test_helper'
3
+
4
+ require 'fileutils'
5
+ require 'tempfile'
6
+
7
+ module Kytoon
8
+ module Providers
9
+ module CloudServersVPC
10
+
11
+ class ServerGroupTest < Test::Unit::TestCase
12
+
13
+ def setup
14
+ @tmp_dir=TmpDir.new_tmp_dir
15
+ ServerGroup.data_dir=@tmp_dir
16
+ end
17
+
18
+ def teardown
19
+ FileUtils.rm_rf(@tmp_dir)
20
+ end
21
+
22
+ TEST_JSON_CONFIG = %{{
23
+ "name": "test",
24
+ "domain_name": "vpc",
25
+ "description": "test description",
26
+ "servers": {
27
+ "login": {
28
+ "image_id": "51",
29
+ "flavor_id": "2",
30
+ "openvpn_server": "true"
31
+ },
32
+ "client1": {
33
+ "image_id": "69",
34
+ "flavor_id": "3"
35
+ }
36
+ }
37
+ }}
38
+
39
+ def test_server_new
40
+ sg=ServerGroup.new(:name => "test", :domain_name => "vpc", :description => "zz")
41
+ assert_equal "test", sg.name
42
+ assert_equal "zz", sg.description
43
+ assert_equal "vpc", sg.domain_name
44
+ assert_equal "172.19.0.0", sg.vpn_network
45
+ assert_equal "255.255.128.0", sg.vpn_subnet
46
+ end
47
+
48
+ def test_gateway_ip
49
+ sg=ServerGroup.from_xml(SERVER_GROUP_XML)
50
+ assert_equal "184.106.205.120", sg.gateway_ip
51
+ assert_equal 1759, sg.id
52
+ assert_equal "test description", sg.description
53
+ assert_equal "dan.prince", sg.owner_name
54
+ assert_equal "172.19.0.0", sg.vpn_network
55
+ assert_equal "255.255.128.0", sg.vpn_subnet
56
+ assert_equal 2, sg.servers.size
57
+ end
58
+
59
+ #def test_vpn_gateway_name
60
+ #sg=ServerGroup.from_xml(SERVER_GROUP_XML)
61
+ #assert_equal "login1", sg.vpn_gateway_name
62
+ #end
63
+
64
+ def test_server_group_from_json_config
65
+ sg=ServerGroup.from_json(TEST_JSON_CONFIG)
66
+ assert_equal "vpc", sg.domain_name
67
+ assert_equal "test", sg.name
68
+ assert_equal "test description", sg.description
69
+ assert_equal 2, sg.servers.size
70
+ assert_equal 1, sg.ssh_public_keys.size
71
+
72
+ # validate the login server
73
+ login_server=sg.server("login")
74
+ assert_equal "51", login_server.image_id
75
+ assert_equal "2", login_server.flavor_id
76
+ assert_equal true, login_server.openvpn_server?
77
+
78
+ # validate the client1 server
79
+ client1_server=sg.server("client1")
80
+ assert_equal "69", client1_server.image_id
81
+ assert_equal "3", client1_server.flavor_id
82
+ assert_equal false, client1_server.openvpn_server?
83
+
84
+ end
85
+
86
+ def test_server_group_from_xml
87
+ sg=ServerGroup.from_xml(SERVER_GROUP_XML)
88
+ assert_equal "mydomain.net", sg.domain_name
89
+ assert_equal "test", sg.name
90
+ assert_equal "test description", sg.description
91
+ assert_equal 2, sg.servers.size
92
+ assert_equal 1759, sg.id
93
+ end
94
+
95
+ def test_server_group_to_xml
96
+ sg=ServerGroup.from_xml(SERVER_GROUP_XML)
97
+ assert_equal "mydomain.net", sg.domain_name
98
+ assert_equal "test", sg.name
99
+ assert_equal "test description", sg.description
100
+ assert_equal 2, sg.servers.size
101
+ assert_equal 1759, sg.id
102
+ xml=sg.to_xml
103
+ end
104
+
105
+ def test_print_server_group
106
+
107
+ sg=ServerGroup.from_xml(SERVER_GROUP_XML)
108
+ tmp = Tempfile.open('kytoon')
109
+ begin
110
+ $stdout = tmp
111
+ sg.pretty_print
112
+ tmp.flush
113
+ output=IO.read(tmp.path)
114
+ $stdout = STDOUT
115
+ assert output =~ /login1/
116
+ assert output =~ /test1/
117
+ assert output =~ /184.106.205.120/
118
+ ensure
119
+ $stdout = STDOUT
120
+ end
121
+
122
+ end
123
+
124
+ def test_server_names
125
+
126
+ sg=ServerGroup.from_xml(SERVER_GROUP_XML)
127
+ names=sg.server_names
128
+
129
+ assert_equal 2, names.size
130
+ assert names.include?("login1")
131
+ assert names.include?("test1")
132
+
133
+ end
134
+
135
+ def test_get
136
+
137
+ tmp_dir=TmpDir.new_tmp_dir
138
+ File.open("#{tmp_dir}/1759.xml", 'w') do |f|
139
+ f.write(SERVER_GROUP_XML)
140
+ end
141
+ ServerGroup.data_dir=tmp_dir
142
+
143
+ Connection.stubs(:get).returns(SERVER_GROUP_XML)
144
+
145
+ sg=ServerGroup.get(:source => "cache")
146
+ assert_not_nil sg
147
+ assert_equal "test", sg.name
148
+
149
+ sg=ServerGroup.get(:id => "1759", :source => "cache")
150
+ assert_not_nil sg
151
+ assert_equal "test", sg.name
152
+
153
+ #nonexistent group from cache
154
+ assert_raises(RuntimeError) do
155
+ ServerGroup.get(:id => "1234", :source => "cache")
156
+ end
157
+
158
+ #invalid get source
159
+ assert_raises(RuntimeError) do
160
+ ServerGroup.get(:id => "1759", :source => "asdf")
161
+ end
162
+
163
+ end
164
+
165
+ def test_index_from_cache
166
+
167
+ tmp_dir=TmpDir.new_tmp_dir
168
+ File.open("#{tmp_dir}/1759.xml", 'w') do |f|
169
+ f.write(SERVER_GROUP_XML)
170
+ end
171
+ ServerGroup.data_dir=tmp_dir
172
+
173
+ server_groups = ServerGroup.index
174
+
175
+ assert_equal 1, server_groups.size
176
+ assert_equal 1759, server_groups[0].id
177
+
178
+ end
179
+
180
+ def test_index_from_remote
181
+
182
+ tmp_dir=TmpDir.new_tmp_dir
183
+ File.open("#{tmp_dir}/1759.xml", 'w') do |f|
184
+ f.write(SERVER_GROUP_XML)
185
+ end
186
+ ServerGroup.data_dir=tmp_dir
187
+
188
+ Connection.stubs(:get).returns(SERVER_GROUP_XML)
189
+ server_groups = ServerGroup.index(:source => "remote")
190
+
191
+ assert_equal 1, server_groups.size
192
+ assert_equal 1759, server_groups[0].id
193
+
194
+ end
195
+
196
+ def test_create
197
+
198
+ sg=ServerGroup.from_json(TEST_JSON_CONFIG)
199
+
200
+ tmp_dir=TmpDir.new_tmp_dir
201
+ File.open("#{tmp_dir}/1759.xml", 'w') do |f|
202
+ f.write(SERVER_GROUP_XML)
203
+ end
204
+ ServerGroup.data_dir=tmp_dir
205
+
206
+ Connection.stubs(:post).returns(SERVER_GROUP_XML)
207
+ Connection.stubs(:get).returns(SERVER_GROUP_XML)
208
+ sg = ServerGroup.create(sg)
209
+ assert_not_nil sg
210
+ assert_equal "mydomain.net", sg.domain_name
211
+ assert_equal "test", sg.name
212
+ assert_equal "test description", sg.description
213
+ assert_equal 2, sg.servers.size
214
+ assert_equal 1759, sg.id
215
+
216
+ end
217
+
218
+ def test_most_recent
219
+
220
+ File.open("#{ServerGroup.data_dir}/5.xml", 'w') do |f|
221
+ f.write(SERVER_GROUP_XML)
222
+ end
223
+
224
+ sg=ServerGroup.most_recent
225
+
226
+ assert_equal "mydomain.net", sg.domain_name
227
+ assert_equal 1759, sg.id
228
+ assert_equal 2, sg.servers.size
229
+
230
+ end
231
+
232
+ def test_cache_to_disk
233
+
234
+ sg=ServerGroup.from_xml(SERVER_GROUP_XML)
235
+ assert sg.cache_to_disk
236
+ assert File.exists?(File.join(ServerGroup.data_dir, "#{sg.id}.xml"))
237
+
238
+ end
239
+
240
+ def test_delete
241
+
242
+ sg=ServerGroup.from_xml(SERVER_GROUP_XML)
243
+ Connection.stubs(:delete).returns("")
244
+ sg.delete
245
+ assert_equal false, File.exists?(File.join(ServerGroup.data_dir, "#{sg.id}.xml"))
246
+
247
+ end
248
+
249
+ end
250
+
251
+ end
252
+ end
253
+ end