staypuft 0.3.0 → 0.3.1

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.
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>