Class: Sfn::Provider
- Inherits:
-
Object
- Object
- Sfn::Provider
- Includes:
- Bogo::AnimalStrings
- Defined in:
- lib/sfn/provider.rb
Overview
Remote provider interface
Constant Summary collapse
- STACK_EXPAND_INTERVAL =
Minimum number of seconds to wait before re-expanding in progress stack
45
- STACK_LIST_INTERVAL =
Default interval for refreshing stack list in cache
120
Instance Attribute Summary collapse
-
#async ⇒ TrueClass, FalseClass
readonly
Async updates.
- #cache ⇒ Cache readonly
- #connection ⇒ Miasma::Models::Orchestration readonly
-
#logger ⇒ Logger, NilClass
readonly
Logger in use.
-
#stack_expansion_interval ⇒ Numeric
readonly
Interval between stack expansions.
-
#stack_list_interval ⇒ Numeric
readonly
Interval between stack list updates.
-
#updater ⇒ Thread, NilClass
Stack list updater.
Instance Method Summary collapse
-
#cached_stacks(stack_id = nil) ⇒ String
Json representation of cached stacks.
-
#expand_stack(stack) ⇒ Object
Expand all lazy loaded attributes within stack.
-
#fetch_stacks(stack_id = nil) ⇒ TrueClass
Request stack information and store in cache.
-
#initialize(args = {}) ⇒ Provider
constructor
Create new instance.
-
#remove_stack(stack_id) ⇒ TrueClass, FalseClass
Remove stack from the cache.
-
#save_expanded_stack(stack_id, stack_attributes) ⇒ TrueClass
Store stack attribute changes.
-
#service_for(service) ⇒ Miasma::Model
Build API connection for service type.
- #stack(stack_id) ⇒ Miasma::Orchestration::Stack, NilClass
- #stacks(stack_id = nil) ⇒ Miasma::Orchestration::Stacks
-
#update_stack_list! ⇒ TrueClass, FalseClass
Start async stack list update.
Constructor Details
#initialize(args = {}) ⇒ Provider
Create new instance
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/sfn/provider.rb', line 40 def initialize(args = {}) args = args.to_smash unless args.get(:miasma, :provider) best_guess = (args[:miasma] || {}).keys.group_by do |key| key.to_s.split("_").first end.sort do |x, y| y.size <=> x.size end.first if best_guess provider = best_guess.first.to_sym else raise ArgumentError.new "Cannot auto determine :provider value for credentials" end else provider = args[:miasma].delete(:provider).to_sym end if provider == :aws if args[:miasma][:region] args[:miasma][:aws_region] = args[:miasma].delete(:region) end end if ENV["DEBUG"].to_s.downcase == "true" log_to = STDOUT else if Gem.win_platform? log_to = "NUL" else log_to = "/dev/null" end end @logger = args.fetch(:logger, Logger.new(log_to)) @stack_expansion_interval = args.fetch(:stack_expansion_interval, STACK_EXPAND_INTERVAL) @stack_list_interval = args.fetch(:stack_list_interval, STACK_LIST_INTERVAL) @connection = Miasma.api( :provider => provider, :type => :orchestration, :credentials => args[:miasma], ) @cache = args.fetch(:cache, Cache.new(:local)) @async = args.fetch(:async, true) @miasma_args = args[:miasma].dup cache.init(:stacks_lock, :lock, :timeout => 0.1) cache.init(:stacks, :stamped) cache.init(:stack_expansion_lock, :lock, :timeout => 0.1) if args.fetch(:fetch, false) async ? update_stack_list! : fetch_stacks end end |
Instance Attribute Details
#async ⇒ TrueClass, FalseClass (readonly)
Returns async updates.
23 24 25 |
# File 'lib/sfn/provider.rb', line 23 def async @async end |
#connection ⇒ Miasma::Models::Orchestration (readonly)
17 18 19 |
# File 'lib/sfn/provider.rb', line 17 def connection @connection end |
#logger ⇒ Logger, NilClass (readonly)
Returns logger in use.
25 26 27 |
# File 'lib/sfn/provider.rb', line 25 def logger @logger end |
#stack_expansion_interval ⇒ Numeric (readonly)
Returns interval between stack expansions.
27 28 29 |
# File 'lib/sfn/provider.rb', line 27 def stack_expansion_interval @stack_expansion_interval end |
#stack_list_interval ⇒ Numeric (readonly)
Returns interval between stack list updates.
29 30 31 |
# File 'lib/sfn/provider.rb', line 29 def stack_list_interval @stack_list_interval end |
#updater ⇒ Thread, NilClass
Returns stack list updater.
21 22 23 |
# File 'lib/sfn/provider.rb', line 21 def updater @updater end |
Instance Method Details
#cached_stacks(stack_id = nil) ⇒ String
Returns json representation of cached stacks.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/sfn/provider.rb', line 95 def cached_stacks(stack_id = nil) if !@initial_fetch_complete || stack_id recache = true if stack_id && @initial_fetch_complete recache = !!stacks.get(stack_id) end fetch_stacks(stack_id) if recache end value = cache[:stacks].value if value value = MultiJson.load(value) if value.respond_to?(:values) value = value.values end MultiJson.dump(value) else "[]" end end |
#expand_stack(stack) ⇒ Object
Expand all lazy loaded attributes within stack
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/sfn/provider.rb', line 153 def (stack) logger.info "Stack expansion requested (#{stack.id})" if ((stack.in_progress? && Time.now.to_i - stack.attributes["Cached"].to_i > stack_expansion_interval) || !stack.attributes["Cached"]) begin = false cache.locked_action(:stack_expansion_lock) do = true stack.reload stack.data["Cached"] = Time.now.to_i end if (stack.id, stack.to_json) end rescue => e logger.error "Stack expansion failed (#{stack.id}) - #{e.class}: #{e}" end else logger.info "Stack has been cached within expand interval. Expansion prevented. (#{stack.id})" end end |
#fetch_stacks(stack_id = nil) ⇒ TrueClass
Request stack information and store in cache
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/sfn/provider.rb', line 178 def fetch_stacks(stack_id = nil) cache.locked_action(:stacks_lock) do logger.info "Lock aquired for stack update. Requesting stacks from upstream. (#{Thread.current})" if stack_id single_stack = connection.stacks.get(stack_id) stacks = single_stack ? {single_stack.id => single_stack} : {} else stacks = Hash[ connection.stacks.reload.all.map do |stack| [stack.id, stack.attributes] end ] end if cache[:stacks].value existing_stacks = MultiJson.load(cache[:stacks].value) # Force common types stacks = MultiJson.load(MultiJson.dump(stacks)) if stack_id stacks = existing_stacks.to_smash.deep_merge(stacks) else # Remove stacks that have been deleted stale_ids = existing_stacks.keys - stacks.keys stacks = existing_stacks.to_smash.deep_merge(stacks) stale_ids.each do |stale_id| stacks.delete(stale_id) end end end cache[:stacks].value = stacks.to_json logger.info "Stack list has been updated from upstream and cached locally" end @initial_fetch_complete = true end |
#remove_stack(stack_id) ⇒ TrueClass, FalseClass
Remove stack from the cache
139 140 141 142 143 144 145 146 147 148 |
# File 'lib/sfn/provider.rb', line 139 def remove_stack(stack_id) current_stacks = MultiJson.load(cached_stacks) logger.info "Attempting to remove stack from internal cache (#{stack_id})" cache.locked_action(:stacks_lock) do val = current_stacks.delete(stack_id) logger.info "Successfully removed stack from internal cache (#{stack_id})" cache[:stacks].value = MultiJson.dump(current_stacks) !!val end end |
#save_expanded_stack(stack_id, stack_attributes) ⇒ TrueClass
Store stack attribute changes
125 126 127 128 129 130 131 132 133 |
# File 'lib/sfn/provider.rb', line 125 def (stack_id, stack_attributes) current_stacks = MultiJson.load(cached_stacks) cache.locked_action(:stacks_lock) do logger.info "Saving expanded stack attributes in cache (#{stack_id})" current_stacks[stack_id] = stack_attributes.merge("Cached" => Time.now.to_i) cache[:stacks].value = MultiJson.dump(current_stacks) end true end |
#service_for(service) ⇒ Miasma::Model
Build API connection for service type
238 239 240 |
# File 'lib/sfn/provider.rb', line 238 def service_for(service) connection.api_for(service) end |
#stack(stack_id) ⇒ Miasma::Orchestration::Stack, NilClass
116 117 118 |
# File 'lib/sfn/provider.rb', line 116 def stack(stack_id) stacks(stack_id).get(stack_id) end |
#stacks(stack_id = nil) ⇒ Miasma::Orchestration::Stacks
90 91 92 |
# File 'lib/sfn/provider.rb', line 90 def stacks(stack_id = nil) connection.stacks.from_json(cached_stacks(stack_id)) end |
#update_stack_list! ⇒ TrueClass, FalseClass
Start async stack list update. Creates thread that loops every ‘self.stack_list_interval` seconds and refreshes stack list in cache
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/sfn/provider.rb', line 216 def update_stack_list! if updater.nil? || !updater.alive? self.updater = Thread.new { loop do begin fetch_stacks sleep(stack_list_interval) rescue => e logger.error "Failure encountered on stack fetch: #{e.class} - #{e}" end end } true else false end end |