diff options
author | Logan Lowell <fractaloop@thefrontside.net> | 2012-04-05 07:43:09 -0500 |
---|---|---|
committer | Bryan McLellan <btm@opscode.com> | 2012-08-03 11:43:30 -0700 |
commit | 32a5f96ef9fe9e0a7531a94b57a8d0fae4fab69b (patch) | |
tree | f873183df6ecd94d11d661ae0eb1c324d5da01cd /chef-server-webui | |
parent | 65f8bd6c38d951d59a80aee65ae0bbaf42ea39f0 (diff) | |
download | chef-32a5f96ef9fe9e0a7531a94b57a8d0fae4fab69b.tar.gz |
Bring over the routes and controllers
Diffstat (limited to 'chef-server-webui')
13 files changed, 1568 insertions, 56 deletions
diff --git a/chef-server-webui/app/controllers/clients_controller.rb b/chef-server-webui/app/controllers/clients_controller.rb new file mode 100644 index 0000000000..39653c613c --- /dev/null +++ b/chef-server-webui/app/controllers/clients_controller.rb @@ -0,0 +1,121 @@ +# +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/api_client' + +class ClientsController < ApplicationController + respond_to :html, :json + before_filter :login_required + before_filter :require_admin, :exclude => [:index, :show] + + # GET /clients + def index + begin + @clients_list = Chef::ApiClient.list().keys.sort + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => "Could not list clients"} + @clients_list = [] + end + respond_with @clients_list + end + + # GET /clients/:id + def show + @client = begin + @client = Chef::ApiClient.load(params[:id]) + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not load client #{params[:id]}"} + Chef::ApiClient.new + end + respond_with @client + end + + # GET /clients/:id/edit + def edit + @client = begin + Chef::ApiClient.load(params[:id]) + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not load client #{params[:id]}"} + Chef::ApiClient.new + end + respond_with @client + end + + # GET /clients/new + def new + raise AdminAccessRequired unless params[:user_id] == session[:user] unless session[:level] == :admin + @client = Chef::ApiClient.new + respond_with @client + end + + # POST /clients + def create + begin + @client = Chef::ApiClient.new + @client.name(params[:name]) + @client.admin(str_to_bool(params[:admin])) if params[:admin] + response = @client.create + @private_key = OpenSSL::PKey::RSA.new(response["private_key"]) + @_message = { :notice => "Created Client #{@client.name}. Please copy the following private key as the client's validation key." } + @client = Chef::ApiClient.load(params[:name]) + render :show + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not create client" } + render :new + end + end + + # PUT /clients/:id + def update + begin + @client = Chef::ApiClient.load(params[:id]) + if params[:regen_private_key] + @client.create_keys + @private_key = @client.private_key + end + params[:admin] ? @client.admin(true) : @client.admin(false) + @client.save + @_message = @private_key.nil? ? { :notice => "Updated Client" } : { :notice => "Created Client #{@client.name}. Please copy the following private key as the client's validation key." } + render :show + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not update client" } + render :edit + end + end + + # DELETE /clients/:id + def destroy + begin + @client = Chef::ApiClient.load(params[:id]) + @client.destroy + redirect_to clients_url, :notice => "Client #{params[:id]} deleted successfully" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => "Could not delete client #{params[:id]}" } + @clients_list = Chef::ApiClient.list() + render :index + end + end + +end + diff --git a/chef-server-webui/app/controllers/cookbooks_controller.rb b/chef-server-webui/app/controllers/cookbooks_controller.rb new file mode 100644 index 0000000000..3a51aeb9e6 --- /dev/null +++ b/chef-server-webui/app/controllers/cookbooks_controller.rb @@ -0,0 +1,186 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Christopher Brown (<cb@opscode.com>) +# Author:: Nuo Yan (<nuo@opscode.com>) +# Author:: Seth Falcon (<seth@opscode.com>) +# Copyright:: Copyright (c) 2008-2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/cookbook_loader' +require 'chef/cookbook_version' + +class CookbooksController < ApplicationController + + respond_to :html + before_filter :login_required + before_filter :params_helper + + attr_reader :cookbook_id + def params_helper + @cookbook_id = params[:id] || params[:cookbook_id] + end + + def index + @cl = fetch_cookbook_versions(6) + respond_with @cl + end + + def show + begin + all_books = fetch_cookbook_versions("all", :cookbook => cookbook_id) + @versions = all_books[cookbook_id].map { |v| v["version"] } + if params[:cb_version] == "_latest" + redirect_to show_specific_version_cookbook_url(cookbook_id, @versions.first) + return + end + @version = params[:cb_version] + if !@versions.include?(@version) + msg = { :warning => ["Cookbook #{cookbook_id} (#{params[:cb_version]})", + "is not available in the #{session[:environment]}", + "environment." + ].join(" ") } + redirect_to cookbooks_url, :flash => msg + return + end + cookbook_url = "cookbooks/#{cookbook_id}/#{@version}" + rest = Chef::REST.new(Chef::Config[:chef_server_url]) + @cookbook = rest.get_rest(cookbook_url) + raise NotFound unless @cookbook + @manifest = @cookbook.manifest + display @cookbook + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => $!} + @cl = {} + render :index + end + end + + # GET /cookbooks/cookbook_id + # provides :json, for the javascript on the environments web form. + def cb_versions + respond_to :json + use_envs = session[:environment] && !params[:ignore_environments] + num_versions = params[:num_versions] || "all" + all_books = fetch_cookbook_versions(num_versions, :cookbook => cookbook_id, + :use_envs => use_envs) + respond_with ({ cookbook_id => all_books[cookbook_id] }) + end + + ## ------ + ## Helpers + ## + ## TODO: move these to a cookbooks helper module + ## ------ + + def recipe_files + # node = params.has_key?('node') ? params[:node] : nil + # @recipe_files = load_all_files(:recipes, node) + r = Chef::REST.new(Chef::Config[:chef_server_url]) + @recipe_files = r.get_rest("cookbooks/#{params[:id]}/recipes") + display @recipe_files + end + + def attribute_files + r = Chef::REST.new(Chef::Config[:chef_server_url]) + @recipe_files = r.get_rest("cookbooks/#{params[:id]}/attributes") + display @attribute_files + end + + def definition_files + r = Chef::REST.new(Chef::Config[:chef_server_url]) + @recipe_files = r.get_rest("cookbooks/#{params[:id]}/definitions") + display @definition_files + end + + def library_files + r = Chef::REST.new(Chef::Config[:chef_server_url]) + @recipe_files = r.get_rest("cookbooks/#{params[:id]}/libraries") + display @lib_files + end + + def more_versions_link(cookbook) + link_to("+", "JavaScript:void(0);", + :title => "show other versions of #{cookbook}", + :data => cookbook, + :class => "cookbook_version_toggle") + end + + def all_versions_link(cookbook) + link_to("show all versions...", "JavaScript:void(0);", + :class => "show_all", + :id => "#{cookbook}_show_all", + :data => cookbook, + :title => "show all versions of #{cookbook}") + end + + def cookbook_link(version) + show_specific_version_cookbook_path(version, @cookbook_id) + end + + def cookbook_parts + Chef::CookbookVersion::COOKBOOK_SEGMENTS.map do |p| + part = p.to_s + case part + when "files" + [part, "plain"] + else + [part, "ruby"] + end + end.sort { |a, b| a[0] <=> b[0] } + end + + def highlight_content(url, type) + case type + when "plain" + show_plain_file(url) + else + syntax_highlight(url) + end + end + + private + + def fetch_cookbook_versions(num_versions, options={}) + opts = { :use_envs => true, :cookbook => nil }.merge(options) + url = if opts[:use_envs] + env = session[:environment] || "_default" + "environments/#{env}/cookbooks" + else + "cookbooks" + end + # we want to display at most 5 versions, but we ask for 6. This + # tells us if we should display a 'show all' button or not. + url += "/#{opts[:cookbook]}" if opts[:cookbook] + url += "?num_versions=#{num_versions}" + begin + result = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest(url) + result.inject({}) do |ans, (name, cb)| + cb["versions"].each do |v| + v["url"] = url(:show_specific_version_cookbook, :cookbook_id => name, + :cb_version => v["version"]) + end + ans[name] = cb["versions"] + ans + end + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => $!} + {} + end + end + +end diff --git a/chef-server-webui/app/controllers/databag_items_controller.rb b/chef-server-webui/app/controllers/databag_items_controller.rb new file mode 100644 index 0000000000..165ea09c4e --- /dev/null +++ b/chef-server-webui/app/controllers/databag_items_controller.rb @@ -0,0 +1,99 @@ +# +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/data_bag_item' + +class DatabagItemsController < ApplicationController + + respond_to :html, :json + before_filter :login_required + + def edit + begin + @databag_item = Chef::DataBagItem.load(params[:databag_id], params[:id]) + @default_data = @databag_item.raw_data + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not load the databag item" } + end + end + + def update + begin + @databag_item = Chef::DataBagItem.new + @databag_item.data_bag params[:databag_id] + @databag_item.raw_data = Chef::JSONCompat.from_json(params[:json_data]) + raise ArgumentError, "Updating id is not allowed" unless @databag_item.raw_data['id'] == params[:id] #to be consistent with other objects, changing id is not allowed. + @databag_item.save + redirect_to databag_databag_items_url(params[:databag_id], @databag_item.name), :notice => "Updated Databag Item #{@databag_item.name}" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not update the databag item" } + @databag_item = Chef::DataBagItem.load(params[:databag_id], params[:id]) + @default_data = @databag_item + render :edit + end + end + + def new + @default_data = {'id'=>''} + end + + def create + begin + @databag_name = params[:databag_id] + @databag_item = Chef::DataBagItem.new + @databag_item.data_bag @databag_name + @databag_item.raw_data = Chef::JSONCompat.from_json(params[:json_data]) + @databag_item.create + redirect_to(databag_databag_items_url(@databag_name), :notice => "Databag item created successfully" ) + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not create databag item" } + render :new + end + end + + def index + end + + def show + begin + @databag_name = params[:databag_id] + @databag_item_name = params[:id] + r = Chef::REST.new(Chef::Config[:chef_server_url]) + @databag_item = r.get_rest("data/#{params[:databag_id]}/#{params[:id]}") + display @databag_item + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + redirect_to databag_databag_items_url, :error => "Could not show the databag item" + end + end + + def destroy(databag_id=params[:databag_id], item_id=params[:id]) + begin + @databag_item = Chef::DataBagItem.new + @databag_item.destroy(databag_id, item_id) + redirect_to databag_databag_items_url, :notice => "Databag item deleted successfully" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + redirect_to databag_databag_items_url, :error => "Could not delete databag item" + end + end + +end diff --git a/chef-server-webui/app/controllers/databags_controller.rb b/chef-server-webui/app/controllers/databags_controller.rb new file mode 100644 index 0000000000..2c55326937 --- /dev/null +++ b/chef-server-webui/app/controllers/databags_controller.rb @@ -0,0 +1,82 @@ +# +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/data_bag' + +class DatabagsController < ApplicationController + + respond_to :html, :json + before_filter :login_required + before_filter :require_admin + + def new + @databag = Chef::DataBag.new + end + + def create + begin + @databag = Chef::DataBag.new + @databag.name params[:name] + @databag.create + redirect_to databags_url, :notice => "Created Databag #{@databag.name}" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not create databag" } + render :new + end + end + + def index + @databags = begin + Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data") + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Could not list databags" } + {} + end + end + + def show + begin + @databag_name = params[:id] + r = Chef::REST.new(Chef::Config[:chef_server_url]) + @databag = r.get_rest("data/#{params[:id]}") + raise NotFound unless @databag + display @databag + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @databags = Chef::DataBag.list + @_message = { :error => "Could not load databag"} + render :index + end + end + + def destroy + begin + r = Chef::REST.new(Chef::Config[:chef_server_url]) + r.delete_rest("data/#{params[:id]}") + redirect_to databags_url, :notice => "Data bag #{params[:id]} deleted successfully" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @databags = Chef::DataBag.list + @_message = { :error => "Could not delete databag"} + render :index + end + end + +end diff --git a/chef-server-webui/app/controllers/environments_controller.rb b/chef-server-webui/app/controllers/environments_controller.rb new file mode 100644 index 0000000000..738ca0fe99 --- /dev/null +++ b/chef-server-webui/app/controllers/environments_controller.rb @@ -0,0 +1,216 @@ +# +# Author:: Stephen Delano (<stephen@opscode.com>) +# Copyright:: Copyright (c) 2010 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/environment' + +class EnvironmentsController < ApplicationController + + respond_to :html, :json + before_filter :login_required + before_filter :require_admin, :only => [:create, :update, :destroy] + + # GET /environments + def index + @environment_list = begin + Chef::Environment.list + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = "Could not list environments" + {} + end + end + + # GET /environments/:id + def show + load_environment + end + + # GET /environemnts/new + def new + @environment = Chef::Environment.new + load_cookbooks + render :new + end + + # POST /environments + def create + @environment = Chef::Environment.new + if @environment.update_from_params(processed_params=process_params) + begin + @environment.create + redirect_to environments_url :notice => "Created Environment #{@environment.name}" + rescue Net::HTTPServerException => e + if conflict?(e) + Chef::Log.debug("Got 409 conflict creating environment #{params[:name]}\n#{format_exception(e)}") + redirect_to new_environment_url, :error => "An environment with that name already exists" + elsif forbidden?(e) + # Currently it's not possible to get 403 here. I leave the code here for completeness and may be useful in the future.[nuo] + Chef::Log.debug("Got 403 forbidden creating environment #{params[:name]}\n#{format_exception(e)}") + redirect_to new_environment_url, :error => "Permission Denied. You do not have permission to create an environment." + else + Chef::Log.error("Error communicating with the API server\n#{format_exception(e)}") + raise + end + end + else + load_cookbooks + # By rendering :new, the view shows errors from @environment.invalid_fields + render :new + end + end + + # GET /environments/:id/edit + def edit + load_environment + if @environment.name == "_default" + msg = { :warning => "The '_default' environment cannot be edited." } + redirect_to environments_url, :flash => msg + return + end + load_cookbooks + end + + # PUT /environments/:id + def update + load_environment + if @environment.update_from_params(process_params(params[:id])) + begin + @environment.save + redirect_to environment_url(@environment.name), :notice => "Updated Environment #{@environment.name}" + rescue Net::HTTPServerException => e + if forbidden?(e) + # Currently it's not possible to get 403 here. I leave the code here for completeness and may be useful in the future.[nuo] + Chef::Log.debug("Got 403 forbidden updating environment #{params[:name]}\n#{format_exception(e)}") + redirect_to edit_environment_url, :error => "Permission Denied. You do not have permission to update an environment." + else + Chef::Log.error("Error communicating with the API server\n#{format_exception(e)}") + raise + end + end + else + load_cookbooks + # By rendering :new, the view shows errors from @environment.invalid_fields + render :edit + end + end + + # DELETE /environments/:id + def destroy + begin + @environment = Chef::Environment.load(params[:id]) + @environment.destroy + redirect_to environments_url, :notice => "Environment #{@environment.name} deleted successfully." + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @environment_list = Chef::Environment.list() + @_message = {:error => "Could not delete environment #{params[:id]}: #{e.message}"} + render :index + end + end + + # GET /environments/:environment_id/cookbooks + def list_cookbooks + # TODO: rescue loading the environment + @environment = Chef::Environment.load(params[:environment_id]) + @cookbooks = begin + r = Chef::REST.new(Chef::Config[:chef_server_url]) + r.get_rest("/environments/#{params[:environment_id]}/cookbooks").inject({}) do |res, (cookbook, url)| + # we just want the cookbook name and the version + res[cookbook] = url.split('/').last + res + end + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = "Could not load cookbooks for environment #{params[:environment_id]}" + {} + end + end + + # GET /environments/:environment_id/nodes + def list_nodes + # TODO: rescue loading the environment + @environment = Chef::Environment.load(params[:environment_id]) + @nodes = begin + r = Chef::REST.new(Chef::Config[:chef_server_url]) + r.get_rest("/environments/#{params[:environment_id]}/nodes").keys.sort + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = "Could not load nodes for environment #{params[:environment_id]}" + [] + end + end + + # GET /environments/:environment/recipes + def list_recipes + respond_with :recipes => list_available_recipes_for(params[:environment_id]) + end + + # GET /environments/:environment_id/set + def select_environment + name = params[:environment_id] + referer = request.referer || nodes_url + if name == '_none' + session[:environment] = nil + else + # TODO: check if environment exists + session[:environment] = name + end + redirect_to referer + end + + private + + def load_environment + @environment = begin + Chef::Environment.load(params[:id]) + rescue Net::HTTPServerException => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = "Could not load environment #{params[:id]}" + @environment = Chef::Environment.new + false + end + end + + def load_cookbooks + begin + # @cookbooks is a hash, keys are cookbook names, values are their URIs. + @cookbooks = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("cookbooks").keys.sort + rescue Net::HTTPServerException => e + Chef::Log.error(format_exception(e)) + redirect_to new_environment_url, :error => "Could not load the list of available cookbooks." + end + end + + def process_params(name=params[:name]) + {:name => name, :description => params[:description], :default_attributes => params[:default_attributes], :override_attributes => params[:override_attributes], :cookbook_version => search_params_for_cookbook_version_constraints} + end + + def search_params_for_cookbook_version_constraints + cookbook_version_constraints = {} + index = 0 + params.each do |k,v| + cookbook_name_box_id = k[/cookbook_name_(\d+)/, 1] + unless cookbook_name_box_id.nil? || v.nil? || v.empty? + cookbook_version_constraints[index] = v + " " + params["operator_#{cookbook_name_box_id}"] + " " + params["cookbook_version_#{cookbook_name_box_id}"].strip # e.g. {"0" => "foo > 0.3.0"} + index = index + 1 + end + end + Chef::Log.debug("cookbook version constraints are: #{cookbook_version_constraints.inspect}") + cookbook_version_constraints + end +end diff --git a/chef-server-webui/app/controllers/nodes_controller.rb b/chef-server-webui/app/controllers/nodes_controller.rb new file mode 100644 index 0000000000..6a646a78d0 --- /dev/null +++ b/chef-server-webui/app/controllers/nodes_controller.rb @@ -0,0 +1,143 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Christopher Brown (<cb@opscode.com>) +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/node' + +class NodesController < ApplicationController + + respond_to :html + + before_filter :login_required + before_filter :require_admin, :only => [:destroy] + + def index + begin + if session[:environment] + node_hash = Chef::Node.list_by_environment(session[:environment]) + else + node_hash = Chef::Node.list + end + @node_list = node_hash.keys.sort + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => "Could not list nodes"} + @node_hash = {} + end + end + + def show + begin + @node =Chef::Node.load(params[:id]) + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => "Could not load node #{params[:id]}"} + @node = Chef::Node.new + end + end + + def new + begin + @node = Chef::Node.new + @node.chef_environment(session[:environment] || "_default") + @available_recipes = list_available_recipes_for(@node.chef_environment) + @available_roles = Chef::Role.list.keys.sort + @run_list = @node.run_list + @env = session[:environment] + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @node_list = Chef::Node.list() + @_message = {:error => "Could not load available recipes, roles, or the run list"} + render :index + end + end + + def edit + begin + @node = Chef::Node.load(params[:id]) + @env = @node.chef_environment + @available_recipes = list_available_recipes_for(@node.chef_environment) + @available_roles = Chef::Role.list.keys.sort + @run_list = @node.run_list + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @node = Chef::Node.new + @available_recipes = [] + @available_roles = [] + @run_list = [] + @_message = {:error => "Could not load node #{params[:id]}"} + end + end + + def create + begin + @node = Chef::Node.new + @node.name params[:name] + @node.chef_environment params[:chef_environment] + @node.normal_attrs = Chef::JSONCompat.from_json(params[:attributes]) + @node.run_list.reset!(params[:for_node] ? params[:for_node] : []) + raise ArgumentError, "Node name cannot be blank" if (params[:name].nil? || params[:name].length==0) + @node.create + redirect_to nodes_url, :notice => "Created Node #{@node.name}" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @node.normal_attrs = Chef::JSONCompat.from_json(params[:attributes]) + @available_recipes = list_available_recipes_for(@node.chef_environment) + @available_roles = Chef::Role.list.keys.sort + @node.run_list params[:for_node] + @run_list = @node.run_list + flash[:error] = "Exception raised creating node, #{e.message.length <= 150 ? e.message : "please check logs for details"}" + render :new + end + end + + def update + begin + @node = Chef::Node.load(params[:id]) + @node.chef_environment(params[:chef_environment]) + @node.run_list.reset!(params[:for_node] ? params[:for_node] : []) + @node.normal_attrs = Chef::JSONCompat.from_json(params[:attributes]) + @node.save + @_message = { :notice => "Updated Node" } + render :show + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @available_recipes = list_available_recipes_for(@node.chef_environment) + @available_roles = Chef::Role.list.keys.sort + @run_list = Chef::RunList.new + @run_list.reset!(params[:for_node]) + flash[:error] = "Exception raised updating node, #{e.message.length <= 150 ? e.message : "please check logs for details"}" + render :edit + end + end + + def destroy + begin + @node = Chef::Node.load(params[:id]) + @node.destroy + redirect_to nodes_url, :notice => "Node #{params[:id]} deleted successfully" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @node_list = Chef::Node.list() + flash[:error] = "Could not delete the node" + render :index + end + end + +end diff --git a/chef-server-webui/app/controllers/openid_consumer_controller.rb b/chef-server-webui/app/controllers/openid_consumer_controller.rb new file mode 100644 index 0000000000..d062d8f3a7 --- /dev/null +++ b/chef-server-webui/app/controllers/openid_consumer_controller.rb @@ -0,0 +1,157 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Christopher Brown (<cb@opscode.com>) +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'pathname' +require 'openid' +require (Chef::Config[:openid_cstore_couchdb] ? 'openid-store-couchdb' : 'openid/store/filesystem') + +class OpenidConsumerController < ApplicationController + + respond_to :html + + def index + if request.xhr? + render :layout => false + else + render :layout => 'login' + end + end + + def start + oid = params[:openid_identifier] + begin + oidreq = consumer.begin(oid) + rescue OpenID::OpenIDError => e + raise BadRequest, "Discovery failed for #{oid}: #{e}" + end + + return_to = openid_consumer_complete_url + realm = openid_consumer_url + + if oidreq.send_redirect?(realm, return_to, params[:immediate]) + return redirect_to(oidreq.redirect_url(realm, return_to, params[:immediate])) + else + @form_text = oidreq.form_markup(realm, return_to, params[:immediate], {'id' => 'openid_form'}) + end + end + + def login + if session[:user] + redirect_to nodes_url, :flash => { :warning => "You've already logged in with user #{session[:user]}" } + else + oid = params[:openid_identifier] + raise(Unauthorized, "Sorry, #{oid} is not an authorized OpenID.") unless is_authorized_openid_identifier?(oid, Chef::Config[:authorized_openid_identifiers]) + raise(Unauthorized, "Sorry, #{oid} is not an authorized OpenID Provider.") unless is_authorized_openid_provider?(oid, Chef::Config[:authorized_openid_providers]) + start + end + end + + def complete + # FIXME - url_for some action is not necessarily the current URL. + current_url = openid_consumer_complete_url + parameters = params.reject{|k,v| k == "controller" || k == "action"} + oidresp = consumer.complete(parameters, current_url) + case oidresp.status + when OpenID::Consumer::FAILURE + raise BadRequest, "Verification failed: #{oidresp.message}" + (oidresp.display_identifier ? " for identifier '#{oidresp.display_identifier}'" : "") + when OpenID::Consumer::SUCCESS + #session[:openid] = oidresp.identity_url + # The "if" condition no longer seems need to/can be reached, so I took it out. [nuo] + # + # if oidresp.display_identifier =~ /openid\/server\/node\/(.+)$/ + # reg_name = $1 + # reg = Chef::OpenIDRegistration.load(reg_name) + # Chef::Log.error("#{reg_name} is an admin #{reg.admin}") + # session[:level] = reg.admin ? :admin : :node + # session[:node_name] = $1 + #else + users = Chef::WebUIUser.list + #TODO: This is expensive. Should think of a better way [nuo] + # Go through each user object and check if the current OpenID associates with the user + users.each do |u, url| + user = Chef::WebUIUser.load(u) + if user.openid == oidresp.identity_url + session[:user] = user.name + if user.admin + session[:level] = :admin + else + session[:level] = :user + end + break + end + end + if session[:user].nil? + redirect_to openid_consumer_url, :error => "No user is associated with this OpenID." + return "No user is associated with this OpenID." + end + #end + redirect_back_or_default(nodes_url) + return "Verification of #{oidresp.display_identifier} succeeded." + when OpenID::Consumer::SETUP_NEEDED + return "Immediate request failed - Setup Needed" + when OpenID::Consumer::CANCEL + return "OpenID transaction cancelled." + else + end + redirect openid_consumer_url + end + + def logout + cleanup_session + redirect_to top_url + end + + private + def is_authorized_openid_provider?(openid, authorized_providers) + Chef::Log.debug("Checking for valid openid provider: openid: #{openid}, authorized providers: #{authorized_providers}") + if authorized_providers and openid + if authorized_providers.length > 0 + authorized_providers.detect { |p| Chef::Log.debug("Openid: #{openid} (#{openid.class}), p: #{p} (#{p.class})"); openid.match(p) } + else + true + end + else + true + end + end + + def is_authorized_openid_identifier?(openid, authorized_identifiers) + Chef::Log.debug("Checking for valid openid identifier: openid: #{openid}, authorized openids: #{authorized_identifiers}") + if authorized_identifiers and openid + if authorized_identifiers.length > 0 + authorized_identifiers.detect { |p| Chef::Log.debug("Openid: #{openid} (#{openid.class}), p: #{p} (#{p.class})"); openid == p } + else + true + end + else + true + end + end + + def consumer + @consumer ||= OpenID::Consumer.new(session, + if Chef::Config[:openid_cstore_couchdb] + OpenID::Store::CouchDB.new(Chef::Config[:couchdb_url]) + else + OpenID::Store::Filesystem.new(Chef::Config[:openid_cstore_path]) + end) + end + +end diff --git a/chef-server-webui/app/controllers/roles_controller.rb b/chef-server-webui/app/controllers/roles_controller.rb new file mode 100644 index 0000000000..16b93de8ca --- /dev/null +++ b/chef-server-webui/app/controllers/roles_controller.rb @@ -0,0 +1,137 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/role' + +class RolesController < ApplicationController + + respond_to :html + before_filter :login_required + before_filter :require_admin, :only => [:destroy] + + # GET /roles + def index + @role_list = begin + Chef::Role.list() + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => "Could not list roles"} + {} + end + end + + # GET /roles/:id + def show + @role = begin + Chef::Role.load(params[:id]) + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => "Could not load role #{params[:id]}."} + Chef::Role.new + end + + @current_env = session[:environment] || "_default" + @env_run_list_exists = @role.env_run_lists.has_key?(@current_env) + @run_list = @role.run_list_for(@current_env) + @recipes = @run_list.expand(@current_env, 'server').recipes + end + + # GET /roles/new + def new + begin + @role = Chef::Role.new + @available_roles = Chef::Role.list.keys.sort + @environments = Chef::Environment.list.keys.sort + @run_lists = @environments.inject({}) { |run_lists, env| run_lists[env] = @role.env_run_lists[env]; run_lists} + @current_env = "_default" + @available_recipes = list_available_recipes_for(@current_env) + @existing_run_list_environments = @role.env_run_lists.keys + # merb select helper has no :include_blank => true, so fix the view in the controller. + @existing_run_list_environments.unshift('') + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + redirect_to roles_url, :error => "Could not load available recipes, roles, or the run list." + end + end + + # GET /roles/:id/edit + def edit + begin + @role = Chef::Role.load(params[:id]) + @available_roles = Chef::Role.list.keys.sort + @environments = Chef::Environment.list.keys.sort + @current_env = session[:environment] || "_default" + @run_list = @role.run_list + @run_lists = @environments.inject({}) { |run_lists, env| run_lists[env] = @role.env_run_lists[env]; run_lists} + @existing_run_list_environments = @role.env_run_lists.keys + # merb select helper has no :include_blank => true, so fix the view in the controller. + @existing_run_list_environments.unshift('') + @available_recipes = list_available_recipes_for(@current_env) + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + redirect_to roles_url, :error => "Could not load role #{params[:id]}. #{e.message}" + end + end + + # POST /roles + def create + begin + @role = Chef::Role.new + @role.name(params[:name]) + @role.env_run_lists(params[:env_run_lists]) + @role.description(params[:description]) if params[:description] != '' + @role.default_attributes(Chef::JSONCompat.from_json(params[:default_attributes])) if params[:default_attributes] != '' + @role.override_attributes(Chef::JSONCompat.from_json(params[:override_attributes])) if params[:override_attributes] != '' + @role.create + redirect_to roles_url, :notice => "Created Role #{@role.name}" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + redirect_to new_role_url, :error => "Could not create role. #{e.message}" + end + end + + # PUT /roles/:id + def update + begin + @role = Chef::Role.load(params[:id]) + @role.env_run_lists(params[:env_run_lists]) + @role.description(params[:description]) if params[:description] != '' + @role.default_attributes(Chef::JSONCompat.from_json(params[:default_attributes])) if params[:default_attributes] != '' + @role.override_attributes(Chef::JSONCompat.from_json(params[:override_attributes])) if params[:override_attributes] != '' + @role.save + redirect_to role_url(params[:id]), :notice => "Updated Role" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + redirect_to edit_role_url(params[:id]), :error => "Could not update role #{params[:id]}. #{e.message}" + end + end + + # DELETE /roles/:id + def destroy + begin + @role = Chef::Role.load(params[:id]) + @role.destroy + redirect_to roles_url, :notice => "Role #{@role.name} deleted successfully." + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + redirect_to roles_url, :error => "Could not delete role #{params[:id]}" + end + end + +end diff --git a/chef-server-webui/app/controllers/search_controller.rb b/chef-server-webui/app/controllers/search_controller.rb new file mode 100644 index 0000000000..7c118f6670 --- /dev/null +++ b/chef-server-webui/app/controllers/search_controller.rb @@ -0,0 +1,60 @@ +# +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2009 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/search/query' + +class SearchController < ApplicationController + + respond_to :html + before_filter :login_required + + def index + @s = Chef::Search::Query.new + @search_indexes = begin + @s.list_indexes + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = {:error => "Could not list search indexes"} + {} + end + end + + def show + begin + @s = Chef::Search::Query.new + query = (params[:q].nil? || params[:q].empty?) ? "*:*" : URI.escape(params[:q], Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) + @results = @s.search(params[:id], query) + @type = if params[:id].to_s == "node" || params[:id].to_s == "role" || params[:id].to_s == "client" || params[:id].to_s == "environment" + params[:id] + else + "databag" + end + @results = @results - @results.last(2) + @results.each do |result| + result.delete(nil) + end + @results + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @_message = { :error => "Unable to find the #{params[:id]}. (#{$!})" } + @search_indexes = @s.list_indexes + render :index + end + end + +end diff --git a/chef-server-webui/app/controllers/search_entries_controller.rb b/chef-server-webui/app/controllers/search_entries_controller.rb new file mode 100644 index 0000000000..9b7304f594 --- /dev/null +++ b/chef-server-webui/app/controllers/search_entries_controller.rb @@ -0,0 +1,62 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Christopher Brown (<cb@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +#require 'chef/search' +#require 'chef/queue' + +class SearchEntriesController < ApplicationController + + respond_to :html + before_filter :login_required + + def index + @s = Chef::Search.new + @entries = @s.search(params[:search_id]) + end + + def show + @s = Chef::Search.new + @entry = @s.search(params[:search_id], "id:'#{params[:search_id]}_#{params[:id]}'").first + end + + def create + @to_index = params + @to_index.delete(:controller) + @to_index["index_name"] = params[:search_id] + @to_index["id"] = "#{params[:search_id]}_#{params[:id]}" + @to_index.delete(:search_id) + Chef::Queue.send_msg(:queue, :index, @to_index) + redirect_to search_url + end + + def update + create + end + + def destroy + @s = Chef::Search.new + @entries = @s.search(params[:id]) + @entries.each do |entry| + Chef::Queue.send_msg(:queue, :remove, entry) + end + @status = 202 + redirect_to search_url + end + +end diff --git a/chef-server-webui/app/controllers/status_controller.rb b/chef-server-webui/app/controllers/status_controller.rb new file mode 100644 index 0000000000..f2dc56c089 --- /dev/null +++ b/chef-server-webui/app/controllers/status_controller.rb @@ -0,0 +1,42 @@ +# +# Author:: Joe Williams (joe@joetify.com) +# Author:: Nuo Yan (nuo@opscode.com) +# Copyright:: Copyright (c) 2009 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/node' + +class StatusController < ApplicationController + + respond_to :html + before_filter :login_required + + def index + begin + @status = Chef::Node.list(true) + if session[:environment] + @status = Chef::Node.list_by_environment(session[:environment],true) + else + @status = Chef::Node.list(true) + end + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @status = {} + @_message = {:error => "Could not list status"} + end + end + +end diff --git a/chef-server-webui/app/controllers/users_controller.rb b/chef-server-webui/app/controllers/users_controller.rb new file mode 100644 index 0000000000..1936f4bf84 --- /dev/null +++ b/chef-server-webui/app/controllers/users_controller.rb @@ -0,0 +1,177 @@ +# +# Author:: Nuo Yan (<nuo@opscode.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'chef/webui_user' +require 'uri' + +class UsersController < ApplicationController + + respond_to :html + before_filter :login_required, :except => [:login, :login_exec, :complete] + before_filter :require_admin, :except => [:login, :login_exec, :complete, :show, :edit, :logout, :destroy] + + # List users, only if the user is admin. + def index + begin + @users = Chef::WebUIUser.list + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + set_user_and_redirect + end + end + + # Edit user. Admin can edit everyone, non-admin user can only edit itself. + def edit + begin + @user = Chef::WebUIUser.load(params[:user_id]) + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + set_user_and_redirect + end + end + + # Show the details of a user. If the user is not admin, only able to show itself; otherwise able to show everyone + def show + begin + @user = Chef::WebUIUser.load(params[:user_id]) + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + set_user_and_redirect + end + end + + # PUT to /users/:user_id/update + def update + begin + @user = Chef::WebUIUser.load(params[:user_id]) + + if session[:level] == :admin and !is_last_admin? + @user.admin = params[:admin] =~ /1/ ? true : false + end + + if params[:user_id] == session[:user] && params[:admin] == 'false' + session[:level] = :user + end + + if not params[:new_password].nil? and not params[:new_password].length == 0 + @user.set_password(params[:new_password], params[:confirm_new_password]) + end + + if params[:openid].length == 0 or params[:openid].nil? + @user.set_openid(nil) + else + @user.set_openid(URI.parse(params[:openid]).normalize.to_s) + end + @user.save + flash[:notice] = "Updated user #{@user.name}." + render :show + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @u = Chef::WebUIUser.load(params[:user_id]) + flash[:error] = "Could not update user #{@user.name}." + render :edit + end + end + + def new + begin + @user = Chef::WebUIUser.new + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + set_user_and_redirect + end + end + + def create + begin + @user = Chef::WebUIUser.new + @user.name = params[:name] + @user.set_password(params[:password], params[:password2]) + @user.admin = true if params[:admin] + (params[:openid].length == 0 || params[:openid].nil?) ? @user.set_openid(nil) : @user.set_openid(URI.parse(params[:openid]).normalize.to_s) + @user.create + redirect_to users_url, :notice => "Created User #{params[:name]}" + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + flash[:error] = "Could not create user" + session[:level] != :admin ? set_user_and_redirect : (render :new) + end + end + + def login + @user = Chef::WebUIUser.new + session[:user] ? (redirect_to nodes_url, :flash => { :warning => "You've already logged in with user #{session[:user]}" } ) : (render :layout => 'login') + end + + def login_exec + begin + @user = Chef::WebUIUser.load(params[:name]) + raise(Unauthorized, "Wrong username or password.") unless @user.verify_password(params[:password]) + complete + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + @user = Chef::WebUIUser.new + flash[:error] = "Could not complete logging in." + render :login + end + end + + def complete + session[:user] = params[:name] + session[:level] = (@user.admin == true ? :admin : :user) + (@user.name == Chef::Config[:web_ui_admin_user_name] && @user.verify_password(Chef::Config[:web_ui_admin_default_password])) ? redirect_to(users_edit_url(@user.name), :flash => { :warning => "Please change the default password" }) : redirect_back_or_default(nodes_url) + end + + def logout + cleanup_session + redirect_to top_url + end + + def destroy + begin + raise Forbidden, "A non-admin user can only delete itself" if (params[:user_id] != session[:user] && session[:level] != :admin) + raise Forbidden, "The last admin user cannot be deleted" if (is_admin? && is_last_admin? && session[:user] == params[:user_id]) + @user = Chef::WebUIUser.load(params[:user_id]) + @user.destroy + logout if params[:user_id] == session[:user] + redirect_to users_url, :notice => "User #{params[:user_id]} deleted successfully." + rescue => e + Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}") + session[:level] != :admin ? set_user_and_redirect : redirect_to_list_users({ :error => $! }) + end + end + + private + + def set_user_and_redirect + begin + @user = Chef::WebUIUser.load(session[:user]) rescue (raise NotFound, "Cannot find User #{session[:user]}, maybe it got deleted by an Administrator.") + rescue + logout_and_redirect_to_login + else + redirect_to users_show_url(session[:user]), :error => $! + end + end + + def redirect_to_list_users(message) + flash = message + @users = Chef::WebUIUser.list + render :index + end + +end diff --git a/chef-server-webui/config/routes.rb b/chef-server-webui/config/routes.rb index 6bcc587859..8bc44f5b46 100644 --- a/chef-server-webui/config/routes.rb +++ b/chef-server-webui/config/routes.rb @@ -1,58 +1,88 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Daniel DeLeo (<dan@opscode.com>) +# Copyright:: Copyright (c) 2008-2010 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + ChefServerWebui::Application.routes.draw do - # The priority is based upon order of creation: - # first created -> highest priority. - - # Sample of regular route: - # match 'products/:id' => 'catalog#view' - # Keep in mind you can assign values other than :controller and :action - - # Sample of named route: - # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase - # This route can be invoked with purchase_url(:id => product.id) - - # Sample resource route (maps HTTP verbs to controller actions automatically): - # resources :products - - # Sample resource route with options: - # resources :products do - # member do - # get 'short' - # post 'toggle' - # end - # - # collection do - # get 'sold' - # end - # end - - # Sample resource route with sub-resources: - # resources :products do - # resources :comments, :sales - # resource :seller - # end - - # Sample resource route with more complex sub-resources - # resources :products do - # resources :comments - # resources :sales do - # get 'recent', :on => :collection - # end - # end - - # Sample resource route within a namespace: - # namespace :admin do - # # Directs /admin/products/* to Admin::ProductsController - # # (app/controllers/admin/products_controller.rb) - # resources :products - # end - - # You can have the root of your site routed with "root" - # just remember to delete public/index.html. - # root :to => 'welcome#index' - - # See how all your routes lay out with "rake routes" - - # This is a legacy wild controller route that's not recommended for RESTful applications. - # Note: This route will make all actions in every controller accessible via GET requests. - # match ':controller(/:action(/:id))(.:format)' + resources :nodes, :id => /[^\/]+/ + match "/nodes/_environments/:environment_id", :to => "nodes#index", :as => :nodes_by_environment + + resources :clients, :id => /[^\/]+/ + resources :roles + + resources :environments do + match "/recipes", :only => :get, :to => "environments#list_recipes" + match "/cookbooks", :to => "environments#list_cookbooks", :as => :cookbooks, :only => :get + match "/nodes", :to => "environments#list_nodes", :as => :nodes, :only => :get + match "/select", :to => "environments#select_environment", :as => :select, :only => :get + end + + # match '/environments/create' :to => "environments#create", :as => :environments_create + + match "/status", :to => "status#index", :as => :status, :only => :get + + resources :searches, :path => "search", :controller => "search" + match "/search/:search_id/entries", :only => 'get', :to => "search_entries", :action => "index" + match "/search/:search_id/entries", :only => 'post', :to => "search_entries", :action => "create" + match "/search/:search_id/entries/:id", :only => 'get', :to => "search_entries", :action => "show" + match "/search/:search_id/entries/:id", :only => 'put', :to => "search_entries", :action => "create" + match "/search/:search_id/entries/:id", :only => 'post', :to => "search_entries", :action => "update" + match "/search/:search_id/entries/:id", :only => 'delete', :to => "search_entries", :action => "destroy" + + match "/cookbooks/_attribute_files", :to => "cookbooks#attribute_files" + match "/cookbooks/_recipe_files", :to => "cookbooks#recipe_files" + match "/cookbooks/_definition_files", :to => "cookbooks#definition_files" + match "/cookbooks/_library_files", :to => "cookbooks#library_files" + match "/cookbooks/_environments/:environment_id", :to => "cookbooks#index", :as => :cookbooks_by_environment + + match "/cookbooks/:cookbook_id", :cookbook_id => /[\w\.]+/, :only => :get, :to => "cookbooks#cb_versions" + match "/cookbooks/:cookbook_id/:cb_version", :cb_version => /[\w\.]+/, :only => :get, :to => "cookbooks#show", :as => :show_specific_version_cookbook + resources :cookbooks + + resources :clients + + match "/databags/:databag_id/databag_items", :only => :get, :to => "databags#show", :id=>":databag_id" + + resources :databags do + resources :databag_items + end + + match '/openid/consumer', :to => 'openid_consumer#index', :as => :openid_consumer + match '/openid/consumer/start', :to => 'openid_consumer#start', :as => :openid_consumer_start + match '/openid/consumer/login', :to => 'openid_consumer#login', :as => :openid_consumer_login + match '/openid/consumer/complete', :to => 'openid_consumer#complete', :as => :openid_consumer_complete + match '/openid/consumer/logout', :to => 'openid_consumer#logout', :as => :openid_consumer_logout + + match '/login', :to => 'users#login', :as => :users_login + match '/logout', :to => 'users#logout', :as => :users_logout + + match '/users', :to => 'users#index', :as => :users + match '/users/create', :to => 'users#create', :as => :users_create + match '/users/start', :to => 'users#start', :as => :users_start + + match '/users/login', :to => 'users#login', :as => :users_login + match '/users/login_exec', :to => 'users#login_exec', :as => :users_login_exec + match '/users/complete', :to => 'users#complete', :as => :users_complete + match '/users/logout', :to => 'users#logout', :as => :users_logout + match '/users/new', :to => 'users#new', :as => :users_new + match '/users/:user_id/edit', :to => 'users#edit', :as => :users_edit + match '/users/:user_id', :to => 'users#show', :as => :users_show + match '/users/:user_id/delete', :only => :delete, :to => 'users#destroy', :as => :users_delete + match '/users/:user_id/update', :only => :put, :to => 'users#update', :as => :users_update + + match '/', :to => 'nodes#index', :as => :top end |