zygote 0.0.0 → 0.0.1
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 +4 -4
- data/lib/zygote.rb +4 -0
- data/lib/{cell_queue.rb → zygote/cell_queue.rb} +5 -1
- data/lib/{http.rb → zygote/http.rb} +50 -20
- data/lib/{memory.rb → zygote/memory.rb} +0 -0
- data/lib/{util.rb → zygote/util.rb} +0 -0
- data/lib/zygote/version.rb +4 -0
- data/views/boot.erb +14 -0
- data/views/menu.erb +118 -0
- metadata +136 -7
- data/lib/chef.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6453638ec4693e43b0a13c53933f4f8e2f7e2273
|
4
|
+
data.tar.gz: 998e036ab3605422f0d3efd18b36e722f06c5ba9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cca8f9c8f57e42fceb778d7f5e1ee79f64255c28ad92c32ea2e0a33fc657ba0e57d7ad769ae17c4fb3f68952a028285044bb2b0a964e6369d84ce36e111834bd
|
7
|
+
data.tar.gz: 56d20bf591b3dd195762c9a4e3151e8e8837b924703c94a95cf879c21b584c3b7744a765e8c8afc931ed7b74bc90b5a29391002d71169fad64b2acfe1524afd2
|
data/lib/zygote.rb
ADDED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'memory'
|
1
|
+
require 'zygote/memory'
|
2
2
|
|
3
3
|
# An entry into the queue
|
4
4
|
class CellQueueEntry < SuperModel::Base
|
@@ -42,4 +42,8 @@ module CellQueue
|
|
42
42
|
entry.data = [] if entry
|
43
43
|
entry.save if entry
|
44
44
|
end
|
45
|
+
|
46
|
+
def all()
|
47
|
+
CellQueueEntry.all
|
48
|
+
end
|
45
49
|
end
|
@@ -4,14 +4,12 @@ require 'genesisreactor'
|
|
4
4
|
require 'genesis/protocol/http'
|
5
5
|
require 'active_support/all'
|
6
6
|
|
7
|
-
require 'util'
|
8
|
-
require 'cell_queue'
|
9
|
-
require 'chef'
|
7
|
+
require 'zygote/util'
|
8
|
+
require 'zygote/cell_queue'
|
10
9
|
|
11
10
|
# Main HTTP class, handles routing methods
|
12
11
|
# Uses sinatra format (all sinatra docs on routing methods apply)
|
13
12
|
class ZygoteWeb < Genesis::Http::Handler
|
14
|
-
CELL_CONFIG = YAML.load(File.read(File.expand_path('../../config/cells.yml', __FILE__))).freeze
|
15
13
|
|
16
14
|
# Requested by iPXE on boot, chains into /boot.
|
17
15
|
# This enables us to customize what details we want iPXE to send us
|
@@ -35,35 +33,56 @@ class ZygoteWeb < Genesis::Http::Handler
|
|
35
33
|
queued_data = CellQueue.shift(sku)
|
36
34
|
cleaned.merge!(queued_data) if queued_data
|
37
35
|
@channel << cleaned
|
38
|
-
body { erb :menu, locals: { opts:
|
36
|
+
body { erb :menu, locals: { opts: ZygoteWeb::cell_config.merge('params' => cleaned || {}) } }
|
39
37
|
end
|
40
38
|
|
41
39
|
# Render an action for a particular cell
|
42
|
-
get %r{/cell/(?<cell>\S*)/(?<action>\S*)} do
|
40
|
+
get %r{/cell/(?<cell>\S*)/(?<action>\S*)$} do
|
43
41
|
# Clean params into a simple hash
|
44
42
|
cleaned = clean_params(params.to_h)
|
45
43
|
# Add the cell to the parameters
|
46
44
|
cell = cleaned['cell']
|
47
45
|
# Merge the cleaned params in with any cell options
|
48
|
-
cell_opts =
|
46
|
+
cell_opts = ZygoteWeb::cell_config['index']['cells'][cell] || {}
|
49
47
|
opts = cell_opts.merge('params' => cleaned || {})
|
50
48
|
@channel << opts # for debugging
|
51
49
|
body { erb :"#{cell}/#{cleaned['action']}".to_sym, locals: { opts: opts } }
|
52
50
|
end
|
53
51
|
|
54
52
|
# Show the queue for a SKU
|
55
|
-
get %r{/queue/(?<sku>\S*)} do
|
53
|
+
get %r{/queue/(?<sku>\S*)$} do
|
56
54
|
body { JSON.pretty_generate(CellQueue.show(params['sku'])) }
|
57
55
|
end
|
58
56
|
|
57
|
+
get %r{/queue} do
|
58
|
+
response = {}
|
59
|
+
CellQueue.all.each do |queue_entry|
|
60
|
+
response[queue_entry.name] = queue_entry.data
|
61
|
+
end
|
62
|
+
body { JSON.pretty_generate(response)}
|
63
|
+
end
|
64
|
+
|
59
65
|
# Delete the queue for a SKU
|
60
|
-
delete
|
66
|
+
delete %r{/queue$} do
|
61
67
|
CellQueue.purge(params['sku'])
|
62
68
|
body { JSON.pretty_generate(CellQueue.show(params['sku'])) }
|
63
69
|
end
|
64
70
|
|
71
|
+
post %r{/queue/bulk$} do
|
72
|
+
|
73
|
+
bulk_queue = JSON.parse(request.body.read)
|
74
|
+
bulk_queue.each do |asset, queue|
|
75
|
+
queue = [queue] unless queue.is_a?(Array)
|
76
|
+
queue.each do |action|
|
77
|
+
CellQueue.push(asset, action)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
200
|
82
|
+
end
|
83
|
+
|
65
84
|
# Enable push cells (with optional data) to the cell queue for a SKU
|
66
|
-
post %r{/queue/(?<sku>\S*)/(?<
|
85
|
+
post %r{/queue/(?<sku>\S*)/(?<selected_cell>\S*)$} do
|
67
86
|
# Clean params into a simple hash
|
68
87
|
cleaned = clean_params(params.to_h)
|
69
88
|
# Enqueue some data for this sku
|
@@ -75,22 +94,33 @@ class ZygoteWeb < Genesis::Http::Handler
|
|
75
94
|
subscribe do |args|
|
76
95
|
puts args if ENV['DEBUG']
|
77
96
|
end
|
97
|
+
|
98
|
+
def ZygoteWeb::cell_config
|
99
|
+
@@cell_config
|
100
|
+
end
|
101
|
+
|
102
|
+
def ZygoteWeb::cell_config= (value)
|
103
|
+
@@cell_config = value
|
104
|
+
end
|
78
105
|
end
|
79
106
|
|
80
|
-
def zygote
|
107
|
+
def zygote(port: 7000, threads:1000, config_path: nil, cells: [], debug:false)
|
108
|
+
debug ||= ENV['DEBUG']
|
109
|
+
|
110
|
+
cell_config= YAML.load(File.read(config_path || File.join(Dir.pwd, 'config', 'cells.yml')))
|
111
|
+
ZygoteWeb::cell_config = cell_config
|
81
112
|
zygote = Genesis::Reactor.new(
|
82
|
-
threads:
|
113
|
+
threads: threads,
|
83
114
|
protocols: {
|
84
|
-
Genesis::Http::Protocol =>
|
115
|
+
Genesis::Http::Protocol => port
|
85
116
|
},
|
86
117
|
handlers: [ZygoteWeb],
|
87
|
-
views: [File.
|
88
|
-
debug:
|
118
|
+
views: [File.expand_path('../../../views', __FILE__), cells ].flatten,
|
119
|
+
debug: debug
|
89
120
|
)
|
121
|
+
if debug
|
122
|
+
$stdout.sync = true
|
123
|
+
$stderr.sync = true
|
124
|
+
end
|
90
125
|
zygote
|
91
126
|
end
|
92
|
-
|
93
|
-
if ENV['DEBUG']
|
94
|
-
$stdout.sync = true
|
95
|
-
$stderr.sync = true
|
96
|
-
end
|
File without changes
|
File without changes
|
data/views/boot.erb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!ipxe
|
2
|
+
# see http://etherboot.org/wiki/commandline for details on smbios strings
|
3
|
+
set boot-url http://${dhcp-server}/chain
|
4
|
+
|
5
|
+
set uri-params mac=${mac}
|
6
|
+
set uri-params ${uri-params}&serial=${serial}
|
7
|
+
set uri-params ${uri-params}&product=${product}
|
8
|
+
set uri-params ${uri-params}&manufacturer=${manufacturer}
|
9
|
+
set uri-params ${uri-params}&board-serial=${board-serial}
|
10
|
+
set uri-params ${uri-params}&board-product=${smbios/2.5.0}
|
11
|
+
set uri-params ${uri-params}&dhcp-server=${dhcp-server}
|
12
|
+
|
13
|
+
set boot-uri ${boot-url}?${uri-params}
|
14
|
+
chain --replace --autofree ${boot-uri} ||
|
data/views/menu.erb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
#!ipxe
|
2
|
+
|
3
|
+
# This template is shamelessly ripped off from https://gist.github.com/robinsmidsrod/2234639
|
4
|
+
# The most notable change is that we are of course dynamically generating the menu using cells.
|
5
|
+
|
6
|
+
<% index = opts['index'] %>
|
7
|
+
<% params = opts['params'] %>
|
8
|
+
<% cells = index['cells'] %>
|
9
|
+
|
10
|
+
# Allow bypassing the menu entirely by calling a specific target cell
|
11
|
+
<% if selected_cell = params['selected_cell'] %>
|
12
|
+
goto <%= selected_cell %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
###################### MAIN MENU ####################################
|
16
|
+
|
17
|
+
set menu-timeout <%= (params['menu_timout'] || index['timeout']) * 1000 %> # timeout is in milliseconds, so let's take seconds instead.
|
18
|
+
set submenu-timeout ${menu-timeout}
|
19
|
+
set menu-default exit
|
20
|
+
|
21
|
+
# This menu should be dynamically generated from cells, probably just make a metadata format
|
22
|
+
|
23
|
+
:start
|
24
|
+
menu iPXE boot menu for <%= params['sku'] || 'unknown' %> from <%= params['ip'] || 'unknown' %>
|
25
|
+
<% os_entries = cells.select{ |_,d| d['menu']['class'] == 'os'} %>
|
26
|
+
<% util_entries = cells.select{ |_,d| d['menu']['class'] == 'util'} %>
|
27
|
+
item --gap -- ------------------------- OS Installation --------------------------------
|
28
|
+
<% os_entries.each do | cell, data | %>
|
29
|
+
<% menu = data['menu'] %>
|
30
|
+
item --key <%= cell[0] %> <%= menu['submenu'] ? "submenu-#{cell}" : cell %> <%= menu['label'] %>
|
31
|
+
<% end %>
|
32
|
+
item --gap -- ------------------------- Tools and utilities ----------------------------
|
33
|
+
<% util_entries.each do | cell, data | %>
|
34
|
+
<% menu = data['menu'] %>
|
35
|
+
item --key <%= cell[0] %> <%= cell %> <%= menu['label'] %>
|
36
|
+
<% end %>
|
37
|
+
item --gap -- ------------------------- Advanced opts -------------------------------
|
38
|
+
item --key c config Configure settings
|
39
|
+
item shell Drop to iPXE shell
|
40
|
+
item reboot Reboot computer
|
41
|
+
item
|
42
|
+
item --key x exit Exit iPXE and continue BIOS boot
|
43
|
+
choose --timeout ${menu-timeout} --default ${menu-default} selected || goto cancel
|
44
|
+
set menu-timeout 0
|
45
|
+
goto ${selected}
|
46
|
+
|
47
|
+
# Generated menu entries for each cell
|
48
|
+
<% cells.each do | cell, _ | %>
|
49
|
+
<%= partial("#{cell}/menu".to_sym, :opts => opts) %>
|
50
|
+
<% end %>
|
51
|
+
|
52
|
+
# Render any submenus
|
53
|
+
<% submenus = cells.select{ |_,d| d['menu']['submenu'] } %>
|
54
|
+
<% submenus.each do |cell, data| %>
|
55
|
+
|
56
|
+
# Create the main submenu entry to render the submenu
|
57
|
+
:submenu-<%= cell %>
|
58
|
+
menu <%= data['menu']['label'] %>
|
59
|
+
|
60
|
+
# Add each entry to the submenu
|
61
|
+
<% data['menu']['submenu'].each do |entry, data| %>
|
62
|
+
item <%= cell %>-<%= entry %> <%= data['label'] %>
|
63
|
+
<% end %>
|
64
|
+
|
65
|
+
# Toss in the boilerplate footer
|
66
|
+
item
|
67
|
+
item --key 0x08 back Back to top menu...
|
68
|
+
choose --timeout ${submenu-timeout} --default ${submenu-default} selected || goto start
|
69
|
+
set submenu-timeout 0
|
70
|
+
goto ${selected}
|
71
|
+
|
72
|
+
# Now generate the boot entries for each submenu label
|
73
|
+
<% data['menu']['submenu'].each do |entry, data| %>
|
74
|
+
<% local_params = (data['params'] || {}).merge(params) %>
|
75
|
+
<% parmstr = {entry: entry}.merge(local_params).map{ |k,v| "#{k}=#{v}"}.join('&').gsub('?','').gsub(' ','') %>
|
76
|
+
:<%= cell %>-<%= entry %>
|
77
|
+
# FIXME: allow overriding the boot action here, but leave it as default
|
78
|
+
chain --replace --autofree http://${dhcp-server}/cell/<%= cell %>/boot<%= parmstr.empty? ? "" : "?#{parmstr}" %>
|
79
|
+
<% end %>
|
80
|
+
<% end %>
|
81
|
+
|
82
|
+
##########################################
|
83
|
+
|
84
|
+
:cancel
|
85
|
+
echo You cancelled the menu, dropping you to a shell
|
86
|
+
|
87
|
+
:shell
|
88
|
+
echo Type 'exit' to get the back to the menu
|
89
|
+
shell
|
90
|
+
set menu-timeout 0
|
91
|
+
set submenu-timeout 0
|
92
|
+
goto start
|
93
|
+
|
94
|
+
:failed
|
95
|
+
echo Booting failed, dropping to shell
|
96
|
+
goto shell
|
97
|
+
|
98
|
+
:reboot
|
99
|
+
reboot
|
100
|
+
|
101
|
+
:exit
|
102
|
+
# On dell servers exit causes a PXE boot loop.
|
103
|
+
# This tells the server to boot from first drive instead
|
104
|
+
# http://ipxe.org/cmd/sanboot
|
105
|
+
# http://ipxe.org/appnote/work_around_bios_halting_on_ipxe_exit
|
106
|
+
|
107
|
+
sanboot --no-describe --drive 0x80
|
108
|
+
#exit
|
109
|
+
|
110
|
+
:config
|
111
|
+
config
|
112
|
+
goto start
|
113
|
+
|
114
|
+
:back
|
115
|
+
set submenu-timeout 0
|
116
|
+
clear submenu-default
|
117
|
+
goto start
|
118
|
+
|
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.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dale Hamel
|
@@ -9,18 +9,147 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2015-11-24 00:00:00.000000000 Z
|
12
|
-
dependencies:
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: chef-provisioner
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.8
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.8
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: genesisreactor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.0.4
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.0.4
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: supermodel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.1.6
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.1.6
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.10.3
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.10.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-byebug
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.3.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.3.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: em-http-request
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.1.2
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.1.2
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 10.4.2
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 10.4.2
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.10.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.10.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 3.2.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 3.2.0
|
13
139
|
description: Automate baremetal server actions with iPXE
|
14
140
|
email: dale.hamel@srvthe.net
|
15
141
|
executables: []
|
16
142
|
extensions: []
|
17
143
|
extra_rdoc_files: []
|
18
144
|
files:
|
19
|
-
- lib/
|
20
|
-
- lib/
|
21
|
-
- lib/http.rb
|
22
|
-
- lib/memory.rb
|
23
|
-
- lib/util.rb
|
145
|
+
- lib/zygote.rb
|
146
|
+
- lib/zygote/cell_queue.rb
|
147
|
+
- lib/zygote/http.rb
|
148
|
+
- lib/zygote/memory.rb
|
149
|
+
- lib/zygote/util.rb
|
150
|
+
- lib/zygote/version.rb
|
151
|
+
- views/boot.erb
|
152
|
+
- views/menu.erb
|
24
153
|
homepage: http://rubygems.org/gems/zygote
|
25
154
|
licenses:
|
26
155
|
- MIT
|
data/lib/chef.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'chef-provisioner'
|
2
|
-
|
3
|
-
module ChefConfig
|
4
|
-
extend self
|
5
|
-
CLIENT_KEY_PATH = File.expand_path('../../tmp/client.pem', __FILE__).freeze
|
6
|
-
SECRETS_JSON_PATH = File.expand_path('../../config/secrets.json', __FILE__).freeze
|
7
|
-
CHEF_CONFIG_DATA = YAML.load(File.read(File.expand_path('../../config/chef.yml', __FILE__)))['chef'].freeze
|
8
|
-
|
9
|
-
def load
|
10
|
-
make_client_pem
|
11
|
-
ChefProvisioner::Chef.configure(endpoint: CHEF_CONFIG_DATA['endpoint'], key_path: CLIENT_KEY_PATH, client: CHEF_CONFIG_DATA['client'])
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def make_client_pem
|
17
|
-
key_data = JSON.load(File.read(SECRETS_JSON_PATH))['chef_client']
|
18
|
-
FileUtils.mkdir_p(File.dirname(CLIENT_KEY_PATH))
|
19
|
-
File.write(CLIENT_KEY_PATH, key_data)
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
ChefConfig.load unless ENV['TESTING']
|