From c5d33c1298834ce40b8fbf344f281045771b5371 Mon Sep 17 00:00:00 2001 From: Ezra Zygmuntowicz Date: Wed, 8 Oct 2008 14:19:52 -0700 Subject: big refactor of the repo layout. move to a chef gem and a chef-server gem all with proper deps --- chef-server/LICENSE | 201 ++++++++++++++ chef-server/NOTICE | 10 + chef-server/README.txt | 77 ++++++ chef-server/Rakefile | 47 ++++ chef-server/bin/chef-indexer | 85 ++++++ chef-server/bin/chef-server | 48 ++++ chef-server/lib/controllers/application.rb | 150 +++++++++++ chef-server/lib/controllers/cookbook_attributes.rb | 55 ++++ .../lib/controllers/cookbook_definitions.rb | 56 ++++ chef-server/lib/controllers/cookbook_files.rb | 117 +++++++++ chef-server/lib/controllers/cookbook_recipes.rb | 56 ++++ chef-server/lib/controllers/cookbook_templates.rb | 77 ++++++ chef-server/lib/controllers/cookbooks.rb | 50 ++++ chef-server/lib/controllers/exceptions.rb | 38 +++ chef-server/lib/controllers/nodes.rb | 78 ++++++ chef-server/lib/controllers/openid_consumer.rb | 117 +++++++++ chef-server/lib/controllers/openid_register.rb | 89 +++++++ chef-server/lib/controllers/openid_server.rb | 236 +++++++++++++++++ chef-server/lib/controllers/search.rb | 71 +++++ chef-server/lib/controllers/search_entries.rb | 68 +++++ chef-server/lib/helpers/global_helpers.rb | 35 +++ chef-server/lib/helpers/nodes_helper.rb | 37 +++ chef-server/lib/helpers/openid_server_helpers.rb | 27 ++ chef-server/lib/init.rb | 206 +++++++++++++++ chef-server/lib/public/images/merb.jpg | Bin 0 -> 5815 bytes chef-server/lib/public/stylesheets/master.css | 292 +++++++++++++++++++++ .../lib/views/cookbook_templates/index.html.haml | 8 + .../lib/views/cookbooks/_attribute_file.html.haml | 2 + .../lib/views/cookbooks/attribute_files.html.haml | 4 + chef-server/lib/views/cookbooks/index.html.haml | 7 + chef-server/lib/views/cookbooks/show.html.haml | 24 ++ .../lib/views/exceptions/bad_request.json.erb | 1 + .../exceptions/internal_server_error.html.erb | 216 +++++++++++++++ .../lib/views/exceptions/not_acceptable.html.erb | 63 +++++ .../lib/views/exceptions/not_found.html.erb | 47 ++++ chef-server/lib/views/layout/application.html.haml | 26 ++ chef-server/lib/views/nodes/_action.html.haml | 13 + chef-server/lib/views/nodes/_node.html.haml | 9 + chef-server/lib/views/nodes/_resource.html.haml | 22 ++ chef-server/lib/views/nodes/compile.html.haml | 5 + chef-server/lib/views/nodes/index.html.haml | 9 + chef-server/lib/views/nodes/show.html.haml | 1 + .../lib/views/openid_consumer/index.html.haml | 25 ++ .../lib/views/openid_consumer/start.html.haml | 4 + chef-server/lib/views/openid_login/index.html.haml | 6 + .../lib/views/openid_register/index.html.haml | 15 ++ .../lib/views/openid_register/show.html.haml | 5 + .../lib/views/openid_server/decide.html.haml | 27 ++ .../lib/views/search/_search_form.html.haml | 6 + chef-server/lib/views/search/index.html.haml | 9 + chef-server/lib/views/search/show.html.haml | 13 + .../lib/views/search_entries/index.html.haml | 9 + .../lib/views/search_entries/show.html.haml | 8 + chef-server/pkg/chef-server-0.0.1.gem | Bin 0 -> 35328 bytes 54 files changed, 2907 insertions(+) create mode 100644 chef-server/LICENSE create mode 100644 chef-server/NOTICE create mode 100644 chef-server/README.txt create mode 100644 chef-server/Rakefile create mode 100755 chef-server/bin/chef-indexer create mode 100755 chef-server/bin/chef-server create mode 100644 chef-server/lib/controllers/application.rb create mode 100644 chef-server/lib/controllers/cookbook_attributes.rb create mode 100644 chef-server/lib/controllers/cookbook_definitions.rb create mode 100644 chef-server/lib/controllers/cookbook_files.rb create mode 100644 chef-server/lib/controllers/cookbook_recipes.rb create mode 100644 chef-server/lib/controllers/cookbook_templates.rb create mode 100644 chef-server/lib/controllers/cookbooks.rb create mode 100644 chef-server/lib/controllers/exceptions.rb create mode 100644 chef-server/lib/controllers/nodes.rb create mode 100644 chef-server/lib/controllers/openid_consumer.rb create mode 100644 chef-server/lib/controllers/openid_register.rb create mode 100644 chef-server/lib/controllers/openid_server.rb create mode 100644 chef-server/lib/controllers/search.rb create mode 100644 chef-server/lib/controllers/search_entries.rb create mode 100644 chef-server/lib/helpers/global_helpers.rb create mode 100644 chef-server/lib/helpers/nodes_helper.rb create mode 100644 chef-server/lib/helpers/openid_server_helpers.rb create mode 100644 chef-server/lib/init.rb create mode 100644 chef-server/lib/public/images/merb.jpg create mode 100644 chef-server/lib/public/stylesheets/master.css create mode 100644 chef-server/lib/views/cookbook_templates/index.html.haml create mode 100644 chef-server/lib/views/cookbooks/_attribute_file.html.haml create mode 100644 chef-server/lib/views/cookbooks/attribute_files.html.haml create mode 100644 chef-server/lib/views/cookbooks/index.html.haml create mode 100644 chef-server/lib/views/cookbooks/show.html.haml create mode 100644 chef-server/lib/views/exceptions/bad_request.json.erb create mode 100644 chef-server/lib/views/exceptions/internal_server_error.html.erb create mode 100644 chef-server/lib/views/exceptions/not_acceptable.html.erb create mode 100644 chef-server/lib/views/exceptions/not_found.html.erb create mode 100644 chef-server/lib/views/layout/application.html.haml create mode 100644 chef-server/lib/views/nodes/_action.html.haml create mode 100644 chef-server/lib/views/nodes/_node.html.haml create mode 100644 chef-server/lib/views/nodes/_resource.html.haml create mode 100644 chef-server/lib/views/nodes/compile.html.haml create mode 100644 chef-server/lib/views/nodes/index.html.haml create mode 100644 chef-server/lib/views/nodes/show.html.haml create mode 100644 chef-server/lib/views/openid_consumer/index.html.haml create mode 100644 chef-server/lib/views/openid_consumer/start.html.haml create mode 100644 chef-server/lib/views/openid_login/index.html.haml create mode 100644 chef-server/lib/views/openid_register/index.html.haml create mode 100644 chef-server/lib/views/openid_register/show.html.haml create mode 100644 chef-server/lib/views/openid_server/decide.html.haml create mode 100644 chef-server/lib/views/search/_search_form.html.haml create mode 100644 chef-server/lib/views/search/index.html.haml create mode 100644 chef-server/lib/views/search/show.html.haml create mode 100644 chef-server/lib/views/search_entries/index.html.haml create mode 100644 chef-server/lib/views/search_entries/show.html.haml create mode 100644 chef-server/pkg/chef-server-0.0.1.gem (limited to 'chef-server') diff --git a/chef-server/LICENSE b/chef-server/LICENSE new file mode 100644 index 0000000000..11069edd79 --- /dev/null +++ b/chef-server/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +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. diff --git a/chef-server/NOTICE b/chef-server/NOTICE new file mode 100644 index 0000000000..856fdc82b0 --- /dev/null +++ b/chef-server/NOTICE @@ -0,0 +1,10 @@ +Chef NOTICE +=========== + +Developed at HJK Solutions (http://www.hjksolutions.com). + +Contributors and Copyright holders: + + * Copyright 2008, Adam Jacob + * Copyright 2008, Arjuna Christensen + * Copyright 2008, Ezra Zygmuntowicz diff --git a/chef-server/README.txt b/chef-server/README.txt new file mode 100644 index 0000000000..08a0d31bf2 --- /dev/null +++ b/chef-server/README.txt @@ -0,0 +1,77 @@ += chef-server + +* http://oss.hjksolutions.com/chef + +== DESCRIPTION: + +Chef is a configuration management tool inspired by Puppet. + +I'm in ur netwerk, cookin up yer servers. :) + +== FEATURES/PROBLEMS: + + +== SYNOPSIS: + + +== REQUIREMENTS: + +RubyGems: + +* stomp +* stompserver +* ultraviolet +* facter +* ferret +* merb-core +* haml +* ruby-openid +* json + +External Servers: + +* stompserver (for easy stomp mq testing) +* CouchDB + +== INSTALL: + +Install all of the above. To fire up a develpment environment, do the following: + + * Start CouchDB with 'couchdb' + * Start stompserver with 'stompserver' + * Start chef-indexer with: + + ./bin/chef-indexer -l debug -c ./config/chef-server.rb + + * Start chef-server on port 4000 with: + + ./bin/chef-server + + * Start chef-server on port 4001 with: + + ./bin/chef-server -p 4001 + + * Test run chef with: + + sudo ./bin/chef-client -l debug -c ./examples/config/chef-solo.rb + +== LICENSE: + +Chef - A configuration management system + +Author:: Adam Jacob () +Copyright:: Copyright (c) 2008 HJK Solutions, LLC +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. + diff --git a/chef-server/Rakefile b/chef-server/Rakefile new file mode 100644 index 0000000000..4f7b21a9e3 --- /dev/null +++ b/chef-server/Rakefile @@ -0,0 +1,47 @@ +# -*- ruby -*- +require 'rubygems' +require 'rake/gempackagetask' + +GEM = "chef-server" +VERSION = "0.0.1" +AUTHOR = "Adam Jacob" +EMAIL = "adam@hjksolutions.com" +HOMEPAGE = "http://hjksolutions.com" +SUMMARY = "A configuration management system server." + +spec = Gem::Specification.new do |s| + s.name = GEM + s.version = VERSION + s.platform = Gem::Platform::RUBY + s.has_rdoc = true + s.extra_rdoc_files = ["README.txt", "LICENSE", 'NOTICE'] + s.summary = SUMMARY + s.description = s.summary + s.author = AUTHOR + s.email = EMAIL + s.homepage = HOMEPAGE + + # Uncomment this to add a dependency + s.add_dependency "stomp" + s.add_dependency "stompserver" + s.add_dependency "ferret" + s.add_dependency "merb-core" + s.add_dependency "haml" + s.add_dependency "ruby-openid" + s.add_dependency "json" + + s.bindir = "bin" + s.executables = %w( chef-indexer chef-server ) + + s.files = %w(LICENSE README.txt Rakefile) + Dir.glob("{lib}/**/*") +end + +Rake::GemPackageTask.new(spec) do |pkg| + pkg.gem_spec = spec +end + +task :install => [:package] do + sh %{sudo gem install pkg/#{GEM}-#{VERSION}} +end + +# vim: syntax=Ruby \ No newline at end of file diff --git a/chef-server/bin/chef-indexer b/chef-server/bin/chef-indexer new file mode 100755 index 0000000000..4788aca0f7 --- /dev/null +++ b/chef-server/bin/chef-indexer @@ -0,0 +1,85 @@ +#!/usr/bin/env ruby +# +# ./chef-indexer - Build indexes from Chef Queues! +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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 'optparse' +require 'chef' +require 'rubygems' +require 'facter' + +config = { + :config_file => "/etc/chef/config.rb", + :log_level => :info +} +opts = OptionParser.new do |opts| + opts.banner = "Usage: #{$0} [-d DIR|-r FILE] (options)" + opts.on("-c CONFIG", "--config CONFIG", "The Chef Config file to use") do |c| + config[:config_file] = c + end + opts.on_tail("-l LEVEL", "--loglevel LEVEL", "Set the log level (debug, info, warn, error, fatal)") do |l| + config[:log_level] = l.to_sym + end + opts.on_tail("-h", "--help", "Show this message") do + puts opts + exit + end +end +opts.parse!(ARGV) + +unless File.exists?(config[:config_file]) && File.readable?(config[:config_file]) + puts "I cannot find or read the config file: #{config[:config_file]}" + puts opts + exit +end + +# Load our config file +Chef::Config.from_file(config[:config_file]) +if config[:log_level] + Chef::Log.level(config[:log_level].to_sym) +end + +# Get a Chef::SearchIndex object +indexer = Chef::SearchIndex.new +Chef::Queue.connect +Chef::Queue.subscribe(:queue, "index") +Chef::Queue.subscribe(:queue, "remove") +while 1 + begin + object, headers = Chef::Queue.receive_msg + Chef::Log.info("Headers #{headers.inspect}") + if headers["destination"] == "/queue/chef/index" + start_timer = Time.new + indexer.add(object) + indexer.commit + final_timer = Time.new + Chef::Log.info("Indexed object from #{headers['destination']} in #{final_timer - start_timer} seconds") + elsif headers["destination"] == "/queue/chef/remove" + start_timer = Time.new + indexer.delete(object) + indexer.commit + final_timer = Time.new + Chef::Log.info("Removed object from #{headers['destination']} in #{final_timer - start_timer} seconds") + end + rescue Exception => e + if e.kind_of?(Interrupt) + raise e + end + Chef::Log.error("Received Exception: #{e}\n#{e.backtrace.join("\n")} continuing") + end +end diff --git a/chef-server/bin/chef-server b/chef-server/bin/chef-server new file mode 100755 index 0000000000..bfd0361156 --- /dev/null +++ b/chef-server/bin/chef-server @@ -0,0 +1,48 @@ +#!/usr/bin/env ruby +# +# ./chef-server - Serving up piping hot infrastructure! +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. + +# Based on the 'merb' command, by Ezra + +require "rubygems" +require "merb-core" +require 'chef' + +if ARGV[0] && ARGV[0] =~ /^[^-]/ + ARGV.push "-H" +end + +unless %w[-a --adapter -i --irb-console -r --script-runner].any? { |o| ARGV.index(o) } + ARGV.push *%w[-a mongrel] +end + +ARGV.push *[ "-I", File.join(File.dirname(__FILE__), "..", "lib", "init.rb") ] + +if index = ARGV.index("-C") + config = ARGV[index+1] + ARGV.delete("-C") + ARGV.delete(config) + Chef::Config.from_file(File.expand_path(config)) +else + Chef::Config.from_file( + File.join("/etc", "chef", "server.rb") + ) +end + +Merb.start diff --git a/chef-server/lib/controllers/application.rb b/chef-server/lib/controllers/application.rb new file mode 100644 index 0000000000..6a501ea29c --- /dev/null +++ b/chef-server/lib/controllers/application.rb @@ -0,0 +1,150 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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" / "mixin" / "checksum" + + +class Application < Merb::Controller + + def fix_up_node_id + if params.has_key?(:id) + params[:id].gsub!(/_/, '.') + end + end + + def escape_node_id + if params.has_key?(:id) + params[:id].gsub(/_/, '.') + end + end + + def login_required + if session[:openid] + return session[:openid] + else + self.store_location + throw(:halt, :access_denied) + end + end + + def authorized_node + if session[:level] == :admin + Chef::Log.debug("Authorized as Administrator") + true + elsif session[:level] == :node + Chef::Log.debug("Authorized as node") + if session[:node_name] == params[:id].gsub(/\./, '_') + true + else + raise( + Unauthorized, + "You are not the correct node for this action: #{session[:node_name]} instead of #{params[:id]}" + ) + end + else + Chef::Log.debug("Unauthorized") + raise Unauthorized, "You are not allowed to take this action." + end + 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.uri + 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 content_type + when :html + store_location + redirect url(:openid_consumer) + else + raise Unauthorized, "You must authenticate first!" + end + 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:: The cookbook to load + # segment:: :attributes, :recipes, :definitions, :libraries + # + # === Returns + # :: 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) + cl = Chef::CookbookLoader.new + cookbook = cl[cookbook_id] + raise NotFound unless cookbook + + files_list = segment_files(segment, cookbook) + + files = Hash.new + files_list.each do |f| + full = File.expand_path(f) + name = File.basename(full) + files[name] = { + :name => name, + :file => full, + } + end + files + end + + def segment_files(segment, cookbook) + files_list = nil + case segment + when :attributes + files_list = cookbook.attribute_files + when :recipes + files_list = cookbook.recipe_files + when :definitions + files_list = cookbook.definition_files + when :libraries + files_list = cookbook.library_files + else + raise ArgumentError, "segment must be one of :attributes, :recipes, :definitions or :libraries" + end + files_list + end + + def load_all_files(segment) + cl = Chef::CookbookLoader.new + files = Array.new + cl.each do |cookbook| + segment_files(segment, cookbook).each do |sf| + files << { + :cookbook => cookbook.name, + :name => File.basename(sf) + } + end + end + files + end + +end \ No newline at end of file diff --git a/chef-server/lib/controllers/cookbook_attributes.rb b/chef-server/lib/controllers/cookbook_attributes.rb new file mode 100644 index 0000000000..803421b6f5 --- /dev/null +++ b/chef-server/lib/controllers/cookbook_attributes.rb @@ -0,0 +1,55 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + + +class CookbookAttributes < Application + + provides :html, :json + + include Chef::Mixin::Checksum + + def load_cookbook_attributes() + @attribute_files = load_cookbook_segment(params[:cookbook_id], :attributes) + end + + def index + if params[:id] + show + else + load_cookbook_attributes() + display @attribute_files + end + end + + def show + only_provides :json + load_cookbook_attributes + raise NotFound, "Cannot find a suitable attribute file!" unless @attribute_files.has_key?(params[:id]) + to_send = @attribute_files[params[:id]][:file] + current_checksum = checksum(to_send) + Chef::Log.debug("old sum: #{params[:checksum]}, new sum: #{current_checksum}") + if current_checksum == params[:checksum] + display "File #{to_send} has not changed", :status => 304 + else + send_file(to_send) + end + end + +end + + diff --git a/chef-server/lib/controllers/cookbook_definitions.rb b/chef-server/lib/controllers/cookbook_definitions.rb new file mode 100644 index 0000000000..dbfeeca4d7 --- /dev/null +++ b/chef-server/lib/controllers/cookbook_definitions.rb @@ -0,0 +1,56 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + + +class CookbookDefinitions < Application + + provides :html, :json + + include Chef::Mixin::Checksum + + def load_cookbook_definitions() + @definition_files = load_cookbook_segment(params[:cookbook_id], :definitions) + end + + def index + if params[:id] + show + else + load_cookbook_definitions() + display @definition_files + end + end + + def show + only_provides :json + load_cookbook_definitions + raise NotFound, "Cannot find a suitable definition file!" unless @definition_files.has_key?(params[:id]) + + to_send = @definition_files[params[:id]][:file] + current_checksum = checksum(to_send) + Chef::Log.debug("Old sum: #{params[:checksum]}, New sum: #{current_checksum}") + if current_checksum == params[:checksum] + display "File #{to_send} has not changed", :status => 304 + else + send_file(to_send) + end + end + +end + + diff --git a/chef-server/lib/controllers/cookbook_files.rb b/chef-server/lib/controllers/cookbook_files.rb new file mode 100644 index 0000000000..2d8078ad7e --- /dev/null +++ b/chef-server/lib/controllers/cookbook_files.rb @@ -0,0 +1,117 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + + +class CookbookFiles < Application + + provides :html, :json + + include Chef::Mixin::Checksum + + layout nil + + def load_cookbook_files() + @cl = Chef::CookbookLoader.new + @cookbook = @cl[params[:cookbook_id]] + raise NotFound unless @cookbook + + @remote_files = Hash.new + @cookbook.remote_files.each do |rf| + full = File.expand_path(rf) + name = File.basename(full) + rf =~ /^.+#{params[:cookbook_id]}[\\|\/]files[\\|\/](.+?)[\\|\/]#{name}/ + singlecopy = $1 + @remote_files[full] = { + :name => name, + :singlecopy => singlecopy, + :file => full, + } + end + @remote_files + end + + def index + if params[:id] + if params[:recursive] == "true" + show_directory + else + show + end + else + load_cookbook_files() + display @remote_files + end + end + + def show + only_provides :json + to_send = find_preferred_file + raise NotFound, "Cannot find a suitable file!" unless to_send + current_checksum = checksum(to_send) + Chef::Log.debug("old sum: #{params[:checksum]}, new sum: #{current_checksum}") + if current_checksum == params[:checksum] + display "File #{to_send} has not changed", :status => 304 + else + send_file(to_send) + end + end + + def show_directory + Chef::Log.info("totally rocking hte show_directory") + dir_to_send = find_preferred_file + unless (dir_to_send && File.directory?(dir_to_send)) + raise NotFound, "Cannot find a suitable directory" + end + + @directory_listing = Array.new + Dir[::File.join(dir_to_send, '**', '*')].sort { |a,b| b <=> a }.each do |file_to_send| + next if File.directory?(file_to_send) + file_to_send =~ /^#{dir_to_send}\/(.+)$/ + @directory_listing << $1 + end + + display @directory_listing + end + + protected + + def find_preferred_file + load_cookbook_files() + preferences = [ + File.join("host-#{params[:fqdn]}", "#{params[:id]}"), + File.join("#{params[:platform]}-#{params[:version]}", "#{params[:id]}"), + File.join("#{params[:platform]}", "#{params[:id]}"), + File.join("default", "#{params[:id]}") + ] + to_send = nil + @remote_files.each_key do |file| + Chef::Log.debug("Looking at #{file}") + preferences.each do |pref| + Chef::Log.debug("Compared to #{pref}") + if file =~ /#{pref}$/ + Chef::Log.debug("Matched #{pref} for #{file}!") + to_send = file + break + end + end + break if to_send + end + to_send + end + +end diff --git a/chef-server/lib/controllers/cookbook_recipes.rb b/chef-server/lib/controllers/cookbook_recipes.rb new file mode 100644 index 0000000000..5081ddced1 --- /dev/null +++ b/chef-server/lib/controllers/cookbook_recipes.rb @@ -0,0 +1,56 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + + +class CookbookRecipes < Application + + provides :html, :json + + include Chef::Mixin::Checksum + + def load_cookbook_recipes() + @recipe_files = load_cookbook_segment(params[:cookbook_id], :recipes) + end + + def index + if params[:id] + show + else + load_cookbook_recipes() + display @recipe_files + end + end + + def show + only_provides :json + load_cookbook_recipes + raise NotFound, "Cannot find a suitable recipe file!" unless @recipe_files.has_key?(params[:id]) + + to_send = @recipe_files[params[:id]][:file] + current_checksum = checksum(to_send) + Chef::Log.debug("old sum: #{params[:checksum]}, new sum: #{current_checksum}") + if current_checksum == params[:checksum] + display "File #{to_send} has not changed", :status => 304 + else + send_file(to_send) + end + end + +end + + diff --git a/chef-server/lib/controllers/cookbook_templates.rb b/chef-server/lib/controllers/cookbook_templates.rb new file mode 100644 index 0000000000..4cb5e4622c --- /dev/null +++ b/chef-server/lib/controllers/cookbook_templates.rb @@ -0,0 +1,77 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +class CookbookTemplates < Application + + provides :html, :json + + def load_cookbook_templates() + @cl = Chef::CookbookLoader.new + @cookbook = @cl[params[:cookbook_id]] + raise NotFound unless @cookbook + + @templates = Hash.new + @cookbook.template_files.each do |tf| + full = File.expand_path(tf) + name = File.basename(full) + tf =~ /^.+#{params[:cookbook_id]}[\\|\/]templates[\\|\/](.+?)[\\|\/]#{name}/ + singlecopy = $1 + @templates[full] = { + :name => name, + :singlecopy => singlecopy, + :file => full, + } + end + @templates + end + + def index + if params[:id] + show + else + load_cookbook_templates() + display @templates + end + end + + def show + load_cookbook_templates() + preferences = [ + File.join("host-#{params[:fqdn]}", "#{params[:id]}"), + File.join("#{params[:platform]}-#{params[:version]}", "#{params[:id]}"), + File.join("#{params[:platform]}", "#{params[:id]}"), + File.join("default", "#{params[:id]}") + ] + to_send = nil + @templates.each_key do |file| + Chef::Log.debug("Looking at #{file}") + preferences.each do |pref| + Chef::Log.debug("Compared to #{pref}") + if file =~ /#{pref}/ + Chef::Log.debug("Matched #{pref} for #{file}!") + to_send = file + break + end + end + break if to_send + end + raise NotFound, "Cannot find a suitable template!" unless to_send + send_file(to_send) + end + +end diff --git a/chef-server/lib/controllers/cookbooks.rb b/chef-server/lib/controllers/cookbooks.rb new file mode 100644 index 0000000000..e2a9d7f319 --- /dev/null +++ b/chef-server/lib/controllers/cookbooks.rb @@ -0,0 +1,50 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +class Cookbooks < Application + + provides :html, :json + + def index + @cl = Chef::CookbookLoader.new + display @cl + end + + def show + @cl = Chef::CookbookLoader.new + @cookbook = @cl[params[:id]] + raise NotFound unless @cookbook + display @cookbook + end + + def recipe_files + @recipe_files = load_all_files(:recipes) + display @recipe_files + end + + def attribute_files + @attribute_files = load_all_files(:attributes) + display @attribute_files + end + + def definition_files + @definition_files = load_all_files(:definitions) + display @definition_files + end + +end diff --git a/chef-server/lib/controllers/exceptions.rb b/chef-server/lib/controllers/exceptions.rb new file mode 100644 index 0000000000..d8f7307637 --- /dev/null +++ b/chef-server/lib/controllers/exceptions.rb @@ -0,0 +1,38 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +class Exceptions < Application + + provides :html, :json + + # handle NotFound exceptions (404) + def not_found + display params + end + + # handle NotAcceptable exceptions (406) + def not_acceptable + display params + end + + # handle BadRequest exceptions (400) + def bad_request + display params + end + +end \ No newline at end of file diff --git a/chef-server/lib/controllers/nodes.rb b/chef-server/lib/controllers/nodes.rb new file mode 100644 index 0000000000..655b264862 --- /dev/null +++ b/chef-server/lib/controllers/nodes.rb @@ -0,0 +1,78 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +class Nodes < Application + + provides :html, :json + + before :fix_up_node_id + before :login_required, :only => [ :create, :update, :destroy ] + before :authorized_node, :only => [ :update, :destroy ] + + def index + @node_list = Chef::Node.list + display @node_list + end + + def show + begin + @node = Chef::Node.load(params[:id]) + rescue Net::HTTPServerException => e + raise NotFound, "Cannot load node #{params[:id]}" + end + display @node + end + + def create + @node = params.has_key?("inflated_object") ? params["inflated_object"] : nil + if @node + @status = 202 + @node.save + display @node + else + raise BadRequest, "You must provide a Node to create" + end + end + + def update + @node = params.has_key?("inflated_object") ? params["inflated_object"] : nil + if @node + @status = 202 + @node.save + display @node + else + raise NotFound, "You must provide a Node to update" + end + end + + def destroy + begin + @node = Chef::Node.load(params[:id]) + rescue RuntimeError => e + raise BadRequest, "Node #{params[:id]} does not exist to destroy!" + end + @status = 202 + @node.destroy + if content_type == :html + redirect url(:nodes) + else + display @node + end + end + +end diff --git a/chef-server/lib/controllers/openid_consumer.rb b/chef-server/lib/controllers/openid_consumer.rb new file mode 100644 index 0000000000..4e3980ce3d --- /dev/null +++ b/chef-server/lib/controllers/openid_consumer.rb @@ -0,0 +1,117 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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 'openid/store/filesystem' + +class OpenidConsumer < Application + + provides :html, :json + + def index + render + end + + def start + check_valid_openid_provider(params[:openid_identifier]) + begin + oidreq = consumer.begin(params[:openid_identifier]) + rescue OpenID::OpenIDError => e + raise BadRequest, "Discovery failed for #{params[:openid_identifier]}: #{e}" + end + return_to = absolute_url(:openid_consumer_complete) + realm = absolute_url(:openid_consumer) + + if oidreq.send_redirect?(realm, return_to, params[:immediate]) + return redirect(oidreq.redirect_url(realm, return_to, params[:immediate])) + else + @form_text = oidreq.form_markup(realm, return_to, params[:immediate], {'id' => 'openid_form'}) + render + end + end + + def complete + # FIXME - url_for some action is not necessarily the current URL. + current_url = absolute_url(:openid_consumer_complete) + parameters = params.reject{|k,v| k == "controller" || k == "action"} + oidresp = consumer.complete(parameters, current_url) + case oidresp.status + when OpenID::Consumer::FAILURE + if oidresp.display_identifier + raise BadRequest, "Verification of #{oidresp.display_identifier} failed: #{oidresp.message}" + else + raise BadRequest, "Verification failed: #{oidresp.message}" + end + when OpenID::Consumer::SUCCESS + session[:openid] = oidresp.identity_url + if oidresp.display_identifier =~ /openid\/server\/node\/(.+)$/ + session[:level] = :node + session[:node_name] = $1 + else + session[:level] = :admin + end + redirect_back_or_default(absolute_url(:nodes)) + 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 absolute_url(:openid_consumer) + end + + def logout + session[:openid] = nil if session.has_key?(:openid) + session[:level] = nil if session.has_key?(:level) + session[:node_name] = nil if session.has_key?(:node_name) + redirect url(:top) + end + + private + + # Returns true if the openid is at a valid provider, based on whether :openid_providers is + # defined. Raises an exception if it is not an allowed provider. + def check_valid_openid_provider(openid) + if Chef::Config[:openid_providers] + fp = Chef::Config[:openid_providers].detect do |p| + case openid + when /^http:\/\/#{p}/, /^#{p}/ + true + else + false + end + end + unless fp + raise Unauthorized, "Sorry, #{openid} is not an allowed OpenID Provider." + end + end + true + end + + def consumer + if @consumer.nil? + dir = Chef::Config[:openid_cstore_path] + store = OpenID::Store::Filesystem.new(dir) + @consumer = OpenID::Consumer.new(session, store) + end + return @consumer + end +end diff --git a/chef-server/lib/controllers/openid_register.rb b/chef-server/lib/controllers/openid_register.rb new file mode 100644 index 0000000000..f5113ef267 --- /dev/null +++ b/chef-server/lib/controllers/openid_register.rb @@ -0,0 +1,89 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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 'openid' + +class OpenidRegister < Application + + provides :html, :json + + before :fix_up_node_id + + def index + @headers['X-XRDS-Location'] = absolute_url(:protocol => "http", :controller => "openid_server", :action => "idp_xrds") + @registered_nodes = Chef::OpenIDRegistration.list(true) + Chef::Log.debug(@registered_nodes.inspect) + display @registered_nodes + end + + def show + begin + @registered_node = Chef::OpenIDRegistration.load(params[:id]) + rescue Net::HTTPServerException => e + if e.message =~ /^404/ + raise NotFound, "Cannot load node registration for #{params[:id]}" + else + raise e + end + end + Merb.logger.debug(@registered_node.inspect) + display @registered_node + end + + def create + params.has_key?(:id) or raise BadRequest, "You must provide an id to register" + params.has_key?(:password) or raise BadRequest, "You must provide a password to register" + if Chef::OpenIDRegistration.has_key?(params[:id]) + raise BadRequest, "You cannot re-register #{params[:id]}!" + end + @registered_node = Chef::OpenIDRegistration.new + @registered_node.name = params[:id] + @registered_node.set_password(params[:password]) + @registered_node.save + display @registered_node + end + + def update + raise BadRequest, "You cannot update your registration -- delete #{params[:id]} and re-register" + end + + def destroy + begin + r = Chef::OpenIDRegistration.load(params[:id]) + rescue Exception => e + raise BadRequest, "Cannot find the registration for #{params[:id]}" + end + r.destroy + if content_type == :html + redirect url(:registrations) + else + display({ :message => "Deleted registration for #{params[:id]}"}) + end + end + + def validate + begin + r = Chef::OpenIDRegistration.load(params[:id]) + rescue Exception => e + raise BadRequest, "Cannot find the registration for #{params[:id]}" + end + r.validated = r.validated ? false : true + r.save + redirect url(:registrations) + end +end diff --git a/chef-server/lib/controllers/openid_server.rb b/chef-server/lib/controllers/openid_server.rb new file mode 100644 index 0000000000..4cdaf67adb --- /dev/null +++ b/chef-server/lib/controllers/openid_server.rb @@ -0,0 +1,236 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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' + +# load the openid library, first trying rubygems +#begin +# require "rubygems" +# require_gem "ruby-openid", ">= 1.0" +#rescue LoadError +require "openid" +require "openid/consumer/discovery" +require 'openid/store/filesystem' +require 'json' +#end + +class OpenidServer < Application + + provides :html, :json + + include Merb::OpenidServerHelper + include OpenID::Server + + layout nil + + before :fix_up_node_id + + def index + + oidreq = server.decode_request(params.reject{|k,v| k == "controller" || k == "action"}) + + # no openid.mode was given + unless oidreq + return "This is the Chef OpenID server endpoint." + end + + oidresp = nil + + if oidreq.kind_of?(CheckIDRequest) + identity = oidreq.identity + + if oidresp + nil + elsif self.is_authorized(identity, oidreq.trust_root) + oidresp = oidreq.answer(true, nil, identity) + elsif oidreq.immediate + server_url = url :openid_server + oidresp = oidreq.answer(false, server_url) + else + if content_type != 'application/json' + session[:last_oidreq] = oidreq + response = { :action => url(:openid_server_decision) } + return response.to_json + else + return show_decision_page(oidreq) + end + end + else + oidresp = server.handle_request(oidreq) + end + + self.render_response(oidresp) + end + + def show_decision_page(oidreq, message="Do you trust this site with your identity?") + session[:last_oidreq] = oidreq + @oidreq = oidreq + + if message + session[:notice] = message + end + + render :template => 'openid_server/decide' + end + + def node_page + unless Chef::OpenIDRegistration.has_key?(params[:id]) + raise NotFound, "Cannot find registration for #{params[:id]}" + end + + # Yadis content-negotiation: we want to return the xrds if asked for. + accept = request.env['HTTP_ACCEPT'] + + # This is not technically correct, and should eventually be updated + # to do real Accept header parsing and logic. Though I expect it will work + # 99% of the time. + if accept and accept.include?('application/xrds+xml') + return node_xrds + end + + # content negotiation failed, so just render the user page + xrds_url = absolute_url(:openid_node_xrds, :id => params[:id]) + identity_page = < + + +

OpenID identity page for registration #{params[:id]}

+ +EOS + + # Also add the Yadis location header, so that they don't have + # to parse the html unless absolutely necessary. + @headers['X-XRDS-Location'] = xrds_url + render identity_page + end + + def node_xrds + types = [ + OpenID::OPENID_2_0_TYPE, + OpenID::OPENID_1_0_TYPE + ] + + render_xrds(types) + end + + def idp_xrds + types = [ + OpenID::OPENID_IDP_2_0_TYPE, + ] + + render_xrds(types) + end + + def decision + oidreq = session[:last_oidreq] + session[:last_oidreq] = nil + + if params.has_key?(:cancel) + Merb.logger.info("Cancelling OpenID Authentication") + return(redirect(oidreq.cancel_url)) + else + identity = oidreq.identity + identity =~ /node\/(.+)$/ + openid_node = Chef::OpenIDRegistration.load($1) + unless openid_node.validated + raise Unauthorized, "This nodes registration has not been validated" + end + if openid_node.password == encrypt_password(openid_node.salt, params[:password]) + if session[:approvals] + session[:approvals] << oidreq.trust_root + else + session[:approvals] = [oidreq.trust_root] + end + oidresp = oidreq.answer(true, nil, identity) + return self.render_response(oidresp) + else + raise Unauthorized, "Invalid credentials" + end + end + end + + protected + + def encrypt_password(salt, password) + Digest::SHA1.hexdigest("--#{salt}--#{password}--") + end + + def server + if @server.nil? + server_url = absolute_url(:openid_server) + dir = Chef::Config[:openid_store_path] + store = OpenID::Store::Filesystem.new(dir) + @server = Server.new(store, server_url) + end + return @server + end + + def approved(trust_root) + return false if session[:approvals].nil? + return session[:approvals].member?(trust_root) + end + + def is_authorized(identity_url, trust_root) + return (session[:username] and (identity_url == url_for_user) and self.approved(trust_root)) + end + + def render_xrds(types) + type_str = "" + + types.each { |uri| + type_str += "#{uri}\n " + } + + yadis = < + + + + #{type_str} + #{absolute_url(:openid_server)} + + + +EOS + + @headers['content-type'] = 'application/xrds+xml' + render yadis + end + + def render_response(oidresp) + if oidresp.needs_signing + signed_response = server.signatory.sign(oidresp) + end + web_response = server.encode_response(oidresp) + + case web_response.code + when HTTP_OK + @status = 200 + render web_response.body + when HTTP_REDIRECT + redirect web_response.headers['location'] + else + @status = 400 + render web_response.body + end + end + + +end diff --git a/chef-server/lib/controllers/search.rb b/chef-server/lib/controllers/search.rb new file mode 100644 index 0000000000..0abbf352b8 --- /dev/null +++ b/chef-server/lib/controllers/search.rb @@ -0,0 +1,71 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +class Search < Application + + provides :html, :json + + def index + @s = Chef::Search.new + @search_indexes = @s.list_indexes + display @search_indexes + end + + def show + @s = Chef::Search.new + @results = nil + if params[:q] + @results = @s.search(params[:id], params[:q] == "" ? "?*" : params[:q]) + else + @results = @s.search(params[:id], "?*") + end + # Boy, this should move to the search function + if params[:a] + attributes = params[:a].split(",").collect { |a| a.to_sym } + unless attributes.length == 0 + @results = @results.collect do |r| + nr = Hash.new + nr[:index_name] = r[:index_name] + nr[:id] = r[:id] + attributes.each do |attrib| + if r.has_key?(attrib) + nr[attrib] = r[attrib] + end + end + nr + end + end + end + display @results + 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 + if content_type == :html + redirect url(:search) + else + display @entries + end + end + +end diff --git a/chef-server/lib/controllers/search_entries.rb b/chef-server/lib/controllers/search_entries.rb new file mode 100644 index 0000000000..c93add3dc5 --- /dev/null +++ b/chef-server/lib/controllers/search_entries.rb @@ -0,0 +1,68 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +class SearchEntries < Application + + provides :html, :json + + def index + @s = Chef::Search.new + @entries = @s.search(params[:search_id], "?*") + display @entries + end + + def show + @s = Chef::Search.new + @entry = @s.search(params[:search_id], "id:'#{params[:search_id]}_#{params[:id]}'").first + display @entry + 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) + if content_type == :html + redirect url(:search) + else + @status = 202 + display @to_index + end + 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 + if content_type == :html + redirect url(:search) + else + display @entries + end + end + +end diff --git a/chef-server/lib/helpers/global_helpers.rb b/chef-server/lib/helpers/global_helpers.rb new file mode 100644 index 0000000000..f3b15129a8 --- /dev/null +++ b/chef-server/lib/helpers/global_helpers.rb @@ -0,0 +1,35 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +module Merb + module GlobalHelpers + # helpers defined here available to all views. + def resource_collection(collection) + html = "
    " + collection.each do |resource| + html << "
  • #{resource.class}
  • " + end + html << "
" + html + end + + def node_escape(node) + node.gsub(/\./, '_') + end + end +end diff --git a/chef-server/lib/helpers/nodes_helper.rb b/chef-server/lib/helpers/nodes_helper.rb new file mode 100644 index 0000000000..44a190a7c6 --- /dev/null +++ b/chef-server/lib/helpers/nodes_helper.rb @@ -0,0 +1,37 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +module Merb + module NodesHelper + def recipe_list(node) + response = "" + node.recipes.each do |recipe| + response << "
  • #{recipe}
  • " + end + response + end + + def attribute_list(node) + response = "" + node.each_attribute do |k,v| + response << "
  • #{k}: #{v}
  • " + end + response + end + end +end \ No newline at end of file diff --git a/chef-server/lib/helpers/openid_server_helpers.rb b/chef-server/lib/helpers/openid_server_helpers.rb new file mode 100644 index 0000000000..dc56d2742f --- /dev/null +++ b/chef-server/lib/helpers/openid_server_helpers.rb @@ -0,0 +1,27 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +module Merb + module OpenidServerHelper + + def url_for_user + url(:openid_node, :username => session[:username]) + end + + end +end diff --git a/chef-server/lib/init.rb b/chef-server/lib/init.rb new file mode 100644 index 0000000000..2aa5781a81 --- /dev/null +++ b/chef-server/lib/init.rb @@ -0,0 +1,206 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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. +# + +Merb.root = File.join(File.dirname(__FILE__)) + +# +# ==== Structure of Merb initializer +# +# 1. Load paths. +# 2. Dependencies configuration. +# 3. Libraries (ORM, testing tool, etc) you use. +# 4. Application-specific configuration. + +# +# ==== Set up load paths +# + +# Make the app's "gems" directory a place where gems are loaded from. +# Note that gems directory must have a structure RubyGems uses for +# directories under which gems are kept. +# +# To conveniently set it up use gem install -i +# when installing gems. This will set up the structure under /gems +# automagically. +# +# An example: +# +# You want to bundle ActiveRecord and ActiveSupport with your Merb +# application to be deployment environment independent. To do so, +# install gems into merb_app_root/gems directory like this: +# +# gem install -i ~/dev/merbapp/gems activesupport-post-2.0.2gem activerecord-post-2.0.2.gem +# +# Since RubyGems will search merb_app_root/gems for dependencies, order +# in statement above is important: we need to install ActiveSupport which +# ActiveRecord depends on first. +# +# Remember that bundling of dependencies as gems with your application +# makes it independent of the environment it runs in and is a very +# good, encouraged practice to follow. +Gem.clear_paths +Gem.path.unshift(Merb.root / "gems") + +# If you want modules and classes from libraries organized like +# merbapp/lib/magicwand/lib/magicwand.rb to autoload, +# uncomment this. + + +# Merb.push_path(:lib, Merb.root / "lib") # uses **/*.rb as path glob. + + +# disable the ActiveSupport json annoying stuff, as it breaks our to_json +Merb.disable :json + +# ==== Dependencies + +# These are some examples of how you might specify dependencies. +# Dependencies load is delayed to one of later Merb app +# boot stages. It may be important when +# later part of your configuration relies on libraries specified +# here. +# +# dependencies "RedCloth", "merb_helpers" +# OR +# dependency "RedCloth", "> 3.0" +# OR +# dependencies "RedCloth" => "> 3.0", "ruby-aes-cext" => "= 1.0" +Merb::BootLoader.after_app_loads do + Chef::Queue.connect + + # create the couch design docs for nodes and openid registrations + Chef::Node.create_design_document + Chef::OpenIDRegistration.create_design_document + + # dependency "magic_admin" # this gem uses the app's model classes +end + +# +# ==== Set up your ORM of choice +# + +# Merb doesn't come with database support by default. You need +# an ORM plugin. Install one, and uncomment one of the following lines, +# if you need a database. + +# Uncomment for DataMapper ORM +# use_orm :datamapper + +# Uncomment for ActiveRecord ORM +# use_orm :activerecord + +# Uncomment for Sequel ORM +# use_orm :sequel + +Merb.push_path(:lib, File.join(File.dirname(__FILE__), "..", "chef")) +Merb.push_path(:controller, File.join(File.dirname(__FILE__), "controllers")) +Merb.push_path(:model, File.join(File.dirname(__FILE__), "models")) +Merb.push_path(:view, File.join(File.dirname(__FILE__), "views")) +Merb.push_path(:helper, File.join(File.dirname(__FILE__), "helpers")) +Merb.push_path(:public, File.join(File.dirname(__FILE__), "public")) + +require 'merb-haml' +#require 'uv' + + +# +# ==== Pick what you test with +# + +# This defines which test framework the generators will use +# rspec is turned on by default +# +# Note that you need to install the merb_rspec if you want to ue +# rspec and merb_test_unit if you want to use test_unit. +# merb_rspec is installed by default if you did gem install +# merb. +# +# use_test :test_unit +use_test :rspec + + +# +# ==== Set up your basic configuration +# +Merb::Config.use do |c| + # Sets up a custom session id key, if you want to piggyback sessions of other applications + # with the cookie session store. If not specified, defaults to '_session_id'. + c[:session_id_key] = '_chef_server_session_id' + c[:session_secret_key] = '0992ea491c30ec76c98367c1ca53b18c1e7c5b30' + c[:session_store] = 'cookie' + c[:exception_details] = true + c[:reload_classes] = true + c[:log_level] = :debug + c[:log_file] = "/var/log/chef-server.log" +end + +Merb.logger.info("Compiling routes...") +Merb::Router.prepare do |r| + # RESTful routes + # r.resources :posts + + # This is the default route for /:controller/:action/:id + # This is fine for most cases. If you're heavily using resource-based + # routes, you may want to comment/remove this line to prevent + # clients from calling your create or destroy actions with a GET + + resources :nodes + resources :searches, :path => "search", :controller => "search" do + resources :entries, :controller => "search_entries" + end + + match("/cookbooks/_attribute_files").to(:controller => "cookbooks", :action => "attribute_files") + match("/cookbooks/_recipe_files").to(:controller => "cookbooks", :action => "recipe_files") + match("/cookbooks/_definition_files").to(:controller => "cookbooks", :action => "definition_files") + +# r.match("/cookbooks/:cookbook_id/templates").to(:controller => "cookbook_templates", :action => "index") + + resources :cookbooks do + resources :templates, :controller => "cookbook_templates" + resources :files, :controller => "cookbook_files" + resources :recipes, :controller => "cookbook_recipes" + resources :attributes, :controller => "cookbook_attributes" + resources :definitions, :controller => "cookbook_definitions" + end + + #r.resources :openid do |res| + # res.resources :register, :controller => "openid_register" + # res.resources :server, :controller => "openid_server" + #end + + resources :registrations, :controller => "openid_register" + resources :registrations, :controller => "openid_register", :member => { :validate => :post } + match("/openid/server").to(:controller => "openid_server", :action => "index").name(:openid_server) + match("/openid/server/server/xrds"). + to(:controller => "openid_server", :action => 'idp_xrds').name(:openid_server_xrds) + match("/openid/server/node/:id"). + to(:controller => "openid_server", :action => 'node_page').name(:openid_node) + match('/openid/server/node/:id/xrds'). + to(:controller => 'openid_server', :action => 'node_xrds').name(:openid_node_xrds) + match('/openid/server/decision').to(:controller => "openid_server", :action => "decision").name(:openid_server_decision) + match('/openid/consumer').to(:controller => 'openid_consumer', :action => 'index').name(:openid_consumer) + match('/openid/consumer/start').to(:controller => 'openid_consumer', :action => 'start').name(:openid_consumer_start) + match('/openid/consumer/complete').to(:controller => 'openid_consumer', :action => 'complete').name(:openid_consumer_complete) + match('/openid/consumer/logout').to(:controller => 'openid_consumer', :action => 'logout').name(:openid_consumer_logout) + + #r.default_routes + + # Change this for your home page to be available at / + match('/').to(:controller => 'nodes', :action =>'index').name(:top) +end + diff --git a/chef-server/lib/public/images/merb.jpg b/chef-server/lib/public/images/merb.jpg new file mode 100644 index 0000000000..a19dcf4048 Binary files /dev/null and b/chef-server/lib/public/images/merb.jpg differ diff --git a/chef-server/lib/public/stylesheets/master.css b/chef-server/lib/public/stylesheets/master.css new file mode 100644 index 0000000000..13bdffbe1b --- /dev/null +++ b/chef-server/lib/public/stylesheets/master.css @@ -0,0 +1,292 @@ +/* body { + font-family: Arial, Verdana, sans-serif; + font-size: 12px; + background-color: #fff; + margin: ; +} +html { + height: 100%; + margin-bottom: 1px; +} +#container { + width: 80%; + text-align: left; + background-color: #fff; + margin-right: auto; + margin-left: auto; +} +#header-container { + width: 100%; + padding-top: 15px; +} +#header-container h1, #header-container h2 { + margin-left: 6px; + margin-bottom: 6px; +} +.spacer { + width: 100%; + height: 15px; +} +hr { + border: 0px; + color: #ccc; + background-color: #cdcdcd; + height: 1px; + width: 100%; + text-align: left; +} +h1 { + font-size: 28px; + color: #c55; + background-color: #fff; + font-family: Arial, Verdana, sans-serif; + font-weight: 300; +} +h2 { + font-size: 15px; + color: #999; + font-family: Arial, Verdana, sans-serif; + font-weight: 300; + background-color: #fff; +} +h3 { + color: #4d9b12; + font-size: 15px; + text-align: left; + font-weight: 300; + padding: 5px; + margin-top: 5px; +} + +#left-container { + float: left; + width: 250px; + background-color: #FFFFFF; + color: black; +} + +#left-container h3 { + color: #c55; +} + +#main-container { + margin: 5px 5px 5px 260px; + padding: 15px; + border-left: 1px solid silver; + min-height: 400px; +} +p { + color: #000; + background-color: #fff; + line-height: 20px; + padding: 5px; +} +a { + color: #4d9b12; + background-color: #fff; + text-decoration: none; +} +a:hover { + color: #4d9b12; + background-color: #fff; + text-decoration: underline; +} +#footer-container { + clear: both; + font-size: 12px; + font-family: Verdana, Arial, sans-serif; +} +.right { + float: right; + font-size: 100%; + margin-top: 5px; + color: #999; + background-color: #fff; +} +.left { + float: left; + font-size: 100%; + margin-top: 5px; + color: #999; + background-color: #fff; +} +#main-container ul { + margin-left: 3.0em; +} + +div.resource_collection { + border: 1px solid #999; + float: left; + clear: both; + margin: 10px; + padding: 5px; +} + +div.resource { + border-top: 1px solid #999; + float: left; + clear: both; +} + +div.attr_group { + float: left; + clear: both; +} + +td.attr_name { + font-weight: bold; + margin-right: 10px; + border-right: 1px solid #999; +} + +td.attr_value { + padding-left: 5px; + border-top: 1px solid #999; +} + +div.node { + float: left; + clear: both; + margin: 10px; + padding: 5px; + border: 1px solid #999; +} +*/ + +pre.twilight .DiffInserted { + background-color: #253B22; + color: #F8F8F8; +} +pre.twilight .DiffHeader { + background-color: #0E2231; + color: #F8F8F8; + font-style: italic; +} +pre.twilight .CssPropertyValue { + color: #F9EE98; +} +pre.twilight .CCCPreprocessorDirective { + color: #AFC4DB; +} +pre.twilight .Constant { + color: #CF6A4C; +} +pre.twilight .DiffChanged { + background-color: #4A410D; + color: #F8F8F8; +} +pre.twilight .EmbeddedSource { + background-color: #A3A6AD; +} +pre.twilight .Support { + color: #9B859D; +} +pre.twilight .MarkupList { + color: #F9EE98; +} +pre.twilight .CssConstructorArgument { + color: #8F9D6A; +} +pre.twilight .Storage { + color: #F9EE98; +} +pre.twilight .line-numbers { + background-color: #DDF0FF; + color: #000000; +} +pre.twilight .CssClass { + color: #9B703F; +} +pre.twilight .StringConstant { + color: #DDF2A4; +} +pre.twilight .CssAtRule { + color: #8693A5; +} +pre.twilight .MetaTagInline { + color: #E0C589; +} +pre.twilight .MarkupHeading { + color: #CF6A4C; +} +pre.twilight .CssTagName { + color: #CDA869; +} +pre.twilight .SupportConstant { + color: #CF6A4C; +} +pre.twilight .DiffDeleted { + background-color: #420E09; + color: #F8F8F8; +} +pre.twilight .CCCPreprocessorLine { + color: #8996A8; +} +pre.twilight .StringRegexpSpecial { + color: #CF7D34; +} +pre.twilight .EmbeddedSourceBright { + background-color: #9C9EA4; +} +pre.twilight .InvalidIllegal { + background-color: #241A24; + color: #F8F8F8; +} +pre.twilight .SupportFunction { + color: #DAD085; +} +pre.twilight .CssAdditionalConstants { + color: #CA7840; +} +pre.twilight .MetaTagAll { + color: #AC885B; +} +pre.twilight .StringRegexp { + color: #E9C062; +} +pre.twilight .StringEmbeddedSource { + color: #DAEFA3; +} +pre.twilight .EntityInheritedClass { + color: #9B5C2E; + font-style: italic; +} +pre.twilight .CssId { + color: #8B98AB; +} +pre.twilight .CssPseudoClass { + color: #8F9D6A; +} +pre.twilight .StringVariable { + color: #8A9A95; +} +pre.twilight .String { + color: #8F9D6A; +} +pre.twilight .Keyword { + color: #CDA869; +} +pre.twilight { + background-color: #141414; + color: #F8F8F8; +} +pre.twilight .CssPropertyName { + color: #C5AF75; +} +pre.twilight .DoctypeXmlProcessing { + color: #494949; +} +pre.twilight .InvalidDeprecated { + color: #D2A8A1; + font-style: italic; +} +pre.twilight .Variable { + color: #7587A6; +} +pre.twilight .Entity { + color: #9B703F; +} +pre.twilight .Comment { + color: #5F5A60; + font-style: italic; +} diff --git a/chef-server/lib/views/cookbook_templates/index.html.haml b/chef-server/lib/views/cookbook_templates/index.html.haml new file mode 100644 index 0000000000..307aefd812 --- /dev/null +++ b/chef-server/lib/views/cookbook_templates/index.html.haml @@ -0,0 +1,8 @@ +%h1 Cookbook Templates +- @templates.each do |template, data| + .index + %table + %tr + %td + %a{ :href => url(:cookbook_template, { :cookbook_id => params[:cookbook_id], :id => data[:link_name], :version => data[:version] }) } + = "#{data[:version]} - #{data[:name]}" diff --git a/chef-server/lib/views/cookbooks/_attribute_file.html.haml b/chef-server/lib/views/cookbooks/_attribute_file.html.haml new file mode 100644 index 0000000000..af859d5ff3 --- /dev/null +++ b/chef-server/lib/views/cookbooks/_attribute_file.html.haml @@ -0,0 +1,2 @@ +%h3= name += ::Uv.parse(contents, "xhtml", "ruby", true, "twilight") \ No newline at end of file diff --git a/chef-server/lib/views/cookbooks/attribute_files.html.haml b/chef-server/lib/views/cookbooks/attribute_files.html.haml new file mode 100644 index 0000000000..56fdcf7bee --- /dev/null +++ b/chef-server/lib/views/cookbooks/attribute_files.html.haml @@ -0,0 +1,4 @@ +%h1 All Attribute Files +- @attribute_files.each do |af_hash| + %h2= "#{af_hash[:cookbook]}" + = partial(:attribute_file, :name => af_hash[:name], :contents => af_hash[:contents]) \ No newline at end of file diff --git a/chef-server/lib/views/cookbooks/index.html.haml b/chef-server/lib/views/cookbooks/index.html.haml new file mode 100644 index 0000000000..008f74765c --- /dev/null +++ b/chef-server/lib/views/cookbooks/index.html.haml @@ -0,0 +1,7 @@ +%h1 Cookbooks +- @cl.each do |cookbook| + .index + %table + %tr + %td + %a{ :href => url(:cookbook, { :id => cookbook.name }) }= cookbook.name diff --git a/chef-server/lib/views/cookbooks/show.html.haml b/chef-server/lib/views/cookbooks/show.html.haml new file mode 100644 index 0000000000..1b6557e012 --- /dev/null +++ b/chef-server/lib/views/cookbooks/show.html.haml @@ -0,0 +1,24 @@ +%h1= "Cookbook #{h @cookbook.name}" +.cookbook +- if @cookbook.attribute_files.length > 0 + %h2 Attribute Files + - @cookbook.attribute_files.each do |af| + = partial(:attribute_file, :name => File.basename(af), :contents => File.read(af)) + +- if @cookbook.definition_files.length > 0 + - @cookbook.definition_files.each do |df| + %h2 Definition Files + %h3= File.basename(df) + = ::Uv.parse(File.read(df), "xhtml", "ruby", true, "twilight") + +- if @cookbook.recipe_files.length > 0 + - @cookbook.recipe_files.each do |rf| + %h2 Recipe Files + %h3= File.basename(rf) + = ::Uv.parse(File.read(rf), "xhtml", "ruby", true, "twilight") + +- if @cookbook.template_files.length > 0 + - @cookbook.template_files.each do |tf| + %h2 Template Files + %h3= File.basename(tf) + = ::Uv.parse(File.read(tf), "xhtml", "html_rails", true, "twilight") diff --git a/chef-server/lib/views/exceptions/bad_request.json.erb b/chef-server/lib/views/exceptions/bad_request.json.erb new file mode 100644 index 0000000000..f266cf99b9 --- /dev/null +++ b/chef-server/lib/views/exceptions/bad_request.json.erb @@ -0,0 +1 @@ +<%= { :error => params[:exception], :code => 400 }.to_json %> \ No newline at end of file diff --git a/chef-server/lib/views/exceptions/internal_server_error.html.erb b/chef-server/lib/views/exceptions/internal_server_error.html.erb new file mode 100644 index 0000000000..aadbfad350 --- /dev/null +++ b/chef-server/lib/views/exceptions/internal_server_error.html.erb @@ -0,0 +1,216 @@ + + + + <%= @exception_name %> + + + +
    + +
    +

    <%= @exception_name %> <%= @exception.class::STATUS %>

    + <% if show_details = ::Merb::Config[:exception_details] -%> +

    <%= @exception.message %>

    + <% else -%> +

    Sorry about that...

    + <% end -%> +

    Parameters

    +
      + <% params[:original_params].each do |param, value| %> +
    • <%= param %>: <%= value.inspect %>
    • + <% end %> + <%= "
    • None
    • " if params[:original_params].empty? %> +
    + +

    Session

    +
      + <% params[:original_session].each do |param, value| %> +
    • <%= param %>: <%= value.inspect %>
    • + <% end %> + <%= "
    • None
    • " if params[:original_session].empty? %> +
    + +

    Cookies

    +
      + <% params[:original_cookies].each do |param, value| %> +
    • <%= param %>: <%= value.inspect %>
    • + <% end %> + <%= "
    • None
    • " if params[:original_cookies].empty? %> +
    +
    + + <% if show_details %> + + <% @exception.backtrace.each_with_index do |line, index| %> + + + + + + + + + + + + <% end %> +
    + + <%= (line.match(/^([^:]+)/)[1] rescue 'unknown').sub(/\/((opt|usr)\/local\/lib\/(ruby\/)?(gems\/)?(1.8\/)?(gems\/)?|.+\/app\/)/, '') %> + <% unless line.match(/\.erb:/) %> + in "<%= line.match(/:in `(.+)'$/)[1] rescue '?' %>" + <% else %> + (ERB Template) + <% end %> + + <%=lineno%>  +
    + <% (__caller_lines__(file, lineno, 5) rescue []).each do |llineno, lcode, lcurrent| %> +<%= llineno %><%='' if llineno==lineno.to_i %><%= lcode.size > 90 ? CGI.escapeHTML(lcode[0..90])+'......' : CGI.escapeHTML(lcode) %><%='' if llineno==lineno.to_i %> +<% end %> + +
    + + <% end %> + +
    + + \ No newline at end of file diff --git a/chef-server/lib/views/exceptions/not_acceptable.html.erb b/chef-server/lib/views/exceptions/not_acceptable.html.erb new file mode 100644 index 0000000000..f632712bb2 --- /dev/null +++ b/chef-server/lib/views/exceptions/not_acceptable.html.erb @@ -0,0 +1,63 @@ +
    +
    + + +

    pocket rocket web framework

    +
    +
    + +
    +

    Exception:

    +

    <%= params[:exception] %>

    +
    + +
    +

    Why am I seeing this page?

    +

    Merb couldn't find an appropriate content_type to return, + based on what you said was available via provides() and + what the client requested.

    + +

    How to add a mime-type

    +
    
    +      Merb.add_mime_type :pdf, :to_pdf, %w[application/pdf], "Content-Encoding" => "gzip"
    +    
    +

    What this means is:

    +
      +
    • Add a mime-type for :pdf
    • +
    • Register the method for converting objects to PDF as #to_pdf.
    • +
    • Register the incoming mime-type "Accept" header as application/pdf.
    • +
    • Specify a new header for PDF types so it will set Content-Encoding to gzip.
    • +
    + +

    You can then do:

    +
    
    +      class Foo < Application
    +        provides :pdf
    +      end
    +    
    + +

    Where can I find help?

    +

    If you have any questions or if you can't figure something out, please take a + look at our project page, + feel free to come chat at irc.freenode.net, channel #merb, + or post to merb mailing list + on Google Groups.

    + +

    What if I've found a bug?

    +

    If you want to file a bug or make your own contribution to Merb, + feel free to register and create a ticket at our + project development page + on Lighthouse.

    + +

    How do I edit this page?

    +

    You can change what people see when this happens by editing app/views/exceptions/not_acceptable.html.erb.

    + +
    + + +
    diff --git a/chef-server/lib/views/exceptions/not_found.html.erb b/chef-server/lib/views/exceptions/not_found.html.erb new file mode 100644 index 0000000000..388c72c31d --- /dev/null +++ b/chef-server/lib/views/exceptions/not_found.html.erb @@ -0,0 +1,47 @@ +
    +
    + + +

    pocket rocket web framework

    +
    +
    + +
    +

    Exception:

    +

    <%= params[:exception] %>

    +
    + +
    +

    Welcome to Merb!

    +

    Merb is a light-weight MVC framework written in Ruby. We hope you enjoy it.

    + +

    Where can I find help?

    +

    If you have any questions or if you can't figure something out, please take a + look at our project page, + feel free to come chat at irc.freenode.net, channel #merb, + or post to merb mailing list + on Google Groups.

    + +

    What if I've found a bug?

    +

    If you want to file a bug or make your own contribution to Merb, + feel free to register and create a ticket at our + project development page + on Lighthouse.

    + +

    How do I edit this page?

    +

    You're seeing this page because you need to edit the following files: +

      +
    • config/router.rb (recommended)
    • +
    • app/views/exceptions/not_found.html.erb (recommended)
    • +
    • app/views/layout/application.html.erb (change this layout)
    • +
    +

    +
    + + +
    diff --git a/chef-server/lib/views/layout/application.html.haml b/chef-server/lib/views/layout/application.html.haml new file mode 100644 index 0000000000..2be4097d29 --- /dev/null +++ b/chef-server/lib/views/layout/application.html.haml @@ -0,0 +1,26 @@ +!!! XML +!!! +%html + %head + %title Chef Server + %meta{"http-equiv" => "content-type", :content => "text/html; charset=utf-8" } + %link{:rel => "stylesheet", :href => "/stylesheets/master.css", :type => "text/css", :media => "screen", :charset => "utf-8" } + %body + .header + %a{:href => url(:searches) } Search + | + %a{:href => url(:nodes) } Nodes + | + %a{:href => url(:cookbooks) } Cookbooks + | + %a{:href => url(:registrations)} Registrations + - if session[:openid] + | + %a{:href => url(:openid_consumer_logout)}= "Logout #{h session[:openid]}" + = "(#{session[:level].to_s})" + - else + | + %a{:href => url(:openid_consumer)} Login + = catch_content :for_layout + + \ No newline at end of file diff --git a/chef-server/lib/views/nodes/_action.html.haml b/chef-server/lib/views/nodes/_action.html.haml new file mode 100644 index 0000000000..8adb39338d --- /dev/null +++ b/chef-server/lib/views/nodes/_action.html.haml @@ -0,0 +1,13 @@ +%table + - actions.each do |action, resource_hash| + %tr + %td.action_name= action.to_s + %td.action_resources + %table + - resource_hash.keys.sort{ |a,b| a.to_s <=> b.to_s }.each do |rk| + %tr + %td.action_when= rk.to_s + %td + - resource_hash[rk].each do |resource| + = partial(:resource, :resource => resource) + \ No newline at end of file diff --git a/chef-server/lib/views/nodes/_node.html.haml b/chef-server/lib/views/nodes/_node.html.haml new file mode 100644 index 0000000000..24b1f2816b --- /dev/null +++ b/chef-server/lib/views/nodes/_node.html.haml @@ -0,0 +1,9 @@ +.node + %h1 + = "Node #{h node.name}" + %h2 Recipes + %ol + = recipe_list(node) + %h2 Attributes + %ol + = attribute_list(node) diff --git a/chef-server/lib/views/nodes/_resource.html.haml b/chef-server/lib/views/nodes/_resource.html.haml new file mode 100644 index 0000000000..7b9776b816 --- /dev/null +++ b/chef-server/lib/views/nodes/_resource.html.haml @@ -0,0 +1,22 @@ +.resource + %h3= "#{h resource.to_s} (#{resource.class})" + %table + - resource.instance_variables.sort.each do |v| + - attr_name = v.gsub(/\@/, "") + - unless attr_name == "collection" + %tr.attr_group + %td.attr_name + = "#{h attr_name}" + %td.attr_value + - value = resource.instance_variable_get(v) + - if value.kind_of?(String) + = "#{h value}" + - elsif value.kind_of?(Array) + = "#{h value.join(", ")}" + - elsif value.kind_of?(Symbol) + = "#{h value.to_s}" + - elsif attr_name == "actions" + = partial(:action, :actions => value) + - else + = "#{h value.inspect}" + diff --git a/chef-server/lib/views/nodes/compile.html.haml b/chef-server/lib/views/nodes/compile.html.haml new file mode 100644 index 0000000000..5656447ea8 --- /dev/null +++ b/chef-server/lib/views/nodes/compile.html.haml @@ -0,0 +1,5 @@ += partial(:node, :node => @output[:node]) +.resource_collection + %h1 Resource Collection + - @output[:collection].each do |resource| + = partial(:resource, :resource => resource) diff --git a/chef-server/lib/views/nodes/index.html.haml b/chef-server/lib/views/nodes/index.html.haml new file mode 100644 index 0000000000..667e1c7317 --- /dev/null +++ b/chef-server/lib/views/nodes/index.html.haml @@ -0,0 +1,9 @@ +%h1 Node List +- @node_list.each do |node| + .node + %a{ :href => url(:node, { :id => node.gsub(/\./, "_") }) } + = node + %form{ :method => "post", :action => url(:node, { :id => node.gsub(/\./, "_") })} + %input{ :type => "hidden", :name => "_method", :value => "delete" } + %input{ :type => "submit", :name => "Delete", :value => "Delete" } + \ No newline at end of file diff --git a/chef-server/lib/views/nodes/show.html.haml b/chef-server/lib/views/nodes/show.html.haml new file mode 100644 index 0000000000..94708af6d3 --- /dev/null +++ b/chef-server/lib/views/nodes/show.html.haml @@ -0,0 +1 @@ += partial(:node, :node => @node) \ No newline at end of file diff --git a/chef-server/lib/views/openid_consumer/index.html.haml b/chef-server/lib/views/openid_consumer/index.html.haml new file mode 100644 index 0000000000..576ef8d787 --- /dev/null +++ b/chef-server/lib/views/openid_consumer/index.html.haml @@ -0,0 +1,25 @@ +%h1 OpenID Relying Party +-if session[:alert] + .alert= h session[:alert] +-if session[:error] + .error= h session[:error] +-if session[:success] + .success= h session[:success] +#verify-form + %form{ :method => "get", "accept-charset" => "UTF-8", :action => url(:openid_consumer_start) } + Identifier: + %input.openid{ :type => "text", :name => "openid_identifier" }/ + %input{ :type => "submit", :value => "Verify"}/ + %br + %input#immediate{ :name => "immediate", :type => "checkbox" }/ + %label{:for => "immediate"} Use immediate mode + %br + %input#immediate{ :name => "use_sreg", :type => "checkbox" }/ + %label{:for => "use_sreg"} Request registration data + %br + %input#immediate{ :name => "use_pape", :type => "checkbox" }/ + %label{:for => "use_pape"} Request phishing-resistent auth policy + %br + %input#immediate{ :name => "force_post", :type => "checkbox" }/ + %label{:for => "force_post"} Force the transaction to POST + %br diff --git a/chef-server/lib/views/openid_consumer/start.html.haml b/chef-server/lib/views/openid_consumer/start.html.haml new file mode 100644 index 0000000000..75ed9a9257 --- /dev/null +++ b/chef-server/lib/views/openid_consumer/start.html.haml @@ -0,0 +1,4 @@ +<%= @form_text %> + \ No newline at end of file diff --git a/chef-server/lib/views/openid_login/index.html.haml b/chef-server/lib/views/openid_login/index.html.haml new file mode 100644 index 0000000000..17ae69017a --- /dev/null +++ b/chef-server/lib/views/openid_login/index.html.haml @@ -0,0 +1,6 @@ +%h1 Login +#login-form + %form{ :method => "get", :action => url(:openid_login_submit) } + %input{ :type => "text", :name => "username" }/ + %input{ :type => "submit", :value => "Log In"}/ + \ No newline at end of file diff --git a/chef-server/lib/views/openid_register/index.html.haml b/chef-server/lib/views/openid_register/index.html.haml new file mode 100644 index 0000000000..fe4798c59d --- /dev/null +++ b/chef-server/lib/views/openid_register/index.html.haml @@ -0,0 +1,15 @@ +%h1 Registered OpenID Nodes List +%table +- @registered_nodes.each do |node| + %tr + %td + %a{ :href => url(:registration, { :id => node.name }) } + = h node.name + %td + - if session[:level] == :admin + %form{ :method => "post", :action => url(:validate_registration, { :id => node.name })} + - submit_name = node.validated ? "Invalidate" : "Validate" + %input{ :type => "submit", :name => submit_name, :value => submit_name } + %form{ :method => "post", :action => url(:registration, { :id => node.name })} + %input{ :type => "hidden", :name => "_method", :value => "delete" } + %input{ :type => "submit", :name => "Delete", :value => "Delete" } diff --git a/chef-server/lib/views/openid_register/show.html.haml b/chef-server/lib/views/openid_register/show.html.haml new file mode 100644 index 0000000000..cfd38e8963 --- /dev/null +++ b/chef-server/lib/views/openid_register/show.html.haml @@ -0,0 +1,5 @@ +%h1= "Registered OpenID Node #{@registered_node.name}" +%ol + %li + %a{ :href => url(:openid_node , { :id => @registered_node.name.gsub(/\./, "_") }) } OpenID URL + %li= "Validated: #{@registered_node.validated}" diff --git a/chef-server/lib/views/openid_server/decide.html.haml b/chef-server/lib/views/openid_server/decide.html.haml new file mode 100644 index 0000000000..8082a5068d --- /dev/null +++ b/chef-server/lib/views/openid_server/decide.html.haml @@ -0,0 +1,27 @@ +%form{:method => "post", :action => url(:openid_server_decision)} + %table + %tr + %td Site: + %td= @oidreq.trust_root + - if @oidreq.id_select + %tr + %td{:colspan => "2"} + You entered the server identifier at the relying party. + You will need to send an identifier of your choosing. + Enter a username and password below. + %tr + %td Identity to send: + %td + %input{:type => "text", :name => "id_to_send", :size => "25"} + - else + %tr + %td Identity: + %td= @oidreq.identity + %tr + %td + %label{:for => "password"} Password: + %td + %input{:type => "password", :name => "password"} + %input{:type => "submit", :name => "submit", :value => "Authenticate"} + %input{:type => "submit", :name => "cancel", :value => "Cancel"} + diff --git a/chef-server/lib/views/search/_search_form.html.haml b/chef-server/lib/views/search/_search_form.html.haml new file mode 100644 index 0000000000..99303e1714 --- /dev/null +++ b/chef-server/lib/views/search/_search_form.html.haml @@ -0,0 +1,6 @@ +%form{ :method => "get", :action => url(:search, { :id => index_name }) } + Q: + %input{ :type => "text", :name => "q" } + A: + %input{ :type => "text", :name => "a" } + %input{ :type => "submit", :value => "Search #{index_name}" } diff --git a/chef-server/lib/views/search/index.html.haml b/chef-server/lib/views/search/index.html.haml new file mode 100644 index 0000000000..742c1110b0 --- /dev/null +++ b/chef-server/lib/views/search/index.html.haml @@ -0,0 +1,9 @@ +%h1 Search Indexes +- @search_indexes.each do |index| + .index + %table + %tr + %td + %a{ :href => url(:search, { :id => index }) }= index + %td + = partial(:search_form, :index_name => index) diff --git a/chef-server/lib/views/search/show.html.haml b/chef-server/lib/views/search/show.html.haml new file mode 100644 index 0000000000..5380a7477a --- /dev/null +++ b/chef-server/lib/views/search/show.html.haml @@ -0,0 +1,13 @@ +%h1 Search Results +.search + = partial(:search_form, :index_name => params[:id]) +.query + %h2= "Search Query was #{params[:q] ? params[:q] : '*'}" +- @results.each do |result| + .search_result + %h3= "#{h result[:index_name]} (#{h result[:id]})" + %table + - result.each do |k, v| + %tr.attr_group + %td.attr_name= k + %td.attr_value= v.kind_of?(Array) ? v.join(",") : v \ No newline at end of file diff --git a/chef-server/lib/views/search_entries/index.html.haml b/chef-server/lib/views/search_entries/index.html.haml new file mode 100644 index 0000000000..77d140242e --- /dev/null +++ b/chef-server/lib/views/search_entries/index.html.haml @@ -0,0 +1,9 @@ +%h1= "Search Index #{h params[:search_id]}" +- @entries.each do |result| + .search_result + %h3= "#{h result[:index_name]} (#{h result[:id]})" + %table + - result.each do |k, v| + %tr.attr_group + %td.attr_name= k + %td.attr_value= v.kind_of?(Array) ? v.join(",") : v \ No newline at end of file diff --git a/chef-server/lib/views/search_entries/show.html.haml b/chef-server/lib/views/search_entries/show.html.haml new file mode 100644 index 0000000000..7ca34b32ab --- /dev/null +++ b/chef-server/lib/views/search_entries/show.html.haml @@ -0,0 +1,8 @@ +%h1= "Search Index #{h params[:search_id]} entry #{h params[:id]}" +.search_result + %h3= "#{h @entry[:index_name]} (#{h @entry[:id]})" + %table + - @entry.each do |k, v| + %tr.attr_group + %td.attr_name= k + %td.attr_value= v.kind_of?(Array) ? v.join(",") : v \ No newline at end of file diff --git a/chef-server/pkg/chef-server-0.0.1.gem b/chef-server/pkg/chef-server-0.0.1.gem new file mode 100644 index 0000000000..86a59594cf Binary files /dev/null and b/chef-server/pkg/chef-server-0.0.1.gem differ -- cgit v1.2.1