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
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 88 |
# File 'lib/sfn/provider.rb', line 41 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.
24 25 26 |
# File 'lib/sfn/provider.rb', line 24 def async @async end |
#connection ⇒ Miasma::Models::Orchestration (readonly)
18 19 20 |
# File 'lib/sfn/provider.rb', line 18 def connection @connection end |
#logger ⇒ Logger, NilClass (readonly)
Returns logger in use.
26 27 28 |
# File 'lib/sfn/provider.rb', line 26 def logger @logger end |
#stack_expansion_interval ⇒ Numeric (readonly)
Returns interval between stack expansions.
28 29 30 |
# File 'lib/sfn/provider.rb', line 28 def stack_expansion_interval @stack_expansion_interval end |
#stack_list_interval ⇒ Numeric (readonly)
Returns interval between stack list updates.
30 31 32 |
# File 'lib/sfn/provider.rb', line 30 def stack_list_interval @stack_list_interval end |
#updater ⇒ Thread, NilClass
Returns stack list updater.
22 23 24 |
# File 'lib/sfn/provider.rb', line 22 def updater @updater end |
Instance Method Details
#cached_stacks(stack_id = nil) ⇒ String
Returns json representation of cached stacks.
96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/sfn/provider.rb', line 96 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 value ? MultiJson.dump(MultiJson.load(value).values) : '[]' end |
#expand_stack(stack) ⇒ Object
Expand all lazy loaded attributes within stack
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/sfn/provider.rb', line 146 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
171 172 173 174 175 176 177 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 |
# File 'lib/sfn/provider.rb', line 171 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
132 133 134 135 136 137 138 139 140 141 |
# File 'lib/sfn/provider.rb', line 132 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
118 119 120 121 122 123 124 125 126 |
# File 'lib/sfn/provider.rb', line 118 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
231 232 233 |
# File 'lib/sfn/provider.rb', line 231 def service_for(service) connection.api_for(service) end |
#stack(stack_id) ⇒ Miasma::Orchestration::Stack, NilClass
109 110 111 |
# File 'lib/sfn/provider.rb', line 109 def stack(stack_id) stacks(stack_id).get(stack_id) end |
#stacks(stack_id = nil) ⇒ Miasma::Orchestration::Stacks
91 92 93 |
# File 'lib/sfn/provider.rb', line 91 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
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/sfn/provider.rb', line 209 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 |