cloud_powers 0.2.7.23 → 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.
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