cloud_powers 0.2.7.23 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.test.env.example +6 -6
  4. data/.travis.yml +1 -1
  5. data/README +190 -0
  6. data/cloud_powers.gemspec +4 -4
  7. data/lib/cloud_powers.rb +3 -13
  8. data/lib/cloud_powers/aws_resources.rb +21 -4
  9. data/lib/cloud_powers/creatable.rb +122 -0
  10. data/lib/cloud_powers/helpers.rb +58 -0
  11. data/lib/cloud_powers/helpers/lang_help.rb +288 -0
  12. data/lib/cloud_powers/helpers/logic_help.rb +152 -0
  13. data/lib/cloud_powers/helpers/path_help.rb +90 -0
  14. data/lib/cloud_powers/node.rb +69 -68
  15. data/lib/cloud_powers/node/instance.rb +52 -0
  16. data/lib/cloud_powers/resource.rb +44 -0
  17. data/lib/cloud_powers/storage.rb +27 -14
  18. data/lib/{stubs → cloud_powers/stubs}/aws_stubs.rb +37 -14
  19. data/lib/cloud_powers/synapse/broadcast.rb +117 -0
  20. data/lib/cloud_powers/synapse/broadcast/channel.rb +44 -0
  21. data/lib/cloud_powers/synapse/pipe.rb +211 -0
  22. data/lib/cloud_powers/synapse/pipe/stream.rb +41 -0
  23. data/lib/cloud_powers/synapse/queue.rb +357 -0
  24. data/lib/cloud_powers/synapse/queue/board.rb +61 -95
  25. data/lib/cloud_powers/synapse/queue/poller.rb +29 -0
  26. data/lib/cloud_powers/synapse/synapse.rb +10 -12
  27. data/lib/cloud_powers/synapse/web_soc.rb +13 -0
  28. data/lib/cloud_powers/synapse/web_soc/soc_client.rb +52 -0
  29. data/lib/cloud_powers/synapse/web_soc/soc_server.rb +48 -0
  30. data/lib/cloud_powers/version.rb +1 -1
  31. data/lib/cloud_powers/zenv.rb +13 -12
  32. metadata +24 -13
  33. data/lib/cloud_powers/context.rb +0 -275
  34. data/lib/cloud_powers/delegator.rb +0 -113
  35. data/lib/cloud_powers/helper.rb +0 -453
  36. data/lib/cloud_powers/synapse/websocket/websocclient.rb +0 -53
  37. data/lib/cloud_powers/synapse/websocket/websocserver.rb +0 -46
  38. data/lib/cloud_powers/workflow_factory.rb +0 -160
@@ -0,0 +1,58 @@
1
+ require 'logger'
2
+ require 'syslog/logger'
3
+ require 'cloud_powers/helpers/lang_help'
4
+ require 'cloud_powers/helpers/logic_help'
5
+ require 'cloud_powers/helpers/path_help'
6
+
7
+ module Smash
8
+ module CloudPowers
9
+ module Helpers
10
+ # methods to help change convert between different cases, like the
11
+ # <tt>from_json</tt> and <tt>to_camel</tt> and other help with Ruby
12
+ include Smash::CloudPowers::LangHelp
13
+ # methods to help awareness, dynamic code and other such fun
14
+ include Smash::CloudPowers::LogicHelp
15
+ # methods to help find locations of files and directories. This provides
16
+ # common locations for code to reference.
17
+ include Smash::CloudPowers::PathHelp
18
+
19
+ # creates a default logger
20
+ #
21
+ # Parameters
22
+ # * log_to +String+ (optional) - location to send logging information to; default is STDOUT
23
+ #
24
+ # Returns
25
+ # +Logger+
26
+ #
27
+ # Notes
28
+ # * TODO: at least make this have overridable defaults
29
+ def create_logger(log_to = STDOUT)
30
+ logger = Logger.new(log_to)
31
+ logger.datetime_format = '%Y-%m-%d %H:%M:%S'
32
+ logger
33
+ end
34
+
35
+ # Gets the path from the environment and sets @log_file using the path
36
+ #
37
+ # Returns
38
+ # @log_file +String+
39
+ #
40
+ # Notes
41
+ # * See +#zfind()+
42
+ def log_file
43
+ @log_file ||= zfind('LOG_FILE')
44
+ end
45
+
46
+ # Returns An instance of Logger, cached as @logger@log_file path <String>
47
+ #
48
+ # Returns
49
+ # +Logger+
50
+ #
51
+ # Notes
52
+ # * See +#create_logger+
53
+ def logger
54
+ @logger ||= create_logger
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,288 @@
1
+ module Smash
2
+ module CloudPowers
3
+ module LangHelp
4
+
5
+ # Allows you to modify all keys, including nested, with a block that you pass.
6
+ # If no block is passed, a copy is returned.
7
+ #
8
+ # Parameters
9
+ # * params +Hash+|+Array+ - hash to be modified
10
+ # * +block+ (optional) - a block to be used to modify each key should
11
+ # modify the key and return that value so it can be used in the copy
12
+ #
13
+ # Returns
14
+ # +Hash+|+Array+ - a copy of the given Array or Hash, with all Hash keys modified
15
+ #
16
+ # Example
17
+ # hash = { 'foo' => 'v1', 'bar' => { fleep: { 'florp' => 'yo' } } }
18
+ # modify_keys_with(hash) { |key| key.to_sym }
19
+ # # => { foo: 'v1', bar: { fleep: { florp: 'yo' } } }
20
+ #
21
+ # Notes
22
+ # * see `#modify_keys_with()` for handling first-level keys
23
+ # * see `#pass_the_buck()` for the way nested structures are handled
24
+ # * case for different types taken from _MultiXML_ (multi_xml.rb)
25
+ # * TODO: look at optimization
26
+ def deep_modify_keys_with(params)
27
+ case params
28
+ when Hash
29
+ params.inject({}) do |carry, (k, v)|
30
+ carry.tap do |h|
31
+ if block_given?
32
+ key = yield k
33
+
34
+ value = if v.kind_of?(Hash)
35
+ deep_modify_keys_with(v) { |new_key| Proc.new.call(new_key) }
36
+ else
37
+ v
38
+ end
39
+
40
+ h[key] = value
41
+ else
42
+ h[k] = v
43
+ end
44
+ end
45
+ end
46
+ when Array
47
+ params.map{ |value| symbolize_keys(value) }
48
+ else
49
+ params
50
+ end
51
+ end
52
+
53
+ # Search through a +Hash+ without knowing if the key is a +String+ or
54
+ # +Symbol+. A +String+ modification that _normalizes_ each value to compare
55
+ # is used that is case insensitive. It only leaves word characters, not
56
+ # including underscore. After the value is found, if it exists and can
57
+ # be found, the +Hash+, minus that value, is returns in an +Array+ with
58
+ # the element you were searching for
59
+ #
60
+ # Parameters
61
+ # * key +String+|+Symbol+ - the key you are searching for
62
+ # * hash +Hash+ - the +Hash+ to search through and return a modified copy
63
+ # from
64
+ def find_and_remove(key, hash)
65
+ candidate_keys = hash.select do |k,v|
66
+ to_pascal(key).casecmp(to_pascal(k)) == 0
67
+ end.keys
68
+
69
+ interesting_value = hash.delete(candidate_keys.first)
70
+ [interesting_value, hash]
71
+ end
72
+
73
+ # Join the message and backtrace into a String with line breaks
74
+ #
75
+ # Parameters
76
+ # * error +Exception+
77
+ #
78
+ # Returns
79
+ # +String+
80
+ def format_error_message(error)
81
+ begin
82
+ [error.message, error.backtrace.join("\n")].join("\n")
83
+ rescue Exception
84
+ # if the formatting won't work, return the original exception
85
+ error
86
+ end
87
+ end
88
+
89
+ # Change valid JSON into a hash
90
+ #
91
+ # Parameter
92
+ # * var +String+
93
+ #
94
+ # Returns
95
+ # +Hash+ or +nil+ - +nil+ is returned if the JSON is invalid
96
+ def from_json(var)
97
+ begin
98
+ JSON.parse(var)
99
+ rescue JSON::ParserError, TypeError
100
+ nil
101
+ end
102
+ end
103
+
104
+ # Allows you to modify all first-level keys with a block that you pass.
105
+ # If no block is passed, a copy is returned.
106
+ #
107
+ # Parameters
108
+ # * params +Hash+|+Array+
109
+ # * block (optional) - should modify the key and return that value so it can be used in the copy
110
+ #
111
+ # Returns
112
+ # +Hash+|+Array+ - a copy of the given Array or Hash, with all Hash keys modified
113
+ #
114
+ # Example
115
+ # hash = { 'foo' => 'v1', 'bar' => { fleep: { 'florp' => 'yo' } } }
116
+ # modify_keys_with(hash) { |k| k.to_sym }
117
+ # # => { :foo => 'v1', :bar => { fleep: { 'florp' => 'yo' } } }
118
+ #
119
+ # Notes
120
+ # * see +#deep_modify_keys_with()+ for handling nested keys
121
+ # * case for different types taken from _MultiXML_ (multi_xml.rb)
122
+ def modify_keys_with(params)
123
+ params.inject({}) do |carry, (k, v)|
124
+ carry.tap do |h|
125
+ key = block_given? ? (yield k) : k
126
+ h[key] = v
127
+ end
128
+ end
129
+ end
130
+
131
+ # Change strings into camelCase
132
+ #
133
+ # Parameters
134
+ # * var +String+
135
+ #
136
+ # Returns
137
+ # +String+
138
+ def to_camel(var)
139
+ var = var.to_s unless var.kind_of? String
140
+ step_one = to_snake(var)
141
+ step_two = to_pascal(step_one)
142
+ step_two[0, 1].downcase + step_two[1..-1]
143
+ end
144
+
145
+ # Change strings into a hyphen delimited phrase
146
+ #
147
+ # Parameters
148
+ # * var +String+
149
+ #
150
+ # Returns
151
+ # +String+
152
+ def to_hyph(var)
153
+ var = var.to_s unless var.kind_of? String
154
+
155
+ var.gsub(/:{2}|\//, '-').
156
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
157
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
158
+ gsub(/\s+/, '-').
159
+ tr("_", "-").
160
+ gsub(/^\W/, '').
161
+ downcase
162
+ end
163
+
164
+ # Assure your arguments are a +Hash+
165
+ #
166
+ # Parameters
167
+ # * start_point +Object+ - Best to start with a +Hash+, then a 2-D Array,
168
+ # then something +Enumerable+ that is at least Ordered
169
+ #
170
+ # Returns
171
+ # +Hash+
172
+ #
173
+ # Notes
174
+ # * If a +Hash+ is given, a copy is returned
175
+ # * If an +Array+ is given,
176
+ # * And if the +Array+ is a properly formatted, 2-D +Array+, <tt>to_h</tt>
177
+ # is called
178
+ # * Else <tt>Hash[<default_key argument>, <the thing we're trying to turn into a hash>]</tt>
179
+ def to_basic_hash(start_point, default_key: 'key')
180
+ case start_point
181
+ when Hash
182
+ start_point
183
+ when Enumerable
184
+ two_dimensional_elements = start_point.select do |value|
185
+ value.respond_to? :each
186
+ end
187
+
188
+ if two_dimensional_elements.count - start_point.count
189
+ start_point.to_h
190
+ else
191
+ Hash[default_key, start_point]
192
+ end
193
+ else
194
+ Hash[default_key, start_point]
195
+ end
196
+ end
197
+
198
+ # Change strings into an i-var format
199
+ #
200
+ # Parameters
201
+ # * var +String+
202
+ #
203
+ # Returns
204
+ # +String+
205
+ def to_i_var(var)
206
+ var = var.to_s unless var.kind_of? String
207
+ /^\W*@\w+/ =~ var ? to_snake(var) : "@#{to_snake(var)}"
208
+ end
209
+
210
+ # Change strings into PascalCase
211
+ #
212
+ # Parameters
213
+ # * var +String+
214
+ #
215
+ # Returns
216
+ # +String+
217
+ def to_pascal(var)
218
+ var = var.to_s unless var.kind_of? String
219
+ var.gsub(/^(.{1})|\W.{1}|\_.{1}/) { |s| s.gsub(/[^a-z0-9]+/i, '').capitalize }
220
+ end
221
+
222
+ # Change strings into a ruby_file_name with extension
223
+ #
224
+ # Parameters
225
+ # * var +String+
226
+ #
227
+ # Returns
228
+ # +String+
229
+ #
230
+ # Notes
231
+ # * given_string.rb
232
+ # * includes ruby file extension
233
+ # * see #to_snake()
234
+ def to_ruby_file_name(name)
235
+ return name if /\w+\.rb$/ =~ name
236
+ "#{to_snake(name)}.rb"
237
+ end
238
+
239
+ # Change strings into PascalCase
240
+ #
241
+ # Parameters
242
+ # * var +String+
243
+ #
244
+ # Returns
245
+ # +String+
246
+ #
247
+ # Notes
248
+ # * given_string
249
+ # * will not have file extensions
250
+ # * see #to_ruby_file_name()
251
+ def to_snake(var)
252
+ var = var.to_s unless var.kind_of? String
253
+
254
+ var.gsub(/:{2}|\//, '_').
255
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
256
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
257
+ gsub(/\s+/, '_').
258
+ tr("-", "_").
259
+ downcase
260
+ end
261
+
262
+ # Predicate method to check if a String is parsable, as JSON
263
+ #
264
+ # Parameters
265
+ # * json +String+
266
+ #
267
+ # Returns
268
+ # +Boolean+
269
+ #
270
+ # Notes
271
+ # * See <tt>from_json</tt>
272
+ def valid_json?(json)
273
+ !!from_json(json)
274
+ end
275
+
276
+ # Predicate method to check if a String is a valid URL
277
+ #
278
+ # Parameters
279
+ # * url +String+
280
+ #
281
+ # Returns
282
+ # +Boolean+
283
+ def valid_url?(url)
284
+ url =~ /\A#{URI::regexp}\z/
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,152 @@
1
+ module Smash
2
+ module CloudPowers
3
+ module LogicHelp
4
+ # Sets an Array of instance variables, individually to a value that a
5
+ # user given block returns.
6
+ #
7
+ # Parameters
8
+ #
9
+ # * keys +Array+
10
+ # * * each object will be used as the name for the instance variable that
11
+ # your block returns
12
+ # +block+ (optional)
13
+ # * this block is called for each object in the Array and is used as the value
14
+ # for the instance variable that is being named and created for each key
15
+ # Returns +Array+ - each object will either be the result of
16
+ # <tt>#instance_variable_set(key, value)</tt> => +value+
17
+ # or instance_variable_get(key)
18
+ # Example
19
+ # keys = ['foo', 'bar', 'yo']
20
+ #
21
+ # attr_map!(keys) { |key| sleep 1; "#{key}:#{Time.now.to_i}" }
22
+ # # => ['foo:1475434058', 'bar:1475434059', 'yo:1475434060']
23
+ #
24
+ # puts @bar
25
+ # # => 'bar:1475434059'
26
+ def attr_map(attributes)
27
+ attributes = [attributes, nil] unless attributes.respond_to? :map
28
+
29
+ attributes.inject(self) do |this, (attribute, before_value)|
30
+ first_place, second_place = yield attribute, before_value if block_given?
31
+
32
+ results = if second_place.nil?
33
+ [attribute, first_place]
34
+ else
35
+ [first_place, second_place]
36
+ end
37
+
38
+ this.instance_variable_set(to_i_var(results.first), results.last)
39
+ this
40
+ end
41
+ end
42
+
43
+ # Does its best job at guessing where this method was called from, in terms
44
+ # of where it is located on the file system. It helps track down where a
45
+ # project root is etc.
46
+ #
47
+ # Returns
48
+ # +String+
49
+ #
50
+ # Notes
51
+ # * Uses +$0+ to figure out what the current file is
52
+ def called_from
53
+ File.expand_path(File.dirname($0))
54
+ end
55
+
56
+ # Create an <tt>attr_accessor</tt> feeling getter and setter for an instance
57
+ # variable. The method doesn't create a getter or setter if it is already
58
+ # defined.
59
+ #
60
+ # Parameters
61
+ # * base_name +String+ - the name, without the '@' symbol
62
+ # # ok
63
+ # add_instance_attr_accessor('my_variable_name', my_value)
64
+ # => <your_instance @my_variable_name=my_value, ...>
65
+ # # not ok
66
+ # add_instance_attr_accessor('@#!!)', my_value)
67
+ # => <your_instance> <i>no new instance variable found</i>
68
+ # * value +Object+ - the actual instance variable that matches the +base_name+
69
+ #
70
+ # Returns
71
+ # * the value of the instance variable that matches the +base_name+ (first) argument
72
+ #
73
+ # Notes
74
+ # * if a matching getter or setter method can be found, this method won't
75
+ # stomp on it. nothing happens, in that case
76
+ # * if an appropriately named instance variable can't be found, the getter
77
+ # method will return nil until you set it again.
78
+ # * <b>it is the responsibility of you and me to make sure our variable names
79
+ # are valid, i.e. proper Ruby instance variable names
80
+ def instance_attr_accessor(base_name)
81
+ i_var_name = to_i_var(base_name)
82
+ getter_signature = to_snake(base_name)
83
+ setter_signature = "#{getter_signature}="
84
+
85
+ unless respond_to? getter_signature
86
+ define_singleton_method(getter_signature) do
87
+ instance_variable_get(i_var_name)
88
+ end
89
+ end
90
+
91
+ unless respond_to? setter_signature
92
+ define_singleton_method(setter_signature) do |argument|
93
+ instance_variable_set(i_var_name, argument)
94
+ end
95
+ end
96
+ end
97
+
98
+ # Lets you retry a piece of logic with 1 second sleep in between attempts
99
+ # until another bit of logic does what it's supposed to, kind of like
100
+ # continuing to poll something and doing something when a package is ready
101
+ # to be taken and processed.
102
+ #
103
+ # Parameters
104
+ # * allowed_attempts +Number+|+Infinity(default)+ - The number of times
105
+ # the loop should be allowed to...well, loop, before a failed retry occurs.
106
+ # * &test +Block+ - A predicate method or block of code that is callable
107
+ # is used to test if the block being retried is successful yet.
108
+ # * []
109
+ #
110
+ # Example
111
+ # check_stuff = lambda { |params| return true }
112
+ # smart_retry(3, check_stuff(params)) { do_stuff_that_needs_to_be_checked }
113
+ def smart_retry(test, allowed_attempts = Float::INFINITY)
114
+ result = yield if block_given?
115
+ tries = 1
116
+ until test.call(result) || tries >= allowed_attempts
117
+ result = yield if block_given?
118
+ tries += 1
119
+ sleep 1
120
+ end
121
+ end
122
+
123
+ # This method provides a default overrideable message body for things like
124
+ # basic status updates.
125
+ #
126
+ # Parameters
127
+ # * instanceId +Hash+
128
+ #
129
+ # Notes
130
+ # * camel casing is used on the keys because most other languages prefer
131
+ # that and it's not a huge problem in ruby. Besides, there's some other
132
+ # handy methods in this module to get you through those issues, like
133
+ # +#to_snake()+ and or +#modify_keys_with()+
134
+ def update_message_body(opts = {})
135
+ # TODO: Better implementation of merging message bodies and config needed
136
+ unless opts.kind_of? Hash
137
+ update = opts.to_s
138
+ opts = {}
139
+ opts[:extraInfo] = { message: update }
140
+ end
141
+ updated_extra_info = opts.delete(:extraInfo) || {}
142
+
143
+ {
144
+ instanceId: @instance_id || 'none-aquired',
145
+ type: 'status-update',
146
+ content: 'running',
147
+ extraInfo: updated_extra_info
148
+ }.merge(opts)
149
+ end
150
+ end
151
+ end
152
+ end