don't crash when saving limits (bnc#553455)
[opensuse:yast-web-client.git] / plugins / status / app / controllers / status_controller.rb
1 require 'yast/service_resource'
2 require 'client_exception'
3 require 'open-uri'
4
5 class StatusController < ApplicationController
6   include ProxyLoader
7   
8   before_filter :login_required
9   layout "main"
10
11   private
12   def client_permissions
13     @client = YaST::ServiceResource.proxy_for('org.opensuse.yast.system.status')
14     unless @client
15       flash[:notice] = _("Invalid session, please login again.")
16       redirect_to( logout_path ) and return
17     end
18     @permissions = @client.permissions
19   end
20
21   def limits_reached
22     @limits_list.each {|key, data|
23       next if key == :reached
24       keys = key.split "/"
25       group = keys[1]
26       metric_name = keys[2]
27
28       if @data_group.has_key? group and @data_group[group].has_key? metric_name
29         for value in @data_group[group][metric_name]
30           if not @limits_list[key][:min][0].nil? and value[1] < @limits_list[key][:min][0][1]\
31              or not @limits_list[key][:max][0].nil? and value[1] > @limits_list[key][:max][0][1]
32             if key == "df"
33               @limits_list[:reached] += _("Disk free limits exceeded;")
34             else
35               @limits_list[:reached] += key + ";"
36             end
37             break
38           end
39         end
40       else
41         logger.debug "error: metric not found"
42       end
43     }
44     @limits_list[:reached]
45   end
46
47   def write_data_group(label, group, metric_name)
48     metric_name += "/" + label.name if label.name != "value" #more than one labels of a group
49     values = label.attributes["values"]
50     if values.uniq != ["invalid"] #use only entries which have at least one valid value
51       value_size = values.length
52       divisor = (group == "memory")? 1024*1024 : 1 # take MByte for the value
53       data_list = Array.new
54       value_size.times{|t| data_list << [t,values[t].to_f/divisor]}
55       if group == "df"
56         data_list.reject! {|value| value[1] == 0 } if group == "df"  #df returns sometime 0 entries
57         data_list = [[0,0]] if data_list.size == 0 #it is really 0 :-)
58       end
59       @data_group[group].merge!({metric_name => data_list})
60
61       limits = label.attributes["limits"]
62       if limits
63         @limits_list["/#{group}/#{metric_name}"] = {:min=>Array.new, :max=>Array.new}
64         if label.attributes["limits"] and limits.attributes["min"] #limits.has_key? "min"
65           minimum = limits.attributes["min"].to_f/divisor
66           value_size.times{|i| @limits_list["/#{group}/#{metric_name}"][:min] << [i,minimum]}
67         end
68         if label.attributes["limits"] and limits.attributes["max"] #limits.has_key? "min"
69           maximum = limits.attributes["max"].to_f/divisor
70           value_size.times{|i| @limits_list["/#{group}/#{metric_name}"][:max] << [i,maximum]}
71         end
72       end
73     else
74       logger.debug "#{group} #{metric_name} #{label.name} has no valid entry"
75     end 
76   end
77
78   def create_data_map(tree)
79     tree.attributes["metric"].each{ |metric|
80       metric_name = metric.name
81       group = metric.metricgroup
82       @data_group[group] ||= Hash.new
83       interval = metric.interval #TODO: not used yet
84       starttime = metric.starttime
85       case metric.attributes["label"]
86       when YaST::ServiceResource::Proxies::Status::Metric::Label # one label
87         write_data_group(metric.attributes["label"], group, metric_name)
88       when Array # several label
89         metric.attributes["label"].each{ |label|
90           write_data_group(label, group, metric_name)
91       }
92       end
93     }
94   end
95
96   def create_data
97     @limits_list = Hash.new
98     @limits_list[:reached] = String.new
99     @data_group = Hash.new
100     status = []
101     
102     till = Time.new
103     from = till - 300 #last 5 minutes
104 #puts File.read(@client.find(:dummy_param, :params => { :start => from.to_i.to_s, :stop => till.to_i.to_s }))
105     ActionController::Base.benchmark("Status data read from the server") do
106       status = @client.find(:dummy_param, :params => { :start => from.to_i.to_s, :stop => till.to_i.to_s })
107     end
108     create_data_map status
109     logger.debug @data_group.inspect
110     true
111   end
112
113   #removing logging data and add limits which are defined in params
114   def create_save_data(status, params, label = "") #TODO: customize for new xml format
115     status.each do |key, value|
116      if key.start_with?("values")
117        status.delete(key)
118      elsif
119        next_label = label+ "/" + key
120        create_save_data(value, params, next_label) if value.is_a? Hash
121      end
122     end
123     if params.has_key?(label+"/value")
124       limit = Hash.new
125       key_split = label.split("/")
126       if key_split.size>1 && key_split[1]=="memory" # MByte for the value --> change it to Byte
127         limit["value"] = params[label+"/value"].to_f*1024*1024
128       else
129         limit["value"] = params[label+"/value"]
130       end
131       limit["maximum"] = params[label+"/maximum"] == "true"?true:false
132       status["limit"] = limit
133     end
134     return status
135   end
136
137  # Initialize GetText and Content-Type.
138   init_gettext "yast_webclient_status"
139
140   public
141
142   def initialize
143   end
144
145   def edit
146     return unless client_permissions
147     create_data
148   end
149
150   def ajax_log_custom
151     # set the site to the view so it can load the log
152     # dynamically
153     if not params.has_key?(:id)
154       raise "Unknown log file"
155     end
156     
157     lines = params[:lines] || 5
158     log_url = URI.parse(YaST::ServiceResource::Session.site.to_s)
159     log_url = log_url.merge("logs/#{params[:id]}.txt?lines=#{lines}")
160     logger.info "requesting #{log_url}"
161     @content = open(log_url).read
162     render :partial => 'status_log'
163   end
164   
165   def index
166     return unless client_permissions
167
168     log = YaST::ServiceResource.proxy_for('org.opensuse.yast.system.logs')
169     @logs = log.find(:all) 
170     
171     create_data
172     limits_reached
173     logger.debug "limits reached for #{@limits_list[:reached].inspect}"
174   end
175
176
177   def show_summary
178     return unless client_permissions
179     begin
180       create_data
181       status = limits_reached
182       status = (_("Limits exceeded for %s") % status) unless status.empty?
183       render :partial => "status_summary", :locals => { :status => status, :error => nil }
184     rescue Exception => error
185       erase_redirect_results #reset all redirects
186       erase_render_results
187       render :partial => "status_summary", :locals => { :status => nil, :error => ClientException.new(error) } and return
188     end
189   end
190
191   def save
192     return unless client_permissions
193     limits = Hash.new
194     params.each_pair{|key, value|
195       if key =~ /\/[-\w]*\/[-\w]*\/min/ # e.g /interface/if_packets-pan0/max
196         unless value.empty?
197           slizes = key.split "/"
198           limits[slizes[1]] ||= Hash.new
199           limits[slizes[1]][slizes[2]] ||= Hash.new
200           limits[slizes[1]][slizes[2]].merge!(:min => value)
201         end
202       elsif key =~ /\/[-\w]*\/[-\w]*\/max/
203         unless value.empty?
204           slizes = key.split "/"
205           limits[slizes[1]] ||= Hash.new
206           limits[slizes[1]][slizes[2]] ||= Hash.new
207           limits[slizes[1]][slizes[2]].merge!(:max => value)
208         end
209       end
210     }
211
212     Rails.logger.debug "New limits: #{limits.inspect}"
213
214     begin
215       ActionController::Base.benchmark("Limits saved on the server") do
216         @client.create(:params => limits.inspect)
217       end
218     rescue Exception => ex
219       flash[:error] = _("Saving limits failed!")
220       redirect_to :controller=>"status", :action=>"edit" and return
221     end
222
223     redirect_to :controller=>"status", :action=>"index"
224
225 #puts "respond: " + respond
226 #    respond = @client.put(:status, :params => params) #:status, {:params => params})
227 #    if respond == :success
228 #      redirect_to :controller=>"status", :action=>"index"
229 #    else
230 #      redirect_to :controller=>"status", :action=>"edit"
231 #    end
232   end
233 =begin
234     begin
235       till = Time.new
236       from = till - 300 #last 5 minutes
237       status = @client.find(:dummy_param, :params => {  :start => from.to_i.to_s, :stop => till.to_i.to_s })
238
239       rescue ActiveResource::ClientError => e
240         flash[:error] = YaST::ServiceResource.error(e)
241         redirect_to :controller=>"status", :action=>"edit"
242         return false
243     end
244
245     save_hash = create_save_data(Hash.from_xml(status.to_xml)["status"], params)
246     logger.debug "writing #{save_hash.inspect}"
247
248     save_status = @client.new()
249     save_status.load(save_hash)
250
251     success = true
252     begin
253       save_status.save
254       logger.debug "limits have been written"
255       flash[:notice] = _("Limits have been written.")
256     rescue ActiveResource::ClientError => e
257        flash[:error] = YaST::ServiceResource.error(e)
258        ExceptionLogger.log_exception e
259        success = false
260     end
261     if success
262       redirect_to :controller=>"status", :action=>"index"
263     else
264       redirect_to :controller=>"status", :action=>"edit"
265     end
266   end
267 =end
268 end