openstack 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +7 -0
- data/README.rdoc +189 -0
- data/VERSION +1 -0
- data/lib/openstack.rb +107 -0
- data/lib/openstack/compute/address.rb +39 -0
- data/lib/openstack/compute/connection.rb +207 -0
- data/lib/openstack/compute/flavor.rb +35 -0
- data/lib/openstack/compute/image.rb +73 -0
- data/lib/openstack/compute/metadata.rb +116 -0
- data/lib/openstack/compute/personalities.rb +23 -0
- data/lib/openstack/compute/server.rb +249 -0
- data/lib/openstack/connection.rb +462 -0
- data/lib/openstack/swift/connection.rb +185 -0
- data/lib/openstack/swift/container.rb +214 -0
- data/lib/openstack/swift/storage_object.rb +311 -0
- metadata +96 -0
data/COPYING
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Unless otherwise noted, all files are released under the MIT license, exceptions contain licensing information in them.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
= Ruby OpenStack
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
Ruby Openstack Compute and Object-Store bindings for the v1.0 OSAPI.
|
6
|
+
|
7
|
+
Currently supports both v1.0 and v2.0 (keystone) auth.
|
8
|
+
|
9
|
+
Use OpenStack::Connection.create to get a handle to an OpenStack service - set the :service_type parameter to either 'compute' or 'object-store' (defaults to 'compute')
|
10
|
+
|
11
|
+
== Examples
|
12
|
+
|
13
|
+
== For Compute:
|
14
|
+
|
15
|
+
See the class definitions for documentation on specific methods and operations.
|
16
|
+
|
17
|
+
require 'openstack'
|
18
|
+
|
19
|
+
os = OpenStack::Connection.create(:username => USERNAME, :api_key => API_KEY, :authtenant => TENANT, :auth_url => API_URL, :service_type => "compute")
|
20
|
+
|
21
|
+
# Get a listing of all current servers
|
22
|
+
>> os.servers
|
23
|
+
=> [{:name=>"Server1", :id=>110917}]
|
24
|
+
|
25
|
+
# Access a specific server
|
26
|
+
>> server = os.server(110917)
|
27
|
+
>> server.name
|
28
|
+
=> "Server1"
|
29
|
+
|
30
|
+
# See what type of server this is
|
31
|
+
>> server.flavor.name
|
32
|
+
=> "256 server"
|
33
|
+
>> server.image.name
|
34
|
+
=> "Ubuntu 8.04.2 LTS (hardy)"
|
35
|
+
|
36
|
+
# Soft-reboot the server
|
37
|
+
>> server.reboot
|
38
|
+
=> true
|
39
|
+
|
40
|
+
# Create a new 512MB CentOS 5.2 server. The root password is returned in the adminPass method.
|
41
|
+
>> image = os.get_image(8)
|
42
|
+
=> #<OpenStack::Compute::Image:0x1014a8060 ...>, status"ACTIVE"
|
43
|
+
>> image.name
|
44
|
+
=> "CentOS 5.2"
|
45
|
+
>> flavor = os.get_flavor(2)
|
46
|
+
=> #<OpenStack::Compute::Flavor:0x101469130 @disk=20, @name="512 server", @id=2, @ram=512>
|
47
|
+
>> flavor.name
|
48
|
+
=> "512 server"
|
49
|
+
>> newserver = os.create_server(:name => "New Server", :imageRef => image.id, :flavorRef => flavor.id)
|
50
|
+
=> #<OpenStack::Compute::Server:0x101433f08 ....
|
51
|
+
>> newserver.status
|
52
|
+
=> "BUILD"
|
53
|
+
>> newserver.progress
|
54
|
+
=> 0
|
55
|
+
>> newserver.adminPass
|
56
|
+
=> "NewServerMbhzUnO"
|
57
|
+
>> newserver.refresh
|
58
|
+
=> true
|
59
|
+
>> newserver.progress
|
60
|
+
=> 12
|
61
|
+
|
62
|
+
# Delete the new server
|
63
|
+
>> newserver.delete!
|
64
|
+
=> true
|
65
|
+
|
66
|
+
== Examples for Object-Store:
|
67
|
+
|
68
|
+
|
69
|
+
os = OpenStack::Connection.create(:username => USERNAME, :api_key => API_KEY, :authtenant => TENANT, :auth_url => API_URL, :service_type => "object-store")
|
70
|
+
|
71
|
+
# Get info on container count and bytes:
|
72
|
+
>> os.get_info
|
73
|
+
=> {:count=>2, :bytes=>495041}
|
74
|
+
|
75
|
+
# Get list of containers under this account:
|
76
|
+
>> os.containers
|
77
|
+
=> ["another_containerfoo", "marios_test_container"]
|
78
|
+
|
79
|
+
# Get details of containers under this account:
|
80
|
+
>> os.containers_detail
|
81
|
+
=>=> {"another_containerfoo"=>{:count=>"3", :bytes=>"1994"}, "marios_test_container"=>{:count=>"2", :bytes=>"493047"}}
|
82
|
+
|
83
|
+
# Check if a container exists
|
84
|
+
>> os.container_exists?("no_such_thing")
|
85
|
+
=> false
|
86
|
+
|
87
|
+
# Create new container
|
88
|
+
>> os.create_container("foo")
|
89
|
+
=> => #<OpenStack::Swift::Container:0xb7275c38 ...... (rest of OpenStack::Swift::Container object)
|
90
|
+
|
91
|
+
# Delete container
|
92
|
+
>> os.delete_container("foo")
|
93
|
+
=> true
|
94
|
+
|
95
|
+
# Get a container (OpenStack::Swift::Container object):
|
96
|
+
>> cont = os.container("foo")
|
97
|
+
=> #<OpenStack::Swift::Container:0xb7262124 ...... (rest of OpenStack::Swift::Container object)
|
98
|
+
|
99
|
+
# Retrieve container metadata:
|
100
|
+
>> cont.container_metadata
|
101
|
+
=>{:count=>"2", :bytes=>"493047", :metadata=>{"foo"=>"bar", "author"=>"foobar", "jj"=>"foobar", "date"=>"today", "owner"=>"foo"}}
|
102
|
+
|
103
|
+
# Retrieve user defined metadata:
|
104
|
+
>> cont.metadata
|
105
|
+
=> {"foo"=>"bar", "author"=>"foobar", "jj"=>"foobar", "date"=>"today", "owner"=>"foo"}
|
106
|
+
|
107
|
+
# Set user defined metadata:
|
108
|
+
>> cont.set_metadata({"X-Container-Meta-Author"=> "msa", "version"=>"1.2", :date=>"today"})
|
109
|
+
=> true
|
110
|
+
|
111
|
+
# Get list of objects:
|
112
|
+
>> cont.objects
|
113
|
+
=> ["fosdem2012.pdf", "moved_object"]
|
114
|
+
|
115
|
+
# Get list of objects with details:
|
116
|
+
>> cont.objects_detail
|
117
|
+
=> {"fosdem2012.pdf"=>{:bytes=>"493009", :content_type=>"application/json", :hash=>"494e444f92a8082dabac80a74cdf2c3b", :last_modified=>"2012-04-26T09:22:51.611230"}, "moved_object"=>{:bytes=>"38", :content_type=>"application/json", :hash=>"a7942f97fe6bd34920a4f61fe5e604a5", :last_modified=>"2012-04-26T09:35:33.839920"}}
|
118
|
+
|
119
|
+
# Check if container is empty:
|
120
|
+
>> cont.empty?
|
121
|
+
=> false
|
122
|
+
|
123
|
+
# Check if object exists:
|
124
|
+
>> cont.object_exists?("foo")
|
125
|
+
=> false
|
126
|
+
|
127
|
+
# Create new object
|
128
|
+
>> new_obj = cont.create_object("foo", {:metadata=>{"herpy"=>"derp"}, :content_type=>"text/plain"}, "this is the data") [can also supply File.open(/path/to/file) and the data]
|
129
|
+
=> #<OpenStack::Swift::StorageObject:0xb72fdac0 ... etc
|
130
|
+
|
131
|
+
# Delete object
|
132
|
+
>> cont.delete_object("foo")
|
133
|
+
=> true
|
134
|
+
|
135
|
+
# Get handle to an OpenStack::Swift::StorageObject Object
|
136
|
+
>> obj = cont.object("foo")
|
137
|
+
=> #<OpenStack::Swift::StorageObject:0xb72fdac0 ... etc
|
138
|
+
|
139
|
+
# Get object metadata
|
140
|
+
>> obj.object_metadata
|
141
|
+
=>
|
142
|
+
|
143
|
+
# Get user defined metadata pairs
|
144
|
+
>> obj.metadata
|
145
|
+
=>
|
146
|
+
|
147
|
+
# Get data (non streaming - returned as a String)
|
148
|
+
>> obj.data
|
149
|
+
=> "This is the text stored in the file"
|
150
|
+
|
151
|
+
# Get data (streaming - requires a block)
|
152
|
+
>> data = ""; object.data_stream do |chunk| data += chunk end
|
153
|
+
=> #<Net::HTTPOK 200 OK readbody=true>
|
154
|
+
>> data
|
155
|
+
=> "This is the text stored in the file"
|
156
|
+
|
157
|
+
# Set user defined metadata
|
158
|
+
>> obj.set_metadata({:foo=>"bar", "X-Object-Meta-herpa"=>"derp", "author"=>"me"})
|
159
|
+
=> true
|
160
|
+
|
161
|
+
# (Over)Write object data
|
162
|
+
>> object.write("This is new data")
|
163
|
+
=> true
|
164
|
+
>> object.data
|
165
|
+
=> "This is new data"
|
166
|
+
|
167
|
+
# Copy object:
|
168
|
+
>>copied = obj.copy('copied_object', "destination_container", {:content_type=>"text/plain", :metadata=>{:herp=>"derp", "X-Object-Meta-foo"=>"bar} } )
|
169
|
+
=> #<OpenStack::Swift::StorageObject:0xb728974c ..... etc
|
170
|
+
|
171
|
+
# Move object: (copy and then delete original):
|
172
|
+
>> moved = obj.move('moved_object', "destination_container", {:content_type=>"text/plain", :metadata=>{:herp=>"derp", "X-Object-Meta-foo"=>"bar"} } )
|
173
|
+
=> #<OpenStack::Swift::StorageObject:0xb7266bd4 ...
|
174
|
+
>> moved.metadata
|
175
|
+
=> {"foo"=>"bar", "herp"=>"derp", "herpy"=>"derp"}
|
176
|
+
>> obj.metadata
|
177
|
+
=> OpenStack::Exception::ItemNotFound: The resource could not be found
|
178
|
+
|
179
|
+
|
180
|
+
== Authors
|
181
|
+
|
182
|
+
By Dan Prince <dprince@redhat.com>, Naveed Massjouni <naveedm9@gmail.com>, Marios Andreou <marios@redhat.com>
|
183
|
+
|
184
|
+
Initial code checkin on May 23rd 2012 - code refactored from and based on the Rackspace Cloud Servers gem
|
185
|
+
(https://github.com/rackspace/ruby-openstack-compute) and Rackspace Cloud Files gem (https://github.com/rackspace/ruby-cloudfiles).
|
186
|
+
|
187
|
+
== License
|
188
|
+
|
189
|
+
See COPYING for license information.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/lib/openstack.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# == Ruby OpenStack API
|
4
|
+
#
|
5
|
+
# See COPYING for license information.
|
6
|
+
# ----
|
7
|
+
#
|
8
|
+
# === Documentation & Examples
|
9
|
+
# To begin reviewing the available methods and examples, view the README.rdoc file
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
# os = OpenStack::Connection.create({:username => "herp@derp.com", :api_key=>"password",
|
13
|
+
# :auth_url => "https://region-a.geo-1.identity.cloudsvc.com:35357/v2.0/",
|
14
|
+
# :authtenant=>"herp@derp.com-default-tenant", :service_type=>"object-store")
|
15
|
+
#
|
16
|
+
# will return a handle to the object-storage service swift. Alternatively, passing
|
17
|
+
# :service_type=>"compute" will return a handle to the compute service nova.
|
18
|
+
|
19
|
+
module OpenStack
|
20
|
+
|
21
|
+
VERSION = IO.read(File.dirname(__FILE__) + '/../VERSION')
|
22
|
+
require 'net/http'
|
23
|
+
require 'net/https'
|
24
|
+
require 'uri'
|
25
|
+
require 'rubygems'
|
26
|
+
require 'json'
|
27
|
+
require 'date'
|
28
|
+
|
29
|
+
unless "".respond_to? :each_char
|
30
|
+
require "jcode"
|
31
|
+
$KCODE = 'u'
|
32
|
+
end
|
33
|
+
|
34
|
+
$:.unshift(File.dirname(__FILE__))
|
35
|
+
require 'openstack/connection'
|
36
|
+
require 'openstack/compute/connection'
|
37
|
+
require 'openstack/compute/server'
|
38
|
+
require 'openstack/compute/image'
|
39
|
+
require 'openstack/compute/flavor'
|
40
|
+
require 'openstack/compute/address'
|
41
|
+
require 'openstack/compute/personalities'
|
42
|
+
require 'openstack/swift/connection'
|
43
|
+
require 'openstack/swift/container'
|
44
|
+
require 'openstack/swift/storage_object'
|
45
|
+
|
46
|
+
# Constants that set limits on server creation
|
47
|
+
MAX_PERSONALITY_ITEMS = 5
|
48
|
+
MAX_PERSONALITY_FILE_SIZE = 10240
|
49
|
+
MAX_SERVER_PATH_LENGTH = 255
|
50
|
+
|
51
|
+
# Helper method to recursively symbolize hash keys.
|
52
|
+
def self.symbolize_keys(obj)
|
53
|
+
case obj
|
54
|
+
when Array
|
55
|
+
obj.inject([]){|res, val|
|
56
|
+
res << case val
|
57
|
+
when Hash, Array
|
58
|
+
symbolize_keys(val)
|
59
|
+
else
|
60
|
+
val
|
61
|
+
end
|
62
|
+
res
|
63
|
+
}
|
64
|
+
when Hash
|
65
|
+
obj.inject({}){|res, (key, val)|
|
66
|
+
nkey = case key
|
67
|
+
when String
|
68
|
+
key.to_sym
|
69
|
+
else
|
70
|
+
key
|
71
|
+
end
|
72
|
+
nval = case val
|
73
|
+
when Hash, Array
|
74
|
+
symbolize_keys(val)
|
75
|
+
else
|
76
|
+
val
|
77
|
+
end
|
78
|
+
res[nkey] = nval
|
79
|
+
res
|
80
|
+
}
|
81
|
+
else
|
82
|
+
obj
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.paginate(options = {})
|
87
|
+
path_args = []
|
88
|
+
path_args.push(URI.encode("limit=#{options[:limit]}")) if options[:limit]
|
89
|
+
path_args.push(URI.encode("offset=#{options[:offset]}")) if options[:offset]
|
90
|
+
path_args.join("&")
|
91
|
+
end
|
92
|
+
|
93
|
+
# e.g. keys = [:limit, :marker]
|
94
|
+
# params = {:limit=>2, :marker="marios", :prefix=>"/"}
|
95
|
+
# you want url = /container_name?limit=2&marker=marios
|
96
|
+
def self.get_query_params(params, keys, url="")
|
97
|
+
set_keys = params.inject([]){|res, (k,v)| res << k if keys.include?(k) and not v.nil?; res }
|
98
|
+
return url if set_keys.empty?
|
99
|
+
url = "#{url}?#{set_keys[0]}=#{params[set_keys[0]]}"
|
100
|
+
set_keys.slice!(0)
|
101
|
+
set_keys.each do |k|
|
102
|
+
url = "#{url}&#{k}=#{params[set_keys[0]]}"
|
103
|
+
end
|
104
|
+
url
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module OpenStack
|
2
|
+
module Compute
|
3
|
+
|
4
|
+
class AddressList < Array
|
5
|
+
def [](index)
|
6
|
+
addresses = Array.new
|
7
|
+
if index.class == Symbol then
|
8
|
+
self.each do |address|
|
9
|
+
if address.label == index.to_s then
|
10
|
+
addresses << address
|
11
|
+
end
|
12
|
+
end
|
13
|
+
addresses
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Address
|
21
|
+
|
22
|
+
attr_reader :address
|
23
|
+
attr_reader :label
|
24
|
+
attr_reader :version
|
25
|
+
|
26
|
+
def initialize(label, address, version = 4)
|
27
|
+
@label = label
|
28
|
+
if address.class == Hash then
|
29
|
+
@address = address["addr"]
|
30
|
+
@version = address["version"]
|
31
|
+
else
|
32
|
+
@address = address
|
33
|
+
@version = version
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
module OpenStack
|
2
|
+
module Compute
|
3
|
+
|
4
|
+
class Connection
|
5
|
+
|
6
|
+
attr_accessor :connection
|
7
|
+
|
8
|
+
def initialize(connection)
|
9
|
+
@connection = connection
|
10
|
+
OpenStack::Authentication.init(@connection)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns true if the authentication was successful and returns false otherwise.
|
14
|
+
#
|
15
|
+
# cs.authok?
|
16
|
+
# => true
|
17
|
+
def authok?
|
18
|
+
@connection.authok
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the OpenStack::Compute::Server object identified by the given id.
|
22
|
+
#
|
23
|
+
# >> server = cs.get_server(110917)
|
24
|
+
# => #<OpenStack::Compute::Server:0x101407ae8 ...>
|
25
|
+
# >> server.name
|
26
|
+
# => "MyServer"
|
27
|
+
def get_server(id)
|
28
|
+
OpenStack::Compute::Server.new(self,id)
|
29
|
+
end
|
30
|
+
alias :server :get_server
|
31
|
+
|
32
|
+
# Returns an array of hashes, one for each server that exists under this account. The hash keys are :name and :id.
|
33
|
+
#
|
34
|
+
# You can also provide :limit and :offset parameters to handle pagination.
|
35
|
+
#
|
36
|
+
# >> cs.list_servers
|
37
|
+
# => [{:name=>"MyServer", :id=>110917}]
|
38
|
+
#
|
39
|
+
# >> cs.list_servers(:limit => 2, :offset => 3)
|
40
|
+
# => [{:name=>"demo-standingcloud-lts", :id=>168867},
|
41
|
+
# {:name=>"demo-aicache1", :id=>187853}]
|
42
|
+
def list_servers(options = {})
|
43
|
+
anti_cache_param="cacheid=#{Time.now.to_i}"
|
44
|
+
path = OpenStack.paginate(options).empty? ? "#{@connection.service_path}/servers?#{anti_cache_param}" : "#{@connection.service_path}/servers?#{OpenStack.paginate(options)}&#{anti_cache_param}"
|
45
|
+
response = @connection.csreq("GET",@connection.service_host,path,@connection.service_port,@connection.service_scheme)
|
46
|
+
OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
47
|
+
OpenStack.symbolize_keys(JSON.parse(response.body)["servers"])
|
48
|
+
end
|
49
|
+
alias :servers :list_servers
|
50
|
+
|
51
|
+
# Returns an array of hashes with more details about each server that exists under this account. Additional information
|
52
|
+
# includes public and private IP addresses, status, hostID, and more. All hash keys are symbols except for the metadata
|
53
|
+
# hash, which are verbatim strings.
|
54
|
+
#
|
55
|
+
# You can also provide :limit and :offset parameters to handle pagination.
|
56
|
+
# >> cs.list_servers_detail
|
57
|
+
# => [{:name=>"MyServer", :addresses=>{:public=>["67.23.42.37"], :private=>["10.176.241.237"]}, :metadata=>{"MyData" => "Valid"}, :imageRef=>10, :progress=>100, :hostId=>"36143b12e9e48998c2aef79b50e144d2", :flavorRef=>1, :id=>110917, :status=>"ACTIVE"}]
|
58
|
+
#
|
59
|
+
# >> cs.list_servers_detail(:limit => 2, :offset => 3)
|
60
|
+
# => [{:status=>"ACTIVE", :imageRef=>10, :progress=>100, :metadata=>{}, :addresses=>{:public=>["x.x.x.x"], :private=>["x.x.x.x"]}, :name=>"demo-standingcloud-lts", :id=>168867, :flavorRef=>1, :hostId=>"xxxxxx"},
|
61
|
+
# {:status=>"ACTIVE", :imageRef=>8, :progress=>100, :metadata=>{}, :addresses=>{:public=>["x.x.x.x"], :private=>["x.x.x.x"]}, :name=>"demo-aicache1", :id=>187853, :flavorRef=>3, :hostId=>"xxxxxx"}]
|
62
|
+
def list_servers_detail(options = {})
|
63
|
+
path = OpenStack.paginate(options).empty? ? "#{@connection.service_path}/servers/detail" : "#{@connection.service_path}/servers/detail?#{OpenStack.paginate(options)}"
|
64
|
+
response = @connection.csreq("GET",@connection.service_host,path,@connection.service_port,@connection.service_scheme)
|
65
|
+
OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
66
|
+
OpenStack.symbolize_keys(JSON.parse(response.body)["servers"])
|
67
|
+
end
|
68
|
+
alias :servers_detail :list_servers_detail
|
69
|
+
|
70
|
+
# Creates a new server instance on OpenStack Compute
|
71
|
+
#
|
72
|
+
# The argument is a hash of options. The keys :name, :flavorRef,
|
73
|
+
# and :imageRef are required; :metadata and :personality are optional.
|
74
|
+
#
|
75
|
+
# :flavorRef and :imageRef are href strings identifying a particular
|
76
|
+
# server flavor and image to use when building the server. The :imageRef
|
77
|
+
# can either be a stock image, or one of your own created with the
|
78
|
+
# server.create_image method.
|
79
|
+
#
|
80
|
+
# The :metadata argument should be a hash of key/value pairs. This
|
81
|
+
# metadata will be applied to the server at the OpenStack Compute API level.
|
82
|
+
#
|
83
|
+
# The "Personality" option allows you to include up to five files, # of
|
84
|
+
# 10Kb or less in size, that will be placed on the created server.
|
85
|
+
# For :personality, pass a hash of the form {'local_path' => 'server_path'}.
|
86
|
+
# The file located at local_path will be base64-encoded and placed at the
|
87
|
+
# location identified by server_path on the new server.
|
88
|
+
#
|
89
|
+
# Returns a OpenStack::Compute::Server object. The root password is
|
90
|
+
# available in the adminPass instance method.
|
91
|
+
#
|
92
|
+
# >> server = cs.create_server(
|
93
|
+
# :name => 'NewServer',
|
94
|
+
# :imageRef => '3',
|
95
|
+
# :flavorRef => '1',
|
96
|
+
# :metadata => {'Racker' => 'Fanatical'},
|
97
|
+
# :personality => {'/home/bob/wedding.jpg' => '/root/wedding.jpg'})
|
98
|
+
# => #<OpenStack::Compute::Server:0x101229eb0 ...>
|
99
|
+
# >> server.name
|
100
|
+
# => "NewServer"
|
101
|
+
# >> server.status
|
102
|
+
# => "BUILD"
|
103
|
+
# >> server.adminPass
|
104
|
+
# => "NewServerSHMGpvI"
|
105
|
+
def create_server(options)
|
106
|
+
raise OpenStack::Exception::MissingArgument, "Server name, flavorRef, and imageRef, must be supplied" unless (options[:name] && options[:flavorRef] && options[:imageRef])
|
107
|
+
options[:personality] = Personalities.get_personality(options[:personality])
|
108
|
+
data = JSON.generate(:server => options)
|
109
|
+
response = @connection.csreq("POST",@connection.service_host,"#{@connection.service_path}/servers",@connection.service_port,@connection.service_scheme,{'content-type' => 'application/json'},data)
|
110
|
+
OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
111
|
+
server_info = JSON.parse(response.body)['server']
|
112
|
+
server = OpenStack::Compute::Server.new(self,server_info['id'])
|
113
|
+
server.adminPass = server_info['adminPass']
|
114
|
+
return server
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns an array of hashes listing available server images that you have access too,
|
118
|
+
# including stock OpenStack Compute images and any that you have created. The "id" key
|
119
|
+
# in the hash can be used where imageRef is required. You can also provide :limit and
|
120
|
+
# :offset parameters to handle pagination.
|
121
|
+
#
|
122
|
+
# >> cs.list_images
|
123
|
+
# => [{:name=>"CentOS 5.2", :id=>2, :updated=>"2009-07-20T09:16:57-05:00", :status=>"ACTIVE", :created=>"2009-07-20T09:16:57-05:00"},
|
124
|
+
# {:name=>"Gentoo 2008.0", :id=>3, :updated=>"2009-07-20T09:16:57-05:00", :status=>"ACTIVE", :created=>"2009-07-20T09:16:57-05:00"},...
|
125
|
+
#
|
126
|
+
# >> cs.list_images(:limit => 3, :offset => 2)
|
127
|
+
# => [{:status=>"ACTIVE", :name=>"Fedora 11 (Leonidas)", :updated=>"2009-12-08T13:50:45-06:00", :id=>13},
|
128
|
+
# {:status=>"ACTIVE", :name=>"CentOS 5.3", :updated=>"2009-08-26T14:59:52-05:00", :id=>7},
|
129
|
+
# {:status=>"ACTIVE", :name=>"CentOS 5.4", :updated=>"2009-12-16T01:02:17-06:00", :id=>187811}]
|
130
|
+
def list_images(options = {})
|
131
|
+
path = OpenStack.paginate(options).empty? ? "#{@connection.service_path}/images/detail" : "#{@connection.service_path}/images/detail?#{OpenStack.paginate(options)}"
|
132
|
+
response = @connection.csreq("GET",@connection.service_host,path,@connection.service_port,@connection.service_scheme)
|
133
|
+
OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
134
|
+
OpenStack.symbolize_keys(JSON.parse(response.body)['images'])
|
135
|
+
end
|
136
|
+
alias :images :list_images
|
137
|
+
|
138
|
+
# Returns a OpenStack::Compute::Image object for the image identified by the provided id.
|
139
|
+
#
|
140
|
+
# >> image = cs.get_image(8)
|
141
|
+
# => #<OpenStack::Compute::Image:0x101659698 ...>
|
142
|
+
def get_image(id)
|
143
|
+
OpenStack::Compute::Image.new(self,id)
|
144
|
+
end
|
145
|
+
alias :image :get_image
|
146
|
+
|
147
|
+
# Returns an array of hashes listing all available server flavors. The :id key in the hash can be used when flavorRef is required.
|
148
|
+
#
|
149
|
+
# You can also provide :limit and :offset parameters to handle pagination.
|
150
|
+
#
|
151
|
+
# >> cs.list_flavors
|
152
|
+
# => [{:name=>"256 server", :id=>1, :ram=>256, :disk=>10},
|
153
|
+
# {:name=>"512 server", :id=>2, :ram=>512, :disk=>20},...
|
154
|
+
#
|
155
|
+
# >> cs.list_flavors(:limit => 3, :offset => 2)
|
156
|
+
# => [{:ram=>1024, :disk=>40, :name=>"1GB server", :id=>3},
|
157
|
+
# {:ram=>2048, :disk=>80, :name=>"2GB server", :id=>4},
|
158
|
+
# {:ram=>4096, :disk=>160, :name=>"4GB server", :id=>5}]
|
159
|
+
def list_flavors(options = {})
|
160
|
+
path = OpenStack.paginate(options).empty? ? "#{@connection.service_path}/flavors/detail" : "#{@connection.service_path}/flavors/detail?#{OpenStack.paginate(options)}"
|
161
|
+
response = @connection.csreq("GET",@connection.service_host,path,@connection.service_port,@connection.service_scheme)
|
162
|
+
OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
163
|
+
OpenStack.symbolize_keys(JSON.parse(response.body)['flavors'])
|
164
|
+
end
|
165
|
+
alias :flavors :list_flavors
|
166
|
+
|
167
|
+
# Returns a OpenStack::Compute::Flavor object for the flavor identified by the provided ID.
|
168
|
+
#
|
169
|
+
# >> flavor = cs.flavor(1)
|
170
|
+
# => #<OpenStack::Compute::Flavor:0x10156dcc0 @name="256 server", @disk=10, @id=1, @ram=256>
|
171
|
+
def get_flavor(id)
|
172
|
+
OpenStack::Compute::Flavor.new(self,id)
|
173
|
+
end
|
174
|
+
alias :flavor :get_flavor
|
175
|
+
|
176
|
+
# Returns the current state of the programatic API limits. Each account has certain limits on the number of resources
|
177
|
+
# allowed in the account, and a rate of API operations.
|
178
|
+
#
|
179
|
+
# The operation returns a hash. The :absolute hash key reveals the account resource limits, including the maxmimum
|
180
|
+
# amount of total RAM that can be allocated (combined among all servers), the maximum members of an IP group, and the
|
181
|
+
# maximum number of IP groups that can be created.
|
182
|
+
#
|
183
|
+
# The :rate hash key returns an array of hashes indicating the limits on the number of operations that can be performed in a
|
184
|
+
# given amount of time. An entry in this array looks like:
|
185
|
+
#
|
186
|
+
# {:regex=>"^/servers", :value=>50, :verb=>"POST", :remaining=>50, :unit=>"DAY", :resetTime=>1272399820, :URI=>"/servers*"}
|
187
|
+
#
|
188
|
+
# This indicates that you can only run 50 POST operations against URLs in the /servers URI space per day, we have not run
|
189
|
+
# any operations today (50 remaining), and gives the Unix time that the limits reset.
|
190
|
+
#
|
191
|
+
# Another example is:
|
192
|
+
#
|
193
|
+
# {:regex=>".*", :value=>10, :verb=>"PUT", :remaining=>10, :unit=>"MINUTE", :resetTime=>1272399820, :URI=>"*"}
|
194
|
+
#
|
195
|
+
# This says that you can run 10 PUT operations on all possible URLs per minute, and also gives the number remaining and the
|
196
|
+
# time that the limit resets.
|
197
|
+
#
|
198
|
+
# Use this information as you're building your applications to put in relevant pauses if you approach your API limitations.
|
199
|
+
def limits
|
200
|
+
response = @connection.csreq("GET",@connection.service_host,"#{@connection.service_path}/limits",@connection.service_port,@connection.service_scheme)
|
201
|
+
OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
202
|
+
OpenStack.symbolize_keys(JSON.parse(response.body)['limits'])
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|