staypuft 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/staypuft/nics_assignment.js +32 -0
- data/app/assets/javascripts/staypuft/staypuft.js +38 -0
- data/app/assets/javascripts/staypuft/subnets_assignment.js +40 -0
- data/app/assets/stylesheets/staypuft/bootstrap_and_overrides.css.scss +5 -1
- data/app/assets/stylesheets/staypuft/staypuft.css.scss +102 -0
- data/app/controllers/staypuft/deployments_controller.rb +5 -0
- data/app/controllers/staypuft/interface_assignments_controller.rb +76 -0
- data/app/controllers/staypuft/steps_controller.rb +15 -1
- data/app/controllers/staypuft/subnet_typings_controller.rb +42 -0
- data/app/helpers/staypuft/deployments_helper.rb +18 -3
- data/app/lib/actions/staypuft/hostgroup/deploy.rb +38 -1
- data/app/lib/staypuft/network_query.rb +35 -0
- data/app/lib/staypuft/seeder.rb +113 -39
- data/app/models/staypuft/concerns/host_interface_management.rb +28 -0
- data/app/models/staypuft/deployment.rb +35 -3
- data/app/models/staypuft/interface_assigner.rb +137 -0
- data/app/models/staypuft/layout.rb +3 -0
- data/app/models/staypuft/layout_subnet_type.rb +12 -0
- data/app/models/staypuft/role.rb +15 -0
- data/app/models/staypuft/subnet_type.rb +27 -0
- data/app/models/staypuft/subnet_typing.rb +11 -0
- data/app/views/staypuft/deployments/_assigned_hosts.html.erb +5 -2
- data/app/views/staypuft/deployments/_assigned_hosts_table.html.erb +13 -46
- data/app/views/staypuft/deployments/_deployed_hosts_table.html.erb +12 -33
- data/app/views/staypuft/deployments/_deployment_overview.html.erb +12 -9
- data/app/views/staypuft/deployments/_deployment_summary.html.erb +18 -0
- data/app/views/staypuft/deployments/_empty_hosts.html.erb +8 -0
- data/app/views/staypuft/deployments/_free_hosts.html.erb +1 -1
- data/app/views/staypuft/deployments/_free_hosts_table.html.erb +11 -34
- data/app/views/staypuft/deployments/_host_head_row.html.erb +11 -0
- data/app/views/staypuft/deployments/_host_row.html.erb +30 -0
- data/app/views/staypuft/deployments/_hosts_header.html.erb +7 -0
- data/app/views/staypuft/deployments/index.html.erb +1 -1
- data/app/views/staypuft/deployments/show.html.erb +2 -2
- data/app/views/staypuft/interface_assignments/create.js.erb +12 -0
- data/app/views/staypuft/interface_assignments/destroy.js.erb +12 -0
- data/app/views/staypuft/interface_assignments/index.html.erb +38 -0
- data/app/views/staypuft/interfaces/_drop_zone.html.erb +30 -0
- data/app/views/staypuft/steps/network_configuration.html.erb +52 -0
- data/app/views/staypuft/steps/services_configuration.html.erb +45 -39
- data/app/views/staypuft/steps/services_overview.html.erb +1 -1
- data/app/views/staypuft/subnet_types/_subnet_type_pull.html.erb +9 -0
- data/app/views/staypuft/subnet_typings/create.js.erb +12 -0
- data/app/views/staypuft/subnet_typings/destroy.js.erb +12 -0
- data/app/views/staypuft/subnet_typings/update.js.erb +14 -0
- data/app/views/staypuft/subnets/_drop_zone.html.erb +16 -0
- data/app/views/staypuft/subnets/_subnet_pull.html.erb +9 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20140701074900_create_subnet_type.rb +9 -0
- data/db/migrate/20140701075033_create_layout_subnet.rb +10 -0
- data/db/migrate/20140701090256_create_staypuft_subnet_typings.rb +14 -0
- data/db/migrate/20140825164900_add_orchestration_to_staypuft_role.rb +5 -0
- data/db/migrate/20140831234000_add_required_to_subnet_types.rb +5 -0
- data/db/seeds.rb +1 -1
- data/lib/staypuft/engine.rb +11 -8
- data/lib/staypuft/version.rb +1 -1
- metadata +135 -91
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21289b770a15e38194b88261c2de8622344538f5
|
4
|
+
data.tar.gz: d53a1a5ca729733020a5da1e539cd3c46f6422e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 08d0914ace7e6cfeadcc1f618bba70a765a3ff02ed933ffb5272d169a8b8e96654f333dd33dc3342742f6ac862476b7be31bd9e2e82e7543264f26b26c8766de
|
7
|
+
data.tar.gz: dab396f6ac46c3ca10b0f614ed42671a88a7ecef079887ee47457b96e53e2e169fb5af26236b458a7bcace11785e98268894eebb0bac0e7482da75eaad5833e7
|
@@ -0,0 +1,32 @@
|
|
1
|
+
$(function() {
|
2
|
+
$("div.subnet-pull.active").draggable({
|
3
|
+
revert: 'invalid'
|
4
|
+
});
|
5
|
+
|
6
|
+
$("div.interface").droppable({
|
7
|
+
activeClass: "ui-state-default",
|
8
|
+
hoverClass: "ui-state-hover",
|
9
|
+
accept: "div.subnet-pull",
|
10
|
+
drop: function(event, ui) {
|
11
|
+
$.ajax({
|
12
|
+
type: 'POST',
|
13
|
+
url: ui.draggable.data('create-url'),
|
14
|
+
data: 'interface=' + $(this).data('interface'),
|
15
|
+
dataType: 'script'
|
16
|
+
});
|
17
|
+
}
|
18
|
+
});
|
19
|
+
$("#subnets").droppable({
|
20
|
+
activeClass: "ui-state-default",
|
21
|
+
hoverClass: "ui-state-hover",
|
22
|
+
accept: "div.subnet-pull.existing",
|
23
|
+
drop: function(event, ui) {
|
24
|
+
$.ajax({
|
25
|
+
type: 'DELETE',
|
26
|
+
url: ui.draggable.data('delete-url'),
|
27
|
+
data: 'interface=' + ui.draggable.closest('div.interface').data('interface'),
|
28
|
+
dataType: 'script'
|
29
|
+
});
|
30
|
+
}
|
31
|
+
});
|
32
|
+
});
|
@@ -11,6 +11,8 @@
|
|
11
11
|
// GO AFTER THE REQUIRES BELOW.
|
12
12
|
//
|
13
13
|
//= require_tree .
|
14
|
+
//= require jquery.ui.draggable
|
15
|
+
//= require jquery.ui.droppable
|
14
16
|
|
15
17
|
$(function () {
|
16
18
|
// Check all checkboxes in table
|
@@ -48,6 +50,22 @@ $(function () {
|
|
48
50
|
$(this).siblings('.hidden_password, .shown_password').toggleClass('hide');
|
49
51
|
});
|
50
52
|
|
53
|
+
$('#ceph_notification_dismissal').click(function(e) {
|
54
|
+
e.preventDefault();
|
55
|
+
$('.ceph_notification').toggleClass('hide');
|
56
|
+
var pathname = window.location.pathname
|
57
|
+
var id = pathname.substring(pathname.lastIndexOf('/') + 1)
|
58
|
+
var cephDeploymentNotification = readFromCookie();
|
59
|
+
cephDeploymentNotification[id] = true
|
60
|
+
$.cookie('ceph-deployment-notification', JSON.stringify(cephDeploymentNotification))
|
61
|
+
});
|
62
|
+
function readFromCookie() {
|
63
|
+
if (r = $.cookie('ceph-deployment-notification'))
|
64
|
+
return $.parseJSON(r);
|
65
|
+
else
|
66
|
+
return {};
|
67
|
+
}
|
68
|
+
|
51
69
|
var duration = 150;
|
52
70
|
|
53
71
|
showPasswords();
|
@@ -127,6 +145,18 @@ $(function () {
|
|
127
145
|
}
|
128
146
|
}
|
129
147
|
|
148
|
+
showCephNotification();
|
149
|
+
function showCephNotification() {
|
150
|
+
var cephDeploymentNotification = readFromCookie();
|
151
|
+
var pathname = window.location.pathname;
|
152
|
+
var id = pathname.substring(pathname.lastIndexOf('/') + 1);
|
153
|
+
if (cephDeploymentNotification !== null && cephDeploymentNotification !== undefined) {
|
154
|
+
if (cephDeploymentNotification[id]) {
|
155
|
+
$('.ceph_notification').addClass('hide');
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
130
160
|
if ($('.configuration').length > 0) {
|
131
161
|
$('.configuration').find('li').first().find('a')[0].click();
|
132
162
|
}
|
@@ -186,6 +216,13 @@ $(function () {
|
|
186
216
|
$(window).scrollTop( 0 );
|
187
217
|
}
|
188
218
|
|
219
|
+
$('.dynamic-submit').click(function() {
|
220
|
+
this.form.action = $(this).data('submit-to');
|
221
|
+
this.form.method = $(this).data('method');
|
222
|
+
this.form.submit();
|
223
|
+
return false;
|
224
|
+
})
|
225
|
+
|
189
226
|
var free_host_checkboxes = $('#free-hosts table input:checkbox');
|
190
227
|
free_host_checkboxes.click(function(){
|
191
228
|
$("#assign_hosts_modal").attr("disabled", !free_host_checkboxes.is(":checked"));
|
@@ -194,6 +231,7 @@ $(function () {
|
|
194
231
|
var assigned_host_checkboxes = $('#assigned-hosts table input:checkbox');
|
195
232
|
assigned_host_checkboxes.click(function(){
|
196
233
|
$("#unassign_hosts_button").attr("disabled", !assigned_host_checkboxes.is(":checked"));
|
234
|
+
$("#configure_networks_button").attr("disabled", !assigned_host_checkboxes.is(":checked"));
|
197
235
|
});
|
198
236
|
|
199
237
|
var deployed_host_checkboxes = $('#deployed-hosts table input:checkbox');
|
@@ -0,0 +1,40 @@
|
|
1
|
+
$(function() {
|
2
|
+
$("div.subnet-type-pull").draggable({
|
3
|
+
revert: 'invalid'
|
4
|
+
});
|
5
|
+
|
6
|
+
$("div.subnet-drop-zone").droppable({
|
7
|
+
activeClass: "ui-state-default",
|
8
|
+
hoverClass: "ui-state-hover",
|
9
|
+
accept: "div.subnet-type-pull",
|
10
|
+
drop: function(event, ui) {
|
11
|
+
if(ui.draggable.hasClass('new')) {
|
12
|
+
$.ajax({
|
13
|
+
type: 'POST',
|
14
|
+
url: ui.draggable.data('create-url'),
|
15
|
+
data: 'subnet_type_id=' + ui.draggable.data('subnet-type-id') + '&subnet_id=' + $(this).data('subnet-id'),
|
16
|
+
dataType: 'script'
|
17
|
+
})
|
18
|
+
} else {
|
19
|
+
$.ajax({
|
20
|
+
type: 'PUT',
|
21
|
+
url: ui.draggable.data('update-url'),
|
22
|
+
data: 'subnet_id=' + $(this).data('subnet-id'),
|
23
|
+
dataType: 'script'
|
24
|
+
})
|
25
|
+
}
|
26
|
+
}
|
27
|
+
});
|
28
|
+
$("#subnet_types").droppable({
|
29
|
+
activeClass: "ui-state-default",
|
30
|
+
hoverClass: "ui-state-hover",
|
31
|
+
accept: "div.subnet-type-pull.existing",
|
32
|
+
drop: function(event, ui) {
|
33
|
+
$.ajax({
|
34
|
+
type: 'DELETE',
|
35
|
+
url: ui.draggable.data('delete-url'),
|
36
|
+
dataType: 'script'
|
37
|
+
});
|
38
|
+
}
|
39
|
+
});
|
40
|
+
});
|
@@ -46,6 +46,10 @@
|
|
46
46
|
padding: 19px 36px;
|
47
47
|
background-color: #f5f5f5;
|
48
48
|
@include center-block;
|
49
|
+
|
50
|
+
table tbody td {
|
51
|
+
background-color: #fff;
|
52
|
+
}
|
49
53
|
}
|
50
54
|
|
51
55
|
.tabbed_side_nav_form{
|
@@ -80,7 +84,7 @@
|
|
80
84
|
}
|
81
85
|
|
82
86
|
.wizard {
|
83
|
-
width:
|
87
|
+
width: 900px;
|
84
88
|
display: block;
|
85
89
|
@include center-block;
|
86
90
|
}
|
@@ -101,6 +101,18 @@ span.editable, span.editable:hover {
|
|
101
101
|
overflow: auto;
|
102
102
|
}
|
103
103
|
|
104
|
+
|
105
|
+
.nav > li > a.roles_list {
|
106
|
+
padding: 0;
|
107
|
+
border: 1px solid #ddd;
|
108
|
+
& > div {
|
109
|
+
padding: 10px;
|
110
|
+
&:not(:first-child) {
|
111
|
+
border-left: 1px solid #ddd;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
104
116
|
.association.well {
|
105
117
|
min-height: 500px;
|
106
118
|
margin-top: 50px;
|
@@ -111,3 +123,93 @@ span.editable, span.editable:hover {
|
|
111
123
|
}
|
112
124
|
}
|
113
125
|
}
|
126
|
+
|
127
|
+
$pull_line_height: 40px;
|
128
|
+
.subnet-type-pull, .empty-zone {
|
129
|
+
height: $pull_line_height;
|
130
|
+
line-height: $pull_line_height;
|
131
|
+
}
|
132
|
+
|
133
|
+
.subnet-type-pull, .subnet-pull, .empty-zone {
|
134
|
+
float: left;
|
135
|
+
min-width: 100px;
|
136
|
+
text-align: center;
|
137
|
+
margin-left: 10px;
|
138
|
+
background-color: #f5f5f5;
|
139
|
+
border-color: #000;
|
140
|
+
border-width: 1px;
|
141
|
+
}
|
142
|
+
|
143
|
+
.subnet-type-pull, .subnet-pull {
|
144
|
+
z-index: 1;
|
145
|
+
border-style: solid;
|
146
|
+
background-color: #ffffff;
|
147
|
+
}
|
148
|
+
|
149
|
+
.subnet-type-pull, .subnet-pull.active {
|
150
|
+
cursor: pointer;
|
151
|
+
background-color: #f5f5f5;
|
152
|
+
}
|
153
|
+
|
154
|
+
.subnet-pull {
|
155
|
+
height: $pull_line_height;
|
156
|
+
display: table;
|
157
|
+
padding-left: 5px;
|
158
|
+
padding-right: 5px;
|
159
|
+
margin-top: 10px;
|
160
|
+
|
161
|
+
.name {
|
162
|
+
font-weight: bold;
|
163
|
+
}
|
164
|
+
|
165
|
+
.content {
|
166
|
+
display: table-cell;
|
167
|
+
vertical-align: middle;
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
.subnet-pull.virtual {
|
172
|
+
background-color: #d7f5f5;
|
173
|
+
}
|
174
|
+
|
175
|
+
div.cleared {
|
176
|
+
clear: left;
|
177
|
+
}
|
178
|
+
|
179
|
+
.empty-zone {
|
180
|
+
border-style: dashed;
|
181
|
+
}
|
182
|
+
|
183
|
+
.subnet-drop-zone {
|
184
|
+
border: 1px solid black;
|
185
|
+
height: 90px;
|
186
|
+
margin-bottom: 10px;
|
187
|
+
|
188
|
+
.name {
|
189
|
+
margin-left: 5px;
|
190
|
+
margin-top: 5px;
|
191
|
+
margin-bottom: 10px;
|
192
|
+
font-weight: bold;
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
div.interface {
|
197
|
+
margin-bottom: 10px;
|
198
|
+
|
199
|
+
div.identifier {
|
200
|
+
float: left;
|
201
|
+
width: 70px;
|
202
|
+
border: 1px solid #000;
|
203
|
+
height: $pull_line_height + 20px;
|
204
|
+
line-height: $pull_line_height + 20px;
|
205
|
+
text-align: center;
|
206
|
+
font-weight: bold;
|
207
|
+
}
|
208
|
+
|
209
|
+
div.subnet-drop-zones {
|
210
|
+
border: 1px solid #000;
|
211
|
+
padding-top: 10px;
|
212
|
+
width: 100%;
|
213
|
+
height: $pull_line_height + 20px;
|
214
|
+
}
|
215
|
+
}
|
@@ -190,6 +190,11 @@ module Staypuft
|
|
190
190
|
# root_pass is not copied for some reason
|
191
191
|
host.root_pass = hostgroup.root_pass
|
192
192
|
|
193
|
+
# clear all virtual devices that may have been created during previous assignment
|
194
|
+
host.clean_vlan_interfaces
|
195
|
+
# by default foreman will try to manage all NICs unless user disables manually after assignment
|
196
|
+
host.make_all_interfaces_managed
|
197
|
+
|
193
198
|
# I do not why but the final save! adds following condytion to the update SQL command
|
194
199
|
# "WHERE "hosts"."type" IN ('Host::Managed') AND "hosts"."id" = 283"
|
195
200
|
# which will not find the record since it's still Host::Discovered.
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Staypuft
|
2
|
+
class InterfaceAssignmentsController < Staypuft::ApplicationController
|
3
|
+
def index
|
4
|
+
@deployment = Deployment.find(params[:deployment_id])
|
5
|
+
@hosts = Host::Managed.where(:id => params[:host_ids]).includes(:interfaces)
|
6
|
+
@subnets = @deployment.subnets.uniq
|
7
|
+
@host = @hosts.first
|
8
|
+
@interfaces = @host ? @host.interfaces.where("type <> 'Nic::BMC'").order(:identifier).physical : []
|
9
|
+
|
10
|
+
errors = {}
|
11
|
+
@hosts.each do |host|
|
12
|
+
host_errors = compare(host, @host)
|
13
|
+
errors[host.name] = host_errors.join(' and ') if host_errors.present?
|
14
|
+
end
|
15
|
+
|
16
|
+
if errors.present?
|
17
|
+
flash[:error] = errors.map{ |k, v| "#{k}: #{v}" }.join('<br />')
|
18
|
+
redirect_to deployment_path(@deployment)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def create
|
23
|
+
@errors = {}
|
24
|
+
@deployment = Deployment.find(params[:deployment_id])
|
25
|
+
@hosts = Host::Managed.where(:id => params[:host_ids])
|
26
|
+
@hosts.each do |host|
|
27
|
+
@interface = host.interfaces.find_by_identifier(params[:interface]) || host
|
28
|
+
@subnet = Subnet.find(params[:subnet_id])
|
29
|
+
@assigner = InterfaceAssigner.new(@deployment, @interface, @subnet)
|
30
|
+
@assigner.assign
|
31
|
+
@errors[host.name] = @assigner.errors if @assigner.errors.present?
|
32
|
+
end
|
33
|
+
@saved = @errors.blank?
|
34
|
+
end
|
35
|
+
|
36
|
+
def destroy
|
37
|
+
@errors = {}
|
38
|
+
@deployment = Deployment.find(params[:deployment_id])
|
39
|
+
@hosts = Host::Managed.where(:id => params[:host_ids])
|
40
|
+
@hosts.each do |host|
|
41
|
+
@interface = host.interfaces.find_by_identifier(params[:interface]) || host
|
42
|
+
@subnet = Subnet.find(params[:subnet_id])
|
43
|
+
@assigner = InterfaceAssigner.new(@deployment, @interface, @subnet)
|
44
|
+
@assigner.unassign
|
45
|
+
@errors[host.name] = @assigner.errors if @assigner.errors.present?
|
46
|
+
end
|
47
|
+
@destroyed = @errors.blank?
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def compare(comparing, original)
|
53
|
+
errors = []
|
54
|
+
# primary interfaces, we don't check subnet_id since it's always PXE subnet
|
55
|
+
if comparing.primary_interface != original.primary_interface
|
56
|
+
errors.push _('does not have interfaces with same names')
|
57
|
+
return errors
|
58
|
+
end
|
59
|
+
|
60
|
+
# other interfaces
|
61
|
+
comparing = get_interfaces_to_compare(comparing)
|
62
|
+
original = get_interfaces_to_compare(original)
|
63
|
+
errors.push _('does not have same amount of interfaces') and return errors if comparing.size != original.size
|
64
|
+
comparing.each do |interface|
|
65
|
+
original_interface = original.select { |i| i.identifier == interface.identifier }.first
|
66
|
+
errors.push _('does not have interfaces with same names') and return errors if original_interface.nil?
|
67
|
+
errors.push _('has different subnet assignment on interface %s') % interface.identifier if interface.subnet_id != original_interface.subnet_id
|
68
|
+
end
|
69
|
+
errors
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_interfaces_to_compare(host)
|
73
|
+
host.interfaces.where("type <> 'Nic::BMC'").order(:identifier)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Staypuft
|
2
2
|
class StepsController < Staypuft::ApplicationController
|
3
3
|
include Wicked::Wizard
|
4
|
-
steps :deployment_settings, :services_overview, :services_configuration
|
4
|
+
steps :deployment_settings, :network_configuration, :services_overview, :services_configuration
|
5
5
|
|
6
6
|
before_filter :get_deployment
|
7
7
|
|
@@ -13,6 +13,8 @@ module Staypuft
|
|
13
13
|
if !@deployment.ha? && @deployment.cinder.lvm_ptable.nil?
|
14
14
|
flash[:warning] = "Missing Partition Table 'LVM with cinder-volumes', LVM cinder backend won't work."
|
15
15
|
end
|
16
|
+
when :network_configuration
|
17
|
+
@subnets = Subnet.search_for(params[:search], :order => params[:order]).includes(:domains, :dhcp).paginate :page => params[:page]
|
16
18
|
when :services_configuration
|
17
19
|
@services_map = [:nova, :neutron, :glance, :cinder]
|
18
20
|
end
|
@@ -30,6 +32,15 @@ module Staypuft
|
|
30
32
|
@deployment.passwords.attributes = params[:staypuft_deployment].delete(:passwords)
|
31
33
|
@deployment.attributes = params[:staypuft_deployment]
|
32
34
|
|
35
|
+
# we don't care too much whether pxe network was detected or all typings were saved since it's
|
36
|
+
# just a helper for user to have all types preassigned to pxe network
|
37
|
+
pxe_network = Subnet.where('dhcp_id IS NOT NULL').first
|
38
|
+
if pxe_network
|
39
|
+
@deployment.unassigned_subnet_types.each do |type|
|
40
|
+
@deployment.subnet_typings.new(:subnet_id => pxe_network.id, :subnet_type_id => type.id).save
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
33
44
|
when :services_overview
|
34
45
|
@deployment.form_step = Deployment::STEP_OVERVIEW
|
35
46
|
|
@@ -41,6 +52,9 @@ module Staypuft
|
|
41
52
|
@deployment.send(service).attributes = params[:staypuft_deployment].delete(service)
|
42
53
|
end
|
43
54
|
end
|
55
|
+
when :network_configuration
|
56
|
+
@deployment.form_step = Deployment::STEP_NETWORKING
|
57
|
+
@subnets = Subnet.search_for(params[:search], :order => params[:order]).includes(:domains, :dhcp).paginate :page => params[:page]
|
44
58
|
else
|
45
59
|
raise 'unknown step'
|
46
60
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Staypuft
|
2
|
+
class SubnetTypingsController < ActionController::Base
|
3
|
+
def create
|
4
|
+
@deployment = Deployment.find(params[:deployment_id])
|
5
|
+
@subnet_type = SubnetType.find(params[:subnet_type_id])
|
6
|
+
@subnet = Subnet.find(params[:subnet_id])
|
7
|
+
check_for_existing_assignments
|
8
|
+
@subnet_typing = @deployment.subnet_typings.new(:subnet_id => @subnet.id, :subnet_type_id => @subnet_type.id)
|
9
|
+
@saved = @subnet_typing.save
|
10
|
+
end
|
11
|
+
|
12
|
+
def update
|
13
|
+
@subnet_typing = SubnetTyping.find(params[:id])
|
14
|
+
@deployment = @subnet_typing.deployment
|
15
|
+
@subnet_type = @subnet_typing.subnet_type
|
16
|
+
@subnet = Subnet.find(params[:subnet_id])
|
17
|
+
check_for_existing_assignments
|
18
|
+
@subnet_typing.subnet = @subnet
|
19
|
+
@saved = @subnet_typing.save
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy
|
23
|
+
@subnet_typing = SubnetTyping.find(params[:id])
|
24
|
+
@deployment = @subnet_typing.deployment
|
25
|
+
@subnet = @subnet_typing.subnet
|
26
|
+
check_for_existing_assignments
|
27
|
+
@subnet_type = @subnet_typing.subnet_type
|
28
|
+
@destroyed = @subnet_typing.destroy
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def check_for_existing_assignments
|
34
|
+
existing = @deployment.hosts.includes(:interfaces).any? do |h|
|
35
|
+
h.subnet_id == @subnet.id || h.interfaces.any? { |i| i.subnet_id == @subnet.id }
|
36
|
+
end
|
37
|
+
if existing
|
38
|
+
@warn = _('Some hosts interfaces were already assigned to this subnet, check interface assignment before deploying!')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -4,6 +4,7 @@ module Staypuft
|
|
4
4
|
wizard_header(
|
5
5
|
step,
|
6
6
|
_("Deployment Settings"),
|
7
|
+
_("Network Configuration"),
|
7
8
|
_("Services Overview"),
|
8
9
|
_("Services Configuration")
|
9
10
|
)
|
@@ -33,9 +34,7 @@ module Staypuft
|
|
33
34
|
style ="label-default"
|
34
35
|
short = s_("Discovered|D")
|
35
36
|
label = _('Discovered Host')
|
36
|
-
|
37
|
-
hash_for_method = [:hash_for_discovered_host_path, :hash_for_discover_path].find { |m| respond_to? m }
|
38
|
-
path = send hash_for_method, host
|
37
|
+
path = hash_for_discovered_host_path(host)
|
39
38
|
else
|
40
39
|
style = 'label-warning'
|
41
40
|
short = s_("Error|E")
|
@@ -48,6 +47,22 @@ module Staypuft
|
|
48
47
|
:class => "label label-light " + style,
|
49
48
|
:"data-original-title" => _(label) }) + link_to(trunc(" #{host}", 32), path)
|
50
49
|
end
|
50
|
+
|
51
|
+
def host_nics(host)
|
52
|
+
host.interfaces_identifiers.compact.sort.join(tag(:br)).html_safe
|
53
|
+
end
|
54
|
+
|
55
|
+
def is_pxe?(deployment, subnet)
|
56
|
+
subnet_typings(deployment, subnet).any? { |t| t.subnet_type.name == Staypuft::SubnetType::PXE }
|
57
|
+
end
|
58
|
+
|
59
|
+
def subnet_types(deployment, subnet)
|
60
|
+
subnet_typings(deployment, subnet).map { |t| h(t.subnet_type.name) }.join(' + ')
|
61
|
+
end
|
62
|
+
|
63
|
+
def subnet_typings(deployment, subnet)
|
64
|
+
deployment.subnet_typings.where(:subnet_id => subnet.id).includes(:subnet_type)
|
65
|
+
end
|
51
66
|
end
|
52
67
|
|
53
68
|
end
|
@@ -26,12 +26,49 @@ module Actions
|
|
26
26
|
# hostgroup.hosts returns already converted hosts from Host::Discovered with build flag
|
27
27
|
# set to false so they are not built when assigned to the hostgroup in wizard
|
28
28
|
# run Hostgroup's Hosts filtered by hosts
|
29
|
-
|
29
|
+
host_list = hostgroup.hosts & hosts
|
30
|
+
orchestration_mode = hostgroup.role.orchestration unless hostgroup.role.nil?
|
31
|
+
|
32
|
+
case orchestration_mode
|
33
|
+
when ::Staypuft::Role::ORCHESTRATION_CONCURRENT
|
34
|
+
deploy_concurrently(host_list)
|
35
|
+
when ::Staypuft::Role::ORCHESTRATION_SERIAL
|
36
|
+
deploy_serially(host_list)
|
37
|
+
when ::Staypuft::Role::ORCHESTRATION_LEADER
|
38
|
+
deploy_leader_first(host_list)
|
39
|
+
else
|
40
|
+
deploy_concurrently(host_list)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def deploy_concurrently(hosts)
|
45
|
+
hosts.each do |host|
|
30
46
|
# planned in concurrence
|
31
47
|
plan_action Host::Deploy, host
|
32
48
|
end
|
33
49
|
end
|
34
50
|
|
51
|
+
def deploy_serially(hosts)
|
52
|
+
sequence do
|
53
|
+
hosts.each do |host|
|
54
|
+
plan_action Host::Deploy, host
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def deploy_leader_first(hosts)
|
60
|
+
first_host = hosts.shift
|
61
|
+
sequence do
|
62
|
+
#deploy first host, then deploy remainder in parallel
|
63
|
+
plan_action Host::Deploy, first_host unless first_host.nil?
|
64
|
+
concurrence do
|
65
|
+
hosts.each do |host|
|
66
|
+
plan_action Host::Deploy, host
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
35
72
|
def humanized_input
|
36
73
|
input[:name]
|
37
74
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Staypuft
|
2
|
+
class NetworkQuery
|
3
|
+
|
4
|
+
def initialize(deployment)
|
5
|
+
@deployment = deployment
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
def interface_hash_for_host(host, subnet_type_name)
|
10
|
+
subnet_type = @deployment.layout.subnet_types.where(:name=> subnet_type_name).first
|
11
|
+
|
12
|
+
# raise error if no subnet with this name is assigned to this layout
|
13
|
+
if subnet_type.nil?
|
14
|
+
raise ArgumentError, "Invalid subnet type '#{subnet_type_name}' for layout of this deployment #{@deployment.name}"
|
15
|
+
end
|
16
|
+
|
17
|
+
subnet_typing = @deployment.subnet_typings.where(:subnet_type_id => subnet_type.id).first
|
18
|
+
# if this subnet type isn't assigned to a subnet for this deployment, return nil
|
19
|
+
return nil if subnet_typing.nil?
|
20
|
+
subnet = subnet_typing.subnet
|
21
|
+
|
22
|
+
secondary_iface = host.interfaces.where(:subnet_id => subnet.id).first
|
23
|
+
# check for primary interface
|
24
|
+
if (host.subnet_id == subnet.id)
|
25
|
+
{:subnet => host.subnet, :ip => host.ip,
|
26
|
+
:interface => host.primary_interface, :mac => host.mac }
|
27
|
+
elsif !iface.nil?
|
28
|
+
{:subnet => secondary_iface.subnet, :ip => secondary_iface.ip,
|
29
|
+
:interface => secondary_iface.name, :mac => secondary_iface.mac }
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|