summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLogan Lowell <fractaloop@thefrontside.net>2012-04-05 07:45:23 -0500
committerBryan McLellan <btm@opscode.com>2012-08-03 11:43:31 -0700
commitae95acaf36f1f340a4cf9d5b51dc4d763a5aa9e4 (patch)
treed8beef7e99993a735f6661013d64700b0ede3aea
parent2a22b95c0f22ad1cebea42a2edde85b4dc94b92d (diff)
downloadchef-ae95acaf36f1f340a4cf9d5b51dc4d763a5aa9e4.tar.gz
Application controller to run the show
-rw-r--r--chef-server-webui/app/controllers/application_controller.rb211
-rw-r--r--chef-server-webui/app/helpers/application_helper.rb42
2 files changed, 252 insertions, 1 deletions
diff --git a/chef-server-webui/app/controllers/application_controller.rb b/chef-server-webui/app/controllers/application_controller.rb
index e8065d9505..e6ecd8c60b 100644
--- a/chef-server-webui/app/controllers/application_controller.rb
+++ b/chef-server-webui/app/controllers/application_controller.rb
@@ -1,3 +1,212 @@
class ApplicationController < ActionController::Base
- protect_from_forgery
+
+ include Chef::Mixin::Checksum
+
+ before_filter :load_environments
+
+ # Check if the user is logged in and if the user still exists
+ def login_required
+ if session[:user]
+ begin
+ load_session_user
+ rescue
+ logout_and_redirect_to_login
+ else
+ return session[:user]
+ end
+ else
+ self.store_location
+ access_denied
+ end
+ end
+
+ def load_session_user
+ Chef::WebUIUser.load(session[:user])
+ rescue
+ raise NotFound, "Cannot find User #{session[:user]}, maybe it got deleted by an Administrator."
+ end
+
+ def cleanup_session
+ [:user,:level, :environment].each { |n| session.delete(n) }
+ end
+
+ def logout_and_redirect_to_login
+ cleanup_session
+ @user = Chef::WebUIUser.new
+ redirect_to users_login_url, :error => $!
+ end
+
+ def require_admin
+ raise AdminAccessRequired unless is_admin?
+ end
+
+ def is_admin?
+ user = Chef::WebUIUser.load(session[:user])
+ user.admin?
+ end
+
+ #return true if there is only one admin left, false otherwise
+ def is_last_admin?
+ count = 0
+ users = Chef::WebUIUser.list
+ users.each do |u, url|
+ user = Chef::WebUIUser.load(u)
+ if user.admin
+ count = count + 1
+ return false if count == 2
+ end
+ end
+ true
+ end
+
+ #whether or not the user should be able to edit a user's admin status
+ def can_edit_admin?
+ return false unless is_admin? && !is_last_admin?
+ true
+ end
+
+ # Store the URI of the current request in the session.
+ #
+ # We can return to this location by calling #redirect_back_or_default.
+ def store_location
+ session[:return_to] = request.url
+ end
+
+ # Redirect to the URI stored by the most recent store_location call or
+ # to the passed default.
+ def redirect_back_or_default(default)
+ loc = session[:return_to] || default
+ session[:return_to] = nil
+ redirect loc
+ end
+
+ def access_denied
+ case request.format
+ when 'text/html'
+ store_location
+ redirect_to users_login_url, :alert => "You don't have access to that, please login."
+ else
+ raise Unauthorized, "You must authenticate first!"
+ end
+ end
+
+ def load_environments
+ @environments = Chef::Environment.list.keys.sort
+ end
+
+ # Load a cookbook and return a hash with a list of all the files of a
+ # given segment (attributes, recipes, definitions, libraries)
+ #
+ # === Parameters
+ # cookbook_id<String>:: The cookbook to load
+ # segment<Symbol>:: :attributes, :recipes, :definitions, :libraries
+ #
+ # === Returns
+ # <Hash>:: A hash consisting of the short name of the file in :name, and the full path
+ # to the file in :file.
+ def load_cookbook_segment(cookbook_id, segment)
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
+ cookbook = r.get_rest("cookbooks/#{cookbook_id}")
+
+ raise NotFound unless cookbook
+
+ files_list = segment_files(segment, cookbook)
+
+ files = Hash.new
+ files_list.each do |f|
+ files[f['name']] = {
+ :name => f["name"],
+ :file => f["uri"],
+ }
+ end
+ files
+ end
+
+ def segment_files(segment, cookbook)
+ files_list = nil
+ case segment
+ when :attributes
+ files_list = cookbook["attributes"]
+ when :recipes
+ files_list = cookbook["recipes"]
+ when :definitions
+ files_list = cookbook["definitions"]
+ when :libraries
+ files_list = cookbook["libraries"]
+ else
+ raise ArgumentError, "segment must be one of :attributes, :recipes, :definitions or :libraries"
+ end
+ files_list
+ end
+
+ def syntax_highlight(file_url)
+ Chef::Log.debug("fetching file from '#{file_url}' for highlighting")
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
+ highlighted_file = nil
+ r.fetch(file_url) do |tempfile|
+ tokens = CodeRay.scan_file(tempfile.path, :ruby)
+ highlighted_file = CodeRay.encode_tokens(tokens, :span)
+ end
+ highlighted_file
+ end
+
+ def show_plain_file(file_url)
+ Chef::Log.debug("fetching file from '#{file_url}' for highlighting")
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
+ r.fetch(file_url) do |tempfile|
+ if binary?(tempfile.path)
+ return "Binary file not shown"
+ elsif ((File.size(tempfile.path) / (1048576)) > 5)
+ return "File too large to display"
+ else
+ return IO.read(tempfile.path)
+ end
+ end
+ end
+
+ def binary?(file)
+ s = (File.read(file, File.stat(file).blksize) || "")
+ s.empty? || ( s.count( "^ -~", "^\r\n" ).fdiv(s.size) > 0.3 || s.index( "\x00" ))
+ end
+
+ def str_to_bool(str)
+ str =~ /true/ ? true : false
+ end
+
+ #for showing search result
+ def determine_name(type, object)
+ case type
+ when :node, :role, :client, :environment
+ object.name
+ else
+ params[:id]
+ end
+ end
+
+ def list_available_recipes_for(environment)
+ Chef::Environment.load_filtered_recipe_list(environment).sort!
+ end
+
+ def format_exception(exception)
+ require 'pp'
+ pretty_params = StringIO.new
+ PP.pp({:request_params => params}, pretty_params)
+ "#{exception.class.name}: #{exception.message}\n#{pretty_params.string}\n#{exception.backtrace.join("\n")}"
+ end
+
+ def conflict?(exception)
+ exception.kind_of?(Net::HTTPServerException) && exception.message =~ /409/
+ end
+
+ def forbidden?(exception)
+ exception.kind_of?(Net::HTTPServerException) && exception.message =~ /403/
+ end
+
+ def not_found?(exception)
+ exception.kind_of?(Net::HTTPServerException) && exception.message =~ /404/
+ end
+
+ def bad_request?(exception)
+ exception.kind_of?(Net::HTTPServerException) && exception.message =~ /400/
+ end
end
diff --git a/chef-server-webui/app/helpers/application_helper.rb b/chef-server-webui/app/helpers/application_helper.rb
index de6be7945c..9741e98d17 100644
--- a/chef-server-webui/app/helpers/application_helper.rb
+++ b/chef-server-webui/app/helpers/application_helper.rb
@@ -1,2 +1,44 @@
module ApplicationHelper
+ ROLE_STR = "role"
+ RECIPE_STR = "recipe"
+
+
+ def chef_version
+ ::ChefServerWebui::VERSION
+ end
+
+ def class_for_run_list_item(item)
+ case item.type.to_s
+ when ROLE_STR
+ 'ui-state-highlight'
+ when RECIPE_STR
+ 'ui-state-default'
+ else
+ raise ArgumentError, "Cannot generate UI class for #{item.inspect}"
+ end
+ end
+
+ def display_run_list_item(item)
+ case item.type.to_s
+ when ROLE_STR
+ item.name
+ when RECIPE_STR
+ # webui not sophisticated enough for versioned recipes
+ # "#{item.name}@#{item.version}"
+ item.name
+ else
+ raise ArgumentError, "can't generate display string for #{item.inspect}"
+ end
+ end
+
+ def nav_link_item(title, dest)
+ name = title.gsub(/ /, "").downcase
+ klass = controller_name == name ? 'class="active"' : ""
+ link = link_to(title, url_for(dest))
+ raw("<li #{klass}>#{link}</li>")
+ end
+
+ def convert_newline_to_br(string)
+ string.to_s.gsub(/\n/, '<br />') unless string.nil?
+ end
end