src/app/controllers/instances_controller.rb
#
# Copyright 2011 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class InstancesController < ApplicationController
before_filter :require_user
before_filter :load_instance, :only => [:show, :key, :edit, :update, :stop, :reboot]
before_filter :set_view_vars, :only => [:show, :index, :export_events]
before_filter :check_inaccessible_instances, :only => [:stop, :multi_stop]
def index
@params = params
@title = _('Instances')
save_breadcrumb(instances_path(:viewstate => viewstate_id))
load_instances
respond_to do |format|
format.html
format.js { render :partial => 'list' }
format.json { render :json => @instances.map{ |instance| view_context.instance_for_mustache(instance) } }
format.xml { @deployment = @instances.first.deployment if params[:deployment_id] }
end
end
def show
load_instances
save_breadcrumb(instance_path(@instance), @instance.name)
@events = @instance.events.paginate(:page => params[:page] || 1)
@view = params[:details_tab].blank? ? 'properties' : params[:details_tab]
@details_tab = 'properties' unless ['properties', 'history',
'parameters', 'permissions'].include?(@details_tab)
@tabs = [
{:name => _('Properties'), :view => @view, :id => 'properties'},
{:name => _('Config Parameters'), :view => 'parameters', :id => 'parameters'},
{:name => _('History'), :view => 'history', :id => 'history'}
]
@details_tab = @tabs.find {|t| t[:view] == @view}
respond_to do |format|
format.html { render :action => 'show'}
format.js do
if params.delete :details_pane
render :partial => 'layouts/details_pane' and return
end
render :partial => @details_tab[:view] and return
end
format.json { render :json => @instance }
format.xml
end
end
def edit
require_privilege(Alberich::Privilege::MODIFY, @instance)
respond_to do |format|
format.html
format.js { render :partial => 'edit', :id => @instance.id }
format.json { render :json => @instance }
end
end
def update
# TODO - This USER_MUTABLE_ATTRS business is because what a user and app components can do
# will be greatly different. (e.g., a user shouldn't be able to change an instance's pool,
# since it won't do what they expect). As we build this out, this logic will become more complex.
attrs = {}
params[:instance].each_pair{|k,v| attrs[k] = v if Instance::USER_MUTABLE_ATTRS.include?(k)}
respond_to do |format|
if check_privilege(Alberich::Privilege::MODIFY, @instance) and @instance.update_attributes(attrs)
flash[:success] = _('The Instance %s was successfully updated.') % @instance.name
format.html { redirect_to @instance }
format.js { render :partial => 'properties' }
format.json { render :json => @instance }
else
flash[:error] = _('The Instance %s could not be updated.') % @instance.name
format.html { render :action => :edit }
format.js { render :partial => 'edit' }
format.json { render :json => @instance.errors, :status => :unprocessable_entity }
end
end
end
def destroy
destroyed = []
failed = []
Instance.find(ids_list).each do |instance|
if check_privilege(Alberich::Privilege::MODIFY, instance) && instance.destroyable?
instance.destroy
destroyed << instance.name
else
failed << instance.name
end
end
flash[:success] = n_('The Instance %s was successfully deleted.','The Instances %s were successfully deleted.',destroyed.size) % destroyed.to_sentence if destroyed.present?
flash[:error] = n_('The Instance %s could not be deleted.','The Instances %s could not be deleted.',failed.size) % failed.to_sentence if failed.present?
respond_to do |format|
# FIXME: _list does not show flash messages, but I'm not sure that showing _list is proper anyway
format.html { render :action => :show }
format.js do
set_view_vars
load_instances
render :partial => 'list'
end
format.json { render :json => {:success => destroyed, :errors => failed} }
end
end
def key
respond_to do |format|
if @instance.instance_key.nil?
flash[:warning] = _('SSH Key not found for this Instance.')
format.html { redirect_to instance_path(@instance) }
format.js { render :partial => 'properties' }
format.json { render :json => flash[:warning], :status => :not_found }
else
format.html { send_data @instance.instance_key.pem,
:filename => "#{@instance.instance_key.name}.pem",
:type => "text/plain" }
format.js do
send_data @instance.instance_key.pem,
:filename => "#{@instance.instance_key.name}.pem",
:type => "text/plain"
end
format.json { render :json => {:key => @instance.instance_key.pem,
:filename => "#{@instance.instance_key.name}.pem",
:type => "text/plain" } }
end
end
end
def multi_stop
notices = []
errors = []
@instances_to_stop.each do |instance|
begin
require_privilege(Alberich::Privilege::USE,instance)
if @inaccessible_instances.include?(instance)
instance.forced_stop(current_user)
notices << "#{instance.name}: #{_('state changed to stopped.')}"
else
instance.stop(current_user)
notices << "#{instance.name}: #{_('stop action was successfully queued.')}"
end
rescue Exception => ex
errors << "#{instance.name}: " + ex.message
log_backtrace(ex)
end
end
errors = _('You must select one or more Instances to stop.') if errors.blank? && notices.blank?
flash[:notice] = notices unless notices.blank?
flash[:error] = errors unless errors.blank?
respond_to do |format|
format.html { redirect_to params[:backlink] || pools_path(:view => 'filter', :details_tab => 'instances') }
format.json { render :json => {:success => notices, :errors => errors} }
end
end
def export_events
send_data(Instance.csv_export(load_instances),
:type => 'text/csv; charset=utf-8; header=present',
:filename => "export.csv")
end
def stop
if @inaccessible_instances.include?(@instance)
do_operation(:forced_stop)
else
do_operation(:stop)
end
end
def reboot
do_operation(:reboot)
end
def multi_reboot
notices = []
errors = []
Instance.find(params[:instance_selected] || []).each do |instance|
begin
require_privilege(Alberich::Privilege::USE,instance)
instance.reboot(current_user)
notices << "#{instance.name}: #{_('%s: reboot action was successfully queued.') % instance.name}"
rescue Exception => ex
errors << "#{instance.name}: " + ex.message
log_backtrace(ex)
end
end
# If nothing is selected, display an error message:
errors = _('You must select one or more Instances to reboot.') if errors.blank? && notices.blank?
flash[:notice] = notices unless notices.blank?
flash[:error] = errors unless errors.blank?
respond_to do |format|
format.html { redirect_to params[:backlink] || pools_path(:view => 'filter', :details_tab => 'instances') }
format.json { render :json => {:success => notices, :errors => errors} }
end
end
def filter
redirect_to_original({"instances_preset_filter" => params[:instances_preset_filter], "instances_search" => params[:instances_search]})
end
private
def load_instance
@instance = Instance.find(Array(params[:id]).first)
require_privilege(Alberich::Privilege::USE,@instance)
end
def init_new_instance_attrs
@pools = Pool.list_for_user(current_session, current_user,
Alberich::Privilege::CREATE, Instance).
where(:enabled => true)
@realms = FrontendRealm.all
@hardware_profiles = HardwareProfile.all(
:include => :architecture,
:conditions => {
:provider_id => nil
#FIXME arch?
}
)
end
def set_view_vars
@header = [
{:name => _('VM NAME'), :sort_attr => 'name'},
{:name => _('STATUS'), :sortable => false},
{:name => _('PUBLIC ADDRESS'), :sort_attr => 'public_addresses'},
{:name => _('PROVIDER'), :sortable => false},
{:name => _('CREATED BY'), :sort_attr => 'users.last_name'},
]
@pools = Pool.list_for_user(current_session, current_user,
Alberich::Privilege::CREATE, Instance)
end
def load_instances
if params[:deployment_id].blank?
@instances = paginate_collection(
Instance.includes(:owner).
apply_filters(:preset_filter_id => params[:instances_preset_filter],
:search_filter => params[:instances_search]).
list_for_user(current_session, current_user, Alberich::Privilege::VIEW).
list(sort_column(Instance), sort_direction).
where("instances.pool_id" => @pools),
params[:page], PER_PAGE)
else
@instances = paginate_collection(
Instance.includes(:owner).
apply_filters(:preset_filter_id => params[:instances_preset_filter],
:search_filter => params[:instances_search]).
list(sort_column(Instance), sort_direction).
list_for_user(current_session, current_user, Alberich::Privilege::VIEW).
where("instances.pool_id" => @pools,
"instances.deployment_id" => params[:deployment_id]),
params[:page], PER_PAGE)
end
end
def check_inaccessible_instances
# @instance is set only on stop action
@instances_to_stop = @instance ? Array(@instance) : Instance.find(Array(params[:instance_selected]))
@instances_to_stop.reject! { |inst| !check_privilege(Alberich::Privilege::USE, inst) }
@inaccessible_instances = Instance.stoppable_inaccessible_instances(@instances_to_stop)
if params[:terminate].blank? and @inaccessible_instances.any?
respond_to do |format|
format.html { render :action => :confirm_terminate }
format.json { render :json => {:inaccessbile_instances => @inaccessible_instances}, :status => :unprocessable_entity }
end
return false
end
true
end
def do_operation(operation)
begin
@instance.send(operation, current_user)
flash[:notice] =
case operation
when :forced_stop
_('state changed to stopped.')
when :stop
_('stop action was successfully queued.')
when :reboot
_('%s: reboot action was successfully queued.') % @instance.name
end
rescue Exception => err
flash[:error] =
case operation
when :stop
_('The Instance %{name} was not stopped because %{err}') % {:name => @instance.name, :err => err}
when :reboot
_('The Instance %{name} was not rebooted because %{err}') % {:name => @instance.name, :err => err}
end
end
respond_to do |format|
format.html { redirect_to deployment_path(@instance.deployment, :details_tab => 'instances') }
end
end
end