zygote 0.2.11 → 0.2.12

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e1710f705eaf6deb71e1287c48ccb34aa694ac5
4
- data.tar.gz: dc68648147162e92d2769f3c61dc24bf5d795fa9
3
+ metadata.gz: 79f6d6d816134c8cfadd3335a62a59c5c199da29
4
+ data.tar.gz: 95426b7b07578c63f29d74c3eeb54385abe66ba1
5
5
  SHA512:
6
- metadata.gz: 50fd707aff6f9d087059356a75c2265a31d154d5195e398dfe1a3216edfd14e45e2df69e1961c6442c708157a8b5dcd4883acc27b9a91b3320509d5f23f051f4
7
- data.tar.gz: 055e5c78d9cb948f3e42b0a7ef9a2c40f04488ff3b82641303ac56febf4ed374f152aea0d58e2a0c662417d7f7a30288eee63a04fa4e832a9f42c5b0a2bb3e08
6
+ metadata.gz: 59fbfb4088ae7fe0adbd49c0b5a172ce943d6cb20b5fa876f37277e01a0b16cce8bfeb905ed27e2281b1c9ceed6998131fb12fe67a8518bcd283f5f7b8577e07
7
+ data.tar.gz: dc120384aad70375fd37cb4ce71c9ca003f639c0e2b6045b7540cbe4c991862a254064912be1b48d8a9aed299eada522ec578aa2537c473e607c38ded37d0d3d
@@ -1,49 +1,51 @@
1
1
  require 'zygote/memory'
2
2
 
3
- # An entry into the queue
4
- class CellQueueEntry < SuperModel::Base
5
- include SuperModel::Marshal::Model
6
- end
3
+ module Zygote
4
+ # An entry into the queue
5
+ class CellQueueEntry < SuperModel::Base
6
+ include SuperModel::Marshal::Model
7
+ end
7
8
 
8
- # A means of storing Cell queue data for a given sku
9
- module CellQueue
10
- extend self
11
- COLLECTION = :assets
12
- ARRAY_KEY = :cell_queue
13
- Memory.load
9
+ # A means of storing Cell queue data for a given sku
10
+ module CellQueue
11
+ extend self
12
+ COLLECTION = :assets
13
+ ARRAY_KEY = :cell_queue
14
+ Memory.load
14
15
 
15
- def push(key, data)
16
- entry = CellQueueEntry.find_by_name(key)
17
- unless entry
18
- entry = CellQueueEntry.new(name: key, data: [])
16
+ def push(key, data)
17
+ entry = CellQueueEntry.find_by_name(key)
18
+ unless entry
19
+ entry = CellQueueEntry.new(name: key, data: [])
20
+ entry.save
21
+ end
22
+ entry.data << data
19
23
  entry.save
24
+ Memory.save
20
25
  end
21
- entry.data << data
22
- entry.save
23
- Memory.save
24
- end
25
26
 
26
- def shift(key)
27
- entry = CellQueueEntry.find_by_name(key)
28
- return nil unless entry
29
- first = entry.data.shift
30
- entry.save
31
- Memory.save
32
- first
33
- end
27
+ def shift(key)
28
+ entry = CellQueueEntry.find_by_name(key)
29
+ return nil unless entry
30
+ first = entry.data.shift
31
+ entry.save
32
+ Memory.save
33
+ first
34
+ end
34
35
 
35
- def show(key)
36
- entry = CellQueueEntry.find_by_name(key)
37
- entry ? entry.data : []
38
- end
36
+ def show(key)
37
+ entry = CellQueueEntry.find_by_name(key)
38
+ entry ? entry.data : []
39
+ end
39
40
 
40
- def purge(key)
41
- entry = CellQueueEntry.find_by_name(key)
42
- entry.data = [] if entry
43
- entry.save if entry
44
- end
41
+ def purge(key)
42
+ entry = CellQueueEntry.find_by_name(key)
43
+ entry.data = [] if entry
44
+ entry.save if entry
45
+ end
45
46
 
46
- def all
47
- CellQueueEntry.all
47
+ def all
48
+ CellQueueEntry.all
49
+ end
48
50
  end
49
51
  end
@@ -8,130 +8,126 @@ require 'rack/contrib'
8
8
 
9
9
  require 'zygote/util'
10
10
  require 'zygote/cell_queue'
11
+ require 'zygote/identifier'
12
+
13
+ # Main zygote container namespace
14
+ module Zygote
15
+ # Main HTTP class, handles routing methods
16
+ # Uses sinatra format (all sinatra docs on routing methods apply)
17
+ class Web < Sinatra::Base
18
+ register Sinatra::Async
19
+
20
+ use ::Rack::PostBodyContentTypeParser
21
+
22
+ # Throw exceptions so we can catch and nicely log them
23
+ set :raise_errors, true
24
+ set :show_exceptions, false
25
+ set :dump_errors, false
26
+
27
+ # Requested by iPXE on boot, chains into /boot.
28
+ # This enables us to customize what details we want iPXE to send us
29
+ # The iPXE undionly.kpxe should contain an embedded script to call this URL
30
+ aget '/' do
31
+ body { erb :boot }
32
+ end
11
33
 
12
- # Main HTTP class, handles routing methods
13
- # Uses sinatra format (all sinatra docs on routing methods apply)
14
- class ZygoteWeb < Sinatra::Base
15
- register Sinatra::Async
16
-
17
- use ::Rack::PostBodyContentTypeParser
18
-
19
- # Throw exceptions so we can catch and nicely log them
20
- set :raise_errors, true
21
- set :show_exceptions, false
22
- set :dump_errors, false
23
-
24
- # Requested by iPXE on boot, chains into /boot.
25
- # This enables us to customize what details we want iPXE to send us
26
- # The iPXE undionly.kpxe should contain an embedded script to call this URL
27
- aget '/' do
28
- body { erb :boot }
29
- end
30
-
31
- # Chainload the primary menu
32
- aget '/chain' do
33
- # Clean params into a simple hash
34
- cleaned = clean_params(params.to_h)
35
- # Add the request ip into the params
36
- ip = request.ip == '127.0.0.1' ? @env['HTTP_X_FORWARDED_FOR'] : request.ip
37
- ip = '127.0.0.1' if ENV['TESTING'] || ip.nil? || ip.empty?
38
- cleaned['ip'] = ip
39
- # Compute SKU from parameters
40
- sku = compute_sku(cleaned['manufacturer'], cleaned['serial'], cleaned['board-serial'])
41
- cleaned['sku'] = sku
42
- # Check if there are is any queued data for this SKU, and if so, merge it in to params
43
- queued_data = CellQueue.shift(sku)
44
- cleaned.merge!(queued_data) if queued_data
45
- body { erb :menu, locals: { opts: ZygoteWeb.cell_config.merge('params' => cleaned || {}) } }
46
- end
47
-
48
- [ :aget, :apost ].each do |method|
49
- send method, %r{/cell/(?<cell>\S*)/(?<action>\S*)$} do
50
- # Render an action for a particular cell
34
+ # Chainload the primary menu
35
+ aget '/chain' do
51
36
  # Clean params into a simple hash
52
37
  cleaned = clean_params(params.to_h)
53
- # Add the cell to the parameters
54
- cell = cleaned['cell']
55
- # Merge the cleaned params in with any cell options
56
- cell_opts = ZygoteWeb.cell_config['index']['cells'][cell] || {}
57
- opts = cell_opts.merge('params' => cleaned || {})
58
- body { erb :"#{cell}/#{cleaned['action']}".to_sym, locals: { opts: opts } }
38
+ # Add the request ip into the params
39
+ ip = request.ip == '127.0.0.1' ? @env['HTTP_X_FORWARDED_FOR'] : request.ip
40
+ ip = '127.0.0.1' if ENV['TESTING'] || ip.nil? || ip.empty?
41
+ cleaned['ip'] = ip
42
+ # Compute SKU from parameters
43
+ sku = compute_sku(cleaned['manufacturer'], cleaned['serial'], cleaned['board-serial'])
44
+ cleaned['sku'] = sku
45
+ # Check if there are is any queued data for this SKU, and if so, merge it in to params
46
+ queued_data = CellQueue.shift(sku)
47
+ cleaned.merge!(queued_data) if queued_data
48
+
49
+ # Provide a hook for an external identifier to alter behavior
50
+ cleaned = Zygote::Identifier.identify(cleaned)
51
+ body { erb :menu, locals: { opts: Zygote::Web.cell_config.merge('params' => cleaned || {}) } }
59
52
  end
60
- end
61
-
62
- # Show the queue for a SKU
63
- aget %r{/queue/(?<sku>\S*)$} do
64
- body { JSON.pretty_generate(CellQueue.show(params['sku'])) }
65
- end
66
53
 
67
- aget %r{/queue} do
68
- response = {}
69
- CellQueue.all.each do |queue_entry|
70
- response[queue_entry.name] = queue_entry.data
54
+ [:aget, :apost].each do |method|
55
+ send method, %r{/cell/(?<cell>\S*)/(?<action>\S*)$} do
56
+ # Render an action for a particular cell
57
+ # Clean params into a simple hash
58
+ cleaned = clean_params(params.to_h)
59
+ # Add the cell to the parameters
60
+ cell = cleaned['cell']
61
+ # Merge the cleaned params in with any cell options
62
+ cell_opts = Zygote::Web.cell_config['index']['cells'][cell] || {}
63
+ opts = cell_opts.merge('params' => cleaned || {})
64
+ body { erb :"#{cell}/#{cleaned['action']}".to_sym, locals: { opts: opts } }
65
+ end
71
66
  end
72
- body { JSON.pretty_generate(response) }
73
- end
74
-
75
- # Delete the queue for a SKU
76
- adelete %r{/queue$} do
77
- CellQueue.purge(params['sku'])
78
- body { JSON.pretty_generate(CellQueue.show(params['sku'])) }
79
- end
80
-
81
- # Enable push cells (with optional data) to the cell queue for a SKU
82
- apost %r{/queue/(?<sku>\S*)/(?<selected_cell>\S*)$} do
83
- # Clean params into a simple hash
84
- cleaned = clean_params(params.to_h)
85
- # Enqueue some data for this sku
86
- sku = cleaned.delete('sku')
87
- CellQueue.push(sku, cleaned)
88
- body { JSON.pretty_generate(CellQueue.show(sku)) }
89
- end
90
-
91
- def self::cell_config
92
- @@cell_config
93
- end
94
-
95
- def self::cell_config=(value)
96
- @@cell_config = value
97
- end
98
67
 
99
- def self::views
100
- @@views
101
- end
68
+ # Show the queue for a SKU
69
+ aget %r{/queue/(?<sku>\S*)$} do
70
+ body { JSON.pretty_generate(CellQueue.show(params['sku'])) }
71
+ end
102
72
 
103
- def self::views=(value)
104
- @@views = value
105
- end
73
+ aget %r{/queue} do
74
+ response = {}
75
+ CellQueue.all.each do |queue_entry|
76
+ response[queue_entry.name] = queue_entry.data
77
+ end
78
+ body { JSON.pretty_generate(response) }
79
+ end
106
80
 
107
- helpers do
108
- # Enable partial template rendering
109
- def partial(template, locals = {})
110
- erb(template, layout: false, locals: locals)
81
+ # Delete the queue for a SKU
82
+ adelete %r{/queue$} do
83
+ CellQueue.purge(params['sku'])
84
+ body { JSON.pretty_generate(CellQueue.show(params['sku'])) }
111
85
  end
112
86
 
113
- # Override template search directorys to add spells
114
- def find_template(_views, *a, &block)
115
- Array(ZygoteWeb.views).each { |v| super(v, *a, &block) }
87
+ # Enable push cells (with optional data) to the cell queue for a SKU
88
+ apost %r{/queue/(?<sku>\S*)/(?<selected_cell>\S*)$} do
89
+ # Clean params into a simple hash
90
+ cleaned = clean_params(params.to_h)
91
+ # Enqueue some data for this sku
92
+ sku = cleaned.delete('sku')
93
+ CellQueue.push(sku, cleaned)
94
+ body { JSON.pretty_generate(CellQueue.show(sku)) }
116
95
  end
117
96
 
118
- # Define our asynchronous scheduling mechanism, could be anything
119
- # Chose EM.defer for simplicity
120
- # This powers our asynchronous requests, and keeps us from blocking the main thread.
121
- def native_async_schedule(&b)
122
- EM.defer(&b)
97
+ class << self
98
+ attr_accessor :cell_config
99
+ attr_accessor :views
123
100
  end
124
101
 
125
- # Needed to properly catch exceptions in async threads
126
- def handle_exception!(context)
127
- if context.message == 'Sinatra::NotFound'
128
- error_msg = "Resource #{request.path} does not exist"
129
- puts error_msg
130
- ahalt(404, error_msg)
131
- else
132
- puts context.message
133
- puts context.backtrace.join("\n")
134
- ahalt(500, 'Uncaught exception occurred')
102
+ helpers do
103
+ # Enable partial template rendering
104
+ def partial(template, locals = {})
105
+ erb(template.to_sym, layout: false, locals: locals)
106
+ end
107
+
108
+ # Override template search directorys to add spells
109
+ def find_template(_views, *a, &block)
110
+ Array(Zygote::Web.views).each { |v| super(v, *a, &block) }
111
+ end
112
+
113
+ # Define our asynchronous scheduling mechanism, could be anything
114
+ # Chose EM.defer for simplicity
115
+ # This powers our asynchronous requests, and keeps us from blocking the main thread.
116
+ def native_async_schedule(&b)
117
+ EM.defer(&b)
118
+ end
119
+
120
+ # Needed to properly catch exceptions in async threads
121
+ def handle_exception!(context)
122
+ if context.message == 'Sinatra::NotFound'
123
+ error_msg = "Resource #{request.path} does not exist"
124
+ puts error_msg
125
+ ahalt(404, error_msg)
126
+ else
127
+ puts context.message
128
+ puts context.backtrace.join("\n")
129
+ ahalt(500, 'Uncaught exception occurred')
130
+ end
135
131
  end
136
132
  end
137
133
  end
@@ -0,0 +1,35 @@
1
+ module Zygote
2
+ # Provides a hook for identifiers to alter boot-time behavior
3
+ # To do so, extend this class with a new identify method.
4
+ # You may NOT define more than one identifier - the last one wins.
5
+ # class MyIdentifier < Zygote::Identifier
6
+ # def identify
7
+ # mutate_params(@params)
8
+ # end
9
+ # end
10
+ class Identifier
11
+ class << self
12
+ def inherited(subclass)
13
+ @identifier = subclass
14
+ end
15
+
16
+ def identify(params)
17
+ @identifier ||= self
18
+ @identifier.new(params).identify
19
+ end
20
+
21
+ def reset!
22
+ @identifier = self
23
+ end
24
+ end
25
+
26
+ def initialize(params)
27
+ @params = params
28
+ end
29
+
30
+ # Called only if this class is never subclassed
31
+ def identify
32
+ @params
33
+ end
34
+ end
35
+ end
@@ -3,24 +3,27 @@ require 'fileutils'
3
3
 
4
4
  require 'supermodel'
5
5
 
6
- # A simple means of persistence
7
- # This can easily be swapped out for redis, but file-based is simpler and good enough for now
8
- # https://github.com/maccman/supermodel/blob/master/README
9
- module Memory
10
- extend self
11
- DATABASE_PATH = (ENV['DATABASE_PATH'] || File.expand_path('../data/memory.db', $PROGRAM_NAME)).freeze
12
- SuperModel::Marshal.path = DATABASE_PATH
6
+ # Zygote container
7
+ module Zygote
8
+ # A simple means of persistence
9
+ # This can easily be swapped out for redis, but file-based is simpler and good enough for now
10
+ # https://github.com/maccman/supermodel/blob/master/README
11
+ module Memory
12
+ extend self
13
+ DATABASE_PATH = (ENV['DATABASE_PATH'] || File.expand_path('../data/memory.db', $PROGRAM_NAME)).freeze
14
+ SuperModel::Marshal.path = DATABASE_PATH
13
15
 
14
- def save
15
- FileUtils.mkdir_p(File.dirname(DATABASE_PATH)) # FIXME: - don't make if it already exists
16
- SuperModel::Marshal.dump
17
- end
16
+ def save
17
+ FileUtils.mkdir_p(File.dirname(DATABASE_PATH)) # FIXME: - don't make if it already exists
18
+ SuperModel::Marshal.dump
19
+ end
18
20
 
19
- def load
20
- SuperModel::Marshal.load
21
+ def load
22
+ SuperModel::Marshal.load
23
+ end
21
24
  end
22
- end
23
25
 
24
- at_exit do
25
- Memory.save
26
+ at_exit do
27
+ Memory.save
28
+ end
26
29
  end
@@ -1,44 +1,53 @@
1
1
  require 'zygote/http'
2
2
  require 'thin'
3
3
 
4
- class ZygoteServer
5
- def initialize(port: 7000, threads:1000, host: '0.0.0.0', config_path: nil, cells: [], debug:false)
6
- debug ||= ENV['DEBUG']
4
+ # Main zygote namespace
5
+ module Zygote
6
+ # Wrapper around thin / event machine to run zygote sinatra rack app in.
7
+ class Server
8
+ def initialize(port: 7000, threads: 1000, host: '0.0.0.0', config_path: nil, cells: [], debug: false)
9
+ debug ||= ENV['DEBUG']
7
10
 
8
- cell_config = YAML.load(File.read(config_path || File.join(Dir.pwd, 'config', 'cells.yml')))
9
- ZygoteWeb.views = [File.expand_path('../../../views', __FILE__), cells].flatten
10
- ZygoteWeb.cell_config = cell_config
11
- if debug
12
- $stdout.sync = true
13
- $stderr.sync = true
14
- end
11
+ cell_config = YAML.load(File.read(config_path || File.join(Dir.pwd, 'config', 'cells.yml')))
12
+ Zygote::Web.views = [File.expand_path('../../../views', __FILE__), cells].flatten
13
+ Zygote::Web.cell_config = cell_config
14
+ if debug
15
+ $stdout.sync = true
16
+ $stderr.sync = true
17
+ end
15
18
 
16
- app = ZygoteWeb.new
17
- dispatch = Rack::Builder.app do
18
- map '/' do
19
- run app
19
+ app = Zygote::Web.new
20
+ dispatch = Rack::Builder.app do
21
+ map '/' do
22
+ run app
23
+ end
20
24
  end
25
+ Thin::Logging.trace = true if debug
26
+ @server = Thin::Server.new(port, host, dispatch, threadpool_size: threads).backend
21
27
  end
22
- Thin::Logging.trace=true if debug
23
- @server = Thin::Server.new(port, host, dispatch, threadpool_size: threads).backend
24
- end
25
28
 
26
- def start
27
- @server.start
28
- rescue => ex
29
- puts ex
30
- puts ex.backtrace.join("\n")
31
- end
32
-
33
- def run
34
- EM.run do
35
- init_sighandlers
29
+ def start
36
30
  @server.start
31
+ rescue => ex
32
+ puts ex
33
+ puts ex.backtrace.join("\n")
34
+ end
35
+
36
+ def run
37
+ EM.run do
38
+ init_sighandlers
39
+ @server.start
40
+ end
37
41
  end
38
42
  end
39
- end
40
43
 
41
- def init_sighandlers
42
- Signal.trap('INT') { 'Got interrupt'; EM.stop; exit }
43
- Signal.trap('TERM') { 'Got term'; EM.stop; exit }
44
+ def init_sighandlers
45
+ clean_quit = lambda do
46
+ EM.stop
47
+ exit
48
+ end
49
+
50
+ Signal.trap('INT') { clean_quit.call }
51
+ Signal.trap('TERM') { clean_quit.call }
52
+ end
44
53
  end
@@ -6,7 +6,9 @@ require 'rspec'
6
6
  require 'em-synchrony'
7
7
  require 'em-synchrony/em-http'
8
8
 
9
+ # Main zygote class
9
10
  module Zygote
11
+ # Helper to set up test config
10
12
  module TestConfig
11
13
  extend self
12
14
  attr_reader :config_path, :cells, :port, :fixtures
@@ -24,7 +26,7 @@ module Zygote
24
26
  mod.class_eval %[
25
27
  around(:each) do |example|
26
28
  EM.synchrony do
27
- ZygoteServer.new(
29
+ Zygote::Server.new(
28
30
  config_path: TestConfig.config_path,
29
31
  cells: TestConfig.cells
30
32
  ).start
@@ -70,7 +72,7 @@ module Zygote
70
72
 
71
73
  # Returns EventMachine::HttpClient
72
74
  def post(uri, params = {})
73
- EM::Synchrony.sync(EventMachine::HttpRequest.new("http://127.0.0.1:#{TestConfig.port}/#{uri}").apost(body: JSON.dump(params), head: {'Content-Type' => 'application/json'}))
75
+ EM::Synchrony.sync(EventMachine::HttpRequest.new("http://127.0.0.1:#{TestConfig.port}/#{uri}").apost(body: JSON.dump(params), head: { 'Content-Type' => 'application/json' }))
74
76
  end
75
77
 
76
78
  def parameterize(params)
@@ -26,7 +26,7 @@ end
26
26
 
27
27
  def clean_params(params)
28
28
  params.delete_if { |x, _| x == 'splat' || x == 'captures' }
29
- params = params.map { |k,v| [k, v.is_a?(Hash) ? encode64(v) : v] }.to_h
29
+ params = params.map { |k, v| [k, v.is_a?(Hash) ? encode64(v) : v] }.to_h
30
30
  params
31
31
  end
32
32
 
@@ -1,4 +1,4 @@
1
1
  # Namespace for our gem
2
2
  module Zygote
3
- VERSION = '0.2.11'.freeze
3
+ VERSION = '0.2.12'.freeze
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zygote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.11
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dale Hamel
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - '='
179
179
  - !ruby/object:Gem::Version
180
180
  version: 3.2.0
181
+ - !ruby/object:Gem::Dependency
182
+ name: rubocop
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 0.40.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 0.40.0
181
195
  description: Automate baremetal server actions with iPXE
182
196
  email: dale.hamel@srvthe.net
183
197
  executables: []
@@ -187,6 +201,7 @@ files:
187
201
  - lib/zygote.rb
188
202
  - lib/zygote/cell_queue.rb
189
203
  - lib/zygote/http.rb
204
+ - lib/zygote/identifier.rb
190
205
  - lib/zygote/memory.rb
191
206
  - lib/zygote/server.rb
192
207
  - lib/zygote/test.rb
@@ -214,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
229
  version: '0'
215
230
  requirements: []
216
231
  rubyforge_project:
217
- rubygems_version: 2.4.8
232
+ rubygems_version: 2.2.3
218
233
  signing_key:
219
234
  specification_version: 4
220
235
  summary: Differentiate servers with iPXE