staypuft 0.4.1 → 0.4.2
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 +13 -5
- data/app/assets/javascripts/staypuft/new_subnet.js +9 -0
- data/app/assets/javascripts/staypuft/staypuft.js +39 -0
- data/app/assets/javascripts/staypuft/subnets_assignment.js +5 -1
- data/app/controllers/staypuft/concerns/hosts_api_extensions.rb +18 -0
- data/app/controllers/staypuft/concerns/hosts_controller_extensions.rb +38 -0
- data/app/controllers/staypuft/subnets_controller.rb +25 -0
- data/app/lib/staypuft/seeder.rb +71 -19
- data/app/models/staypuft/deployment.rb +11 -2
- data/app/models/staypuft/deployment/cinder_service.rb +1 -1
- data/app/models/staypuft/deployment/cinder_service/equallogic.rb +1 -23
- data/app/models/staypuft/deployment/ip_address_validator.rb +30 -0
- data/app/models/staypuft/deployment/neutron_service.rb +55 -9
- data/app/models/staypuft/deployment/neutron_service/cisconexus.rb +1 -12
- data/app/models/staypuft/simple_subnet.rb +115 -0
- data/app/overrides/foreman_hosts_edit.rb +13 -0
- data/app/overrides/select_multiple_systems_hostgroup.rb +15 -0
- data/app/views/staypuft/steps/_neutron.html.erb +35 -22
- data/app/views/staypuft/steps/deployment_settings.html.erb +2 -0
- data/app/views/staypuft/steps/network_configuration.html.erb +28 -1
- data/app/views/staypuft/subnets/_form.html.erb +24 -0
- data/app/views/staypuft/subnets/create.js.erb +14 -0
- data/app/views/staypuft/subnets/new.html.erb +3 -0
- data/config/routes.rb +4 -0
- data/db/migrate/20141009064907_add_custom_repos_to_deployment.rb +5 -0
- data/lib/staypuft/engine.rb +5 -2
- data/lib/staypuft/version.rb +1 -1
- metadata +151 -140
@@ -4,11 +4,13 @@ module Staypuft
|
|
4
4
|
'neutron'
|
5
5
|
end
|
6
6
|
|
7
|
-
SEGMENTATION_LIST
|
8
|
-
VLAN_HELP
|
9
|
-
ML2MECHANISM_TYPES
|
7
|
+
SEGMENTATION_LIST = ['vxlan', 'vlan', 'gre', 'flat']
|
8
|
+
VLAN_HELP = N_('[1-4094] (e.g. 10:15)')
|
9
|
+
ML2MECHANISM_TYPES = :ml2_openvswitch, :ml2_l2population, :ml2_cisco_nexus
|
10
|
+
N1KV_PARAMS = :n1kv_vsm_ip, :n1kv_vsm_password
|
10
11
|
|
11
|
-
param_attr :network_segmentation, :tenant_vlan_ranges,
|
12
|
+
param_attr :network_segmentation, :tenant_vlan_ranges, :core_plugin,
|
13
|
+
*ML2MECHANISM_TYPES, *N1KV_PARAMS
|
12
14
|
param_attr_array :nexuses => Cisconexus
|
13
15
|
|
14
16
|
module NetworkSegmentation
|
@@ -26,6 +28,19 @@ module Staypuft
|
|
26
28
|
|
27
29
|
validates :network_segmentation, presence: true, inclusion: { in: NetworkSegmentation::TYPES }
|
28
30
|
|
31
|
+
module CorePlugin
|
32
|
+
ML2 = 'ml2'
|
33
|
+
N1KV = 'n1kv'
|
34
|
+
LABELS = { ML2 => N_("ML2 Core Plugin"),
|
35
|
+
N1KV => N_("N1KV Core Plugin") }
|
36
|
+
MODULES = { ML2 => 'neutron.plugins.ml2.plugin.Ml2Plugin',
|
37
|
+
N1KV => 'neutron.plugins.cisco.network_plugin.PluginV2'}
|
38
|
+
TYPES = LABELS.keys
|
39
|
+
HUMAN = N_('Core Plugin Type')
|
40
|
+
end
|
41
|
+
|
42
|
+
validates :core_plugin, presence: true, inclusion: { in: CorePlugin::TYPES }
|
43
|
+
|
29
44
|
module TenantVlanRanges
|
30
45
|
HUMAN = N_('Tenant (VM Data) VLAN Ranges')
|
31
46
|
HUMAN_AFTER = VLAN_HELP
|
@@ -40,6 +55,18 @@ module Staypuft
|
|
40
55
|
:if => :vlan_segmentation?,
|
41
56
|
:neutron_vlan_ranges => true
|
42
57
|
|
58
|
+
class N1kvIpAddressValidator < ActiveModel::EachValidator
|
59
|
+
include Staypuft::Deployment::IpAddressValidator
|
60
|
+
end
|
61
|
+
|
62
|
+
validates :n1kv_vsm_ip,
|
63
|
+
:presence => true,
|
64
|
+
:if => :n1kv_plugin?,
|
65
|
+
:n1kv_ip_address => true
|
66
|
+
validates :n1kv_vsm_password,
|
67
|
+
:presence => true,
|
68
|
+
:if => :n1kv_plugin?
|
69
|
+
|
43
70
|
module Ml2Mechanisms
|
44
71
|
OPENVSWITCH = 'openvswitch'
|
45
72
|
L2POPULATION = 'l2population'
|
@@ -50,23 +77,27 @@ module Staypuft
|
|
50
77
|
TYPES = LABELS.keys
|
51
78
|
HUMAN = N_('ML2 Mechanism Drivers')
|
52
79
|
end
|
53
|
-
validate :at_least_one_mechanism_selected
|
80
|
+
validate :at_least_one_mechanism_selected,
|
81
|
+
:if => :ml2_plugin?
|
54
82
|
validate :cisco_nexuses,
|
55
|
-
:if => :cisco_nexus_mechanism?
|
83
|
+
:if => [:ml2_plugin?, :cisco_nexus_mechanism?]
|
56
84
|
validates :nexuses,
|
57
85
|
:presence => true,
|
58
|
-
:if => :cisco_nexus_mechanism?
|
86
|
+
:if => [:ml2_plugin?, :cisco_nexus_mechanism?]
|
59
87
|
|
60
88
|
class Jail < Safemode::Jail
|
61
89
|
allow :networker_vlan_ranges, :compute_vlan_ranges, :network_segmentation, :enable_tunneling?,
|
62
90
|
:tenant_iface, :networker_ovs_bridge_mappings, :networker_ovs_bridge_uplinks,
|
63
91
|
:compute_ovs_bridge_mappings, :compute_ovs_bridge_uplinks, :ovs_tunnel_types,
|
64
92
|
:openvswitch_mechanism?, :l2population_mechanism?, :cisco_nexus_mechanism?,
|
65
|
-
:ml2_mechanisms, :nexuses, :active?, :compute_cisco_nexus_config
|
93
|
+
:ml2_mechanisms, :nexuses, :active?, :compute_cisco_nexus_config, :core_plugin,
|
94
|
+
:ml2_plugin?, :n1kv_plugin?, :n1kv_vsm_ip, :n1kv_vsm_password,
|
95
|
+
:core_plugin_module
|
66
96
|
end
|
67
97
|
|
68
98
|
def set_defaults
|
69
99
|
self.network_segmentation = NetworkSegmentation::VXLAN
|
100
|
+
self.core_plugin = CorePlugin::ML2
|
70
101
|
self.ml2_openvswitch = "true"
|
71
102
|
self.ml2_l2population = "true"
|
72
103
|
self.ml2_cisco_nexus = "false"
|
@@ -145,6 +176,18 @@ module Staypuft
|
|
145
176
|
self.ml2_cisco_nexus == "true"
|
146
177
|
end
|
147
178
|
|
179
|
+
def ml2_plugin?
|
180
|
+
self.core_plugin == CorePlugin::ML2
|
181
|
+
end
|
182
|
+
|
183
|
+
def n1kv_plugin?
|
184
|
+
self.core_plugin == CorePlugin::N1KV
|
185
|
+
end
|
186
|
+
|
187
|
+
def core_plugin_module
|
188
|
+
CorePlugin::MODULES[self.core_plugin]
|
189
|
+
end
|
190
|
+
|
148
191
|
def compute_cisco_nexus_config
|
149
192
|
Hash[nexuses.map { |nexus| [nexus.hostname, nexus.config_hash] }]
|
150
193
|
end
|
@@ -155,11 +198,14 @@ module Staypuft
|
|
155
198
|
|
156
199
|
def param_hash
|
157
200
|
{ 'network_segmentation' => network_segmentation,
|
201
|
+
'core_plugin' => core_plugin,
|
158
202
|
'tenant_vlan_ranges' => tenant_vlan_ranges,
|
159
203
|
'ml2_openvswitch' => ml2_openvswitch,
|
160
204
|
'ml2_l2population' => ml2_l2population,
|
161
205
|
'ml2_cisco_nexus' => ml2_cisco_nexus,
|
162
|
-
'nexuses' => nexuses
|
206
|
+
'nexuses' => nexuses,
|
207
|
+
'n1kv_vsm_ip' => n1kv_vsm_ip,
|
208
|
+
'n1kv_vsm_password' => n1kv_vsm_password }
|
163
209
|
end
|
164
210
|
|
165
211
|
private
|
@@ -29,18 +29,7 @@ module Staypuft
|
|
29
29
|
end
|
30
30
|
|
31
31
|
class IpValueValidator < ActiveModel::EachValidator
|
32
|
-
|
33
|
-
return if value.empty?
|
34
|
-
|
35
|
-
ip_addr = IPAddr.new(value)
|
36
|
-
ip_range = ip_addr.to_range
|
37
|
-
if ip_range.begin == ip_range.end
|
38
|
-
true
|
39
|
-
else
|
40
|
-
record.errors.add attribute, "Specify single IP address, not range"
|
41
|
-
false
|
42
|
-
end
|
43
|
-
end
|
32
|
+
include Staypuft::Deployment::IpAddressValidator
|
44
33
|
end
|
45
34
|
|
46
35
|
class PortMapValueValidator < ActiveModel::EachValidator
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'ipaddress'
|
2
|
+
|
3
|
+
module Staypuft
|
4
|
+
class SimpleSubnet
|
5
|
+
extend ActiveModel::Naming
|
6
|
+
include ActiveModel::AttributeMethods
|
7
|
+
include ActiveModel::Validations
|
8
|
+
|
9
|
+
DHCP_SERVER_TYPE = {
|
10
|
+
'external' => 'External DHCP',
|
11
|
+
'none' => 'No existing DHCP'
|
12
|
+
}
|
13
|
+
ATTRS = [:name, :dhcp_server, :network_address, :vlan, :gateway,
|
14
|
+
:ip_range_from, :ip_range_to]
|
15
|
+
attr_accessor *ATTRS
|
16
|
+
attr_accessor :subnet, :deployment
|
17
|
+
delegate :to_key, :to => :subnet, :allow_nil => true
|
18
|
+
|
19
|
+
validates :name, :dhcp_server, :network_address, presence: true
|
20
|
+
validates :gateway, :presence => true,
|
21
|
+
:if => Proc.new { |subnet| subnet.dhcp_server == 'none' }
|
22
|
+
validates_format_of :gateway, :with => Net::Validations::IP_REGEXP,
|
23
|
+
:if => Proc.new { |subnet| subnet.dhcp_server == 'none' }
|
24
|
+
validate :validate_network_address
|
25
|
+
validate :validate_ranges, :if => Proc.new { |subnet| subnet.dhcp_server == 'none' }
|
26
|
+
|
27
|
+
def initialize(attrs={})
|
28
|
+
self.dhcp_server = 'external'
|
29
|
+
if attrs.is_a?(::Subnet)
|
30
|
+
@subnet = Subnet.find_by_name(attrs.name)
|
31
|
+
convert_attributes_from
|
32
|
+
else
|
33
|
+
@subnet = Subnet.new
|
34
|
+
ATTRS.each do |attr|
|
35
|
+
self.send("#{attr}=", attrs.has_key?(attr) ? attrs[attr] : nil)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def save
|
41
|
+
if self.valid?
|
42
|
+
@subnet = Subnet.find_or_initialize_by_name(name)
|
43
|
+
convert_attributes_to
|
44
|
+
@subnet.save
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def convert_attributes_to
|
53
|
+
@subnet.boot_mode = self.dhcp_server == 'external' ? ::Subnet::BOOT_MODES[:dhcp] : ::Subnet::BOOT_MODES[:static]
|
54
|
+
@subnet.ipam = self.dhcp_server == 'external' ? ::Subnet::IPAM_MODES[:none] : ::Subnet::IPAM_MODES[:db]
|
55
|
+
@subnet.network = get_network
|
56
|
+
@subnet.mask = get_mask
|
57
|
+
@subnet.vlanid = self.vlan
|
58
|
+
if self.dhcp_server == 'none'
|
59
|
+
@subnet.gateway = self.gateway
|
60
|
+
@subnet.from = self.ip_range_from
|
61
|
+
@subnet.to = self.ip_range_to
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def convert_attributes_from
|
66
|
+
self.name = @subnet.name
|
67
|
+
if @subnet.boot_mode == ::Subnet::BOOT_MODES[:dhcp] && @subnet.ipam == ::Subnet::IPAM_MODES[:none]
|
68
|
+
self.dhcp_server = 'external'
|
69
|
+
elsif @subnet.boot_mode == ::Subnet::BOOT_MODES[:static] && @subnet.ipam == ::Subnet::IPAM_MODES[:db]
|
70
|
+
self.dhcp_server = 'none'
|
71
|
+
else
|
72
|
+
raise 'unknown simple subnet combination'
|
73
|
+
end
|
74
|
+
|
75
|
+
self.network_address = @subnet.network_address
|
76
|
+
self.gateway = @subnet.gateway
|
77
|
+
self.vlan = @subnet.vlanid
|
78
|
+
self.ip_range_from = @subnet.from
|
79
|
+
self.ip_range_to = @subnet.to
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_network
|
83
|
+
IPAddress::IPv4.new(self.network_address).network.address
|
84
|
+
rescue Exception => ex
|
85
|
+
Rails.logger.warn("failed to parse network address: #{ex.message}")
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_mask
|
90
|
+
IPAddress::IPv4.new(self.network_address).netmask
|
91
|
+
rescue Exception => ex
|
92
|
+
Rails.logger.warn("failed to parse network mask: #{ex.message}")
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def validate_network_address
|
97
|
+
network = get_network
|
98
|
+
mask = get_mask
|
99
|
+
if !network || !mask || !(network =~ Net::Validations::IP_REGEXP) ||
|
100
|
+
!(mask =~ Net::Validations::MASK_REGEXP)
|
101
|
+
errors.add(:network_address, _("invalid Network Address"))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def validate_ranges
|
106
|
+
errors.add(:ip_range_from, _("invalid IP address")) if ip_range_from.present? && !(ip_range_from =~ Net::Validations::IP_REGEXP)
|
107
|
+
errors.add(:ip_range_to, _("invalid IP address")) if ip_range_to.present? && !(ip_range_to =~ Net::Validations::IP_REGEXP)
|
108
|
+
if ip_range_from.present? or ip_range_to.present?
|
109
|
+
errors.add(:ip_range_from, _("must be specified if 'IP Range End' is defined")) if ip_range_from.blank?
|
110
|
+
errors.add(:ip_range_to, _("must be specified if 'IP Range Start' is defined")) if ip_range_to.blank?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
@@ -22,3 +22,16 @@ Deface::Override.new(:virtual_path => "hosts/_unattended",
|
|
22
22
|
:insert_after => "#network",
|
23
23
|
:text => "<div class='tab-pane' id='fencing'><%= render 'hosts/fencing', :host => @host, :f => f %></div>"
|
24
24
|
)
|
25
|
+
|
26
|
+
Deface::Override.new(:virtual_path => "hosts/_form",
|
27
|
+
:name => "remove_openstack_hostgroups",
|
28
|
+
:replace => "#{erb_tag}:contains(':hostgroup_id')",
|
29
|
+
:original => '04903c858c6f96ed5c015cac5960e02708d8fea8'
|
30
|
+
) do
|
31
|
+
" <%= select_f f, :hostgroup_id, accessible_hostgroups.reject { |hg| hg.to_label =~ /#{Setting[:base_hostgroup]}\\/.*/ }, :id, :to_label,
|
32
|
+
{ :include_blank => true},
|
33
|
+
{ :onchange => 'hostgroup_changed(this);', :'data-host-id' => @host.id,
|
34
|
+
:'data-url' => (@host.new_record? || @host.type_changed?) ? process_hostgroup_hosts_path : hostgroup_or_environment_selected_hosts_path,
|
35
|
+
:help_inline => :indicator } %>
|
36
|
+
"
|
37
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# older deface requires code prefix for erb tags
|
2
|
+
if Gem.loaded_specs['deface'].version >= Gem::Version.new('1.0.0')
|
3
|
+
erb_tag = 'erb[loud]'
|
4
|
+
else
|
5
|
+
erb_tag = 'code[erb-loud]'
|
6
|
+
end
|
7
|
+
|
8
|
+
Deface::Override.new(:virtual_path => "hosts/select_multiple_hostgroup",
|
9
|
+
:name => "remove_openstack_hostgroups_multiple",
|
10
|
+
:replace => "#{erb_tag}:contains(':id')",
|
11
|
+
:original => '<%= selectable_f f, :id, [[_("Select host group"),"disabled"],[_("*Clear host group*"), "" ]] + Hostgroup.all.map{|h| [h.to_label, h.id]}.sort,{}, :onchange => "toggle_multiple_ok_button(this)" %>'
|
12
|
+
) do
|
13
|
+
" <%= selectable_f f, :id, [[_(\"Select host group\"),\"disabled\"],[_(\"*Clear host group*\"), \"\" ]] + Hostgroup.all.reject{ |hg| hg.to_label =~ /#{Setting[:base_hostgroup]}\\/.*/ }.map{|h| [h.to_label, h.id]}.sort,{},
|
14
|
+
:onchange => \"toggle_multiple_ok_button(this)\" %>"
|
15
|
+
end
|
@@ -16,29 +16,42 @@
|
|
16
16
|
help_inline: _(Staypuft::Deployment::NeutronService::TenantVlanRanges::HUMAN_AFTER)) %>
|
17
17
|
</div>
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
19
|
+
<%= change_label_width(4, field(p, :core_plugin, :label => _(Staypuft::Deployment::NeutronService::CorePlugin::HUMAN)) do
|
20
|
+
Staypuft::Deployment::NeutronService::CorePlugin::LABELS.map do |value, label|
|
21
|
+
radio_button_f_non_inline(p, :core_plugin,
|
22
|
+
:checked => @deployment.neutron.core_plugin == value,
|
23
|
+
:value => value,
|
24
|
+
:text => label)
|
25
|
+
end.join
|
26
|
+
end) %>
|
27
|
+
|
28
|
+
<div class="neutron_ml2_mechanisms inset_form hide">
|
29
|
+
<%= _(Staypuft::Deployment::NeutronService::Ml2Mechanisms::HUMAN) %>
|
30
|
+
<%= check_box_f_non_inline(p, :ml2_openvswitch,
|
31
|
+
:checked_value => 'true',
|
32
|
+
:unchecked_value => 'false',
|
33
|
+
:checked => @deployment.neutron.openvswitch_mechanism?,
|
34
|
+
:text => _(Staypuft::Deployment::NeutronService::Ml2Mechanisms::LABELS['openvswitch']))
|
35
|
+
%>
|
36
|
+
<%= check_box_f_non_inline(p, :ml2_l2population,
|
37
|
+
:checked_value => 'true',
|
38
|
+
:unchecked_value => 'false',
|
39
|
+
:checked => @deployment.neutron.l2population_mechanism?,
|
40
|
+
:text => _(Staypuft::Deployment::NeutronService::Ml2Mechanisms::LABELS['l2population']))
|
41
|
+
%>
|
42
|
+
<%= check_box_f_non_inline(p, :ml2_cisco_nexus,
|
43
|
+
:checked_value => 'true',
|
44
|
+
:unchecked_value => 'false',
|
45
|
+
:checked => @deployment.neutron.cisco_nexus_mechanism?,
|
46
|
+
:text => _(Staypuft::Deployment::NeutronService::Ml2Mechanisms::LABELS['cisco_nexus']))
|
47
|
+
%>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
<div class="neutron_n1kv_parameters inset_form hide">
|
51
|
+
<%= change_label_width 4, text_f(p, :n1kv_vsm_ip, class: "neutron_n1kv_vsm_ip", label: _('VSM IP')) %>
|
52
|
+
<%= change_label_width 4, text_f(p, :n1kv_vsm_password, class: "neutron_n1kv_vsm_password", label: _('VSM Password')) %>
|
41
53
|
</div>
|
54
|
+
|
42
55
|
<div class="neutron_cisco_nexus col-md-offset-1 hide">
|
43
56
|
<div id="nexuses" class="neutron_nexus_picker">
|
44
57
|
<% @deployment.neutron.nexuses.each_with_index do |nexus, index| %>
|
@@ -55,6 +55,8 @@
|
|
55
55
|
:step => Staypuft::Deployment::STEP_SETTINGS } %>
|
56
56
|
|
57
57
|
<% end %>
|
58
|
+
|
59
|
+
<%= textarea_f f, :custom_repos, :rows => 3, :help_inline => _('If you need to add custom repositories on provisioned hosts you can specify base urls here, one per line. These repositories will have highest priority (50)') %>
|
58
60
|
<% end %>
|
59
61
|
</div>
|
60
62
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
<%= javascript 'staypuft/subnets_assignment' %>
|
2
|
+
<%= javascript 'staypuft/new_subnet' %>
|
2
3
|
|
3
4
|
<%= render :layout => 'title' do %>
|
4
5
|
<%= alert_if_deployed %>
|
@@ -25,7 +26,11 @@
|
|
25
26
|
<div class="row">
|
26
27
|
<div id="title_action" class="col-md-12">
|
27
28
|
<div class="btn-toolbar pull-right">
|
28
|
-
|
29
|
+
<button type="button" class= "btn btn-success"
|
30
|
+
id="new_subnet_button" data-toggle = "modal"
|
31
|
+
data-target = "#new_subnet_modal">
|
32
|
+
<%= _("New Subnet") %>
|
33
|
+
</button>
|
29
34
|
</div>
|
30
35
|
</div>
|
31
36
|
</div>
|
@@ -57,4 +62,26 @@
|
|
57
62
|
</div>
|
58
63
|
</div>
|
59
64
|
</div>
|
65
|
+
|
66
|
+
<div class="modal fade" id="new_subnet_modal" tabindex="-1" role="dialog" aria-labelledby="<%= _("New Subnet") %>" aria-hidden="true" data-path="<%= new_staypuft_subnet_path(:deployment_id => @deployment) %>">
|
67
|
+
<div class="modal-dialog modal-lg">
|
68
|
+
<div class="modal-content">
|
69
|
+
<div class="modal-header">
|
70
|
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
71
|
+
<h2 class="modal-title">
|
72
|
+
<%= _("New Subnet") %>
|
73
|
+
</h2>
|
74
|
+
</div>
|
75
|
+
<div id="new_subnet_ajax_content">
|
76
|
+
<div class="modal-body">
|
77
|
+
<div id="new_subnet_form"><%= image_tag '/assets/spinner.gif', style: "display: block; margin-left: auto; margin-right: auto" %></div>
|
78
|
+
</div>
|
79
|
+
<div class="modal-footer">
|
80
|
+
<button type="button" class="btn btn-default" data-dismiss="modal"><%= _("Cancel") %></button>
|
81
|
+
<button id="create_subnet_btn" type="button" class="btn btn-primary done" data-dismiss="modal"><%= _("Done") %></button>
|
82
|
+
</div>
|
83
|
+
</div>
|
84
|
+
</div>
|
85
|
+
</div>
|
86
|
+
</div>
|
60
87
|
<% end %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<%= form_for(subnet, :url => staypuft_subnets_path(:deployment_id => deployment), :remote => true, :html => {:id => "new_subnet_form", :class => ""}) do |f| %>
|
2
|
+
<div class="modal-body">
|
3
|
+
<%= change_label_width(4, text_f(f, :name, :label => _("Name"))) %>
|
4
|
+
<%= change_label_width(4, select_f(f, :dhcp_server,
|
5
|
+
::Staypuft::SimpleSubnet::DHCP_SERVER_TYPE,
|
6
|
+
:first, :last,
|
7
|
+
{ include_blank: false },
|
8
|
+
{ label: _("DHCP server") })) %>
|
9
|
+
<%= change_label_width(4, text_f(f, :network_address, :label => _("Network Address"),
|
10
|
+
:help_inline => _("Network Address using CIDR notation (eg. 1.2.3.4/24)"))) %>
|
11
|
+
<%= change_label_width(4, text_f(f, :vlan, :label => _("VLAN"))) %>
|
12
|
+
<div id="no_existing_dhcp_fields" style="display: <%= subnet.dhcp_server == 'none' ? 'block' : 'none' %>">
|
13
|
+
<%= change_label_width(4, text_f(f, :gateway, :label => _("Gateway"))) %>
|
14
|
+
<%= change_label_width(4, text_f(f, :ip_range_from, :label => _("IP Range Start"))) %>
|
15
|
+
<%= change_label_width(4, text_f(f, :ip_range_to, :label => _("IP Range End"))) %>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
<div class="modal-footer">
|
19
|
+
<button type="button" class="btn btn-default" data-dismiss="modal"><%= _("Cancel") %></button>
|
20
|
+
<%= submit_tag _("Create Subnet"),
|
21
|
+
:id => "create_subnet_btn",
|
22
|
+
:class => "btn btn-primary done" %>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<% if @result %>
|
2
|
+
$("#subnets").append(
|
3
|
+
'<%=j render 'staypuft/subnets/drop_zone',
|
4
|
+
:subnet => @simple_subnet.subnet,
|
5
|
+
:deployment => @deployment %>');
|
6
|
+
$('#new_subnet_modal').modal('toggle');
|
7
|
+
subnets_assigments();
|
8
|
+
<% else %>
|
9
|
+
$("#new_subnet_ajax_content").html(
|
10
|
+
'<%=j render 'staypuft/subnets/form',
|
11
|
+
:deployment => @deployment,
|
12
|
+
:subnet => @simple_subnet %>');
|
13
|
+
new_subnet();
|
14
|
+
<% end %>
|