openstack 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -93,11 +93,12 @@ See the class definitions for documentation on specific methods and operations.
93
93
  >> newserver.progress
94
94
  => 12
95
95
 
96
- # Create a new server and specify the keyname to be used (some provider support the Keys extension):
97
- >> server = os.create_server({:imageRef=>14075, :flavorRef=>100, :key_name=>"my_default_key", :name=>"marios_server"})
96
+ # Create a new server and specify the keyname and security_groups to be used (dependent on provider support for these API extensions):
97
+ >> server = os.create_server({:imageRef=>14075, :flavorRef=>100, :key_name=>"my_default_key", :security_groups=>["test", "default"], :name=>"marios_server"})
98
98
  => #<OpenStack::Compute::Server:0x101433f08 ....
99
99
  >> server.key_name
100
100
  => "my_default_key"
101
+ >> server.security_groups
101
102
 
102
103
  # Delete the new server
103
104
  >> newserver.delete!
@@ -143,6 +144,41 @@ See the class definitions for documentation on specific methods and operations.
143
144
  >> os.delete_keypair("test_key_imported")
144
145
  => true
145
146
 
147
+ # List all security groups:
148
+ >> os.security_groups
149
+ => { "1381" => { :tenant_id=>"12345678909876", :id=>1381, :name=>"default", :description=>"default",
150
+ :rules=> [
151
+ {:from_port=>22, :group=>{}, :ip_protocol=>"tcp", :to_port=>22,
152
+ :parent_group_id=>1381, :ip_range=>{:cidr=>"0.0.0.0/0"}, :id=>4902},
153
+ ]
154
+ },
155
+ "1234" => { ... } }
156
+
157
+ # Get a specific security group:
158
+ >> os.security_group(1381)
159
+ => { "1381" => { :tenant_id=>"12345678909876", :id=>1381, :name=>"default", :description=>"default",
160
+ :rules=> [
161
+ {:from_port=>22, :group=>{}, :ip_protocol=>"tcp", :to_port=>22,
162
+ :parent_group_id=>1381, :ip_range=>{:cidr=>"0.0.0.0/0"}, :id=>4902},
163
+ ]
164
+ }}
165
+
166
+ #Create a new security group:
167
+ >> os.create_security_group("devel_group", "all development machines")
168
+ => {"9573"=>{:rules=>[], :tenant_id=>"46871569847393", :id=>9573, :name=>"devel_group", :description=>"all development machines"}}
169
+
170
+ #Create a new security group rule - first param is id of the security group for this rule. Instead of :cidr you may specify :group_id to use another group as source:
171
+ >> os.create_security_group_rule(9567, {:ip_protocol=>"tcp", :from_port=>"123", :to_port=>"123", :cidr=>"192.168.0.1/16" })
172
+ => => {"27375"=>{:from_port=>123, :group=>{}, :ip_protocol=>"tcp", :to_port=>123, :parent_group_id=>9573, :ip_range=>{:cidr=>"192.168.0.1/16"}, :id=>27375}}
173
+
174
+ #Delete a security group rule:
175
+ >> os.delete_security_group_rule(27375)
176
+ => true
177
+
178
+ #Delete a security group:
179
+ >> os.delete_security_group(9571)
180
+ => true
181
+
146
182
  == Examples for Object-Store:
147
183
 
148
184
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.2
@@ -1,3 +1,4 @@
1
+ require 'ipaddr'
1
2
  module OpenStack
2
3
  module Compute
3
4
 
@@ -33,6 +34,34 @@ module Compute
33
34
  @version = version
34
35
  end
35
36
  end
37
+
38
+ NON_ROUTABLE_ADDRESSES = [IPAddr.new("10.0.0.0/8"), IPAddr.new("192.168.0.0/16"), IPAddr.new("172.16.0.0/12")]
39
+
40
+ def self.is_private?(address_string)
41
+ NON_ROUTABLE_ADDRESSES.each do |no_route|
42
+ return true if no_route.include?(address_string)
43
+ end
44
+ false
45
+ end
46
+
47
+ #IN: { "private"=> [{"addr"=>"10.7.206.171", "version"=>4}, {"addr"=>"15.185.160.208", "version"=>4}]}
48
+ #OUT: { "private"=> [{"addr"=>"10.7.206.171", "version"=>4}],
49
+ # "public"=> [{"addr"=>"15.185.160.208", "version"=>4}] }
50
+ def self.fix_labels(addresses_info)
51
+ addresses_info.inject({"public"=>[], "private"=>[]}) do |res, (label,address_struct_list)|
52
+ address_struct_list.each do |address_struct|
53
+ if(address_struct["version"==6])#v6 addresses are all routable...
54
+ res["public"] << address_struct
55
+ else
56
+ is_private?(address_struct["addr"])? res["private"] << address_struct : res["public"] << address_struct
57
+ end
58
+ end
59
+ res
60
+ end
61
+ end
62
+
63
+
64
+
36
65
  end
37
66
 
38
67
  end
@@ -4,8 +4,10 @@ module Compute
4
4
  class Connection
5
5
 
6
6
  attr_accessor :connection
7
+ attr_accessor :extensions
7
8
 
8
9
  def initialize(connection)
10
+ @extensions = nil
9
11
  @connection = connection
10
12
  OpenStack::Authentication.init(@connection)
11
13
  end
@@ -63,14 +65,19 @@ module Compute
63
65
  path = OpenStack.paginate(options).empty? ? "#{@connection.service_path}/servers/detail" : "#{@connection.service_path}/servers/detail?#{OpenStack.paginate(options)}"
64
66
  response = @connection.csreq("GET",@connection.service_host,path,@connection.service_port,@connection.service_scheme)
65
67
  OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
66
- OpenStack.symbolize_keys(JSON.parse(response.body)["servers"])
68
+ json_server_list = JSON.parse(response.body)["servers"]
69
+ json_server_list.each do |server|
70
+ server["addresses"] = OpenStack::Compute::Address.fix_labels(server["addresses"])
71
+ end
72
+ OpenStack.symbolize_keys(json_server_list)
67
73
  end
68
74
  alias :servers_detail :list_servers_detail
69
75
 
70
76
  # Creates a new server instance on OpenStack Compute
71
77
  #
72
78
  # The argument is a hash of options. The keys :name, :flavorRef,
73
- # and :imageRef are required; :metadata and :personality are optional.
79
+ # and :imageRef are required; :metadata, :security_groups,
80
+ # :key_name and :personality are optional.
74
81
  #
75
82
  # :flavorRef and :imageRef are href strings identifying a particular
76
83
  # server flavor and image to use when building the server. The :imageRef
@@ -94,7 +101,9 @@ module Compute
94
101
  # :imageRef => '3',
95
102
  # :flavorRef => '1',
96
103
  # :metadata => {'Racker' => 'Fanatical'},
97
- # :personality => {'/home/bob/wedding.jpg' => '/root/wedding.jpg'})
104
+ # :personality => {'/home/bob/wedding.jpg' => '/root/wedding.jpg'},
105
+ # :key_name => "mykey",
106
+ # :security_groups => [ "devel", "test"])
98
107
  # => #<OpenStack::Compute::Server:0x101229eb0 ...>
99
108
  # >> server.name
100
109
  # => "NewServer"
@@ -105,6 +114,7 @@ module Compute
105
114
  def create_server(options)
106
115
  raise OpenStack::Exception::MissingArgument, "Server name, flavorRef, and imageRef, must be supplied" unless (options[:name] && options[:flavorRef] && options[:imageRef])
107
116
  options[:personality] = Personalities.get_personality(options[:personality])
117
+ options[:security_groups] = (options[:security_groups] || []).inject([]){|res, c| res << {"name"=>c} ;res}
108
118
  data = JSON.generate(:server => options)
109
119
  response = @connection.csreq("POST",@connection.service_host,"#{@connection.service_path}/servers",@connection.service_port,@connection.service_scheme,{'content-type' => 'application/json'},data)
110
120
  OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
@@ -228,10 +238,13 @@ module Compute
228
238
  # }
229
239
  #
230
240
  def api_extensions
231
- response = @connection.req("GET", "/extensions")
232
- OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
233
- res = OpenStack.symbolize_keys(JSON.parse(response.body))
234
- res[:extensions].inject({}){|result, c| result[c[:alias].to_sym] = c ; result}
241
+ if @extensions.nil?
242
+ response = @connection.req("GET", "/extensions")
243
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
244
+ res = OpenStack.symbolize_keys(JSON.parse(response.body))
245
+ @extensions = res[:extensions].inject({}){|result, c| result[c[:alias].to_sym] = c ; result}
246
+ end
247
+ @extensions
235
248
  end
236
249
 
237
250
  # Retrieve a list of key pairs associated with the current authenticated account
@@ -313,6 +326,67 @@ module Compute
313
326
  true
314
327
  end
315
328
 
329
+ #Security Groups:
330
+ #Returns a hash with the security group IDs as keys:
331
+ #=> { "1381" => { :tenant_id=>"12345678909876", :id=>1381, :name=>"default", :description=>"default",
332
+ # :rules=> [
333
+ # {:from_port=>22, :group=>{}, :ip_protocol=>"tcp", :to_port=>22,
334
+ # :parent_group_id=>1381, :ip_range=>{:cidr=>"0.0.0.0/0"}, :id=>4902},
335
+ # {:from_port=>80, :group=>{}, :ip_protocol=>"tcp", :to_port=>80,
336
+ # :parent_group_id=>1381, :ip_range=>{:cidr=>"0.0.0.0/0"}, :id=>4903},
337
+ # {:from_port=>443, :group=>{}, :ip_protocol=>"tcp", :to_port=>443,
338
+ # :parent_group_id=>1381, :ip_range=>{:cidr=>"0.0.0.0/0"}, :id=>4904},
339
+ # {:from_port=>-1, :group=>{}, :ip_protocol=>"icmp", :to_port=>-1,
340
+ # :parent_group_id=>1381, :ip_range=>{:cidr=>"0.0.0.0/0"}, :id=>4905}],
341
+ # ]
342
+ # },
343
+ # "1234" => { ... } }
344
+ #
345
+ def security_groups
346
+ raise OpenStack::Exception::NotImplemented.new("os-security-groups not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-security-groups"] or api_extensions[:security_groups]
347
+ response = @connection.req("GET", "/os-security-groups")
348
+ res = OpenStack.symbolize_keys(JSON.parse(response.body))
349
+ res[:security_groups].inject({}){|result, c| result[c[:id].to_s] = c ; result }
350
+ end
351
+
352
+ def security_group(id)
353
+ raise OpenStack::Exception::NotImplemented.new("os-security-groups not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-security-groups"] or api_extensions[:security_groups]
354
+ response = @connection.req("GET", "/os-security-groups/#{id}")
355
+ res = OpenStack.symbolize_keys(JSON.parse(response.body))
356
+ {res[:security_group][:id].to_s => res[:security_group]}
357
+ end
358
+
359
+ def create_security_group(name, description)
360
+ raise OpenStack::Exception::NotImplemented.new("os-security-groups not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-security-groups"] or api_extensions[:security_groups]
361
+ data = JSON.generate(:security_group => { "name" => name, "description" => description})
362
+ response = @connection.req("POST", "/os-security-groups", {:data => data})
363
+ res = OpenStack.symbolize_keys(JSON.parse(response.body))
364
+ {res[:security_group][:id].to_s => res[:security_group]}
365
+ end
366
+
367
+ def delete_security_group(id)
368
+ raise OpenStack::Exception::NotImplemented.new("os-security-groups not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-security-groups"] or api_extensions[:security_groups]
369
+ response = @connection.req("DELETE", "/os-security-groups/#{id}")
370
+ true
371
+ end
372
+
373
+ #params: { :ip_protocol=>"tcp", :from_port=>"123", :to_port=>"123", :cidr=>"192.168.0.1/16", :group_id:="123" }
374
+ #observed behaviour against Openstack@HP cloud - can specify either cidr OR group_id as source, but not both
375
+ #if both specified, the group is used and the cidr ignored.
376
+ def create_security_group_rule(security_group_id, params)
377
+ raise OpenStack::Exception::NotImplemented.new("os-security-groups not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-security-groups"] or api_extensions[:security_groups]
378
+ params.merge!({:parent_group_id=>security_group_id.to_s})
379
+ data = JSON.generate(:security_group_rule => params)
380
+ response = @connection.req("POST", "/os-security-group-rules", {:data => data})
381
+ res = OpenStack.symbolize_keys(JSON.parse(response.body))
382
+ {res[:security_group_rule][:id].to_s => res[:security_group_rule]}
383
+ end
384
+
385
+ def delete_security_group_rule(id)
386
+ raise OpenStack::Exception::NotImplemented.new("os-security-groups not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-security-groups"] or api_extensions[:security_groups]
387
+ response = @connection.req("DELETE", "/os-security-group-rules/#{id}")
388
+ true
389
+ end
316
390
  end
317
391
  end
318
392
  end
@@ -17,6 +17,7 @@ module Compute
17
17
  attr_reader :metadata
18
18
  attr_accessor :adminPass
19
19
  attr_reader :key_name
20
+ attr_reader :security_groups
20
21
 
21
22
  # This class is the representation of a single Server object. The constructor finds the server identified by the specified
22
23
  # ID number, accesses the API via the populate method to get information about that server, and returns the object.
@@ -53,7 +54,7 @@ module Compute
53
54
  OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
54
55
  data = JSON.parse(response.body)["server"]
55
56
  end
56
- @id = data["id"]
57
+ @id = data["uuid"]
57
58
  @name = data["name"]
58
59
  @status = data["status"]
59
60
  @progress = data["progress"]
@@ -63,6 +64,7 @@ module Compute
63
64
  @image = data["image"]
64
65
  @flavor = data["flavor"]
65
66
  @key_name = data["key_name"] # if provider uses the keys API extension for accessing servers
67
+ @security_groups = data["security_groups"].inject([]){|res, c| res << c["id"] ; res}
66
68
  true
67
69
  end
68
70
  alias :refresh :populate
@@ -234,6 +236,7 @@ module Compute
234
236
  end
235
237
 
236
238
  def get_addresses(address_info)
239
+ address_info = OpenStack::Compute::Address.fix_labels(address_info)
237
240
  address_list = OpenStack::Compute::AddressList.new
238
241
  address_info.each do |label, addr|
239
242
  addr.each do |address|
metadata CHANGED
@@ -1,48 +1,42 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: openstack
3
- version: !ruby/object:Gem::Version
4
- hash: 21
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 0
9
- - 1
10
- version: 1.0.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Dan Prince
14
9
  - Marios Andreou
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2012-06-22 00:00:00 Z
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
13
+ date: 2012-08-24 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
22
16
  name: json
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
25
18
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
33
23
  type: :runtime
34
- version_requirements: *id001
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
35
31
  description: API Binding for OpenStack
36
- email:
32
+ email:
37
33
  - dprince@redhat.com
38
34
  - marios@redhat.com
39
35
  executables: []
40
-
41
36
  extensions: []
42
-
43
- extra_rdoc_files:
37
+ extra_rdoc_files:
44
38
  - README.rdoc
45
- files:
39
+ files:
46
40
  - COPYING
47
41
  - README.rdoc
48
42
  - VERSION
@@ -60,37 +54,27 @@ files:
60
54
  - lib/openstack/swift/storage_object.rb
61
55
  homepage: https://github.com/ruby-openstack/ruby-openstack
62
56
  licenses: []
63
-
64
57
  post_install_message:
65
58
  rdoc_options: []
66
-
67
- require_paths:
59
+ require_paths:
68
60
  - lib
69
- required_ruby_version: !ruby/object:Gem::Requirement
61
+ required_ruby_version: !ruby/object:Gem::Requirement
70
62
  none: false
71
- requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- hash: 3
75
- segments:
76
- - 0
77
- version: "0"
78
- required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
68
  none: false
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- hash: 3
84
- segments:
85
- - 0
86
- version: "0"
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
87
73
  requirements: []
88
-
89
74
  rubyforge_project:
90
- rubygems_version: 1.7.2
75
+ rubygems_version: 1.8.24
91
76
  signing_key:
92
77
  specification_version: 3
93
78
  summary: OpenStack Ruby API
94
79
  test_files: []
95
-
96
- has_rdoc: false
80
+ has_rdoc: