miasma 0.1.0 → 0.2.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.
@@ -1,19 +1,38 @@
1
1
  require 'miasma'
2
- require 'miasma/utils/smash'
3
- require 'time'
2
+ require 'miasma/contrib/open_stack'
4
3
 
5
4
  module Miasma
6
5
  module Contrib
7
6
 
8
7
  # Rackspace API core helper
9
- class RackspaceApiCore
8
+ class RackspaceApiCore < OpenStackApiCore
9
+
10
+ # Authentication helper class
11
+ class Authenticate < OpenStackApiCore::Authenticate
12
+ # Authentication implementation compatible for v2
13
+ class Version2 < OpenStackApiCore::Authenticate::Version2
14
+
15
+ # @return [Smash] authentication request body
16
+ def authentication_request
17
+ Smash.new(
18
+ 'RAX-KSKEY:apiKeyCredentials' => Smash.new(
19
+ 'username' => credentials[:open_stack_username],
20
+ 'apiKey' => credentials[:open_stack_token]
21
+ )
22
+ )
23
+ end
24
+
25
+ end
26
+ end
10
27
 
28
+ # Common API methods
11
29
  module ApiCommon
12
30
 
13
31
  # Set attributes into model
14
32
  #
15
33
  # @param klass [Class]
16
34
  def self.included(klass)
35
+ klass.attributes.clear
17
36
  klass.class_eval do
18
37
  attribute :rackspace_api_key, String, :required => true
19
38
  attribute :rackspace_username, String, :required => true
@@ -21,26 +40,8 @@ module Miasma
21
40
  end
22
41
  end
23
42
 
24
- # @return [HTTP] with auth token provided
25
- def connection
26
- super.with_headers('X-Auth-Token' => token)
27
- end
28
-
29
- # @return [String] endpoint URL
30
- def endpoint
31
- rackspace_api.endpoint_for(
32
- Utils.snake(self.class.to_s.split('::')[-2]).to_sym,
33
- rackspace_region
34
- )
35
- end
36
-
37
- # @return [String] valid API token
38
- def token
39
- rackspace_api.api_token
40
- end
41
-
42
43
  # @return [Miasma::Contrib::RackspaceApiCore]
43
- def rackspace_api
44
+ def open_stack_api
44
45
  key = "miasma_rackspace_api_#{attributes.checksum}".to_sym
45
46
  memoize(key, :direct) do
46
47
  Miasma::Contrib::RackspaceApiCore.new(attributes)
@@ -70,88 +71,27 @@ module Miasma
70
71
  'load_balancer' => 'cloudLoadBalancers'
71
72
  )
72
73
 
73
- # @return [String] username
74
- attr_reader :user
75
- # @return [Smash] remote service catalog
76
- attr_reader :service_catalog
77
- # @return [Smash] token information
78
- attr_reader :token
79
- # @return [Smash] credentials in use
80
- attr_reader :credentials
81
-
82
74
  # Create a new api instance
83
75
  #
84
76
  # @param creds [Smash] credential hash
85
77
  # @return [self]
86
78
  def initialize(creds)
87
- @credentials = creds
88
- end
89
-
90
- # Provide end point URL for service
91
- #
92
- # @param api_name [String] name of api
93
- # @param region [String] region in use
94
- # @return [String] public URL
95
- def endpoint_for(api_name, region)
96
- identify_and_load unless service_catalog
97
- api = API_MAP[api_name]
98
- srv = service_catalog.detect do |info|
99
- info[:name] == api
79
+ if(creds[:rackspace_region].to_s == 'lon')
80
+ endpoint = AUTH_ENDPOINT[:uk]
81
+ else
82
+ endpoint = AUTH_ENDPOINT[:us]
100
83
  end
101
- unless(srv)
102
- raise NotImplementedError.new("No API mapping found for `#{api_name}`")
103
- end
104
- region = region.to_s.upcase
105
- point = srv[:endpoints].detect do |endpoint|
106
- endpoint[:region] == region
107
- end
108
- if(point)
109
- point[:publicURL]
110
- end
111
- end
112
-
113
- # @return [String] API token
114
- def api_token
115
- if(token.nil? || Time.now > token[:expires])
116
- identify_and_load
117
- end
118
- token[:id]
84
+ super Smash.new(
85
+ :open_stack_username => creds[:rackspace_username],
86
+ :open_stack_token => creds[:rackspace_api_key],
87
+ :open_stack_region => creds[:rackspace_region],
88
+ :open_stack_identity_url => endpoint
89
+ )
119
90
  end
120
91
 
121
92
  # @return [String] ID of account
122
93
  def account_id
123
- if(token.nil? || Time.now > token[:expires])
124
- identify_and_load
125
- end
126
- token[:tenant][:id]
127
- end
128
-
129
- # Identify with authentication service and load
130
- # token information and service catalog
131
- #
132
- # @return [TrueClass]
133
- def identify_and_load
134
- endpoint = credentials[:rackspace_region].to_s == 'lon' ? AUTH_ENDPOINT[:uk] : AUTH_ENDPOINT[:us]
135
- result = HTTP.post(File.join(endpoint, 'tokens'),
136
- :json => {
137
- 'auth' => {
138
- 'RAX-KSKEY:apiKeyCredentials' => {
139
- 'username' => credentials[:rackspace_username],
140
- 'apiKey' => credentials[:rackspace_api_key]
141
- }
142
- }
143
- }
144
- )
145
- unless(result.status == 200)
146
- raise Error::ApiError::AuthenticationError.new('Failed to authenticate', :response => result)
147
- end
148
- info = MultiJson.load(result.body.to_s).to_smash
149
- info = info[:access]
150
- @user = info[:user]
151
- @service_catalog = info[:serviceCatalog]
152
- @token = info[:token]
153
- token[:expires] = Time.parse(token[:expires])
154
- true
94
+ identity.token[:tenant][:id]
155
95
  end
156
96
 
157
97
  end
@@ -3,101 +3,10 @@ require 'miasma'
3
3
  module Miasma
4
4
  module Models
5
5
  class Compute
6
- class Rackspace < Compute
6
+ class Rackspace < OpenStack
7
7
 
8
8
  include Contrib::RackspaceApiCore::ApiCommon
9
9
 
10
- # @return [Smash] map state to valid internal values
11
- SERVER_STATE_MAP = Smash.new(
12
- 'ACTIVE' => :running,
13
- 'DELETED' => :terminated,
14
- 'SUSPENDED' => :stopped,
15
- 'PASSWORD' => :running
16
- )
17
-
18
- def server_save(server)
19
- unless(server.persisted?)
20
- server.load_data(server.attributes)
21
- result = request(
22
- :expects => 202,
23
- :method => :post,
24
- :path => '/servers',
25
- :json => {
26
- :server => {
27
- :flavorRef => server.flavor_id,
28
- :name => server.name,
29
- :imageRef => server.image_id,
30
- :metadata => server.metadata,
31
- :personality => server.personality,
32
- :key_pair => server.key_name
33
- }
34
- }
35
- )
36
- server.id = result.get(:body, :server, :id)
37
- else
38
- raise "WAT DO I DO!?"
39
- end
40
- end
41
-
42
- def server_destroy(server)
43
- if(server.persisted?)
44
- result = request(
45
- :expects => 204,
46
- :method => :delete,
47
- :path => "/servers/#{server.id}"
48
- )
49
- else
50
- raise "this doesn't even exist"
51
- end
52
- end
53
-
54
- def server_change_state(server, state)
55
- end
56
-
57
- def server_reload(server)
58
- res = servers.reload.all
59
- node = res.detect do |s|
60
- s.id == server.id
61
- end
62
- if(node)
63
- server.load_data(node.data.dup)
64
- server.valid_state
65
- else
66
- server.data[:state] = :terminated
67
- server.dirty.clear
68
- server
69
- end
70
- end
71
-
72
- def server_all
73
- result = request(
74
- :method => :get,
75
- :path => '/servers/detail'
76
- )
77
- result[:body].fetch(:servers, []).map do |srv|
78
- Server.new(
79
- self,
80
- :id => srv[:id],
81
- :name => srv[:name],
82
- :image_id => srv.get(:image, :id),
83
- :flavor_id => srv.get(:flavor, :id),
84
- :state => SERVER_STATE_MAP.fetch(srv[:status], :pending),
85
- :addresses_private => srv.fetch(:addresses, :private, []).map{|a|
86
- Server::Address.new(
87
- :version => a[:version].to_i, :address => a[:addr]
88
- )
89
- },
90
- :addresses_public => srv.fetch(:addresses, :public, []).map{|a|
91
- Server::Address.new(
92
- :version => a[:version].to_i, :address => a[:addr]
93
- )
94
- },
95
- :status => srv[:status],
96
- :key_name => srv[:key_name]
97
- ).valid_state
98
- end
99
- end
100
-
101
10
  end
102
11
  end
103
12
  end
@@ -3,7 +3,7 @@ require 'miasma'
3
3
  module Miasma
4
4
  module Models
5
5
  class Orchestration
6
- class Rackspace < Orchestration
6
+ class Rackspace < OpenStack
7
7
 
8
8
  include Contrib::RackspaceApiCore::ApiCommon
9
9
 
@@ -19,236 +19,6 @@ module Miasma
19
19
  )
20
20
  )
21
21
 
22
- # Save the stack
23
- #
24
- # @param stack [Models::Orchestration::Stack]
25
- # @return [Models::Orchestration::Stack]
26
- def stack_save(stack)
27
- if(stack.persisted?)
28
- stack.load_data(stack.attributes)
29
- result = request(
30
- :expects => 202,
31
- :method => :put,
32
- :path => "/stacks/#{stack.name}/#{stack.id}",
33
- :json => {
34
- :stack_name => stack.name,
35
- :template => MultiJson.dump(stack.template),
36
- :parameters => stack.parameters || {}
37
- }
38
- )
39
- stack.valid_state
40
- else
41
- stack.load_data(stack.attributes)
42
- result = request(
43
- :expects => 201,
44
- :method => :post,
45
- :path => '/stacks',
46
- :json => {
47
- :stack_name => stack.name,
48
- :template => MultiJson.dump(stack.template),
49
- :parameters => stack.parameters || {},
50
- :disable_rollback => (!!stack.disable_rollback).to_s
51
- }
52
- )
53
- stack.id = result.get(:body, :stack, :id)
54
- stack.valid_state
55
- end
56
- end
57
-
58
- # Reload the stack data from the API
59
- #
60
- # @param stack [Models::Orchestration::Stack]
61
- # @return [Models::Orchestration::Stack]
62
- def stack_reload(stack)
63
- if(stack.persisted?)
64
- result = request(
65
- :method => :get,
66
- :path => "/stacks/#{stack.name}/#{stack.id}",
67
- :expects => 200
68
- )
69
- stk = result.get(:body, :stack)
70
- stack.load_data(
71
- :id => stk[:id],
72
- :capabilities => stk[:capabilities],
73
- :creation_time => Time.parse(stk[:creation_time]),
74
- :description => stk[:description],
75
- :disable_rollback => stk[:disable_rollback].to_s.downcase == 'true',
76
- :notification_topics => stk[:notification_topics],
77
- :name => stk[:stack_name],
78
- :state => stk[:stack_status].downcase.to_sym,
79
- :status => stk[:stack_status],
80
- :status_reason => stk[:stack_status_reason],
81
- :template_description => stk[:template_description],
82
- :timeout_in_minutes => stk[:timeout_mins].to_s.empty? ? nil : stk[:timeout_mins].to_i,
83
- :updated_time => stk[:updated_time].to_s.empty? ? nil : Time.parse(stk[:updated_time]),
84
- :parameters => stk.fetch(:parameters, Smash.new),
85
- :outputs => stk.fetch(:outputs, []).map{ |output|
86
- Smash.new(
87
- :key => output[:output_key],
88
- :value => output[:output_value],
89
- :description => output[:description]
90
- )
91
- }
92
- ).valid_state
93
- end
94
- stack
95
- end
96
-
97
- # Delete the stack
98
- #
99
- # @param stack [Models::Orchestration::Stack]
100
- # @return [TrueClass, FalseClass]
101
- def stack_destroy(stack)
102
- if(stack.persisted?)
103
- request(
104
- :method => :delete,
105
- :path => "/stacks/#{stack.name}/#{stack.id}",
106
- :expects => 204
107
- )
108
- true
109
- else
110
- false
111
- end
112
- end
113
-
114
- # Fetch stack template
115
- #
116
- # @param stack [Stack]
117
- # @return [Smash] stack template
118
- def stack_template_load(stack)
119
- if(stack.persisted?)
120
- result = request(
121
- :method => :get,
122
- :path => "/stacks/#{stack.name}/#{stack.id}/template"
123
- )
124
- result.fetch(:body, Smash.new)
125
- else
126
- Smash.new
127
- end
128
- end
129
-
130
- # Validate stack template
131
- #
132
- # @param stack [Stack]
133
- # @return [NilClass, String] nil if valid, string error message if invalid
134
- def stack_template_validate(stack)
135
- begin
136
- result = request(
137
- :method => :post,
138
- :path => '/validate',
139
- :json => Smash.new(
140
- :template => stack.template
141
- )
142
- )
143
- nil
144
- rescue Error::ApiError::RequestError => e
145
- MultiJson.load(e.response.body.to_s).to_smash.get(:error, :message)
146
- end
147
- end
148
-
149
- # Return all stacks
150
- #
151
- # @param options [Hash] filter
152
- # @return [Array<Models::Orchestration::Stack>]
153
- # @todo check if we need any mappings on state set
154
- def stack_all(options={})
155
- result = request(
156
- :method => :get,
157
- :path => '/stacks'
158
- )
159
- result.fetch(:body, :stacks, []).map do |s|
160
- Stack.new(
161
- self,
162
- :id => s[:id],
163
- :creation_time => Time.parse(s[:creation_time]),
164
- :description => s[:description],
165
- :name => s[:stack_name],
166
- :state => s[:stack_status].downcase.to_sym,
167
- :status => s[:stack_status],
168
- :status_reason => s[:stack_status_reason],
169
- :updated_time => s[:updated_time].to_s.empty? ? nil : Time.parse(s[:updated_time])
170
- ).valid_state
171
- end
172
- end
173
-
174
- # Return all resources for stack
175
- #
176
- # @param stack [Models::Orchestration::Stack]
177
- # @return [Array<Models::Orchestration::Stack::Resource>]
178
- def resource_all(stack)
179
- result = request(
180
- :method => :get,
181
- :path => "/stacks/#{stack.name}/#{stack.id}/resources",
182
- :expects => 200
183
- )
184
- result.fetch(:body, :resources, []).map do |resource|
185
- Stack::Resource.new(
186
- stack,
187
- :id => resource[:physical_resource_id],
188
- :name => resource[:resource_name],
189
- :type => resource[:resource_type],
190
- :logical_id => resource[:logical_resource_id],
191
- :state => resource[:resource_status].downcase.to_sym,
192
- :status => resource[:resource_status],
193
- :status_reason => resource[:resource_status_reason],
194
- :updated_time => Time.parse(resource[:updated_time])
195
- ).valid_state
196
- end
197
- end
198
-
199
- # Reload the stack resource data from the API
200
- #
201
- # @param resource [Models::Orchestration::Stack::Resource]
202
- # @return [Models::Orchestration::Resource]
203
- def resource_reload(resource)
204
- resource.stack.resources.reload
205
- resource.stack.resources.get(resource.id)
206
- end
207
-
208
- # Return all events for stack
209
- #
210
- # @param stack [Models::Orchestration::Stack]
211
- # @return [Array<Models::Orchestration::Stack::Event>]
212
- def event_all(stack, marker = nil)
213
- params = marker ? {:marker => marker} : {}
214
- result = request(
215
- :path => "/stacks/#{stack.name}/#{stack.id}/events",
216
- :method => :get,
217
- :expects => 200,
218
- :params => params
219
- )
220
- result.fetch(:body, :events, []).map do |event|
221
- Stack::Event.new(
222
- stack,
223
- :id => event[:id],
224
- :resource_id => event[:physical_resource_id],
225
- :resource_name => event[:resource_name],
226
- :resource_logical_id => event[:logical_resource_id],
227
- :resource_state => event[:resource_status].downcase.to_sym,
228
- :resource_status => event[:resource_status],
229
- :resource_status_reason => event[:resource_status_reason],
230
- :time => Time.parse(event[:event_time])
231
- ).valid_state
232
- end
233
- end
234
-
235
- # Return all new events for event collection
236
- #
237
- # @param events [Models::Orchestration::Stack::Events]
238
- # @return [Array<Models::Orchestration::Stack::Event>]
239
- def event_all_new(events)
240
- event_all(events.stack, events.all.first.id)
241
- end
242
-
243
- # Reload the stack event data from the API
244
- #
245
- # @param resource [Models::Orchestration::Stack::Event]
246
- # @return [Models::Orchestration::Event]
247
- def event_reload(event)
248
- event.stack.events.reload
249
- event.stack.events.get(event.id)
250
- end
251
-
252
22
  end
253
23
  end
254
24
  end