zygote 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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']
|