staypuft 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/staypuft/nics_assignment.js +32 -0
  3. data/app/assets/javascripts/staypuft/staypuft.js +38 -0
  4. data/app/assets/javascripts/staypuft/subnets_assignment.js +40 -0
  5. data/app/assets/stylesheets/staypuft/bootstrap_and_overrides.css.scss +5 -1
  6. data/app/assets/stylesheets/staypuft/staypuft.css.scss +102 -0
  7. data/app/controllers/staypuft/deployments_controller.rb +5 -0
  8. data/app/controllers/staypuft/interface_assignments_controller.rb +76 -0
  9. data/app/controllers/staypuft/steps_controller.rb +15 -1
  10. data/app/controllers/staypuft/subnet_typings_controller.rb +42 -0
  11. data/app/helpers/staypuft/deployments_helper.rb +18 -3
  12. data/app/lib/actions/staypuft/hostgroup/deploy.rb +38 -1
  13. data/app/lib/staypuft/network_query.rb +35 -0
  14. data/app/lib/staypuft/seeder.rb +113 -39
  15. data/app/models/staypuft/concerns/host_interface_management.rb +28 -0
  16. data/app/models/staypuft/deployment.rb +35 -3
  17. data/app/models/staypuft/interface_assigner.rb +137 -0
  18. data/app/models/staypuft/layout.rb +3 -0
  19. data/app/models/staypuft/layout_subnet_type.rb +12 -0
  20. data/app/models/staypuft/role.rb +15 -0
  21. data/app/models/staypuft/subnet_type.rb +27 -0
  22. data/app/models/staypuft/subnet_typing.rb +11 -0
  23. data/app/views/staypuft/deployments/_assigned_hosts.html.erb +5 -2
  24. data/app/views/staypuft/deployments/_assigned_hosts_table.html.erb +13 -46
  25. data/app/views/staypuft/deployments/_deployed_hosts_table.html.erb +12 -33
  26. data/app/views/staypuft/deployments/_deployment_overview.html.erb +12 -9
  27. data/app/views/staypuft/deployments/_deployment_summary.html.erb +18 -0
  28. data/app/views/staypuft/deployments/_empty_hosts.html.erb +8 -0
  29. data/app/views/staypuft/deployments/_free_hosts.html.erb +1 -1
  30. data/app/views/staypuft/deployments/_free_hosts_table.html.erb +11 -34
  31. data/app/views/staypuft/deployments/_host_head_row.html.erb +11 -0
  32. data/app/views/staypuft/deployments/_host_row.html.erb +30 -0
  33. data/app/views/staypuft/deployments/_hosts_header.html.erb +7 -0
  34. data/app/views/staypuft/deployments/index.html.erb +1 -1
  35. data/app/views/staypuft/deployments/show.html.erb +2 -2
  36. data/app/views/staypuft/interface_assignments/create.js.erb +12 -0
  37. data/app/views/staypuft/interface_assignments/destroy.js.erb +12 -0
  38. data/app/views/staypuft/interface_assignments/index.html.erb +38 -0
  39. data/app/views/staypuft/interfaces/_drop_zone.html.erb +30 -0
  40. data/app/views/staypuft/steps/network_configuration.html.erb +52 -0
  41. data/app/views/staypuft/steps/services_configuration.html.erb +45 -39
  42. data/app/views/staypuft/steps/services_overview.html.erb +1 -1
  43. data/app/views/staypuft/subnet_types/_subnet_type_pull.html.erb +9 -0
  44. data/app/views/staypuft/subnet_typings/create.js.erb +12 -0
  45. data/app/views/staypuft/subnet_typings/destroy.js.erb +12 -0
  46. data/app/views/staypuft/subnet_typings/update.js.erb +14 -0
  47. data/app/views/staypuft/subnets/_drop_zone.html.erb +16 -0
  48. data/app/views/staypuft/subnets/_subnet_pull.html.erb +9 -0
  49. data/config/routes.rb +3 -0
  50. data/db/migrate/20140701074900_create_subnet_type.rb +9 -0
  51. data/db/migrate/20140701075033_create_layout_subnet.rb +10 -0
  52. data/db/migrate/20140701090256_create_staypuft_subnet_typings.rb +14 -0
  53. data/db/migrate/20140825164900_add_orchestration_to_staypuft_role.rb +5 -0
  54. data/db/migrate/20140831234000_add_required_to_subnet_types.rb +5 -0
  55. data/db/seeds.rb +1 -1
  56. data/lib/staypuft/engine.rb +11 -8
  57. data/lib/staypuft/version.rb +1 -1
  58. metadata +135 -91
@@ -103,7 +103,9 @@ module Staypuft
103
103
  :horizon_ha => { :name => 'Horizon (HA)', :class => ['quickstack::pacemaker::horizon'] },
104
104
  :galera_ha => { :name => 'Galera (HA)', :class => ['quickstack::pacemaker::galera'] },
105
105
  :mysql_ha => { :name => 'Mysql (HA)', :class => ['quickstack::pacemaker::mysql'] },
106
- :neutron_ha => { :name => 'Neutron (HA)', :class => ['quickstack::pacemaker::neutron'] }
106
+ :neutron_ha => { :name => 'Neutron (HA)', :class => ['quickstack::pacemaker::neutron'] },
107
+ :generic_rhel_7 => { :name => 'Generic RHEL 7', :class => ['quickstack::openstack_common'] },
108
+ :ceph_osd => { :name => 'Ceph Storage (OSD) (node)', :class => ['quickstack::openstack_common'] },
107
109
  }
108
110
 
109
111
  # The list of roles is still from astapor
@@ -112,44 +114,94 @@ module Staypuft
112
114
  # until we get the real list of roles per layout
113
115
  # layout refs below specify layout keys from layouts hash
114
116
  ROLES = [
115
- { :name => 'Controller (Nova)',
116
- :class => 'quickstack::nova_network::controller',
117
- :layouts => [[:non_ha_nova, 1]],
118
- :services => [:non_ha_amqp, :mysql, :non_ha_keystone, :nova_controller, :non_ha_glance,
119
- :cinder_controller, :heat, :ceilometer] },
120
- { :name => 'Compute (Nova)',
121
- :class => [],
122
- :layouts => [[:ha_nova, 10], [:non_ha_nova, 10]],
123
- :services => [:nova_compute] },
124
- { :name => 'Controller (Neutron)',
125
- :class => 'quickstack::neutron::controller',
126
- :layouts => [[:non_ha_neutron, 1]],
127
- :services => [:non_ha_amqp, :mysql, :non_ha_keystone, :neutron_controller, :non_ha_glance,
128
- :cinder_controller, :heat, :ceilometer] },
129
- { :name => 'Compute (Neutron)',
130
- :class => [],
131
- :layouts => [[:ha_neutron, 10], [:non_ha_neutron, 10]],
132
- :services => [:neutron_compute] },
133
- { :name => 'Neutron Networker',
134
- :class => [],
135
- :layouts => [[:non_ha_neutron, 3]],
136
- :services => [:neutron_networker] },
137
- { :name => 'Cinder Block Storage',
138
- :class => [],
139
- :layouts => [],
140
- :services => [:cinder_node] },
141
- { :name => 'Swift Storage Node',
142
- :class => [],
143
- :layouts => [],
144
- :services => [:swift] },
145
- { :name => 'HA Controller',
146
- :class => [],
147
- :layouts => [[:ha_nova, 1], [:ha_neutron, 1]],
148
- :services => [:ha_controller, :keystone_ha, :load_balancer_ha, :memcached_ha, :qpid_ha,
149
- :glance_ha, :nova_ha, :heat_ha, :cinder_ha, :swift_ha, :horizon_ha, :mysql_ha,
150
- :neutron_ha, :galera_ha] }]
117
+ { :name => 'Controller (Nova)',
118
+ :class => 'quickstack::nova_network::controller',
119
+ :layouts => [[:non_ha_nova, 1]],
120
+ :services => [:non_ha_amqp, :mysql, :non_ha_keystone, :nova_controller, :non_ha_glance,
121
+ :cinder_controller, :heat, :ceilometer],
122
+ :orchestration => 'concurrent' },
123
+ { :name => 'Compute (Nova)',
124
+ :class => [],
125
+ :layouts => [[:ha_nova, 10], [:non_ha_nova, 10]],
126
+ :services => [:nova_compute],
127
+ :orchestration => 'leader' },
128
+ { :name => 'Controller (Neutron)',
129
+ :class => 'quickstack::neutron::controller',
130
+ :layouts => [[:non_ha_neutron, 1]],
131
+ :services => [:non_ha_amqp, :mysql, :non_ha_keystone, :neutron_controller, :non_ha_glance,
132
+ :cinder_controller, :heat, :ceilometer],
133
+ :orchestration => 'concurrent' },
134
+ { :name => 'Compute (Neutron)',
135
+ :class => [],
136
+ :layouts => [[:ha_neutron, 10], [:non_ha_neutron, 10]],
137
+ :services => [:neutron_compute],
138
+ :orchestration => 'concurrent' },
139
+ { :name => 'Neutron Networker',
140
+ :class => [],
141
+ :layouts => [[:non_ha_neutron, 3]],
142
+ :services => [:neutron_networker],
143
+ :orchestration => 'concurrent' },
144
+ { :name => 'Cinder Block Storage',
145
+ :class => [],
146
+ :layouts => [],
147
+ :services => [:cinder_node],
148
+ :orchestration => 'concurrent' },
149
+ { :name => 'Swift Storage Node',
150
+ :class => [],
151
+ :layouts => [],
152
+ :services => [:swift],
153
+ :orchestration => 'concurrent' },
154
+ { :name => 'HA Controller',
155
+ :class => [],
156
+ :layouts => [[:ha_nova, 1], [:ha_neutron, 1]],
157
+ :services => [:ha_controller, :keystone_ha, :load_balancer_ha, :memcached_ha, :qpid_ha,
158
+ :glance_ha, :nova_ha, :heat_ha, :cinder_ha, :swift_ha, :horizon_ha, :mysql_ha,
159
+ :neutron_ha, :galera_ha],
160
+ :orchestration => 'concurrent' },
161
+ { :name => 'Generic RHEL 7',
162
+ :class => '',
163
+ :layouts => [[:non_ha_nova, 20],[:non_ha_neutron, 20], [:ha_nova, 20], [:ha_neutron, 20]],
164
+ :services => [:generic_rhel_7],
165
+ :orchestration => 'concurrent' },
166
+ { :name => 'Ceph Storage Node (OSD)',
167
+ :class => '',
168
+ :layouts => [[:non_ha_nova, 20], [:non_ha_neutron, 20], [:ha_nova, 20], [:ha_neutron, 20]],
169
+ :services => [:ceph_osd],
170
+ :orchestration => 'concurrent' },
171
+ ]
151
172
 
152
173
  CONTROLLER_ROLES = ROLES.select { |h| h.fetch(:name) =~ /Controller/ }
174
+ CEPH_ROLES = ROLES.select {|h| h.fetch(:name) =~ /Ceph/ }
175
+
176
+ ALL_LAYOUTS = LAYOUTS.keys
177
+ SUBNET_TYPES = { :pxe => { :name => Staypuft::SubnetType::PXE,
178
+ :required => true,
179
+ :layouts => ALL_LAYOUTS},
180
+ :management => { :name => Staypuft::SubnetType::MANAGEMENT,
181
+ :required => true,
182
+ :layouts => ALL_LAYOUTS},
183
+ :external => { :name => Staypuft::SubnetType::EXTERNAL,
184
+ :required => true,
185
+ :layouts => ALL_LAYOUTS},
186
+ :cluster_mgmt => { :name => Staypuft::SubnetType::CLUSTER_MGMT,
187
+ :required => true,
188
+ :layouts => ALL_LAYOUTS},
189
+ :admin_api => { :name => Staypuft::SubnetType::ADMIN_API,
190
+ :required => true,
191
+ :layouts => ALL_LAYOUTS},
192
+ :public_api => { :name => Staypuft::SubnetType::PUBLIC_API,
193
+ :required => true,
194
+ :layouts => ALL_LAYOUTS},
195
+ :tenant => { :name => Staypuft::SubnetType::TENANT,
196
+ :required => true,
197
+ :layouts => ALL_LAYOUTS},
198
+ :storage => { :name => Staypuft::SubnetType::STORAGE,
199
+ :required => false,
200
+ :layouts => ALL_LAYOUTS},
201
+ :storage_cluster => { :name => Staypuft::SubnetType::STORAGE_CLUSTERING,
202
+ :required => false,
203
+ :layouts => ALL_LAYOUTS}
204
+ }
153
205
 
154
206
  def get_host_format(param_name)
155
207
  { :string => '<%%= d = @host.deployment; d.ha? ? d.vips.get(:%s) : d.ips.controller_ip %%>' % param_name }
@@ -201,7 +253,7 @@ module Staypuft
201
253
  pcmk_fs_manage = { :string => '<%= @host.deployment.glance.pcmk_fs_manage %>' }
202
254
  pcmk_fs_options = { :string => '<%= @host.deployment.glance.pcmk_fs_options %>' }
203
255
  glance_rbd_store_user = 'images'
204
- glance_rbd_store_pool = 'images'
256
+ glance_rbd_store_pool = 'images'
205
257
 
206
258
  # Cinder
207
259
  volume = true
@@ -662,13 +714,15 @@ module Staypuft
662
714
 
663
715
  def seed_roles
664
716
  ROLES.each do |role_hash|
665
- role = Staypuft::Role.where(:name => role_hash[:name]).first_or_create!
717
+ role = Staypuft::Role.where(:name => role_hash[:name]).first_or_initialize
666
718
 
667
719
  puppet_classes = collect_puppet_classes(Array(role_hash[:class]))
668
720
  puppet_classes.each { |pc| apply_astapor_defaults pc }
669
721
  role.puppetclasses = puppet_classes
670
722
 
671
723
  role.description = role_hash[:description]
724
+ role.orchestration = role_hash[:orchestration]
725
+ role.save!
672
726
  old_role_services_arr = role.role_services.to_a
673
727
  role_hash[:services].each do |key|
674
728
  role_service = role.role_services.where(:service_id => SERVICES[key][:obj].id).first_or_create!
@@ -719,11 +773,31 @@ module Staypuft
719
773
  end
720
774
  end
721
775
 
776
+ def seed_subnet_types
777
+ # default subnet types
778
+ SUBNET_TYPES.each do |key, subnet_type_hash|
779
+ subnet_type = Staypuft::SubnetType.where(:name => subnet_type_hash[:name]).first_or_initialize
780
+ subnet_type.is_required = subnet_type_hash[:required]
781
+ subnet_type.save!
782
+ old_layout_subnet_types_arr = subnet_type.layout_subnet_types.to_a
783
+ subnet_type_hash[:layouts].each do |layout|
784
+ layout_subnet_type = subnet_type.layout_subnet_types.where(:layout_id => LAYOUTS[layout][:obj].id).first_or_create!
785
+ old_layout_subnet_types_arr.delete(layout_subnet_type)
786
+ end
787
+ # delete any prior mappings that remain
788
+ old_layout_subnet_types_arr.each do |layout_subnet_type|
789
+ Rails.logger.warn "destroying old layout_subnet_type for #{layout_subnet_type.layout.name}, #{subnet_type.name}: This should not happen on a clean install"
790
+ subnet_type.layouts.destroy(layout_subnet_type.layout)
791
+ end
792
+ end
793
+ end
794
+
722
795
  def seed
723
796
  seed_layouts
724
797
  seed_services
725
798
  seed_roles
726
799
  seed_functional_dependencies
800
+ seed_subnet_types
727
801
  end
728
802
 
729
803
  def collect_puppet_classes(puppet_class_names)
@@ -0,0 +1,28 @@
1
+ module Staypuft
2
+ module Concerns
3
+ module HostInterfaceManagement
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+
8
+ end
9
+
10
+ def clean_vlan_interfaces
11
+ self.interfaces.virtual.map(&:destroy)
12
+ end
13
+
14
+ def interfaces_identifiers
15
+ interfaces = [ self.primary_interface ]
16
+ interfaces += self.respond_to?(:interfaces) ? self.interfaces.where("type <> 'Nic::BMC'").physical.map(&:identifier) : []
17
+ interfaces
18
+ end
19
+
20
+ def make_all_interfaces_managed
21
+ self.interfaces.each do |interface|
22
+ interface.managed = true
23
+ interface.save!
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -7,12 +7,13 @@ module Staypuft
7
7
  STEP_CONFIGURATION = :configuration
8
8
  STEP_COMPLETE = :complete
9
9
  STEP_OVERVIEW = :overview
10
+ STEP_NETWORKING = :networking
10
11
 
11
12
  NEW_NAME_PREFIX = 'uninitialized_'
12
13
 
13
14
  # supporting import/export
14
15
  EXPORT_PARAMS = [:amqp_provider, :networking, :layout_name, :platform]
15
- EXPORT_SERVICES = [:nova, :neutron, :glance, :cinder, :passwords]
16
+ EXPORT_SERVICES = [:nova, :neutron, :glance, :cinder, :passwords]
16
17
 
17
18
  attr_accessible :description, :name, :layout_id, :layout,
18
19
  :amqp_provider, :layout_name, :networking, :platform
@@ -40,11 +41,17 @@ module Staypuft
40
41
  has_many :services, :through => :roles
41
42
  has_many :hosts, :through => :child_hostgroups
42
43
 
44
+ has_many :subnet_typings, :dependent => :destroy
45
+ has_many :subnet_types, :through => :subnet_typings
46
+ has_many :subnets, :through => :subnet_typings
47
+
43
48
  validates :name, :presence => true, :uniqueness => true
44
49
 
45
50
  validates :layout, :presence => true
46
51
  validates :hostgroup, :presence => true
47
52
 
53
+ validate :all_required_subnet_types_associated, :if => Proc.new { |o| o.form_step == STEP_NETWORKING }
54
+
48
55
  after_validation :check_form_complete
49
56
  before_save :update_layout
50
57
  after_save :update_based_on_settings
@@ -114,6 +121,10 @@ module Staypuft
114
121
  ForemanTasks::Lock.locked? self, nil
115
122
  end
116
123
 
124
+ def hide_ceph_notification?
125
+ ceph_hostgroup.hosts.empty?
126
+ end
127
+
117
128
  # Helper method for getting the in progress foreman task for this
118
129
  # deployment.
119
130
  def task
@@ -127,7 +138,7 @@ module Staypuft
127
138
  end
128
139
 
129
140
  def progress_summary
130
- self.in_progress? ? self.task.humanized[:output] : nil
141
+ self.in_progress? ? self.task.humanized[:output] : nil
131
142
  end
132
143
 
133
144
  # Helper method for getting the progress of this deployment
@@ -186,7 +197,8 @@ module Staypuft
186
197
 
187
198
  class Jail < Safemode::Jail
188
199
  allow :amqp_provider, :networking, :layout_name, :platform, :nova_networking?, :neutron_networking?,
189
- :nova, :neutron, :glance, :cinder, :passwords, :vips, :ips, :ha?, :non_ha?
200
+ :nova, :neutron, :glance, :cinder, :passwords, :vips, :ips, :ha?, :non_ha?,
201
+ :hide_ceph_notification?
190
202
  end
191
203
 
192
204
  # TODO(mtaylor)
@@ -257,6 +269,17 @@ module Staypuft
257
269
  first
258
270
  end
259
271
 
272
+ def unassigned_subnet_types
273
+ self.layout.subnet_types - self.subnet_types
274
+ end
275
+
276
+ def ceph_hostgroup
277
+ Hostgroup.includes(:deployment_role_hostgroup).
278
+ where(DeploymentRoleHostgroup.table_name => { deployment_id: self,
279
+ role_id: Staypuft::Role.cephosd }).
280
+ first
281
+ end
282
+
260
283
  private
261
284
 
262
285
  def update_layout
@@ -269,6 +292,15 @@ module Staypuft
269
292
  update_hostgroup_list
270
293
  end
271
294
 
295
+ def all_required_subnet_types_associated
296
+ associated_subnet_types = self.subnet_typings.map(&:subnet_type)
297
+ missing_required = self.layout.subnet_types.required.select { |t| !associated_subnet_types.include?(t) }
298
+ unless missing_required.empty?
299
+ errors.add :base,
300
+ _("Some required subnet types are missing association of a subnet. Please drag and drop following types: %s") % missing_required.map(&:name).join(', ')
301
+ end
302
+ end
303
+
272
304
  def update_hostgroup_name
273
305
  hostgroup.name = self.name
274
306
  hostgroup.save!
@@ -0,0 +1,137 @@
1
+ module Staypuft
2
+ class InterfaceAssigner
3
+ attr_accessor :deployment, :interface, :subnet, :errors
4
+
5
+ def initialize(deployment, interface, subnet)
6
+ @deployment = deployment
7
+ if interface.is_a?(Nic::Base)
8
+ @interface = interface
9
+ else
10
+ # interface may be Host::Managed which means primary interface, so we create pseudo-interface object
11
+ @interface = Nic::Managed.new(
12
+ :mac => interface.mac,
13
+ :virtual => false,
14
+ :identifier => interface.primary_interface,
15
+ :host => interface,
16
+ :subnet => interface.subnet)
17
+ end
18
+
19
+ @host = @interface.host
20
+ @subnet = subnet
21
+ @errors = []
22
+ end
23
+
24
+ def assign
25
+ if virtual_assignment?
26
+ if (existing = conflicting_interface)
27
+ @errors.push _("Another interface %s on same physical interface with same VLAN exists") % existing.identifier
28
+ return false
29
+ end
30
+ ActiveRecord::Base.transaction do
31
+ unassign_from_other_nics
32
+ assign_virtual
33
+ raise ActiveRecord::Rollback if @errors.present?
34
+ return true
35
+ end
36
+ else
37
+ if @interface.subnet.present? && @interface.subnet != @subnet
38
+ @errors.push _("Interface is already assigned to subnet %s") % @interface.subnet.name
39
+ return false
40
+ end
41
+ ActiveRecord::Base.transaction do
42
+ unassign_from_other_nics
43
+ assign_physical
44
+ raise ActiveRecord::Rollback if @errors.present?
45
+ return true
46
+ end
47
+ end
48
+
49
+ return false # we can get there only after rollback
50
+ end
51
+
52
+ def unassign
53
+ base = @host.interfaces
54
+ base = virtual_assignment? ? base.virtual : base.physical
55
+ ActiveRecord::Base.transaction do
56
+ base.where(:subnet_id => @subnet.id).each do |interface|
57
+ virtual_assignment? ? unassign_virtual(interface) : unassign_physical(interface)
58
+ end
59
+ raise ActiveRecord::Rollback if @errors.present?
60
+ end
61
+ end
62
+
63
+ def virtual_assignment?
64
+ @subnet.vlanid.present?
65
+ end
66
+
67
+ private
68
+
69
+ def assign_virtual
70
+ interface = Nic::Managed.new(
71
+ :subnet => @subnet,
72
+ :physical_device => @interface.identifier,
73
+ :mac => @interface.mac,
74
+ :host => @host,
75
+ :virtual => true,
76
+ :identifier => @interface.identifier + ".#{@subnet.vlanid}")
77
+ suggest_ip(interface) if @subnet.ipam?
78
+ unless interface.save
79
+ @errors.push(*interface.errors.full_messages)
80
+ end
81
+ end
82
+
83
+ def assign_physical
84
+ @interface.subnet = @subnet
85
+ suggest_ip(@interface) if @subnet.ipam?
86
+ unless @interface.save
87
+ @errors.push(*@interface.errors.full_messages)
88
+ end
89
+ end
90
+
91
+ # we have to be sure that we remove both physical and virtual,
92
+ # subnet could become virtual/physical meanwhile
93
+ def unassign_from_other_nics
94
+ unassign_physicals
95
+ unassign_virtuals
96
+ end
97
+
98
+ def unassign_physicals
99
+ @host.interfaces.physical.where(:subnet_id => @subnet.id).each do |interface|
100
+ unassign_physical(interface)
101
+ end
102
+ end
103
+
104
+ # if subnet has IP suggesting enabled we also clear the IP that was suggested
105
+ # this IP will be used for another interface
106
+ def unassign_physical(interface)
107
+ interface.ip = nil if interface.subnet.ipam?
108
+ interface.subnet_id = nil
109
+ unless interface.save
110
+ @errors.push(interface.errors.full_messages)
111
+ end
112
+ end
113
+
114
+ def unassign_virtuals
115
+ @host.interfaces.virtual.where(:subnet_id => @subnet.id).each do |interface|
116
+ unassign_virtual(interface)
117
+ end
118
+ end
119
+
120
+ def unassign_virtual(interface)
121
+ unless interface.destroy
122
+ @errors.push _("Interface %s could not be destroyed") % interface.name
123
+ end
124
+ end
125
+
126
+ def conflicting_interface
127
+ @host.interfaces.
128
+ where(:identifier => @interface.identifier + ".#{subnet.vlanid}").
129
+ where(['id <> ?', @interface.id]).
130
+ first
131
+ end
132
+
133
+ def suggest_ip(interface)
134
+ interface.ip = @subnet.unused_ip if interface.ip.blank?
135
+ end
136
+ end
137
+ end
@@ -5,6 +5,9 @@ module Staypuft
5
5
  has_many :layout_roles, :dependent => :destroy, :order => "staypuft_layout_roles.deploy_order ASC"
6
6
  has_many :roles, :through => :layout_roles, :order => "staypuft_layout_roles.deploy_order ASC"
7
7
 
8
+ has_many :layout_subnet_types, :dependent => :destroy
9
+ has_many :subnet_types, :through => :layout_subnet_types
10
+
8
11
  attr_accessible :description, :name, :networking
9
12
 
10
13
  validates :name, :presence => true, :uniqueness => {:scope => :networking}
@@ -0,0 +1,12 @@
1
+ module Staypuft
2
+ class LayoutSubnetType < ActiveRecord::Base
3
+ attr_accessible :layout_id, :layout, :subnet_type_id, :subnet_type
4
+
5
+ belongs_to :layout
6
+ belongs_to :subnet_type
7
+
8
+ validates :layout, :presence => true
9
+ validates :subnet_type, :presence => true
10
+ validates :layout_id, :uniqueness => { :scope => :subnet_type_id }
11
+ end
12
+ end
@@ -1,5 +1,16 @@
1
1
  module Staypuft
2
2
  class Role < ActiveRecord::Base
3
+ # until we have puppetssh, "run puppet" below means "provision and run puppet"
4
+
5
+ # run puppet on all nodes concurrently
6
+ ORCHESTRATION_CONCURRENT = "concurrent"
7
+ # run puppet on one node at a time
8
+ ORCHESTRATION_SERIAL = "serial"
9
+ # run puppet on the first mode, then the rest concurrently
10
+ ORCHESTRATION_LEADER = "leader"
11
+
12
+ ORCHESTRATION_MODES = [ORCHESTRATION_CONCURRENT, ORCHESTRATION_SERIAL, ORCHESTRATION_LEADER]
13
+
3
14
  has_many :layout_roles, :dependent => :destroy
4
15
  has_many :layouts, :through => :layout_roles
5
16
 
@@ -17,11 +28,15 @@ module Staypuft
17
28
 
18
29
  validates :name, :presence => true, :uniqueness => true
19
30
 
31
+ validates :orchestration, :inclusion => {:in => ORCHESTRATION_MODES }
32
+
20
33
  scope(:in_deployment, lambda do |deployment|
21
34
  joins(:deployment_role_hostgroups).
22
35
  where(DeploymentRoleHostgroup.table_name => { deployment_id: deployment })
23
36
  end)
24
37
 
25
38
  scope(:controller, where(name: Seeder::CONTROLLER_ROLES.map { |h| h.fetch(:name) }))
39
+
40
+ scope(:cephosd, where(name: Seeder::CEPH_ROLES.map { |h| h.fetch(:name) }))
26
41
  end
27
42
  end
@@ -0,0 +1,27 @@
1
+ module Staypuft
2
+ class SubnetType < ActiveRecord::Base
3
+ PXE = 'Provisioning/PXE'
4
+
5
+ MANAGEMENT = 'Management'
6
+ EXTERNAL = 'External'
7
+ CLUSTER_MGMT = 'Cluster Management'
8
+ ADMIN_API = 'Admin API'
9
+ PUBLIC_API = 'Public API'
10
+ TENANT = 'Tenant'
11
+
12
+ STORAGE = 'Storage'
13
+ STORAGE_CLUSTERING = 'Storage Clustering'
14
+
15
+ validates :name, :presence => true
16
+
17
+ has_many :layout_subnet_types, :dependent => :destroy
18
+ has_many :layouts, :through => :layout_subnet_types
19
+
20
+ attr_accessible :name
21
+
22
+ has_many :subnet_typings
23
+ has_many :subnets, :through => :subnet_typings
24
+
25
+ scope :required, lambda { where(:is_required => true) }
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ module Staypuft
2
+ class SubnetTyping < ActiveRecord::Base
3
+ belongs_to :deployment
4
+ belongs_to :subnet_type
5
+ belongs_to :subnet
6
+
7
+ attr_accessible :subnet_type, :subnet_type_id, :subnet, :subnet_id
8
+
9
+ validates :subnet_type_id, :uniqueness => { :scope => :deployment_id }
10
+ end
11
+ end
@@ -5,7 +5,10 @@
5
5
  <div class="pull-right top_actions">
6
6
  <%= render partial: "hosts_filter" %>
7
7
  <div class="pull-right">
8
- <%= submit_tag _("Configure Networks"), :class => "btn btn-default btn-sm", :style => "visibility: hidden" %>
8
+
9
+ <%= submit_tag _("Configure Networks"), :class => "btn btn-default btn-sm dynamic-submit", :disabled => true,
10
+ :'data-submit-to' => deployment_interface_assignments_path(@deployment), :'data-method' => 'GET',
11
+ :id => "configure_networks_button"%>
9
12
  <%= submit_tag _("Unassign Hosts"), :class => "btn btn-primary btn-sm", :disabled => true, :id => "unassign_hosts_button" %>
10
13
  </div>
11
14
  </div>
@@ -40,7 +43,7 @@
40
43
  </td>
41
44
  <td><%= host.cpus %></td>
42
45
  <td><%= host.mem %></td>
43
- <td><%= host.network_interfaces.join('<br/>') if host.network_interfaces %></td>
46
+ <td><%= host_nics(host) %></td>
44
47
  <td class="hidden-s hidden-xs"><%= host.ip %></td>
45
48
  </tr>
46
49
  <% end %>
@@ -1,60 +1,27 @@
1
1
  <div class="tab-pane" id="<%= child_hostgroup.name.parameterize.underscore %>_assigned_hosts">
2
- <% if child_hostgroup.hosts.present? %>
2
+ <% if hosts.present? %>
3
3
  <%= form_tag(unassign_host_deployment_path(id: deployment), class: 'form-horizontal well association') do |f| %>
4
- <h4 class="pull-left"><%= _("Assigned Hosts") %></h4>
5
- <button type="button" class="close pull-right" aria-hidden="true">&nbsp;&nbsp;×</button>
6
- <%= submit_tag _("Unassign Hosts"), :class => "btn btn-primary btn-sm pull-right" %>
7
- <p class="clearfix"></p>
8
- <%= hidden_field_tag :hostgroup_id, child_hostgroup.id %>
4
+
5
+ <%= render 'hosts_header', :header => _("Assigned Hosts"), :child_hostgroup => child_hostgroup, :assign_text => _("Unassign Hosts") %>
6
+
9
7
  <table class="table table-bordered table-striped table-condensed">
10
8
  <thead>
11
- <tr>
12
- <th class="ca">
13
- <%= tag :input, type: 'checkbox', class: 'check_all' %>
14
- </th>
15
- <th><%= sort :name, :as => _('Name') %></th>
16
- <th class="hidden-s hidden-xs"><%= _('Deploying?') %></th>
17
- <th class="hidden-s hidden-xs"><%= sort :ip, :as => _('IP Address') %></th>
18
- </tr>
9
+ <%= render 'host_head_row', :deploying_col => true %>
19
10
  </thead>
20
11
  <tbody>
21
- <% child_hostgroup.hosts.each do |host| %>
12
+ <% hosts.each do |host| %>
22
13
  <% disabled = ForemanTasks::Lock.locked?(deployment, nil) && host.open_stack_deployed? %>
23
- <tr class="<%= ['checkbox_highlight',
24
- ('deploying' if disabled)
25
- ].compact.join(' ') %>">
26
- <td class="ca">
27
- <%= check_box_tag 'host_ids[]',
28
- host.id,
29
- false,
30
- id: "host_ids_#{host.id}",
31
- disabled: disabled %>
32
- <%= hidden_field_tag 'host_ids[]', host.id if disabled %>
33
- </td>
34
- <td class="ellipsis">
35
- <%= host_label(host) %>
36
- </td>
37
- <td class="hidden-s hidden-xs">
38
- <% if disabled %>
39
- <span class="glyphicon glyphicon-cloud-upload"></span>
40
- <% else %>
41
- <span class="glyphicon glyphicon-minus"></span>
42
- <% end %>
43
- </td>
44
- <td class="hidden-s hidden-xs"><%= host.ip %></td>
45
- </tr>
14
+ <%= render 'host_row',
15
+ :custom_css_class => disabled ? 'deploying' : '',
16
+ :disabled => disabled,
17
+ :host => host,
18
+ :checkbox_value => false %>
46
19
  <% end %>
47
20
  </tbody>
48
21
  </table>
22
+
49
23
  <% end %>
50
24
  <% else %>
51
- <div class="well association">
52
- <button type="button" class="close pull-right" aria-hidden="true">×</button>
53
- <h4><%= _("Assigned Hosts") %></h4>
54
- <div class="alert alert-warning">
55
- <span class="glyphicon glyphicon-warning-sign">&nbsp;</span>
56
- <%= _("No hosts were assigned to this group yet.") %>
57
- </div>
58
- </div>
25
+ <%= render 'empty_hosts', :header => _("Assigned Hosts"), :message => _("No hosts were assigned to this group yet.") %>
59
26
  <% end %>
60
27
  </div>