chef-server-api 0.9.18 → 0.10.0.beta.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -48,11 +48,7 @@ class Roles < Application
48
48
  raise NotFound, "Cannot load role #{params[:id]}"
49
49
  end
50
50
 
51
- @role.description(params["inflated_object"].description)
52
- @role.recipes(params["inflated_object"].recipes) if defined?(params["inflated_object"].recipes)
53
- @role.run_list(params["inflated_object"].run_list)
54
- @role.default_attributes(params["inflated_object"].default_attributes)
55
- @role.override_attributes(params["inflated_object"].override_attributes)
51
+ @role.update_from!(params["inflated_object"])
56
52
  @role.cdb_save
57
53
  self.status = 200
58
54
  @role.couchdb_rev = nil
@@ -70,4 +66,26 @@ class Roles < Application
70
66
  display @role
71
67
  end
72
68
 
69
+ # GET /roles/:id/environments/:env_id
70
+ def environment
71
+ begin
72
+ @role = Chef::Role.cdb_load(params[:role_id])
73
+ rescue Chef::Exceptions::CouchDBNotFound => e
74
+ raise NotFound, "Cannot load role #{params[:role_id]}"
75
+ end
76
+ display("run_list" => @role.env_run_lists[params[:env_id]])
77
+ end
78
+
79
+ # GET /roles/:id/environments
80
+ def environments
81
+ begin
82
+ @role = Chef::Role.cdb_load(params[:role_id])
83
+ rescue Chef::Exceptions::CouchDBNotFound => e
84
+ raise NotFound, "Cannot load role #{params[:role_id]}"
85
+ end
86
+
87
+ display(@role.env_run_lists.keys.sort)
88
+ end
89
+
90
+
73
91
  end
@@ -17,7 +17,7 @@
17
17
  # limitations under the License.
18
18
 
19
19
 
20
- require 'chef/solr/query'
20
+ require 'chef/solr_query'
21
21
 
22
22
  class Search < Application
23
23
  provides :json
@@ -27,34 +27,24 @@ class Search < Application
27
27
 
28
28
  def index
29
29
  indexes = valid_indexes
30
- display(indexes.inject({}) { |r,i| r[i] = absolute_url(:search, i); r })
30
+ display(indexes.inject({}) { |r,i| r[i] = absolute_url(:search_show, i); r })
31
31
  end
32
32
 
33
33
  def valid_indexes
34
34
  indexes = Chef::DataBag.cdb_list(false)
35
- indexes += %w{ role node client }
35
+ indexes += %w{ role node client environment}
36
36
  end
37
37
 
38
38
  def show
39
39
  unless valid_indexes.include?(params[:id])
40
40
  raise NotFound, "I don't know how to search for #{params[:id]} data objects."
41
41
  end
42
-
43
- query = Chef::Solr::Query.new(Chef::Config[:solr_url])
44
- params[:q] ||= "*:*"
45
- params[:sort] ||= nil
46
- params[:start] ||= 0
47
- params[:rows] ||= 20
48
- objects, start, total = query.search(params[:id], params[:q], params[:sort], params[:start], params[:rows])
49
- display({
50
- "rows" => objects,
51
- "start" => start,
52
- "total" => total
53
- })
42
+ params[:type] = params.delete(:id)
43
+ display(Chef::SolrQuery.from_params(params).search)
54
44
  end
55
45
 
56
46
  def reindex
57
- display(Chef::Solr.new.rebuild_index)
47
+ display(Chef::SolrQuery.new.rebuild_index)
58
48
  end
59
49
 
60
50
  end
@@ -0,0 +1,72 @@
1
+ #
2
+ # Author:: Stephen Delano (<stephen@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ module Merb
20
+ module CookbookVersionHelper
21
+
22
+ include Merb::ControllerExceptions
23
+
24
+ # takes a cookbook_name and an array of versions and returns a hash
25
+ # params:
26
+ # - cookbook_name: the name of the cookbook
27
+ # - versions: a sorted list of version strings
28
+ #
29
+ # returns:
30
+ # {
31
+ # :url => http://url,
32
+ # :versions => [
33
+ # { :version => version, :url => http://url/version },
34
+ # { :version => version, :url => http://url/version }
35
+ # ]
36
+ # }
37
+ def expand_cookbook_urls(cookbook_name, versions, num_versions)
38
+ versions = versions[0...num_versions.to_i] unless num_versions == "all"
39
+ version_list = versions.inject([]) do |res, version|
40
+ res.push({
41
+ :url => absolute_url(:cookbook_version, :cookbook_name => cookbook_name, :cookbook_version => version),
42
+ :version => version
43
+ })
44
+ res
45
+ end
46
+ url = absolute_url(:cookbook, :cookbook_name => cookbook_name)
47
+ {:url => url, :versions => version_list}
48
+ end
49
+
50
+ # validate and return the number of versions requested
51
+ # by the user
52
+ #
53
+ # raises an exception if an invalid number is requested
54
+ #
55
+ # params:
56
+ # - default: the number of versions to default to
57
+ #
58
+ # valid num_versions query parameter:
59
+ # - an integer >= 0
60
+ # - the string "all"
61
+ def num_versions!(default="1")
62
+ input = params[:num_versions]
63
+ result = if input
64
+ valid_input = (input == "all" || Integer(input) >= 0) rescue false
65
+ raise BadRequest, "You have requested an invalid number of versions (x >= 0 || 'all')" unless valid_input
66
+ input
67
+ else
68
+ default
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,49 @@
1
+ <?xml version='1.0' encoding='utf-8' ?>
2
+ <!DOCTYPE html>
3
+ <html>
4
+ <head>
5
+ <meta content='text/html; charset=utf-8' http-equiv='content-type' />
6
+ <title>Chef Server</title>
7
+ <link href="/stylesheets/base.css" type="text/css" rel="Stylesheet" charset="utf-8" media="all" />
8
+ <link href="/stylesheets/themes/djime-cerulean/style.css" type="text/css" rel="Stylesheet" charset="utf-8" media="all" />
9
+ <link href="/stylesheets/chef.css" type="text/css" rel="Stylesheet" charset="utf-8" media="all" />
10
+ </head>
11
+ <body>
12
+ <div id='container'>
13
+ <div id='header'>
14
+ <h1><a href="<%= absolute_url(:top) -%>">Chef REST API</a></h1>
15
+ </div>
16
+ <div id='main-navigation'>
17
+ <div class='clear'></div>
18
+ </div>
19
+ <div id='wrapper'>
20
+ <div id='main'>
21
+ <div class='block' id='block-text'>
22
+ <div class='content'>
23
+ <h2 class='title'>The REST API</h2>
24
+ <div class='inner'>
25
+ This is the Chef API Server.
26
+ <% if @webui_url %>
27
+ <a href="<%= @webui_url -%>">Are you looking for the Web UI?</a>
28
+ <% end %>
29
+ </div>
30
+ <div class='inner'>
31
+ For more information about Chef, head on over to the <a href="http://wiki.opscode.com/">wiki.</a>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ <div id='footer'>
36
+ <div class='block'>
37
+ <p>Copyright &copy; 2009-2011 Opscode, Inc.</p>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ <div id='sidebar'>
42
+ <div class='block notice' id='sidebar_block_notice'></div>
43
+ <div class='block' id='sidebar_block'></div>
44
+ </div>
45
+ <div class='clear'></div>
46
+ </div>
47
+ </div>
48
+ </body>
49
+ </html>
File without changes
data/bin/chef-server CHANGED
@@ -25,6 +25,7 @@ require "merb-core"
25
25
 
26
26
  # Load chef and chef-server-api from source rather than gem, if present
27
27
  $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../chef/lib/'))
28
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../chef-solr/lib/'))
28
29
  $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
29
30
 
30
31
  # Print the version if we have -v or --version
data/config/init.rb CHANGED
@@ -38,8 +38,10 @@ require 'chef/data_bag_item'
38
38
  require 'chef/cookbook_version'
39
39
  require 'chef/sandbox'
40
40
  require 'chef/checksum'
41
+ require 'chef/environment'
41
42
  require 'chef/monkey_patches/regexp'
42
43
 
44
+
43
45
  require 'mixlib/authentication'
44
46
 
45
47
  Mixlib::Authentication::Log.logger = Ohai::Log.logger = Chef::Log.logger
@@ -72,6 +74,7 @@ unless Merb::Config.environment == "test"
72
74
  Chef::CookbookVersion.create_design_document
73
75
  Chef::Sandbox.create_design_document
74
76
  Chef::Checksum.create_design_document
77
+ Chef::Environment.create_design_document
75
78
 
76
79
  # Create the signing key and certificate
77
80
  Chef::Certificate.generate_signing_ca
@@ -82,6 +85,9 @@ unless Merb::Config.environment == "test"
82
85
  # Generate the Web UI Key
83
86
  Chef::Certificate.gen_validation_key(Chef::Config[:web_ui_client_name], Chef::Config[:web_ui_key], true)
84
87
 
88
+ # Create the '_default' Environment
89
+ Chef::Environment.create_default_environment
90
+
85
91
  Chef::Log.info('Loading roles')
86
92
  Chef::Role.sync_from_disk_to_couchdb
87
93
  end
data/config/rack.rb CHANGED
@@ -19,5 +19,8 @@
19
19
  # Correctly set a content length.
20
20
  use Rack::ContentLength
21
21
 
22
+ # Serve assets for the html page from /public
23
+ use Merb::Rack::Static, Merb.dir_for(:public)
24
+
22
25
  # this is our main merb application
23
26
  run Merb::Rack::Application.new
data/config/router.rb CHANGED
@@ -27,7 +27,20 @@ Merb::Router.prepare do
27
27
  :method => 'get').
28
28
  to(:controller => "nodes", :action => "cookbooks")
29
29
  # Roles
30
- resources :roles
30
+ resources :roles do |r|
31
+ r.match('/environments', :method => 'get').to(:controller => "roles", :action => "environments")
32
+ r.match('/environments/:env_id', :method => 'get').to(:controller=>"roles", :action=>"environment")
33
+ end
34
+
35
+ # Environments
36
+ resources :environments do |e|
37
+ e.match("/cookbooks", :method => "get").to(:controller=>"environments", :action=>"list_cookbooks")
38
+ e.match("/cookbooks/:cookbook_id", :method => "get").to(:controller=>"environments", :action=>"cookbook")
39
+ e.match("/recipes", :method => "get").to(:controller=>"environments", :action=>"list_recipes")
40
+ e.match("/nodes", :method => "get").to(:controller=>"environments", :action=>"list_nodes")
41
+ e.match("/roles/:role_id", :method => "get").to(:controller=>"environments", :action => "role")
42
+ e.match("/cookbook_versions", :method => "post").to(:controller=>"environments", :action=>"cookbook_versions_for_run_list")
43
+ end
31
44
 
32
45
  # Status
33
46
  match("/status").to(:controller => "status", :action => "index").name(:status)
@@ -40,7 +53,9 @@ Merb::Router.prepare do
40
53
  match("/clients/:id", :id => /[\w\.-]+/, :method=>"delete").to(:controller=>'clients', :action=>'destroy')
41
54
 
42
55
  # Search
43
- resources :search
56
+ #resources :search
57
+ match('/search', :method => 'get').to(:controller => 'search', :action => 'index').name(:search)
58
+ match('/search/:id', :method => 'get').to(:controller => 'search', :action => 'show').name(:search_show)
44
59
  match('/search/reindex', :method => 'post').to(:controller => "search", :action => "reindex")
45
60
 
46
61
  # Cookbooks
@@ -48,9 +63,7 @@ Merb::Router.prepare do
48
63
 
49
64
  match("/cookbooks",
50
65
  :method => 'get'
51
- ).to(:controller => "cookbooks", :action => "index")
52
-
53
- match("/cookbooks/_latest", :method=>'get').to(:controller=>'cookbooks',:action=>'index_latest')
66
+ ).to(:controller => "cookbooks", :action => "index").name(:cookbooks)
54
67
 
55
68
  match("/cookbooks/_recipes", :method=>'get').to(:controller=>'cookbooks',:action=>'index_recipes')
56
69
 
@@ -120,10 +133,10 @@ Merb::Router.prepare do
120
133
  @json_params ||= begin
121
134
  if Merb::Const::JSON_MIME_TYPE_REGEXP.match(content_type)
122
135
  begin
123
- # Call Chef's JSON utility instead of the default in Merb,
136
+ # Call Chef's JSON utility instead of the default in Merb,
124
137
  # JSON.parse.
125
138
  jobj = Chef::JSONCompat.from_json(raw_post)
126
- jobj = jobj.to_mash if jobj.is_a?(Hash)
139
+ jobj = Mash.from_hash(jobj) if jobj.is_a?(Hash)
127
140
  rescue JSON::ParserError
128
141
  jobj = Mash.new
129
142
  end
@@ -1,3 +1,3 @@
1
1
  module ChefServerApi
2
- VERSION = '0.9.18'
2
+ VERSION = '0.10.0.beta.0'
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,83 @@
1
- require 'rubygems'
2
- $:.unshift File.expand_path(File.dirname(__FILE__) + '/../app')
3
- $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
- $:.unshift File.expand_path(File.dirname(__FILE__) + '/../../chef/lib')
1
+ #
2
+ # Author:: Tim Hinderliter (<tim@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require "rubygems"
20
+ require "merb-core"
21
+ require "rspec"
22
+
23
+ Merb.push_path(:spec_helpers, "spec" / "spec_helpers", "**/*.rb")
24
+ Merb.push_path(:spec_fixtures, "spec" / "fixtures", "**/*.rb")
25
+
26
+ Merb.start_environment(:testing => true, :adapter => 'runner', :environment => ENV['MERB_ENV'] || 'test')
27
+
28
+ RSpec.configure do |config|
29
+ config.include(Merb::Test::RouteHelper)
30
+ config.include(Merb::Test::ControllerHelper)
31
+ end
32
+
33
+ def get_json(path, params = {}, env = {}, &block)
34
+ request_json("GET", path, params, env, &block)
35
+ end
36
+
37
+ def post_json(path, post_body, env = {}, &block)
38
+ request_json("POST", path, {}, env) do |controller|
39
+ # Merb FakeRequest allows me no way to pass JSON across the
40
+ # FakeRequest/StringIO boundary, so we hack it here.
41
+ if post_body.is_a?(Hash)
42
+ controller.params.merge!(post_body)
43
+ else
44
+ controller.params['inflated_object'] = post_body
45
+ end
46
+ block.call if block
47
+ end
48
+ end
49
+
50
+ # Make an HTTP call of <method>, assign the accept header to
51
+ # application/json, and return the JSON-parsed output.
52
+ #
53
+ # Side effects:
54
+ # Raw textual output available in @response_raw
55
+ # Controller used available in @controller
56
+ def request_json(method, path, params, env, &block)
57
+ @controller = mock_request(path, params, env.merge({'HTTP_ACCEPT' => "application/json", :request_method => method})) do |controller|
58
+ stub_authentication(controller)
59
+ block.call(controller) if block
60
+ end
61
+
62
+ @response_raw = @controller.body
63
+ @response_json = Chef::JSONCompat.from_json(@response_raw)
64
+ end
65
+
66
+ def stub_authentication(controller)
67
+ username = "tester"
68
+
69
+ user = Chef::ApiClient.new
70
+ user.name(username)
71
+ user.admin(true)
72
+
73
+ # authenticate_every has a side-effect of setting @auth_user
74
+ controller.stub!(:authenticate_every).and_return(true)
75
+ controller.instance_variable_set(:@auth_user, user)
76
+ end
77
+
78
+ def root_url
79
+ # include organization name to run these tests in the platform
80
+ "http://localhost"
81
+ end
82
+
5
83
 
6
- require 'chef'
@@ -0,0 +1,67 @@
1
+ #
2
+ # Author:: Tim Hinderliter (<tim@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ # Set of methods to create model objects for spec tests.
20
+ # None of these methods save or otherwise commit the objects they
21
+ # create; they simply initialize the respective model object and
22
+ # set its name (and other important attributes, where appropriate).
23
+
24
+ def make_node(name)
25
+ res = Chef::Node.new
26
+ res.name(name)
27
+ res
28
+ end
29
+
30
+ def make_role(name)
31
+ res = Chef::Role.new
32
+ res.name(name)
33
+ res
34
+ end
35
+
36
+ def make_environment(name)
37
+ res = Chef::Environment.new
38
+ res.name(name)
39
+ res
40
+ end
41
+
42
+ def make_cookbook(name, version)
43
+ res = Chef::CookbookVersion.new(name)
44
+ res.version = version
45
+ res
46
+ end
47
+
48
+ def make_runlist(*items)
49
+ res = Chef::RunList.new
50
+ items.each do |item|
51
+ res << item
52
+ end
53
+ res
54
+ end
55
+
56
+ # Take an Array of cookbook_versions,
57
+ # And return a hash like:
58
+ # {
59
+ # "cookbook_name" => [CookbookVersion, CookbookVersion],
60
+ # }
61
+ def make_filtered_cookbook_hash(*array_cookbook_versions)
62
+ array_cookbook_versions.inject({}) do |res, cookbook_version|
63
+ res[cookbook_version.name] ||= Array.new
64
+ res[cookbook_version.name] << cookbook_version
65
+ res
66
+ end
67
+ end