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.
@@ -29,6 +29,7 @@ module Miasma
29
29
  def initialize(msg, args={})
30
30
  super
31
31
  @response = args.to_smash[:response]
32
+ @message = msg
32
33
  extract_error_message(@response)
33
34
  end
34
35
 
@@ -54,9 +55,11 @@ module Miasma
54
55
  rescue MultiJson::ParseError
55
56
  begin
56
57
  content = MultiXml.parse(response.body.to_s).to_smash
57
- if(content.get('ErrorResponse', 'Error'))
58
- @response_error_msg = "#{content.get('ErrorResponse', 'Error', 'Code')}: #{content.get('ErrorResponse', 'Error', 'Message')}"
59
- end
58
+ @response_error_msg = [['ErrorResponse', 'Error'], ['Error']].map do |path|
59
+ if(result = content.get(*path))
60
+ "#{result['Code']}: #{result['Message']}"
61
+ end
62
+ end.compact.first
60
63
  rescue MultiXml::ParseError
61
64
  content = Smash.new
62
65
  end
@@ -78,8 +81,7 @@ module Miasma
78
81
  # Orchestration error
79
82
  class OrchestrationError < Error
80
83
  # Template failed to validate
81
- class InvalidTemplate < OrchestrationError
82
- end
84
+ class InvalidTemplate < OrchestrationError; end
83
85
  end
84
86
 
85
87
  # Invalid modification request
@@ -14,7 +14,7 @@ module Miasma
14
14
  attribute :state, Symbol, :required => true, :allowed_values => Orchestration::VALID_RESOURCE_STATES
15
15
  attribute :status, [String, Symbol], :required => true, :coerce => lambda{|v| v.to_s.to_sym}
16
16
  attribute :status_reason, String
17
- attribute :updated_time, Time, :coerce => lambda{|v| Time.parse(v.to_s)}
17
+ attribute :updated, Time, :coerce => lambda{|v| Time.parse(v.to_s)}
18
18
 
19
19
  attr_reader :stack
20
20
 
@@ -35,8 +35,8 @@ module Miasma
35
35
  attribute :outputs, Output, :coerce => lambda{|v, stack| Output.new(stack, v) }, :multiple => true
36
36
  attribute :status, String
37
37
  attribute :status_reason, String
38
- attribute :creation_time, Time, :coerce => lambda{|v| Time.parse(v.to_s)}
39
- attribute :updated_time, Time, :coerce => lambda{|v| Time.parse(v.to_s)}
38
+ attribute :created, Time, :coerce => lambda{|v| Time.parse(v.to_s)}
39
+ attribute :updated, Time, :coerce => lambda{|v| Time.parse(v.to_s)}
40
40
  attribute :parameters, Smash, :coerce => lambda{|v| v.to_smash }
41
41
  attribute :template, Smash, :depends => :perform_template_load, :coerce => lambda{|v| v = MultiJson.load(v) if v.is_a?(String); v.to_smash }
42
42
  attribute :template_url, String
@@ -5,19 +5,26 @@ module Miasma
5
5
  # Abstract storage API
6
6
  class Storage < Types::Api
7
7
 
8
+ autoload :Buckets, 'miasma/models/storage/buckets'
9
+ autoload :Bucket, 'miasma/models/storage/bucket'
10
+ autoload :Files, 'miasma/models/storage/files'
11
+ autoload :File, 'miasma/models/storage/file'
12
+
8
13
  # Storage buckets
9
14
  #
10
15
  # @param filter [Hash] filtering options
11
16
  # @return [Types::Collection<Models::Storage::Bucket>] buckets
12
17
  def buckets(args={})
13
- Buckets.new(self)
18
+ memoize(:buckets) do
19
+ Buckets.new(self)
20
+ end
14
21
  end
15
22
 
16
- # Create a new bucket
23
+ # Save bucket
17
24
  #
18
25
  # @param bucket [Models::Storage::Bucket]
19
26
  # @return [Models::Storage::Bucket]
20
- def bucket_create(bucket)
27
+ def bucket_save(bucket)
21
28
  raise NotImplementedError
22
29
  end
23
30
 
@@ -25,16 +32,15 @@ module Miasma
25
32
  #
26
33
  # @param bucket [Models::Storage::Bucket]
27
34
  # @return [TrueClass, FalseClass]
28
- def bucket_delete(bucket)
35
+ def bucket_destroy(bucket)
29
36
  raise NotImplementedError
30
37
  end
31
38
 
32
- # Rename bucket
39
+ # Reload the bucket
33
40
  #
34
41
  # @param bucket [Models::Storage::Bucket]
35
- # @param new_name [String]
36
- # @return [Models::Storage::Bucket] new bucket with updated name
37
- def bucket_rename(bucket, new_name)
42
+ # @return [Models::Storage::Bucket]
43
+ def bucket_reload(bucket)
38
44
  raise NotImplementedError
39
45
  end
40
46
 
@@ -53,7 +59,29 @@ module Miasma
53
59
  raise NotImplementedError
54
60
  end
55
61
 
62
+ # Save file
63
+ #
64
+ # @param file [Models::Storage::File]
65
+ # @return [Models::Storage::File]
66
+ def file_save(file)
67
+ raise NotImplementedError
68
+ end
56
69
 
70
+ # Destroy file
71
+ #
72
+ # @param file [Models::Storage::File]
73
+ # @return [TrueClass, FalseClass]
74
+ def file_destroy(file)
75
+ raise NotImplementedError
76
+ end
77
+
78
+ # Reload the file
79
+ #
80
+ # @param file [Models::Storage::File]
81
+ # @return [Models::Storage::File]
82
+ def file_reload(file)
83
+ raise NotImplementedError
84
+ end
57
85
 
58
86
  end
59
87
  end
@@ -6,27 +6,40 @@ module Miasma
6
6
  # Abstract bucket
7
7
  class Bucket < Types::Model
8
8
 
9
- attribute :metadata, Hash, :coerce => lambda{|o| o.to_smash}
9
+ attribute :name, String, :required => true
10
+ attribute :created, Time, :coerce => lambda{|t| Time.parse(t.to_s)}
11
+ attribute :metadata, Smash, :coerce => lambda{|o| o.to_smash}
12
+
13
+ # @return [Files]
14
+ def files
15
+ memoize(:files) do
16
+ Files.new(self)
17
+ end
18
+ end
10
19
 
11
20
  # Filter buckets
12
21
  #
13
22
  # @param filter [Hash]
14
23
  # @return [Array<Bucket>]
15
24
  def filter(filter={})
25
+ raise NotImplementedError
16
26
  end
17
27
 
18
- # Rename bucket
19
- #
20
- # @param new_name [String]
21
- # @return [self]
22
- def rename(new_name)
23
- perform_rename(new_name)
28
+ protected
29
+
30
+ # Proxy reload action up to the API
31
+ def perform_reload
32
+ api.bucket_reload(self)
24
33
  end
25
34
 
26
- protected
35
+ # Proxy save action up to the API
36
+ def perform_save
37
+ api.bucket_save(self)
38
+ end
27
39
 
28
- def perform_rename(new_name)
29
- api.bucket_rename(self, new_name)
40
+ # Proxy destroy action up to the API
41
+ def perform_destroy
42
+ api.bucket_destroy(self)
30
43
  end
31
44
 
32
45
  end
@@ -6,15 +6,18 @@ module Miasma
6
6
  class Storage
7
7
 
8
8
  # Abstract file
9
- class File < Types::Collection
9
+ class File < Types::Model
10
10
 
11
- attribute :body, IO, :coerce => lambda{|v| StringIO.new(v.to_s) }
11
+ attribute :name, String, :required => true
12
12
  attribute :content_type, String
13
13
  attribute :content_disposition, String
14
+ attribute :content_encoding, String
14
15
  attribute :etag, String
15
- attribute :last_modified, DateTime
16
+ attribute :updated, Time, :coerce => lambda{|t| Time.parse(t.to_s)}
16
17
  attribute :size, Integer
17
- attribute :metadata, Hash, :coerce => lambda{|o| o.to_smash}
18
+ attribute :metadata, Smash, :coerce => lambda{|o| o.to_smash}
19
+
20
+ on_missing :reload
18
21
 
19
22
  # @return [Bucket] parent bucket
20
23
  attr_reader :bucket
@@ -38,6 +41,43 @@ module Miasma
38
41
  raise NotImplementedError
39
42
  end
40
43
 
44
+ # @return [IO-ish]
45
+ # @note object returned will provide #readpartial
46
+ def body
47
+ unless(attributes[:body])
48
+ data[:body] ||= api.file_body(self)
49
+ end
50
+ attributes[:body]
51
+ end
52
+
53
+ # Set file body
54
+ #
55
+ # @param io [IO, String]
56
+ # @return [IO]
57
+ def body=(io)
58
+ unless(io.is_a?(IO))
59
+ io = StringIO.new(io)
60
+ end
61
+ dirty[:body] = io
62
+ end
63
+
64
+ protected
65
+
66
+ # Proxy reload action up to the API
67
+ def perform_reload
68
+ api.file_reload(self)
69
+ end
70
+
71
+ # Proxy save action up to the API
72
+ def perform_save
73
+ api.file_save(self)
74
+ end
75
+
76
+ # Proxy destroy action up to the API
77
+ def perform_destroy
78
+ api.file_destroy(self)
79
+ end
80
+
41
81
  end
42
82
 
43
83
  end
@@ -30,7 +30,12 @@ module Miasma
30
30
 
31
31
  # @return [File] new unsaved instance
32
32
  def build(args={})
33
- File.new(api, args.to_smash)
33
+ instance = self.model.new(bucket)
34
+ args.each do |m_name, m_value|
35
+ m_name = "#{m_name}="
36
+ instance.send(m_name, m_value)
37
+ end
38
+ instance
34
39
  end
35
40
 
36
41
  # @return [File] collection item class
@@ -75,8 +75,9 @@ module Miasma
75
75
  raise ArgumentError.new 'Invalid request method provided!'
76
76
  end
77
77
  request_args = [].tap do |ary|
78
+ _endpoint = args.delete(:endpoint) || endpoint
78
79
  ary.push(
79
- File.join(endpoint, args[:path].to_s)
80
+ File.join(_endpoint, args[:path].to_s)
80
81
  )
81
82
  options = {}.tap do |opts|
82
83
  [:form, :params, :json, :body].each do |key|
@@ -117,20 +118,25 @@ module Miasma
117
118
  # @return [Smash]
118
119
  def format_response(result)
119
120
  extracted_headers = Smash[result.headers.map{|k,v| [Utils.snake(k), v]}]
120
- if(extracted_headers[:content_type].include?('application/json'))
121
+ if(extracted_headers[:content_type].to_s.end_with?('json'))
121
122
  begin
122
123
  extracted_body = MultiJson.load(result.body.to_s).to_smash
123
124
  rescue MultiJson::ParseError
124
125
  extracted_body = result.body.to_s
125
126
  end
126
- elsif(extracted_headers[:content_type].include?('text/xml'))
127
+ elsif(extracted_headers[:content_type].to_s.end_with?('xml'))
127
128
  begin
128
129
  extracted_body = MultiXml.parse(result.body.to_s).to_smash
129
130
  rescue MultiXml::ParseError
130
131
  extracted_body = result.body.to_s
131
132
  end
132
133
  else
133
- extracted_body = result.body.to_s
134
+ # @note if body is over 100KB, do not extract
135
+ if(extracted_headers[:content_length].to_i < 102400)
136
+ extracted_body = result.body.to_s
137
+ else
138
+ extracted_body = result.body
139
+ end
134
140
  end
135
141
  Smash.new(
136
142
  :response => result,
@@ -6,6 +6,8 @@ module Miasma
6
6
  # Base model
7
7
  class Model < Data
8
8
 
9
+ include Utils::Memoization
10
+
9
11
  # @return [Miasma::Types::Api] underlying service API
10
12
  attr_reader :api
11
13
 
@@ -35,7 +37,7 @@ module Miasma
35
37
  @dirty = Smash.new
36
38
  if(model_data)
37
39
  if(model_data.is_a?(Hash))
38
- load_data(model_data)
40
+ load_data(model_data) unless model_data.empty?
39
41
  else
40
42
  raise TypeError.new "Expecting `model_data` to be of type `Hash`. Received: `#{model_data.class}`"
41
43
  end
@@ -73,6 +75,7 @@ module Miasma
73
75
  #
74
76
  # @return [self]
75
77
  def reload
78
+ clear_memoizations!
76
79
  perform_reload
77
80
  self
78
81
  end
@@ -182,8 +182,13 @@ module Miasma
182
182
  if(param.is_a?(Symbol))
183
183
  @missing_method = param
184
184
  else
185
- if(@missing_method)
186
- param.send(@missing_method)
185
+ if(@missing_method && !@calling_on_missing)
186
+ @calling_on_missing = true
187
+ begin
188
+ param.send(@missing_method)
189
+ ensure
190
+ @calling_on_missing = false
191
+ end
187
192
  end
188
193
  @missing_method
189
194
  end
@@ -1,4 +1,4 @@
1
1
  module Miasma
2
2
  # current library version
3
- VERSION = Gem::Version.new('0.1.0')
3
+ VERSION = Gem::Version.new('0.2.0')
4
4
  end
@@ -14,5 +14,6 @@ Gem::Specification.new do |s|
14
14
  s.add_dependency 'http'
15
15
  s.add_dependency 'multi_json'
16
16
  s.add_dependency 'multi_xml'
17
- s.files = Dir['lib/**/*'] + %w(miasma.gemspec README.md CHANGELOG.md)
17
+ s.add_dependency 'xml-simple'
18
+ s.files = Dir['lib/**/*'] + %w(miasma.gemspec README.md CHANGELOG.md LICENSE)
18
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miasma
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-16 00:00:00.000000000 Z
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: xml-simple
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: Smoggy API
70
84
  email: code@chrisroberts.org
71
85
  executables: []
@@ -73,6 +87,7 @@ extensions: []
73
87
  extra_rdoc_files: []
74
88
  files:
75
89
  - CHANGELOG.md
90
+ - LICENSE
76
91
  - README.md
77
92
  - lib/miasma.rb
78
93
  - lib/miasma/contrib/aws.rb
@@ -80,6 +95,10 @@ files:
80
95
  - lib/miasma/contrib/aws/compute.rb
81
96
  - lib/miasma/contrib/aws/load_balancer.rb
82
97
  - lib/miasma/contrib/aws/orchestration.rb
98
+ - lib/miasma/contrib/aws/storage.rb
99
+ - lib/miasma/contrib/open_stack.rb
100
+ - lib/miasma/contrib/open_stack/compute.rb
101
+ - lib/miasma/contrib/open_stack/orchestration.rb
83
102
  - lib/miasma/contrib/rackspace.rb
84
103
  - lib/miasma/contrib/rackspace/auto_scale.rb
85
104
  - lib/miasma/contrib/rackspace/compute.rb