staypuft 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/staypuft/nics_assignment.js +5 -5
  3. data/app/assets/javascripts/staypuft/staypuft.js +58 -5
  4. data/app/assets/javascripts/staypuft/subnets_assignment.js +5 -4
  5. data/app/assets/stylesheets/staypuft/bootstrap_and_overrides.css.scss +16 -0
  6. data/app/assets/stylesheets/staypuft/staypuft.css.scss +30 -71
  7. data/app/controllers/staypuft/deployments_controller.rb +23 -0
  8. data/app/controllers/staypuft/interface_assignments_controller.rb +2 -1
  9. data/app/lib/staypuft/network_query.rb +88 -5
  10. data/app/lib/staypuft/seeder.rb +75 -71
  11. data/app/models/staypuft/concerns/host_interface_management.rb +25 -2
  12. data/app/models/staypuft/concerns/subnet_ip_management.rb +17 -0
  13. data/app/models/staypuft/concerns/vip_nic_scopes.rb +13 -0
  14. data/app/models/staypuft/deployment/attribute_param_storage.rb +59 -1
  15. data/app/models/staypuft/deployment/cinder_service/equallogic.rb +80 -0
  16. data/app/models/staypuft/deployment/cinder_service.rb +53 -94
  17. data/app/models/staypuft/deployment/neutron_service.rb +20 -83
  18. data/app/models/staypuft/deployment/nova_service.rb +2 -31
  19. data/app/models/staypuft/deployment.rb +9 -7
  20. data/app/models/staypuft/subnet_type.rb +4 -0
  21. data/app/views/staypuft/deployments/_assigned_hosts.html.erb +23 -4
  22. data/app/views/staypuft/deployments/_deployment_access_all_details_dialogue.html.erb +5 -5
  23. data/app/views/staypuft/deployments/_deployment_hosts.html.erb +1 -1
  24. data/app/views/staypuft/deployments/_free_hosts.html.erb +4 -4
  25. data/app/views/staypuft/interface_assignments/index.html.erb +36 -31
  26. data/app/views/staypuft/interfaces/_drop_zone.html.erb +22 -22
  27. data/app/views/staypuft/steps/_cinder.html.erb +48 -26
  28. data/app/views/staypuft/steps/_cinder_equallogic_form.html.erb +13 -0
  29. data/app/views/staypuft/steps/_neutron.html.erb +0 -28
  30. data/app/views/staypuft/steps/_nova.html.erb +0 -11
  31. data/app/views/staypuft/steps/network_configuration.html.erb +27 -19
  32. data/app/views/staypuft/steps/services_configuration.html.erb +1 -1
  33. data/app/views/staypuft/subnet_typings/destroy.js.erb +1 -1
  34. data/app/views/staypuft/subnets/_drop_zone.html.erb +5 -5
  35. data/app/views/staypuft/subnets/_subnet_pull.html.erb +3 -4
  36. data/lib/staypuft/engine.rb +2 -0
  37. data/lib/staypuft/version.rb +1 -1
  38. metadata +6 -4
  39. data/app/models/staypuft/deployment/ips.rb +0 -25
  40. data/app/models/staypuft/deployment/vips.rb +0 -40
@@ -203,13 +203,13 @@ module Staypuft
203
203
  :layouts => ALL_LAYOUTS}
204
204
  }
205
205
 
206
- def get_host_format(param_name)
207
- { :string => '<%%= d = @host.deployment; d.ha? ? d.vips.get(:%s) : d.ips.controller_ip %%>' % param_name }
206
+ def get_host_format(param_name, subnet_type_name)
207
+ { :string => "<%= d = @host.deployment; d.ha? ? d.network_query.get_vip(:#{param_name}) : d.network_query.controller_ip('#{subnet_type_name}') %>" }
208
208
  end
209
209
 
210
210
  # virtual ip addresses
211
211
  def vip_format(param_name)
212
- { :string => '<%%= @host.deployment.vips.get(:%s) %%>' % param_name }
212
+ { :string => '<%%= @host.deployment.network_query.get_vip(:%s) %%>' % param_name }
213
213
  end
214
214
 
215
215
  def functional_dependencies
@@ -224,8 +224,8 @@ module Staypuft
224
224
  network_num_networks = { :string => '<%= @host.deployment.nova.num_networks %>' }
225
225
  network_fixed_range = { :string => '<%= @host.deployment.nova.private_fixed_range %>' }
226
226
  network_floating_range = { :string => '<%= @host.deployment.nova.public_floating_range %>' }
227
- network_private_iface = { :string => '<%= @host.deployment.nova.private_iface %>' }
228
- network_public_iface = { :string => '<%= @host.deployment.nova.public_iface %>' }
227
+ network_private_iface = { :string => "<%= @host.deployment.network_query.interface_for_host(@host, '#{Staypuft::SubnetType::TENANT}') %>" }
228
+ network_public_iface = { :string => "<%= @host.deployment.network_query.interface_for_host(@host, '#{Staypuft::SubnetType::EXTERNAL}') %>" }
229
229
  network_create_networks = true
230
230
 
231
231
  # Neutron
@@ -237,12 +237,12 @@ module Staypuft
237
237
  ml2_tunnel_id_ranges = ['10:1000']
238
238
  ml2_vni_ranges = ['10:1000']
239
239
  ovs_tunnel_types = ['vxlan', 'gre']
240
- ovs_tunnel_iface = { :string => '<%= n = @host.deployment.neutron; n.enable_tunneling? ? n.networker_tenant_iface : "" %>' }
241
- ovs_bridge_mappings = { :array => '<%= @host.deployment.neutron.networker_ovs_bridge_mappings %>' }
242
- ovs_bridge_uplinks = { :array => '<%= @host.deployment.neutron.networker_ovs_bridge_uplinks %>' }
243
- compute_ovs_tunnel_iface = { :string => '<%= n = @host.deployment.neutron; n.enable_tunneling? ? n.compute_tenant_iface : "" %>' }
244
- compute_ovs_bridge_mappings = { :array => '<%= @host.deployment.neutron.compute_ovs_bridge_mappings %>' }
245
- compute_ovs_bridge_uplinks = { :array => '<%= @host.deployment.neutron.compute_ovs_bridge_uplinks %>' }
240
+ ovs_tunnel_iface = { :string => '<%= n = @host.deployment.neutron; n.enable_tunneling? ? n.tenant_iface(@host) : "" %>' }
241
+ ovs_bridge_mappings = { :array => '<%= @host.deployment.neutron.networker_ovs_bridge_mappings(@host) %>' }
242
+ ovs_bridge_uplinks = { :array => '<%= @host.deployment.neutron.networker_ovs_bridge_uplinks(@host) %>' }
243
+ compute_ovs_tunnel_iface = { :string => '<%= n = @host.deployment.neutron; n.enable_tunneling? ? n.tenant_iface(@host) : "" %>' }
244
+ compute_ovs_bridge_mappings = { :array => '<%= @host.deployment.neutron.compute_ovs_bridge_mappings(@host) %>' }
245
+ compute_ovs_bridge_uplinks = { :array => '<%= @host.deployment.neutron.compute_ovs_bridge_uplinks(@host) %>' }
246
246
  enable_tunneling = { :string => '<%= @host.deployment.neutron.enable_tunneling?.to_s %>' }
247
247
 
248
248
  # Glance
@@ -263,7 +263,7 @@ module Staypuft
263
263
  cinder_backend_iscsi_name = 'iscsi_backend'
264
264
  cinder_backend_nfs = { :string => '<%= @host.deployment.cinder.nfs_backend? %>' }
265
265
  cinder_backend_nfs_name = 'nfs_backend'
266
- cinder_multiple_backends = false
266
+ cinder_multiple_backends = { :string => '<%= @host.deployment.cinder.multiple_backends? %>' }
267
267
  cinder_nfs_shares = ['<%= @host.deployment.cinder.nfs_uri %>']
268
268
  cinder_nfs_mount_options = 'nosharecache'
269
269
 
@@ -280,11 +280,11 @@ module Staypuft
280
280
  cinder_backend_eqlx_name = ['eqlx_backend']
281
281
  # TODO: confirm these params and add them to model where user input is needed
282
282
  # below dynamic calls are commented out since the model does not yet have san/chap entries
283
- cinder_san_ip = ['<%= @host.deployment.cinder.san_ip %>']
284
- cinder_san_login = ['<%= @host.deployment.cinder.san_login %>']
285
- cinder_san_password = ['<%= @host.deployment.cinder.san_password %>']
286
- cinder_eqlx_group_name = ['<%= @host.deployment.cinder.eqlx_group_name %>']
287
- cinder_eqlx_pool = ['<%= @host.deployment.cinder.eqlx_pool %>']
283
+ cinder_san_ip = { :array => '<%= @host.deployment.cinder.compute_eqlx_san_ips %>' }
284
+ cinder_san_login = { :array => '<%= @host.deployment.cinder.compute_eqlx_san_logins %>' }
285
+ cinder_san_password = { :array => '<%= @host.deployment.cinder.compute_eqlx_san_passwords %>' }
286
+ cinder_eqlx_group_name = { :array => '<%= @host.deployment.cinder.compute_eqlx_group_names %>' }
287
+ cinder_eqlx_pool = { :array => '<%= @host.deployment.cinder.compute_eqlx_pools %>'}
288
288
 
289
289
  cinder_san_thin_provision = ['false']
290
290
  cinder_eqlx_use_chap = ['false']
@@ -326,15 +326,20 @@ module Staypuft
326
326
  neutron_metadata_proxy_secret = { :string => '<%= @host.deployment.passwords.neutron_metadata_proxy_secret %>' }
327
327
 
328
328
 
329
- private_ip = { :string => '<%= @host.ip %>' }
330
- amqp_host = get_host_format :amqp
331
- mysql_host = get_host_format :db
332
- glance_host = get_host_format :glance
333
- auth_host = get_host_format :keystone
334
- neutron_host = get_host_format :neutron
335
- nova_host = get_host_format :nova
329
+ private_ip = { :string => "<%= @host.deployment.network_query.ip_for_host(@host, '#{Staypuft::SubnetType::MANAGEMENT}') %>" }
330
+ # private API/management
331
+ amqp_host = get_host_format :amqp_vip, Staypuft::SubnetType::MANAGEMENT
332
+ mysql_host = get_host_format :db_vip, Staypuft::SubnetType::MANAGEMENT
333
+ glance_host = get_host_format :glance_private_vip, Staypuft::SubnetType::MANAGEMENT
334
+ neutron_host = get_host_format :neutron_private_vip, Staypuft::SubnetType::MANAGEMENT
335
+ #admin API
336
+ auth_host = get_host_format :keystone_admin_vip, Staypuft::SubnetType::ADMIN_API
337
+ # public API
338
+ nova_host = get_host_format :nova_public_vip, Staypuft::SubnetType::PUBLIC_API
336
339
 
337
- controller_host = { :string => '<%= d = @host.deployment; d.ha? ? nil : d.ips.controller_ip %>'}
340
+ controller_admin_host = { :string => "<%= d = @host.deployment; d.ha? ? nil : d.network_query.controller_ip('#{Staypuft::SubnetType::ADMIN_API}') %>"}
341
+ controller_priv_host = { :string => "<%= d = @host.deployment; d.ha? ? nil : d.network_query.controller_ip('#{Staypuft::SubnetType::MANAGEMENT}') %>"}
342
+ controller_pub_host = { :string => "<%= d = @host.deployment; d.ha? ? nil : d.network_query.controller_ip('#{Staypuft::SubnetType::PUBLIC_API}') %>"}
338
343
 
339
344
  {
340
345
  'quickstack::nova_network::controller' => {
@@ -394,11 +399,11 @@ module Staypuft
394
399
  'mysql_host' => mysql_host,
395
400
  'swift_shared_secret' => swift_shared_secret,
396
401
  'swift_ringserver_ip' => '',
397
- 'swift_storage_ips' => { :array => '<%= @host.deployment.ips.controller_ips %>' },
402
+ 'swift_storage_ips' => { :array => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::MANAGEMENT}') %>" },
398
403
  'cinder_gluster_shares' => [],
399
- 'controller_admin_host' => controller_host,
400
- 'controller_priv_host' => controller_host,
401
- 'controller_pub_host' => controller_host },
404
+ 'controller_admin_host' => controller_admin_host,
405
+ 'controller_priv_host' => controller_priv_host,
406
+ 'controller_pub_host' => controller_pub_host },
402
407
  'quickstack::neutron::controller' => {
403
408
  'amqp_provider' => amqp_provider,
404
409
  'tenant_network_type' => tenant_network_type,
@@ -467,11 +472,11 @@ module Staypuft
467
472
  'mysql_host' => mysql_host,
468
473
  'swift_shared_secret' => swift_shared_secret,
469
474
  'swift_ringserver_ip' => '',
470
- 'swift_storage_ips' => { :array => '<%= @host.deployment.ips.controller_ips %>' },
475
+ 'swift_storage_ips' => { :array => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::MANAGEMENT}') %>" },
471
476
  'cinder_gluster_shares' => [],
472
- 'controller_admin_host' => controller_host,
473
- 'controller_priv_host' => controller_host,
474
- 'controller_pub_host' => controller_host },
477
+ 'controller_admin_host' => controller_admin_host,
478
+ 'controller_priv_host' => controller_priv_host,
479
+ 'controller_pub_host' => controller_pub_host },
475
480
  'quickstack::pacemaker::params' => {
476
481
  'include_swift' => 'false',
477
482
  'include_neutron' => neutron,
@@ -494,43 +499,43 @@ module Staypuft
494
499
  'amqp_password' => amqp_pw,
495
500
  'heat_auth_encryption_key' => heat_auth_encrypt_key,
496
501
  'neutron_metadata_proxy_secret' => neutron_metadata_proxy_secret,
497
- 'ceilometer_admin_vip' => vip_format(:ceilometer),
498
- 'ceilometer_private_vip' => vip_format(:ceilometer),
499
- 'ceilometer_public_vip' => vip_format(:ceilometer),
500
- 'cinder_admin_vip' => vip_format(:cinder),
501
- 'cinder_private_vip' => vip_format(:cinder),
502
- 'cinder_public_vip' => vip_format(:cinder),
503
- 'db_vip' => vip_format(:db),
504
- 'glance_admin_vip' => vip_format(:glance),
505
- 'glance_private_vip' => vip_format(:glance),
506
- 'glance_public_vip' => vip_format(:glance),
507
- 'heat_admin_vip' => vip_format(:heat),
508
- 'heat_private_vip' => vip_format(:heat),
509
- 'heat_public_vip' => vip_format(:heat),
510
- 'heat_cfn_admin_vip' => vip_format(:heat_cfn),
511
- 'heat_cfn_private_vip' => vip_format(:heat_cfn),
512
- 'heat_cfn_public_vip' => vip_format(:heat_cfn),
513
- 'horizon_admin_vip' => vip_format(:horizon),
514
- 'horizon_private_vip' => vip_format(:horizon),
515
- 'horizon_public_vip' => vip_format(:horizon),
516
- 'keystone_admin_vip' => vip_format(:keystone),
517
- 'keystone_private_vip' => vip_format(:keystone),
518
- 'keystone_public_vip' => vip_format(:keystone),
519
- 'loadbalancer_vip' => vip_format(:loadbalancer),
520
- 'neutron_admin_vip' => vip_format(:neutron),
521
- 'neutron_private_vip' => vip_format(:neutron),
522
- 'neutron_public_vip' => vip_format(:neutron),
523
- 'nova_admin_vip' => vip_format(:nova),
524
- 'nova_private_vip' => vip_format(:nova),
525
- 'nova_public_vip' => vip_format(:nova),
526
- 'amqp_vip' => vip_format(:amqp),
527
- 'swift_public_vip' => vip_format(:swift),
502
+ 'ceilometer_admin_vip' => vip_format(:ceilometer_admin_vip),
503
+ 'ceilometer_private_vip' => vip_format(:ceilometer_private_vip),
504
+ 'ceilometer_public_vip' => vip_format(:ceilometer_public_vip),
505
+ 'cinder_admin_vip' => vip_format(:cinder_admin_vip),
506
+ 'cinder_private_vip' => vip_format(:cinder_private_vip),
507
+ 'cinder_public_vip' => vip_format(:cinder_public_vip),
508
+ 'db_vip' => vip_format(:db_vip),
509
+ 'glance_admin_vip' => vip_format(:glance_admin_vip),
510
+ 'glance_private_vip' => vip_format(:glance_private_vip),
511
+ 'glance_public_vip' => vip_format(:glance_public_vip),
512
+ 'heat_admin_vip' => vip_format(:heat_admin_vip),
513
+ 'heat_private_vip' => vip_format(:heat_private_vip),
514
+ 'heat_public_vip' => vip_format(:heat_public_vip),
515
+ 'heat_cfn_admin_vip' => vip_format(:heat_cfn_admin_vip),
516
+ 'heat_cfn_private_vip' => vip_format(:heat_cfn_private_vip),
517
+ 'heat_cfn_public_vip' => vip_format(:heat_cfn_public_vip),
518
+ 'horizon_admin_vip' => vip_format(:horizon_admin_vip),
519
+ 'horizon_private_vip' => vip_format(:horizon_private_vip),
520
+ 'horizon_public_vip' => vip_format(:horizon_public_vip),
521
+ 'keystone_admin_vip' => vip_format(:keystone_admin_vip),
522
+ 'keystone_private_vip' => vip_format(:keystone_private_vip),
523
+ 'keystone_public_vip' => vip_format(:keystone_public_vip),
524
+ 'loadbalancer_vip' => vip_format(:loadbalancer_vip),
525
+ 'neutron_admin_vip' => vip_format(:neutron_admin_vip),
526
+ 'neutron_private_vip' => vip_format(:neutron_private_vip),
527
+ 'neutron_public_vip' => vip_format(:neutron_public_vip),
528
+ 'nova_admin_vip' => vip_format(:nova_admin_vip),
529
+ 'nova_private_vip' => vip_format(:nova_private_vip),
530
+ 'nova_public_vip' => vip_format(:nova_public_vip),
531
+ 'amqp_vip' => vip_format(:amqp_vip),
532
+ 'swift_public_vip' => vip_format(:swift_public_vip),
528
533
  'private_ip' => private_ip,
529
- 'cluster_control_ip' => { :string => '<%= @host.deployment.ips.controller_ips.first %>' },
530
- 'lb_backend_server_addrs' => { :array => '<%= @host.deployment.ips.controller_ips %>' },
531
- 'lb_backend_server_names' => { :array => '<%= @host.deployment.ips.controller_fqdns %>' } },
534
+ 'cluster_control_ip' => { :string => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::MANAGEMENT}').first %>" },
535
+ 'lb_backend_server_addrs' => { :array => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::MANAGEMENT}') %>" },
536
+ 'lb_backend_server_names' => { :array => '<%= @host.deployment.network_query.controller_fqdns %>' } },
532
537
  'quickstack::pacemaker::common' => {
533
- 'pacemaker_cluster_members' => { :string => '<%= @host.deployment.ips.controller_ips.join(" ") %>' } },
538
+ 'pacemaker_cluster_members' => { :string => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::MANAGEMENT}').join(' ') %>" } },
534
539
  'quickstack::pacemaker::neutron' => {
535
540
  'ml2_network_vlan_ranges' => ml2_network_vlan_ranges,
536
541
  'ml2_tenant_network_types' => ml2_tenant_network_types,
@@ -580,10 +585,9 @@ module Staypuft
580
585
  'secret_key' => horizon_secret_key },
581
586
  'quickstack::pacemaker::galera' => {
582
587
  'mysql_root_password' => mysql_root_pw,
583
- 'wsrep_cluster_members' => { :array => '<%= @host.deployment.ips.controller_ips %>' } },
588
+ 'wsrep_cluster_members' => { :array => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::MANAGEMENT}') %>" } },
584
589
  'quickstack::pacemaker::swift' => {
585
590
  'swift_shared_secret' => swift_shared_secret,
586
- 'swift_internal_vip' => vip_format(:swift),
587
591
  'swift_storage_ips' => [] },
588
592
  'quickstack::pacemaker::nova' => {
589
593
  'multi_host' => 'true',
@@ -605,7 +609,7 @@ module Staypuft
605
609
  'neutron_metadata_proxy_secret' => neutron_metadata_proxy_secret,
606
610
  'amqp_host' => amqp_host,
607
611
  'mysql_host' => mysql_host,
608
- 'controller_priv_host' => controller_host },
612
+ 'controller_priv_host' => controller_priv_host },
609
613
  'quickstack::storage_backend::cinder' => {
610
614
  'amqp_provider' => amqp_provider,
611
615
  'cinder_db_password' => cinder_db_pw,
@@ -13,16 +13,39 @@ module Staypuft
13
13
 
14
14
  def interfaces_identifiers
15
15
  interfaces = [ self.primary_interface ]
16
- interfaces += self.respond_to?(:interfaces) ? self.interfaces.where("type <> 'Nic::BMC'").physical.map(&:identifier) : []
16
+ interfaces += self.respond_to?(:interfaces) ? self.interfaces.where("type <> 'Nic::BMC'").non_vip.physical.map(&:identifier) : []
17
17
  interfaces
18
18
  end
19
19
 
20
20
  def make_all_interfaces_managed
21
- self.interfaces.each do |interface|
21
+ self.interfaces.non_vip.each do |interface|
22
22
  interface.managed = true
23
23
  interface.save!
24
24
  end
25
25
  end
26
+
27
+ def build_vips(parameters)
28
+ deployment = self.hostgroup.deployment
29
+ typings = deployment.subnet_typings
30
+ types = SubnetType.where(:name => parameters.values).all
31
+ n = 0
32
+
33
+ parameters.each do |parameter, subnet_type|
34
+ type = types.find { |t| t.name == subnet_type }
35
+ raise "unable to find subnet type with name #{subnet_type}" if type.nil?
36
+
37
+ subnet = typings.where(:subnet_type_id => type.id).first.subnet
38
+ raise "unable to find subnet assigned to type #{subnet_type} in deployment #{deployment.name}" if subnet.nil?
39
+
40
+ interface = self.interfaces.build(:type => 'Nic::Managed')
41
+ interface.identifier = "vip#{n}"
42
+ interface.subnet = subnet
43
+ interface.managed = false
44
+ interface.mac = "00:00:00:00:00:#{n.to_s(16).rjust(2, '0')}"
45
+ interface.tag = parameter
46
+ n += 1
47
+ end
48
+ end
26
49
  end
27
50
  end
28
51
  end
@@ -0,0 +1,17 @@
1
+ module Staypuft
2
+ module Concerns
3
+ module SubnetIpManagement
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before_save :reserve_ip
8
+ end
9
+
10
+ def reserve_ip
11
+ if self.identifier =~ /\Avip\d+\Z/ && self.subnet.present? && self.subnet.ipam?
12
+ self.ip ||= self.subnet.unused_ip
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Staypuft
2
+ module Concerns
3
+ module VipNicScopes
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ scope :vip, lambda { where(['identifier LIKE ?', 'vip%']) }
8
+ scope :non_vip, lambda { where(['identifier NOT LIKE ?', 'vip%']) }
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -16,7 +16,7 @@ module Staypuft
16
16
  end
17
17
 
18
18
  define_method "#{name}=" do |value|
19
- instance_variable_set(ivar_name, value)
19
+ instance_variable_set(:"@#{name}", value)
20
20
  end
21
21
 
22
22
  after_save do
@@ -36,6 +36,64 @@ module Staypuft
36
36
  end
37
37
  end
38
38
  end
39
+
40
+ def param_attr_array(*names)
41
+ names.each do |item|
42
+ item.each do |name, type|
43
+ ivar_name = :"@#{name}"
44
+ param_base_name = "ui::#{param_scope}::#{name}"
45
+
46
+ define_method name do
47
+ instance_variable_get(ivar_name) or
48
+ begin
49
+ params = hostgroup.group_parameters.where(['name LIKE ?', "#{param_base_name}%"])
50
+ ivar = []
51
+ params.each do |param|
52
+ value = param.try(:value)
53
+ unless value.nil?
54
+ full, index = *param.name.match(/#{param_base_name}::(\d+)/)
55
+ ivar[index.to_i] ||= type.new({id: index.to_i }.merge(JSON.parse(value)))
56
+ end
57
+ end
58
+ instance_variable_set(ivar_name, ivar)
59
+ end
60
+ end
61
+
62
+ define_method "#{name}=" do |value|
63
+ if value.is_a? Hash
64
+ values = []
65
+ value.each do |k,v|
66
+ values << type.new(v)
67
+ end
68
+ instance_variable_set(:"@#{name}", values)
69
+ else
70
+ instance_variable_set(:"@#{name}", value)
71
+ end
72
+ end
73
+
74
+ define_method "#{name}_attributes=" do |attributes|
75
+ Rails.logger.error attributes
76
+ end
77
+
78
+ after_save do
79
+ values = send(name)
80
+ # Delete all params since array can shrink
81
+ params = hostgroup.group_parameters.where(['name LIKE ?', "#{param_base_name}%"])
82
+ params.each do |param|
83
+ param.try(:destroy)
84
+ end
85
+ if not values.blank?
86
+ values.each_with_index do |value, index|
87
+ param = hostgroup.
88
+ group_parameters.
89
+ find_or_initialize_by_name( "#{param_base_name}::#{index}")
90
+ param.update_attributes!(value: value.to_json(root:false))
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
39
97
  end
40
98
  end
41
99
 
@@ -0,0 +1,80 @@
1
+ #encoding: utf-8
2
+ module Staypuft
3
+ class Deployment::CinderService::Equallogic
4
+ include ActiveModel::Serializers::JSON
5
+ include ActiveModel::Validations
6
+ extend ActiveModel::Naming
7
+
8
+ attr_accessor :id, :san_ip, :san_login, :san_password, :pool, :group_name
9
+ attr_reader :errors
10
+
11
+ def initialize(attrs = {})
12
+ @errors = ActiveModel::Errors.new(self)
13
+ self.attributes = attrs
14
+ end
15
+
16
+ def self.human_attribute_name(attr, options = {})
17
+ attr
18
+ end
19
+
20
+ def self.lookup_ancestors
21
+ [self]
22
+ end
23
+
24
+ def attributes
25
+ { 'san_ip' => nil, 'san_login' => nil, 'san_password' => nil, 'pool' => nil, 'group_name' => nil }
26
+ end
27
+
28
+ def attributes=(attrs)
29
+ attrs.each { |attr, value| send "#{attr}=", value } unless attrs.nil?
30
+ end
31
+
32
+ class SanIpValueValidator < ActiveModel::EachValidator
33
+ def validate_each(record, attribute, value)
34
+ return if value.empty?
35
+
36
+ begin
37
+ ip_addr = IPAddr.new(value)
38
+ ip_range = ip_addr.to_range
39
+ if ip_range.begin == ip_range.end
40
+ true
41
+ else
42
+ record.errors.add attribute, "Specify single IP address, not range"
43
+ false
44
+ end
45
+ rescue
46
+ # not IP addr
47
+ # validating as fqdn
48
+ if /(?=^.{1,254}$)(^(((?!-)[a-zA-Z0-9-]{1,63}(?<!-))|((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.)+[a-zA-Z]{2,63})$)/ =~ value
49
+ true
50
+ else
51
+ record.errors.add attribute, "Invalid IP address or FQDN supplied"
52
+ false
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ validates :san_ip,
59
+ presence: true,
60
+ san_ip_value: true
61
+ validates :san_login,
62
+ presence: true,
63
+ format: /\A[a-zA-Z\d][\w\.\-]*[\w\-]\z/,
64
+ length: { maximum: 16 }
65
+ validates :san_password,
66
+ presence: true,
67
+ format: /\A[!-~]+\z/,
68
+ length: { minimum:3, maximum: 16 }
69
+ validates :pool,
70
+ presence: true,
71
+ format: /\A[[^\p{Z}\p{C}!"\#$%&'\(\)\*\+,\/;<=>\?@\[\]\\\^\{\}|~\.\-:]][[^\p{Z}\p{C}!"\#$%&'\(\)\*\+,\/;<=>\?@\[\]\\\^\{\}|~]]+[[^\p{Z}\p{C}!"\#$%&'\(\)\*\+,\/;<=>\?@\[\]\\\^\{\}|~\.\-:]]\z/,
72
+ length: { maximum: 63,
73
+ too_long: "Too long: max length is %{count} bytes. Using multibyte characters reduces the maximum number of characters allowed.",
74
+ tokenizer: lambda {|str| str.bytes.to_a } }
75
+ validates :group_name,
76
+ presence: true,
77
+ format: /\A[a-zA-Z\d][a-zA-Z\d\-]*\z/,
78
+ length: { maximum: 54 }
79
+ end
80
+ end