staypuft 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/staypuft/staypuft.js +99 -1
  3. data/app/assets/stylesheets/staypuft/bootstrap_and_overrides.css.scss +48 -4
  4. data/app/assets/stylesheets/staypuft/staypuft.css.scss +7 -11
  5. data/app/controllers/staypuft/deployments_controller.rb +23 -20
  6. data/app/controllers/staypuft/steps_controller.rb +18 -24
  7. data/app/helpers/staypuft/application_helper.rb +16 -1
  8. data/app/helpers/staypuft/deployments_helper.rb +1 -1
  9. data/app/lib/actions/staypuft/host/wait_until_host_ready.rb +2 -8
  10. data/app/lib/staypuft/seeder.rb +702 -0
  11. data/app/models/staypuft/concerns/host_open_stack_affiliation.rb +29 -2
  12. data/app/models/staypuft/concerns/hostgroup_extensions.rb +28 -3
  13. data/app/models/staypuft/concerns/lookup_key_extensions.rb +72 -0
  14. data/app/models/staypuft/deployment/abstract_param_scope.rb +31 -0
  15. data/app/models/staypuft/deployment/attribute_param_storage.rb +41 -0
  16. data/app/models/staypuft/deployment/cinder_service.rb +87 -0
  17. data/app/models/staypuft/deployment/glance_service.rb +85 -0
  18. data/app/models/staypuft/deployment/ips.rb +26 -0
  19. data/app/models/staypuft/deployment/neutron_service.rb +165 -0
  20. data/app/models/staypuft/deployment/nova_service.rb +84 -0
  21. data/app/models/staypuft/deployment/passwords.rb +66 -0
  22. data/app/models/staypuft/deployment/vips.rb +36 -0
  23. data/app/models/staypuft/deployment.rb +179 -72
  24. data/app/models/staypuft/deployment_role_hostgroup.rb +1 -1
  25. data/app/models/staypuft/role.rb +8 -1
  26. data/app/models/staypuft/service/ui_params.rb +12 -1
  27. data/app/views/staypuft/deployments/_assigned_hosts_table.html.erb +60 -0
  28. data/app/views/staypuft/deployments/_deployed_hosts_table.html.erb +51 -0
  29. data/app/views/staypuft/deployments/_free_hosts_table.html.erb +47 -0
  30. data/app/views/staypuft/deployments/edit.html.erb +50 -0
  31. data/app/views/staypuft/deployments/show.html.erb +41 -79
  32. data/app/views/staypuft/deployments/summary.html.erb +4 -1
  33. data/app/views/staypuft/steps/_cinder.html.erb +17 -0
  34. data/app/views/staypuft/steps/_glance.html.erb +16 -0
  35. data/app/views/staypuft/steps/_neutron.html.erb +57 -0
  36. data/app/views/staypuft/steps/_nova.html.erb +34 -0
  37. data/app/views/staypuft/steps/deployment_settings.html.erb +41 -17
  38. data/app/views/staypuft/steps/services_configuration.html.erb +19 -32
  39. data/app/views/staypuft/steps/{services_selection.html.erb → services_overview.html.erb} +7 -3
  40. data/config/routes.rb +2 -0
  41. data/db/migrate/20140623142500_remove_amqp_provider_from_staypuft_deployment.rb +6 -0
  42. data/db/seeds.rb +1 -314
  43. data/lib/staypuft/engine.rb +1 -0
  44. data/lib/staypuft/version.rb +1 -1
  45. metadata +23 -3
@@ -0,0 +1,66 @@
1
+ module Staypuft
2
+ class Deployment::Passwords < Deployment::AbstractParamScope
3
+ PASSWORD_LIST = :admin, :ceilometer_user, :cinder_db, :cinder_user,
4
+ :glance_db, :glance_user, :heat_db, :heat_user, :heat_cfn_user, :mysql_root,
5
+ :keystone_db, :keystone_user, :neutron_db, :neutron_user, :nova_db, :nova_user,
6
+ :swift_admin, :swift_user, :amqp, :amqp_nssdb, :keystone_admin_token,
7
+ :ceilometer_metering_secret, :heat_auth_encrypt_key, :horizon_secret_key,
8
+ :swift_shared_secret, :neutron_metadata_proxy_secret
9
+
10
+ OTHER_ATTRS_LIST = :mode, :single_password
11
+
12
+ def self.param_scope
13
+ 'passwords'
14
+ end
15
+
16
+ param_attr *OTHER_ATTRS_LIST, *PASSWORD_LIST
17
+
18
+ def initialize(deployment)
19
+ super deployment
20
+ self.single_password_confirmation = single_password
21
+ end
22
+
23
+ module Mode
24
+ SINGLE = 'single'
25
+ RANDOM = 'random'
26
+ LABELS = { RANDOM => N_('Generate random password for each service'),
27
+ SINGLE => N_('Use single password for all services') }
28
+ TYPES = LABELS.keys
29
+ HUMAN = N_('Service Password')
30
+ end
31
+
32
+ validates :mode, presence: true, inclusion: { in: Mode::TYPES }
33
+
34
+ # using old hash syntax here since if:, while validly parsing as :if => in
35
+ # ruby itself, in irb the parser treats it as an if keyword, as does both
36
+ # emacs and rubymine, which really messes with indention, etc.
37
+ validates :single_password,
38
+ :presence => true,
39
+ :confirmation => true,
40
+ :if => :single_mode?,
41
+ :length => { minimum: 6 }
42
+
43
+ def set_defaults
44
+ self.mode = Mode::RANDOM
45
+ PASSWORD_LIST.each do |password_field|
46
+ self.send("#{password_field}=", SecureRandom.hex)
47
+ end
48
+ end
49
+
50
+ def single_mode?
51
+ mode == Mode::SINGLE
52
+ end
53
+
54
+ def effective_value(password_field)
55
+ if single_mode?
56
+ single_password
57
+ else
58
+ send(password_field)
59
+ end
60
+ end
61
+
62
+ def id # compatibility with password_f
63
+ single_password
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,36 @@
1
+ module Staypuft
2
+ class Deployment::VIPS < Deployment::AbstractParamScope
3
+
4
+ VIP_NAMES = [:ceilometer, :cinder, :db, :glance, :heat, :horizon, :keystone, :loadbalancer,
5
+ :nova, :neutron, :amqp, :swift]
6
+ COUNT = VIP_NAMES.size
7
+
8
+ def self.param_scope
9
+ 'vips'
10
+ end
11
+
12
+ param_attr :user_range
13
+
14
+ HUMAN = N_('Virtual IP addresses range')
15
+
16
+ def range
17
+ (user_range || default_range)
18
+ # TODO reserve the IP addresses
19
+ end
20
+
21
+ # TODO validate range that it is array with size 11 and that it contains only IPS
22
+
23
+ def default_range
24
+ @default_range ||= begin
25
+ top_ip = hostgroup.subnet.to.split('.').map &:to_i
26
+ ((top_ip[-1]-(COUNT-1))..top_ip[-1]).
27
+ map { |last| [*top_ip[0..2], last] }.
28
+ map { |ip| ip.join '.' }
29
+ end
30
+ end
31
+
32
+ def get(name)
33
+ range[VIP_NAMES.index(name) || raise(ArgumentError, "unknown #{name}")]
34
+ end
35
+ end
36
+ end
@@ -6,22 +6,19 @@ module Staypuft
6
6
  STEP_SETTINGS = :settings
7
7
  STEP_CONFIGURATION = :configuration
8
8
  STEP_COMPLETE = :complete
9
- STEP_SELECTION = :selection
9
+ STEP_OVERVIEW = :overview
10
10
 
11
- NEW_NAME_PREFIX="uninitialized_"
11
+ NEW_NAME_PREFIX = 'uninitialized_'
12
12
 
13
- # amqp providers
14
- AMQP_RABBITMQ = "rabbitmq"
15
- AMQP_QPID = "qpid"
16
- AMQP_PROVIDERS = [AMQP_RABBITMQ, AMQP_QPID]
17
- AMQP_PROVIDER_LABELS = {AMQP_RABBITMQ => "RabbitMQ",
18
- AMQP_QPID => "Qpid" }
19
-
20
- attr_accessible :description, :name, :layout_id, :layout, :amqp_provider
13
+ attr_accessible :description, :name, :layout_id, :layout,
14
+ :amqp_provider, :layout_name, :networking, :platform
21
15
  after_save :update_hostgroup_name
22
16
  after_validation :check_form_complete
23
17
 
24
18
  belongs_to :layout
19
+
20
+ # needs to be defined before hostgroup association
21
+ before_destroy :prepare_destroy
25
22
  belongs_to :hostgroup, :dependent => :destroy
26
23
 
27
24
  has_many :deployment_role_hostgroups, :dependent => :destroy
@@ -45,80 +42,123 @@ module Staypuft
45
42
  validates :layout, :presence => true
46
43
  validates :hostgroup, :presence => true
47
44
 
48
- validates :amqp_provider, :presence => true, :inclusion => {:in => AMQP_PROVIDERS }
45
+ after_validation :check_form_complete
46
+ before_save :update_layout
47
+ after_save :update_based_on_settings
49
48
 
50
- # TODO(mtaylor)
51
- # Use conditional validations to validate the deployment multi-step form.
52
- # deployment.form_step should be used to check the form step the user is
53
- # currently on.
54
- # e.g.
55
- # validates :name, :presence => true, :if => :form_step_is_configuation?
49
+ SCOPES = [[:nova, :@nova_service, NovaService],
50
+ [:neutron, :@neutron_service, NeutronService],
51
+ [:glance, :@glance_service, GlanceService],
52
+ [:cinder, :@cinder_service, CinderService],
53
+ [:passwords, :@passwords, Passwords],
54
+ [:vips, :@vips, VIPS],
55
+ [:ips, :@ips, IPS]]
56
56
 
57
- scoped_search :on => :name, :complete_value => :true
57
+ SCOPES.each do |name, ivar, scope_class|
58
+ define_method name do
59
+ instance_variable_get ivar or
60
+ instance_variable_set ivar, scope_class.new(self)
61
+ end
62
+ after_save { send(name).run_callbacks :save }
63
+ end
58
64
 
59
- def self.available_locks
60
- [:deploy]
65
+ validates_associated :nova, :if => lambda { |d| d.form_step_is_past_configuration? && d.nova.active? }
66
+ validates_associated :neutron, :if => lambda { |d| d.form_step_is_past_configuration? && d.neutron.active? }
67
+ validates_associated :glance, :if => lambda {|d| d.form_step_is_past_configuration? && d.glance.active? }
68
+ validates_associated :cinder, :if => lambda {|d| d.form_step_is_past_configuration? && d.cinder.active? }
69
+ validates_associated :passwords
70
+
71
+ def initialize(attributes = {}, options = {})
72
+ super({ amqp_provider: AmqpProvider::RABBITMQ,
73
+ layout_name: LayoutName::NON_HA,
74
+ networking: Networking::NOVA,
75
+ platform: Platform::RHEL7 }.merge(attributes),
76
+ options)
77
+
78
+ self.hostgroup = Hostgroup.new(name: name, parent: Hostgroup.get_base_hostgroup)
79
+
80
+ self.nova.set_defaults
81
+ self.neutron.set_defaults
82
+ self.glance.set_defaults
83
+ self.cinder.set_defaults
84
+ self.passwords.set_defaults
85
+ self.layout = Layout.where(:name => self.layout_name,
86
+ :networking => self.networking).first
61
87
  end
62
88
 
63
- def destroy
64
- child_hostgroups.each do |h|
65
- h.destroy
66
- end
67
- #do the main destroy
68
- super
89
+ extend AttributeParamStorage
90
+
91
+ # Returns a list of hosts that are currently being deployed.
92
+ def in_progress_hosts(hostgroup)
93
+ return in_progress? ? hostgroup.openstack_hosts : {}
69
94
  end
70
95
 
71
- # After setting or changing layout, update the set of child hostgroups,
72
- # adding groups for any roles not already represented, and removing others
73
- # no longer needed.
74
- def update_hostgroup_list
75
- old_role_hostgroups_arr = deployment_role_hostgroups.to_a
76
- layout.layout_roles.each do |layout_role|
77
- role_hostgroup = deployment_role_hostgroups.where(:role_id => layout_role.role).first_or_initialize do |drh|
78
- drh.hostgroup = Hostgroup.new(name: layout_role.role.name, parent: hostgroup)
79
- end
96
+ # Helper method for checking whether this deployment is in progress or not.
97
+ def in_progress?
98
+ ForemanTasks::Lock.locked? self, nil
99
+ end
80
100
 
81
- role_hostgroup.hostgroup.add_puppetclasses_from_resource(layout_role.role)
82
- layout_role.role.services.each do |service|
83
- role_hostgroup.hostgroup.add_puppetclasses_from_resource(service)
84
- end
85
- role_hostgroup.hostgroup.save!
101
+ # Returns all deployed hosts with no errors (default behaviour). Set
102
+ # errors=true to return all deployed hosts that have errors
103
+ def deployed_hosts(hostgroup, errors=false)
104
+ in_progress? ? {} : hostgroup.openstack_hosts(errors)
105
+ end
86
106
 
87
- role_hostgroup.deploy_order = layout_role.deploy_order
88
- role_hostgroup.save!
107
+ def self.param_scope
108
+ 'deployment'
109
+ end
89
110
 
90
- old_role_hostgroups_arr.delete(role_hostgroup)
91
- end
92
- # delete any prior mappings that remain
93
- old_role_hostgroups_arr.each do |role_hostgroup|
94
- role_hostgroup.hostgroup.destroy
95
- end
111
+ module AmqpProvider
112
+ RABBITMQ = 'rabbitmq'
113
+ QPID = 'qpid'
114
+ LABELS = { RABBITMQ => N_('RabbitMQ'), QPID => N_('Qpid') }
115
+ TYPES = LABELS.keys
116
+ HUMAN = N_('Messaging provider')
96
117
  end
97
118
 
98
- # If layout networking is set to 'neutron', then set include_neutron and
99
- # neutron on the hostgroup if it includes the "quickstack::pacemaker::params"
100
- # puppetclass
101
- def set_custom_params
102
- child_hostgroups.each do |the_hostgroup|
103
- the_hostgroup.puppetclasses.each do |pclass|
104
-
105
- # set params relating to neutron/nova networking choice
106
- if pclass.class_params.where(:key => "include_neutron").first
107
- the_hostgroup.set_param_value_if_changed(pclass, "include_neutron",
108
- layout.networking == 'neutron')
109
- end
110
- if pclass.class_params.where(:key => "neutron").first
111
- the_hostgroup.set_param_value_if_changed(pclass, "neutron",
112
- layout.networking == 'neutron')
113
- end
114
-
115
- # set params relating to rabbitmq/qpid amqp choice
116
- if pclass.class_params.where(:key => "amqp_server").first
117
- the_hostgroup.set_param_value_if_changed(pclass, "amqp_server",
118
- amqp_provider)
119
- end
120
- end
121
- end
119
+ module Networking
120
+ NOVA = 'nova'
121
+ NEUTRON = 'neutron'
122
+ LABELS = { NOVA => N_('Nova Network'), NEUTRON => N_('Neutron Networking') }
123
+ TYPES = LABELS.keys
124
+ HUMAN = N_('Networking')
125
+ end
126
+
127
+ module LayoutName
128
+ NON_HA = 'Controller / Compute'
129
+ HA = 'High Availability Controllers / Compute'
130
+ LABELS = { NON_HA => N_('Controller / Compute'),
131
+ HA => N_('High Availability Controllers / Compute') }
132
+ TYPES = LABELS.keys
133
+ HUMAN = N_('High Availability')
134
+ end
135
+
136
+ module Platform
137
+ RHEL7 = 'rhel7'
138
+ RHEL6 = 'rhel6'
139
+ LABELS = { RHEL7 => N_('Red Hat Enterprise Linux OpenStack Platform 5 with RHEL 7'),
140
+ RHEL6 => N_('Red Hat Enterprise Linux OpenStack Platform 5 with RHEL 6') }
141
+ TYPES = LABELS.keys
142
+ HUMAN = N_('Platform')
143
+ end
144
+
145
+ param_attr :amqp_provider, :networking, :layout_name, :platform
146
+ validates :amqp_provider, :presence => true, :inclusion => { :in => AmqpProvider::TYPES }
147
+ validates :networking, :presence => true, :inclusion => { :in => Networking::TYPES }
148
+ validates :layout_name, presence: true, inclusion: { in: LayoutName::TYPES }
149
+ validates :platform, presence: true, inclusion: { in: Platform::TYPES }
150
+
151
+ # TODO(mtaylor)
152
+ # Use conditional validations to validate the deployment multi-step form.
153
+ # deployment.form_step should be used to check the form step the user is
154
+ # currently on.
155
+ # e.g.
156
+ # validates :name, :presence => true, :if => :form_step_is_configuration?
157
+
158
+ scoped_search :on => :name, :complete_value => :true
159
+
160
+ def self.available_locks
161
+ [:deploy]
122
162
  end
123
163
 
124
164
  def services_hostgroup_map
@@ -133,20 +173,87 @@ module Staypuft
133
173
  self.hosts.any?(&:open_stack_deployed?)
134
174
  end
135
175
 
176
+ def form_step_is_configuration?
177
+ self.form_step.to_sym == Deployment::STEP_CONFIGURATION
178
+ end
179
+
180
+ def form_step_is_past_configuration?
181
+ self.form_step_is_configuration? || self.form_complete?
182
+ end
183
+
136
184
  def form_complete?
137
185
  self.form_step.to_sym == Deployment::STEP_COMPLETE
138
186
  end
139
187
 
188
+ def ha?
189
+ self.layout_name == LayoutName::HA
190
+ end
191
+
140
192
  private
193
+
194
+ def update_layout
195
+ self.layout = Layout.where(:name => layout_name, :networking => networking).first
196
+ end
197
+
198
+ def update_based_on_settings
199
+ update_hostgroup_name
200
+ update_operating_system
201
+ update_hostgroup_list
202
+ end
203
+
141
204
  def update_hostgroup_name
142
205
  hostgroup.name = self.name
143
206
  hostgroup.save!
144
207
  end
145
208
 
209
+ def update_operating_system
210
+ self.hostgroup.operatingsystem = case platform
211
+ when Platform::RHEL6
212
+ Operatingsystem.where(name: 'RedHat', major: '6', minor: '5').first
213
+ when Platform::RHEL7
214
+ Operatingsystem.where(name: 'RedHat', major: '7', minor: '0').first
215
+ Operatingsystem.where(name: 'RedHat', major: '6', minor: '5').first
216
+ end or
217
+ raise 'missing Operatingsystem'
218
+ self.hostgroup.save!
219
+ end
220
+
221
+ # After setting or changing layout, update the set of child hostgroups,
222
+ # adding groups for any roles not already represented, and removing others
223
+ # no longer needed.
224
+ def update_hostgroup_list
225
+ old_deployment_role_hostgroups = deployment_role_hostgroups.to_a
226
+ new_deployment_role_hostgroups = layout.layout_roles.map do |layout_role|
227
+ deployment_role_hostgroup = deployment_role_hostgroups.where(:role_id => layout_role.role).first_or_initialize do |drh|
228
+ drh.hostgroup = Hostgroup.new(name: layout_role.role.name, parent: hostgroup)
229
+ end
230
+
231
+ deployment_role_hostgroup.hostgroup.add_puppetclasses_from_resource(layout_role.role)
232
+ layout_role.role.services.each do |service|
233
+ deployment_role_hostgroup.hostgroup.add_puppetclasses_from_resource(service)
234
+ end
235
+ # deployment_role_hostgroup.hostgroup.save!
236
+
237
+ deployment_role_hostgroup.deploy_order = layout_role.deploy_order
238
+ deployment_role_hostgroup.save!
239
+
240
+ deployment_role_hostgroup
241
+ end
242
+
243
+ # delete any prior mappings that remain
244
+ (old_deployment_role_hostgroups - new_deployment_role_hostgroups).each &:destroy
245
+ end
246
+
146
247
  # Checks to see if the form step was the last in the series. If so it sets
147
248
  # the form_step field to complete.
148
249
  def check_form_complete
149
250
  self.form_step = Deployment::STEP_COMPLETE if self.form_step.to_sym == Deployment::STEP_CONFIGURATION
150
251
  end
252
+
253
+ def prepare_destroy
254
+ hosts.each &:open_stack_unassign
255
+ child_hostgroups.each &:destroy
256
+ end
257
+
151
258
  end
152
259
  end
@@ -3,7 +3,7 @@ module Staypuft
3
3
  attr_accessible :deployment, :deployment_id, :hostgroup, :hostgroup_id, :role, :role_id, :deploy_order
4
4
 
5
5
  belongs_to :deployment
6
- belongs_to :hostgroup
6
+ belongs_to :hostgroup, dependent: :destroy
7
7
  belongs_to :role
8
8
  has_many :services, :through => :role
9
9
 
@@ -15,6 +15,13 @@ module Staypuft
15
15
 
16
16
  attr_accessible :description, :max_hosts, :min_hosts, :name
17
17
 
18
- validates :name, :presence => true, :uniqueness => true
18
+ validates :name, :presence => true, :uniqueness => true
19
+
20
+ scope(:in_deployment, lambda do |deployment|
21
+ joins(:deployment_role_hostgroups).
22
+ where(DeploymentRoleHostgroup.table_name => { deployment_id: deployment })
23
+ end)
24
+
25
+ scope(:controller, where(name: Seeder::CONTROLLER_ROLES.map { |h| h.fetch(:name) }))
19
26
  end
20
27
  end
@@ -83,7 +83,10 @@ Staypuft::Service::UI_PARAMS = {
83
83
  'swift_storage_device',
84
84
  'swift_storage_ips'],
85
85
  'Glance (non-HA)' => ['glance_db_password',
86
- 'glance_user_password'],
86
+ 'glance_user_password',
87
+ 'glance_backend',
88
+ 'glance_rbd_store_user',
89
+ 'glance_rbd_store_pool'],
87
90
  'Cinder (controller)' => ['cinder_backend_eqlx',
88
91
  'cinder_backend_eqlx_name',
89
92
  'cinder_backend_gluster',
@@ -92,6 +95,8 @@ Staypuft::Service::UI_PARAMS = {
92
95
  'cinder_backend_iscsi_name',
93
96
  'cinder_backend_nfs',
94
97
  'cinder_backend_nfs_name',
98
+ 'cinder_backend_rbd',
99
+ 'cinder_backend_rbd_name',
95
100
  'cinder_db_password',
96
101
  'cinder_multiple_backends',
97
102
  'cinder_gluster_shares',
@@ -106,6 +111,12 @@ Staypuft::Service::UI_PARAMS = {
106
111
  'cinder_eqlx_use_chap',
107
112
  'cinder_eqlx_chap_login',
108
113
  'cinder_eqlx_chap_password',
114
+ 'cinder_rbd_pool',
115
+ 'cinder_rbd_ceph_conf',
116
+ 'cinder_rbd_flatten_volume_from_snapshot',
117
+ 'cinder_rbd_max_clone_depth',
118
+ 'cinder_rbd_user',
119
+ 'cinder_rbd_secret_uuid',
109
120
  'cinder_user_password'],
110
121
  'Heat' => ['heat_cfn',
111
122
  'heat_cloudwatch',
@@ -0,0 +1,60 @@
1
+ <div class="tab-pane" id="<%= child_hostgroup.name.parameterize.underscore %>_assigned_hosts">
2
+ <% if child_hostgroup.hosts.present? %>
3
+ <%= form_tag(unassign_host_deployment_path(id: deployment), class: 'form-horizontal well association') do |f| %>
4
+ <%= submit_tag _("Unassign Hosts"), :class => "btn btn-primary btn-sm pull-left" %>
5
+ <h4 class="pull-left"><%= _("Assigned Hosts") %></h4>
6
+ <button type="button" class="close" aria-hidden="true">×</button>
7
+ <p class="clearfix"></p>
8
+ <%= hidden_field_tag :hostgroup_id, child_hostgroup.id %>
9
+ <table class="table table-bordered table-striped table-condensed">
10
+ <thead>
11
+ <tr>
12
+ <th class="ca">
13
+ <%= check_box_tag :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>
19
+ </thead>
20
+ <tbody>
21
+ <% child_hostgroup.hosts.each do |host| %>
22
+ <% 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>
46
+ <% end %>
47
+ </tbody>
48
+ </table>
49
+ <% end %>
50
+ <% 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>
59
+ <% end %>
60
+ </div>
@@ -0,0 +1,51 @@
1
+ <div class="tab-pane" id="<%= child_hostgroup.name.parameterize.underscore %>_deployed_hosts">
2
+ <% if child_hostgroup.hosts.select { |h| !ForemanTasks::Lock.locked?(deployment, nil) && h.open_stack_deployed? }.present? %>
3
+ <%= form_tag(unassign_host_deployment_path(id: deployment), class: 'form-horizontal well association') do |f| %>
4
+ <%= submit_tag _("Unassign Hosts"),
5
+ :class => "btn btn-danger btn-sm pull-left",
6
+ :'data-toggle' => "tooltip",
7
+ :'data-placement' => "right",
8
+ :title => _("Unassigning deployed hosts may lead to unexpected problems.") %>
9
+ <h4 class="pull-left"><%= _("Deployed Hosts") %></h4>
10
+ <button type="button" class="close" aria-hidden="true">×</button>
11
+ <p class="clearfix"></p>
12
+ <%= hidden_field_tag :hostgroup_id, child_hostgroup.id %>
13
+ <table class="table table-bordered table-striped table-condensed">
14
+ <thead>
15
+ <tr>
16
+ <th class="ca">
17
+ <%= check_box_tag :check_all %>
18
+ </th>
19
+ <th><%= sort :name, :as => _('Name') %></th>
20
+ <th class="hidden-s hidden-xs"><%= sort :ip, :as => _('IP Address') %></th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <% child_hostgroup.hosts.select{ |h| !ForemanTasks::Lock.locked?(deployment, nil) && h.open_stack_deployed? }.each do |host| %>
25
+ <tr class="checkbox_highlight deployed">
26
+ <td class="ca">
27
+ <%= check_box_tag 'host_ids[]',
28
+ host.id,
29
+ false,
30
+ id: "host_ids_#{host.id}" %>
31
+ </td>
32
+ <td class="ellipsis">
33
+ <%= host_label(host) %>
34
+ </td>
35
+ <td class="hidden-s hidden-xs"><%= host.ip %></td>
36
+ </tr>
37
+ <% end %>
38
+ </tbody>
39
+ </table>
40
+ <% end %>
41
+ <% else %>
42
+ <div class="well association">
43
+ <button type="button" class="close pull-right" aria-hidden="true">×</button>
44
+ <h4><%= _("Deployed Hosts") %></h4>
45
+ <div class="alert alert-warning">
46
+ <span class="glyphicon glyphicon-warning-sign">&nbsp;</span>
47
+ <%= _("No hosts from this group have been deployed yet.") %>
48
+ </div>
49
+ </div>
50
+ <% end %>
51
+ </div>
@@ -0,0 +1,47 @@
1
+ <div class="tab-pane" id="<%= child_hostgroup.name.parameterize.underscore %>_free_hosts">
2
+ <% if child_hostgroup.free_hosts.present? %>
3
+ <%= form_tag(associate_host_deployment_path(id: deployment), class: 'form-horizontal well association') do |f| %>
4
+ <%= submit_tag _("Assign Hosts"), :class => "btn btn-primary btn-sm pull-left" %>
5
+ <h4 class="pull-left"><%= _("Free Hosts") %></h4>
6
+ <button type="button" class="close" aria-hidden="true">×</button>
7
+ <p class="clearfix"></p>
8
+ <%= hidden_field_tag :hostgroup_id, child_hostgroup.id %>
9
+ <table class="table table-bordered table-striped table-condensed">
10
+ <thead>
11
+ <tr>
12
+ <th class="ca">
13
+ <%= check_box_tag :check_all %>
14
+ </th>
15
+ <th><%= sort :name, :as => _('Name') %></th>
16
+ <th class="hidden-s hidden-xs"><%= sort :ip, :as => _('IP Address') %></th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <% child_hostgroup.free_hosts.each do |host| %>
21
+ <tr class="checkbox_highlight">
22
+ <td class="ca">
23
+ <%= check_box_tag 'host_ids[]',
24
+ host.id,
25
+ child_hostgroup.host_ids.include?(host.id),
26
+ id: "host_ids_#{host.id}" %>
27
+ </td>
28
+ <td class="ellipsis">
29
+ <%= host_label(host) %>
30
+ </td>
31
+ <td class="hidden-s hidden-xs"><%= host.ip %></td>
32
+ </tr>
33
+ <% end %>
34
+ </tbody>
35
+ </table>
36
+ <% end %>
37
+ <% else %>
38
+ <div class="well association">
39
+ <button type="button" class="close pull-right" aria-hidden="true">×</button>
40
+ <h4><%= _("Free Hosts") %></h4>
41
+ <div class="alert alert-warning">
42
+ <span class="glyphicon glyphicon-warning-sign">&nbsp;</span>
43
+ <%= _("All available hosts have been already assigned.") %>
44
+ </div>
45
+ </div>
46
+ <% end %>
47
+ </div>