openstack 1.0.0

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.
@@ -0,0 +1,35 @@
1
+ module OpenStack
2
+ module Compute
3
+ class Flavor
4
+
5
+ attr_reader :id
6
+ attr_reader :name
7
+ attr_reader :ram
8
+ attr_reader :disk
9
+ attr_reader :vcpus
10
+
11
+ # This class provides an object for the "Flavor" of a server. The Flavor can generally be taken as the server specification,
12
+ # providing information on things like memory and disk space.
13
+ #
14
+ # The disk attribute is an integer representing the disk space in GB. The memory attribute is an integer representing the RAM in MB.
15
+ #
16
+ # This is called from the get_flavor method on a OpenStack::Compute::Connection object, returns a OpenStack::Compute::Flavor object, and will likely not be called directly.
17
+ #
18
+ # >> flavor = cs.get_flavor(1)
19
+ # => #<OpenStack::Compute::Flavor:0x1014f8bc8 @name="256 server", @disk=10, @id=1, @ram=256>
20
+ # >> flavor.name
21
+ # => "256 server"
22
+ def initialize(compute,id)
23
+ response = compute.connection.csreq("GET",compute.connection.service_host,"#{compute.connection.service_path}/flavors/#{URI.escape(id.to_s)}",compute.connection.service_port,compute.connection.service_scheme)
24
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
25
+ data = JSON.parse(response.body)['flavor']
26
+ @id = data['id']
27
+ @name = data['name']
28
+ @ram = data['ram']
29
+ @disk = data['disk']
30
+ @vcpus = data['vcpus']
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,73 @@
1
+ module OpenStack
2
+ module Compute
3
+ class Image
4
+
5
+ require 'openstack/compute/metadata'
6
+
7
+ attr_reader :id
8
+ attr_reader :name
9
+ attr_reader :server
10
+ attr_reader :updated
11
+ attr_reader :created
12
+ attr_reader :status
13
+ attr_reader :minDisk
14
+ attr_reader :minRam
15
+ attr_reader :progress
16
+ attr_reader :metadata
17
+
18
+ # This class provides an object for the "Image" of a server. The Image refers to the Operating System type and version.
19
+ #
20
+ # Returns the Image object identifed by the supplied ID number. Called from the get_image instance method of OpenStack::Compute::Connection,
21
+ # it will likely not be called directly from user code.
22
+ #
23
+ # >> cs = OpenStack::Compute::Connection.new(USERNAME,API_KEY)
24
+ # >> image = cs.get_image(2)
25
+ # => #<OpenStack::Compute::Image:0x1015371c0 ...>
26
+ # >> image.name
27
+ # => "CentOS 5.2"
28
+ def initialize(compute,id)
29
+ @id = id
30
+ @compute = compute
31
+ populate
32
+ end
33
+
34
+ # Makes the HTTP call to load information about the provided image. Can also be called directly on the Image object to refresh data.
35
+ # Returns true if the refresh call succeeds.
36
+ #
37
+ # >> image.populate
38
+ # => true
39
+ def populate
40
+ path = "/images/#{URI.escape(self.id.to_s)}"
41
+ response = @compute.connection.req("GET", path)
42
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
43
+ data = JSON.parse(response.body)['image']
44
+ @id = data['id']
45
+ @name = data['name']
46
+ @server = data['server']
47
+ if data['updated'] then
48
+ @updated = DateTime.parse(data['updated'])
49
+ end
50
+ @created = DateTime.parse(data['created'])
51
+ @metadata = OpenStack::Compute::Metadata.new(@compute, path, data['metadata'])
52
+ @status = data['status']
53
+ @minDisk = data['minDisk']
54
+ @minRam = data['minRam']
55
+ @progress = data['progress']
56
+ return true
57
+ end
58
+ alias :refresh :populate
59
+
60
+ # Delete an image. This should be returning invalid permissions when attempting to delete system images, but it's not.
61
+ # Returns true if the deletion succeeds.
62
+ #
63
+ # >> image.delete!
64
+ # => true
65
+ def delete!
66
+ response = @compute.connection.csreq("DELETE",@compute.connection.service_host,"#{@compute.connection.service_path}/images/#{URI.escape(self.id.to_s)}",@compute.connection.service_port,@compute.connection.service_scheme)
67
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
68
+ true
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,116 @@
1
+ module OpenStack
2
+ module Compute
3
+
4
+ class Metadata
5
+
6
+ def initialize(compute, parent_url, metadata=nil)
7
+ @compute = compute
8
+ @base_url = "#{parent_url}/metadata"
9
+ @metadata = metadata
10
+ end
11
+
12
+ def [](key)
13
+ refresh if @metadata.nil?
14
+ @metadata[key]
15
+ end
16
+
17
+ def []=(key, value)
18
+ @metadata = {} if @metadata.nil?
19
+ @metadata[key] = value
20
+ end
21
+
22
+ def store(key, value)
23
+ @metadata = {} if @metadata.nil?
24
+ @metadata[key] = value
25
+ end
26
+
27
+ def each_pair
28
+ @metadata = {} if @metadata.nil?
29
+ @metadata.each_pair do |k,v|
30
+ yield k, v
31
+ end
32
+ end
33
+
34
+ def size
35
+ @metadata = {} if @metadata.nil?
36
+ @metadata.size
37
+ end
38
+
39
+ def each
40
+ refresh if @metadata.nil?
41
+ @metadata.each
42
+ end
43
+
44
+ def save
45
+ return if @metadata.nil?
46
+ json = JSON.generate(:metadata => @metadata)
47
+ response = @compute.connection.req('PUT', @base_url, :data => json)
48
+ @metadata = JSON.parse(response.body)['metadata']
49
+ end
50
+
51
+ def update(keys=nil)
52
+ return if @metadata.nil?
53
+ if keys.nil?
54
+ json = JSON.generate(:metadata => @metadata)
55
+ response = @compute.connection.req('POST', @base_url, :data => json)
56
+ @metadata = JSON.parse(response.body)['metadata']
57
+ else
58
+ keys.each { |key|
59
+ next if not @metadata.has_key?(key)
60
+ json = JSON.generate(:meta => { key => @metadata[key] })
61
+ @compute.connection.req('PUT', "#{@base_url}/#{key}", :data => json)
62
+ }
63
+ end
64
+ end
65
+
66
+ def refresh(keys=nil)
67
+ if keys.nil?
68
+ response = @compute.connection.req('GET', @base_url)
69
+ @metadata = JSON.parse(response.body)['metadata']
70
+ else
71
+ @metadata = {} if @metadata == nil
72
+ keys.each { |key|
73
+ response = @compute.connection.req('GET', "#{@base_url}/#{key}")
74
+ next if response.code == "404"
75
+ meta = JSON.parse(response.body)['meta']
76
+ meta.each { |k, v| @metadata[k] = v }
77
+ }
78
+ end
79
+ end
80
+
81
+ def delete(keys)
82
+ return if @metadata.nil?
83
+ keys.each { |key|
84
+ @metadata.delete(key)
85
+ }
86
+ end
87
+
88
+ def delete!(keys)
89
+ keys.each { |key|
90
+ @compute.connection.req('DELETE', "#{@base_url}/#{key}")
91
+ @metadata.delete(key) if not @metadata.nil?
92
+ }
93
+ end
94
+
95
+ def clear
96
+ if @metadata.nil?
97
+ @metadata = {}
98
+ else
99
+ @metadata.clear
100
+ end
101
+ end
102
+
103
+ def clear!
104
+ clear
105
+ save
106
+ end
107
+
108
+ def has_key?(key)
109
+ return False if @metadata.nil?
110
+ return @metadata.has_key?(key)
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,23 @@
1
+ module OpenStack
2
+ module Compute
3
+ module Personalities
4
+
5
+ # Handles parsing the Personality hash to load it up with Base64-encoded data.
6
+ def self.get_personality(options)
7
+ return if options.nil?
8
+ require 'base64'
9
+ data = []
10
+ itemcount = 0
11
+ options.each do |localpath,svrpath|
12
+ raise OpenStack::Exception::TooManyPersonalityItems, "Personality files are limited to a total of #{MAX_PERSONALITY_ITEMS} items" if itemcount >= MAX_PERSONALITY_ITEMS
13
+ raise OpenStack::Exception::PersonalityFilePathTooLong, "Server-side path of #{svrpath} exceeds the maximum length of #{MAX_SERVER_PATH_LENGTH} characters" if svrpath.size > MAX_SERVER_PATH_LENGTH
14
+ raise OpenStack::Exception::PersonalityFileTooLarge, "Local file #{localpath} exceeds the maximum size of #{MAX_PERSONALITY_FILE_SIZE} bytes" if File.size(localpath) > MAX_PERSONALITY_FILE_SIZE
15
+ b64 = Base64.encode64(IO.read(localpath))
16
+ data.push({:path => svrpath, :contents => b64})
17
+ itemcount += 1
18
+ end
19
+ data
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,249 @@
1
+ module OpenStack
2
+ module Compute
3
+ class Server
4
+
5
+ require 'openstack/compute/metadata'
6
+
7
+ attr_reader :id
8
+ attr_reader :name
9
+ attr_reader :status
10
+ attr_reader :progress
11
+ attr_reader :accessipv4
12
+ attr_reader :accessipv6
13
+ attr_reader :addresses
14
+ attr_reader :hostId
15
+ attr_reader :image
16
+ attr_reader :flavor
17
+ attr_reader :metadata
18
+ attr_accessor :adminPass
19
+
20
+ # This class is the representation of a single Server object. The constructor finds the server identified by the specified
21
+ # ID number, accesses the API via the populate method to get information about that server, and returns the object.
22
+ #
23
+ # Will be called via the get_server or create_server methods on the OpenStack::Compute::Connection object, and will likely not be called directly.
24
+ #
25
+ # >> server = cs.get_server(110917)
26
+ # => #<OpenStack::Compute::Server:0x1014e5438 ....>
27
+ # >> server.name
28
+ # => "RenamedRubyTest"
29
+ def initialize(compute,id)
30
+ @compute = compute
31
+ @id = id
32
+ @svrmgmthost = @compute.connection.service_host
33
+ @svrmgmtpath = @compute.connection.service_path
34
+ @svrmgmtport = @compute.connection.service_port
35
+ @svrmgmtscheme = @compute.connection.service_scheme
36
+ populate
37
+ return self
38
+ end
39
+
40
+ # Makes the actual API call to get information about the given server object. If you are attempting to track the status or project of
41
+ # a server object (for example, when rebuilding, creating, or resizing a server), you will likely call this method within a loop until
42
+ # the status becomes "ACTIVE" or other conditions are met.
43
+ #
44
+ # Returns true if the API call succeeds.
45
+ #
46
+ # >> server.refresh
47
+ # => true
48
+ def populate(data=nil)
49
+ path = "/servers/#{URI.encode(@id.to_s)}"
50
+ if data.nil? then
51
+ response = @compute.connection.req("GET", path)
52
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
53
+ data = JSON.parse(response.body)["server"]
54
+ end
55
+ @id = data["id"]
56
+ @name = data["name"]
57
+ @status = data["status"]
58
+ @progress = data["progress"]
59
+ @addresses = get_addresses(data["addresses"])
60
+ @metadata = OpenStack::Compute::Metadata.new(@compute, path, data["metadata"])
61
+ @hostId = data["hostId"]
62
+ @image = data["image"]
63
+ @flavor = data["flavor"]
64
+ true
65
+ end
66
+ alias :refresh :populate
67
+
68
+ # Sends an API request to reboot this server. Takes an optional argument for the type of reboot, which can be "SOFT" (graceful shutdown)
69
+ # or "HARD" (power cycle). The hard reboot is also triggered by server.reboot!, so that may be a better way to call it.
70
+ #
71
+ # Returns true if the API call succeeds.
72
+ #
73
+ # >> server.reboot
74
+ # => true
75
+ def reboot(type="SOFT")
76
+ data = JSON.generate(:reboot => {:type => type})
77
+ response = @compute.connection.csreq("POST",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}/action",@svrmgmtport,@svrmgmtscheme,{'content-type' => 'application/json'},data)
78
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
79
+ true
80
+ end
81
+
82
+ # Sends an API request to hard-reboot (power cycle) the server. See the reboot method for more information.
83
+ #
84
+ # Returns true if the API call succeeds.
85
+ #
86
+ # >> server.reboot!
87
+ # => true
88
+ def reboot!
89
+ self.reboot("HARD")
90
+ end
91
+
92
+ # Updates various parameters about the server. Currently, the only operations supported are changing the server name (not the actual hostname
93
+ # on the server, but simply the label in the Servers API) and the administrator password (note: changing the admin password will trigger
94
+ # a reboot of the server). Other options are ignored. One or both key/value pairs may be provided. Keys are case-sensitive.
95
+ #
96
+ # Input hash key values are :name and :adminPass. Returns true if the API call succeeds.
97
+ #
98
+ # >> server.update(:name => "MyServer", :adminPass => "12345")
99
+ # => true
100
+ # >> server.name
101
+ # => "MyServer"
102
+ def update(options)
103
+ data = JSON.generate(:server => options)
104
+ response = @compute.connection.csreq("PUT",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}",@svrmgmtport,@svrmgmtscheme,{'content-type' => 'application/json'},data)
105
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
106
+ # If we rename the instance, repopulate the object
107
+ self.populate if options[:name]
108
+ true
109
+ end
110
+
111
+ # Deletes the server from OpenStack Compute. The server will be shut down, data deleted, and billing stopped.
112
+ #
113
+ # Returns true if the API call succeeds.
114
+ #
115
+ # >> server.delete!
116
+ # => true
117
+ def delete!
118
+ response = @compute.connection.csreq("DELETE",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}",@svrmgmtport,@svrmgmtscheme)
119
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
120
+ true
121
+ end
122
+
123
+ # The rebuild function removes all data on the server and replaces it with
124
+ # the specified image. The serverRef and all IP addresses will remain the
125
+ # same. If name and metadata are specified, they will replace existing
126
+ # values, otherwise they will not change. A rebuild operation always
127
+ # removes data injected into the file system via server personality. You
128
+ # may reinsert data into the filesystem during the rebuild.
129
+ #
130
+ # This method expects a hash of the form:
131
+ # {
132
+ # :imageRef => "https://foo.com/v1.1/images/2",
133
+ # :name => "newName",
134
+ # :metadata => { :values => { :foo : "bar" } },
135
+ # :personality => [
136
+ # {
137
+ # :path => "/etc/banner.txt",
138
+ # :contents => : "ICAgpY2hhcmQgQmFjaA=="
139
+ # }
140
+ # ]
141
+ # }
142
+ #
143
+ # This will wipe and rebuild the server, but keep the server ID number,
144
+ # name, and IP addresses the same.
145
+ #
146
+ # Returns true if the API call succeeds.
147
+ #
148
+ # >> server.rebuild!
149
+ # => true
150
+ def rebuild!(options)
151
+ options[:personality] = Personalities.get_personality(options[:personality])
152
+ json = JSON.generate(:rebuild => options)
153
+ response = @compute.connection.req('POST', "/servers/#{@id}/action", :data => json)
154
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
155
+ data = JSON.parse(response.body)['server']
156
+ self.populate(data)
157
+ self.adminPass = data['adminPass']
158
+ true
159
+ end
160
+
161
+ # Takes a snapshot of the server and creates a server image from it. That image can then be used to build new servers. The
162
+ # snapshot is saved asynchronously. Check the image status to make sure that it is ACTIVE before attempting to perform operations
163
+ # on it.
164
+ #
165
+ # A name string for the saved image must be provided. A new OpenStack::Compute::Image object for the saved image is returned.
166
+ #
167
+ # The image is saved as a backup, of which there are only three available slots. If there are no backup slots available,
168
+ # A OpenStack::Exception::OpenStackComputeFault will be raised.
169
+ #
170
+ # >> image = server.create_image(:name => "My Rails Server")
171
+ # =>
172
+ def create_image(options)
173
+ data = JSON.generate(:createImage => options)
174
+ response = @compute.connection.csreq("POST",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}/action",@svrmgmtport,@svrmgmtscheme,{'content-type' => 'application/json'},data)
175
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
176
+ image_id = response["Location"].scan(/.*\/(.*)/).flatten
177
+ OpenStack::Compute::Image.new(@compute, image_id)
178
+ end
179
+
180
+ # Resizes the server to the size contained in the server flavor found at ID flavorRef. The server name, ID number, and IP addresses
181
+ # will remain the same. After the resize is done, the server.status will be set to "VERIFY_RESIZE" until the resize is confirmed or reverted.
182
+ #
183
+ # Refreshes the OpenStack::Compute::Server object, and returns true if the API call succeeds.
184
+ #
185
+ # >> server.resize!(1)
186
+ # => true
187
+ def resize!(flavorRef)
188
+ data = JSON.generate(:resize => {:flavorRef => flavorRef})
189
+ response = @compute.connection.csreq("POST",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}/action",@svrmgmtport,@svrmgmtscheme,{'content-type' => 'application/json'},data)
190
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
191
+ self.populate
192
+ true
193
+ end
194
+
195
+ # After a server resize is complete, calling this method will confirm the resize with the OpenStack API, and discard the fallback/original image.
196
+ #
197
+ # Returns true if the API call succeeds.
198
+ #
199
+ # >> server.confirm_resize!
200
+ # => true
201
+ def confirm_resize!
202
+ # If the resize bug gets figured out, should put a check here to make sure that it's in the proper state for this.
203
+ data = JSON.generate(:confirmResize => nil)
204
+ response = @compute.connection.csreq("POST",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}/action",@svrmgmtport,@svrmgmtscheme,{'content-type' => 'application/json'},data)
205
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
206
+ self.populate
207
+ true
208
+ end
209
+
210
+ # After a server resize is complete, calling this method will reject the resized server with the OpenStack API, destroying
211
+ # the new image and replacing it with the pre-resize fallback image.
212
+ #
213
+ # Returns true if the API call succeeds.
214
+ #
215
+ # >> server.confirm_resize!
216
+ # => true
217
+ def revert_resize!
218
+ # If the resize bug gets figured out, should put a check here to make sure that it's in the proper state for this.
219
+ data = JSON.generate(:revertResize => nil)
220
+ response = @compute.connection.csreq("POST",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}/action",@svrmgmtport,@svrmgmtscheme,{'content-type' => 'application/json'},data)
221
+ OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
222
+ self.populate
223
+ true
224
+ end
225
+
226
+ # Changes the admin password.
227
+ # Returns the password if it succeeds.
228
+ def change_password!(password)
229
+ json = JSON.generate(:changePassword => { :adminPass => password })
230
+ @compute.connection.req('POST', "/servers/#{@id}/action", :data => json)
231
+ @adminPass = password
232
+ end
233
+
234
+ def get_addresses(address_info)
235
+ address_list = OpenStack::Compute::AddressList.new
236
+ address_info.each do |label, addr|
237
+ addr.each do |address|
238
+ address_list << OpenStack::Compute::Address.new(label,address)
239
+ if address_list.last.version == 4 && (!@accessipv4 || accessipv4 == "") then
240
+ @accessipv4 = address_list.last.address
241
+ end
242
+ end
243
+ end
244
+ address_list
245
+ end
246
+
247
+ end
248
+ end
249
+ end