chef-server-webui 0.8.16 → 0.9.0.a3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/Rakefile +14 -10
  2. data/app/controllers/application.rb +111 -128
  3. data/app/controllers/clients.rb +10 -10
  4. data/app/controllers/cookbook_attributes.rb +1 -1
  5. data/app/controllers/cookbook_definitions.rb +1 -1
  6. data/app/controllers/cookbook_files.rb +1 -1
  7. data/app/controllers/cookbook_libraries.rb +1 -1
  8. data/app/controllers/cookbook_recipes.rb +1 -1
  9. data/app/controllers/cookbook_templates.rb +1 -1
  10. data/app/controllers/cookbooks.rb +21 -3
  11. data/app/controllers/databag_items.rb +6 -6
  12. data/app/controllers/databags.rb +3 -3
  13. data/app/controllers/main.rb +1 -1
  14. data/app/controllers/nodes.rb +21 -21
  15. data/app/controllers/openid_consumer.rb +9 -9
  16. data/app/controllers/roles.rb +3 -3
  17. data/app/controllers/search.rb +1 -1
  18. data/app/controllers/search_entries.rb +1 -1
  19. data/app/controllers/status.rb +1 -1
  20. data/app/controllers/users.rb +7 -7
  21. data/app/helpers/application_helper.rb +1 -156
  22. data/app/helpers/global_helpers.rb +20 -16
  23. data/app/helpers/nodes_helper.rb +24 -22
  24. data/app/helpers/openid_server_helpers.rb +13 -10
  25. data/app/helpers/search_helper.rb +44 -38
  26. data/app/helpers/status_helper.rb +10 -3
  27. data/app/views/clients/_navigation.html.haml +5 -5
  28. data/app/views/clients/edit.html.haml +1 -1
  29. data/app/views/clients/index.html.haml +4 -4
  30. data/app/views/clients/new.html.haml +1 -1
  31. data/app/views/cookbooks/index.html.haml +1 -1
  32. data/app/views/cookbooks/show.html.haml +25 -16
  33. data/app/views/databag_items/_form.html.haml +1 -1
  34. data/app/views/databag_items/_navigation.html.haml +5 -5
  35. data/app/views/databag_items/edit.html.haml +1 -1
  36. data/app/views/databag_items/new.html.haml +1 -1
  37. data/app/views/databags/_item_navigation.html.haml +4 -4
  38. data/app/views/databags/_navigation.html.haml +5 -5
  39. data/app/views/databags/edit.html.haml +1 -1
  40. data/app/views/databags/index.html.haml +3 -3
  41. data/app/views/databags/new.html.haml +1 -1
  42. data/app/views/databags/show.html.haml +3 -3
  43. data/app/views/layout/{chef_server_webui.html.haml → application.html.haml} +11 -11
  44. data/app/views/layout/login.html.haml +1 -1
  45. data/app/views/nodes/_form.html.haml +1 -1
  46. data/app/views/nodes/_navigation.html.haml +5 -5
  47. data/app/views/nodes/edit.html.haml +1 -1
  48. data/app/views/nodes/index.html.haml +6 -6
  49. data/app/views/nodes/new.html.haml +1 -1
  50. data/app/views/nodes/show.html.haml +4 -5
  51. data/app/views/openid_consumer/index.html.haml +2 -2
  52. data/app/views/openid_register/index.html.haml +4 -4
  53. data/app/views/openid_register/show.html.haml +1 -1
  54. data/app/views/roles/_form.html.haml +1 -1
  55. data/app/views/roles/_navigation.html.haml +5 -5
  56. data/app/views/roles/edit.html.haml +1 -1
  57. data/app/views/roles/index.html.haml +4 -4
  58. data/app/views/roles/new.html.haml +1 -1
  59. data/app/views/roles/show.html.haml +3 -4
  60. data/app/views/search/_search_form.html.haml +1 -1
  61. data/app/views/search/index.html.haml +1 -1
  62. data/app/views/search/show.html.haml +1 -1
  63. data/app/views/status/index.html.haml +9 -12
  64. data/app/views/users/_form.html.haml +1 -1
  65. data/app/views/users/_navigation.html.haml +5 -5
  66. data/app/views/users/edit.html.haml +1 -1
  67. data/app/views/users/index.html.haml +3 -3
  68. data/app/views/users/login.html.haml +1 -1
  69. data/app/views/users/new.html.haml +1 -1
  70. data/bin/chef-server-webui +72 -0
  71. data/config.ru +10 -74
  72. data/config/init.rb +30 -11
  73. data/config/rack.rb +5 -0
  74. data/config/router.rb +62 -5
  75. data/lib/chef-server-webui.rb +2 -155
  76. data/lib/chef-server-webui/version.rb +3 -0
  77. data/public/javascripts/drop_down_menu.js +22 -0
  78. metadata +60 -48
  79. data/stubs/app/controllers/application.rb +0 -2
  80. data/stubs/app/controllers/main.rb +0 -2
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ require File.dirname(__FILE__) + '/lib/chef-server-webui/version'
2
+
1
3
  require 'rubygems'
2
4
  require 'rake/gempackagetask'
3
5
 
@@ -5,7 +7,6 @@ require 'merb-core'
5
7
  require 'merb-core/tasks/merb'
6
8
 
7
9
  GEM_NAME = "chef-server-webui"
8
- CHEF_SERVER_VERSION="0.8.16"
9
10
  AUTHOR = "Opscode"
10
11
  EMAIL = "chef@opscode.com"
11
12
  HOMEPAGE = "http://wiki.opscode.com/display/chef"
@@ -13,7 +14,7 @@ SUMMARY = "A systems integration framework, built to bring the benefits of confi
13
14
 
14
15
  spec = Gem::Specification.new do |s|
15
16
  s.name = GEM_NAME
16
- s.version = CHEF_SERVER_VERSION
17
+ s.version = ChefServerWebui::VERSION
17
18
  s.platform = Gem::Platform::RUBY
18
19
  s.has_rdoc = true
19
20
  s.extra_rdoc_files = ["README.rdoc", "LICENSE" ]
@@ -23,17 +24,20 @@ spec = Gem::Specification.new do |s|
23
24
  s.email = EMAIL
24
25
  s.homepage = HOMEPAGE
25
26
 
26
- s.add_dependency "merb-core", "~> 1.0.0"
27
- s.add_dependency "merb-slices", "~> 1.0.0"
28
- s.add_dependency "merb-assets", "~> 1.0.0"
29
- s.add_dependency "merb-helpers", "~> 1.0.0"
30
- s.add_dependency "merb-haml", "~> 1.0.0"
31
- s.add_dependency "merb-param-protection", "~> 1.0.0"
27
+ s.add_dependency "merb-core", "~> 1.0"
28
+ s.add_dependency "merb-slices", "~> 1.0"
29
+ s.add_dependency "merb-assets", "~> 1.0"
30
+ s.add_dependency "merb-helpers", "~> 1.0"
31
+ s.add_dependency "merb-haml", "~> 1.0"
32
+ s.add_dependency "merb-param-protection", "~> 1.0"
32
33
 
33
34
  s.add_dependency "json", "<= 1.4.2"
34
35
 
35
36
  %w{thin haml ruby-openid coderay}.each { |g| s.add_dependency g}
36
37
 
38
+ s.bindir = "bin"
39
+ s.executables = %w( chef-server-webui )
40
+
37
41
  s.require_path = 'lib'
38
42
  s.files = %w(LICENSE README.rdoc Rakefile config.ru) + Dir.glob("{bin,config,lib,spec,app,public,stubs}/**/*")
39
43
  end
@@ -44,12 +48,12 @@ end
44
48
 
45
49
  desc "Install the gem"
46
50
  task :install => :package do
47
- sh %{gem install pkg/#{GEM_NAME}-#{CHEF_SERVER_VERSION} --no-rdoc --no-ri}
51
+ sh %{gem install pkg/#{GEM_NAME}-#{ChefServerWebui::VERSION} --no-rdoc --no-ri}
48
52
  end
49
53
 
50
54
  desc "Uninstall the gem"
51
55
  task :uninstall do
52
- sh %{gem uninstall #{GEM_NAME} -x -v #{CHEF_SERVER_VERSION} }
56
+ sh %{gem uninstall #{GEM_NAME} -x -v #{ChefServerWebui::VERSION} }
53
57
  end
54
58
 
55
59
  desc "Create a gemspec file"
@@ -8,9 +8,9 @@
8
8
  # Licensed under the Apache License, Version 2.0 (the "License");
9
9
  # you may not use this file except in compliance with the License.
10
10
  # You may obtain a copy of the License at
11
- #
11
+ #
12
12
  # http://www.apache.org/licenses/LICENSE-2.0
13
- #
13
+ #
14
14
  # Unless required by applicable law or agreed to in writing, software
15
15
  # distributed under the License is distributed on an "AS IS" BASIS,
16
16
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,67 +21,42 @@
21
21
  require "chef" / "mixin" / "checksum"
22
22
  require "chef" / "cookbook_loader"
23
23
 
24
- class ChefServerWebui::Application < Merb::Controller
24
+ class Application < Merb::Controller
25
25
 
26
26
  include Chef::Mixin::Checksum
27
27
 
28
- controller_for_slice
29
-
30
- # Generate the absolute url for a slice - takes the slice's :path_prefix into account.
31
- #
32
- # @param slice_name<Symbol>
33
- # The name of the slice - in identifier_sym format (underscored).
34
- # @param *args<Array[Symbol,Hash]>
35
- # There are several possibilities regarding arguments:
36
- # - when passing a Hash only, the :default route of the current
37
- # slice will be used
38
- # - when a Symbol is passed, it's used as the route name
39
- # - a Hash with additional params can optionally be passed
40
- #
41
- # @return <String> A uri based on the requested slice.
42
- #
43
- # @example absolute_slice_url(:awesome, :format => 'html')
44
- # @example absolute_slice_url(:forum, :posts, :format => 'xml')
45
- def absolute_slice_url(slice_name, *args)
46
- options = extract_options_from_args!(args) || {}
47
- protocol = options.delete(:protocol) || request.protocol
48
- host = options.delete(:host) || request.host
49
-
50
- protocol + "://" + host + slice_url(slice_name,*args)
51
- end
52
-
53
28
  # Check if the user is logged in and if the user still exists
54
29
  def login_required
55
30
  if session[:user]
56
31
  begin
57
32
  Chef::WebUIUser.load(session[:user]) rescue (raise NotFound, "Cannot find User #{session[:user]}, maybe it got deleted by an Administrator.")
58
- rescue
33
+ rescue
59
34
  logout_and_redirect_to_login
60
- else
35
+ else
61
36
  return session[:user]
62
- end
63
- else
37
+ end
38
+ else
64
39
  self.store_location
65
40
  throw(:halt, :access_denied)
66
41
  end
67
42
  end
68
-
43
+
69
44
  def cleanup_session
70
45
  [:user,:level].each { |n| session.delete(n) }
71
- end
72
-
46
+ end
47
+
73
48
  def logout_and_redirect_to_login
74
49
  cleanup_session
75
50
  @user = Chef::WebUIUser.new
76
- redirect(slice_url(:users_login), {:message => { :error => $! }, :permanent => true})
77
- end
78
-
79
-
51
+ redirect(url(:users_login), {:message => { :error => $! }, :permanent => true})
52
+ end
53
+
54
+
80
55
  def is_admin(name)
81
56
  user = Chef::WebUIUser.load(name)
82
57
  return user.admin
83
58
  end
84
-
59
+
85
60
  #return true if there is only one admin left, false otehrwise
86
61
  def is_last_admin
87
62
  count = 0
@@ -95,32 +70,12 @@ class ChefServerWebui::Application < Merb::Controller
95
70
  end
96
71
  true
97
72
  end
98
-
73
+
99
74
  #whether or not the user should be able to edit a user's admin status
100
75
  def edit_admin
101
76
  is_admin(params[:user_id]) ? (!is_last_admin) : true
102
- end
103
-
104
- def authorized_node
105
- # if session[:level] == :admin
106
- # Chef::Log.debug("Authorized as Administrator")
107
- # true
108
- # elsif session[:level] == :node
109
- # Chef::Log.debug("Authorized as node")
110
- # if session[:node_name] == params[:id].gsub(/\./, '_')
111
- # true
112
- # else
113
- # raise(
114
- # Unauthorized,
115
- # "You are not the correct node for this action: #{session[:node_name]} instead of #{params[:id]}"
116
- # )
117
- # end
118
- # else
119
- # Chef::Log.debug("Unauthorized")
120
- # raise Unauthorized, "You are not allowed to take this action."
121
- # end
122
77
  end
123
-
78
+
124
79
  def authorized_user
125
80
  if session[:level] == :admin
126
81
  Chef::Log.debug("Authorized as Administrator")
@@ -128,9 +83,9 @@ class ChefServerWebui::Application < Merb::Controller
128
83
  else
129
84
  Chef::Log.debug("Unauthorized")
130
85
  raise Unauthorized, "The current user is not an Administrator, you can only Show and Edit the user itself. To control other users, login as an Administrator."
131
- end
132
- end
133
-
86
+ end
87
+ end
88
+
134
89
  # Store the URI of the current request in the session.
135
90
  #
136
91
  # We can return to this location by calling #redirect_back_or_default.
@@ -145,18 +100,18 @@ class ChefServerWebui::Application < Merb::Controller
145
100
  session[:return_to] = nil
146
101
  redirect loc
147
102
  end
148
-
103
+
149
104
  def access_denied
150
105
  case content_type
151
106
  when :html
152
107
  store_location
153
- redirect slice_url(:users_login), :message => { :error => "You don't have access to that, please login."}
108
+ redirect url(:users_login), :message => { :error => "You don't have access to that, please login."}
154
109
  else
155
110
  raise Unauthorized, "You must authenticate first!"
156
111
  end
157
112
  end
158
-
159
- # Load a cookbook and return a hash with a list of all the files of a
113
+
114
+ # Load a cookbook and return a hash with a list of all the files of a
160
115
  # given segment (attributes, recipes, definitions, libraries)
161
116
  #
162
117
  # === Parameters
@@ -166,14 +121,14 @@ class ChefServerWebui::Application < Merb::Controller
166
121
  # === Returns
167
122
  # <Hash>:: A hash consisting of the short name of the file in :name, and the full path
168
123
  # to the file in :file.
169
- def load_cookbook_segment(cookbook_id, segment)
124
+ def load_cookbook_segment(cookbook_id, segment)
170
125
  r = Chef::REST.new(Chef::Config[:chef_server_url])
171
126
  cookbook = r.get_rest("cookbooks/#{cookbook_id}")
172
127
 
173
128
  raise NotFound unless cookbook
174
-
129
+
175
130
  files_list = segment_files(segment, cookbook)
176
-
131
+
177
132
  files = Hash.new
178
133
  files_list.each do |f|
179
134
  files[f['name']] = {
@@ -183,7 +138,7 @@ class ChefServerWebui::Application < Merb::Controller
183
138
  end
184
139
  files
185
140
  end
186
-
141
+
187
142
  def segment_files(segment, cookbook)
188
143
  files_list = nil
189
144
  case segment
@@ -201,59 +156,87 @@ class ChefServerWebui::Application < Merb::Controller
201
156
  files_list
202
157
  end
203
158
 
204
- #
205
- # The following should no longer be necessary for the re-factored cookbooks replated webui controllers (which talks to the API)
206
- # But I want to wait until further verified before removing the code. [nuo]
207
- #
208
- # def specific_cookbooks(node_name, cl)
209
- # valid_cookbooks = Hash.new
210
- # begin
211
- # node = Chef::Node.load(node_name)
212
- # recipes, default_attrs, override_attrs = node.run_list.expand
213
- # rescue Net::HTTPServerException
214
- # recipes = []
215
- # end
216
- # recipes.each do |recipe|
217
- # valid_cookbooks = expand_cookbook_deps(valid_cookbooks, cl, recipe)
218
- # end
219
- # valid_cookbooks
220
- # end
221
- #
222
- # def expand_cookbook_deps(valid_cookbooks, cl, recipe)
223
- # cookbook = recipe
224
- # if recipe =~ /^(.+)::/
225
- # cookbook = $1
226
- # end
227
- # Chef::Log.debug("Node requires #{cookbook}")
228
- # valid_cookbooks[cookbook] = true
229
- # cl.metadata[cookbook.to_sym].dependencies.each do |dep, versions|
230
- # expand_cookbook_deps(valid_cookbooks, cl, dep) unless valid_cookbooks[dep]
231
- # end
232
- # valid_cookbooks
233
- # end
234
- #
235
- # def load_all_files(segment, node_name=nil)
236
- # r = Chef::REST.new(Chef::Config[:chef_server_url])
237
- # cookbooks = r.get_rest("cookbooks")
238
- #
239
- # files = Array.new
240
- # valid_cookbooks = node_name ? specific_cookbooks(node_name, cookbooks) : {}
241
- # cl.each do |cookbook|
242
- # if node_name
243
- # next unless valid_cookbooks[cookbook.name.to_s]
244
- # end
245
- # segment_files(segment, cookbook).each do |sf|
246
- # mo = sf.match("cookbooks/#{cookbook.name}/#{segment}/(.+)")
247
- # file_name = mo[1]
248
- # files << {
249
- # :cookbook => cookbook.name,
250
- # :name => file_name,
251
- # :checksum => checksum(sf)
252
- # }
253
- # end
254
- # end
255
- # files
256
- # end
159
+ def build_tree(name, node)
160
+ html = "<table id='#{name}' class='tree table'>"
161
+ html << "<tr><th class='first'>Attribute</th><th class='last'>Value</th></tr>"
162
+ count = 0
163
+ parent = 0
164
+ append_tree(name, html, node, count, parent)
165
+ html << "</table>"
166
+ html
167
+ end
168
+
169
+ def append_tree(name, html, node, count, parent)
170
+ to_do = node
171
+ #to_do = node.kind_of?(Chef::Node) ? node.attribute : node
172
+ Chef::Log.error("I have #{to_do.inspect}")
173
+ to_do.sort{ |a,b| a[0] <=> b[0] }.each do |key, value|
174
+ Chef::Log.error("I am #{key.inspect} #{value.inspect}")
175
+ to_send = Array.new
176
+ count += 1
177
+ is_parent = false
178
+ local_html = ""
179
+ local_html << "<tr id='#{name}-#{count}' class='collapsed #{name}"
180
+ if parent != 0
181
+ local_html << " child-of-#{name}-#{parent}' style='display: none;'>"
182
+ else
183
+ local_html << "'>"
184
+ end
185
+ local_html << "<td class='table-key'><span toggle='#{name}-#{count}'/>#{key}</td>"
186
+ case value
187
+ when Hash
188
+ is_parent = true
189
+ local_html << "<td></td>"
190
+ p = count
191
+ to_send << Proc.new { append_tree(name, html, value, count, p) }
192
+ when Array
193
+ is_parent = true
194
+ local_html << "<td></td>"
195
+ as_hash = {}
196
+ value.each_index { |i| as_hash[i] = value[i] }
197
+ p = count
198
+ to_send << Proc.new { append_tree(name, html, as_hash, count, p) }
199
+ else
200
+ local_html << "<td><div class='json-attr'>#{value}</div></td>"
201
+ end
202
+ local_html << "</tr>"
203
+ local_html.sub!(/class='collapsed/, 'class=\'collapsed parent') if is_parent
204
+ local_html.sub!(/<span/, "<span class='expander'") if is_parent
205
+ html << local_html
206
+ to_send.each { |s| count = s.call }
207
+ count += to_send.length
208
+ end
209
+ count
210
+ end
211
+
212
+ def syntax_highlight(code)
213
+ tokens = File.exists?(code) ? CodeRay.scan_file(code, :ruby) : CodeRay.scan(code, :ruby)
214
+ CodeRay.encode_tokens(tokens, :span)
215
+ end
216
+
217
+ def get_file(uri)
218
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
219
+ content = r.get_rest(uri)
220
+ a = Tempfile.new("cookbook_temp_file")
221
+ File.open(a.path, 'w'){|f| f.write(content)}
222
+ path = a.path
223
+ a.close
224
+ path
225
+ end
226
+
227
+ def str_to_bool(str)
228
+ str =~ /true/ ? true : false
229
+ end
230
+
231
+ #for showing search result
232
+ def determine_name(type, object)
233
+ case type
234
+ when :node, :role, :client
235
+ object.name
236
+ else
237
+ params[:id]
238
+ end
239
+ end
257
240
 
258
241
  def get_available_recipes
259
242
  r = Chef::REST.new(Chef::Config[:chef_server_url])
@@ -264,7 +247,7 @@ class ChefServerWebui::Application < Merb::Controller
264
247
  cb["recipes"].each do |recipe|
265
248
  recipe["name"] =~ /(.+)\.rb/
266
249
  r_name = $1;
267
- if r_name == "default"
250
+ if r_name == "default"
268
251
  result << key
269
252
  else
270
253
  result << "#{key}::#{r_name}"
@@ -273,7 +256,7 @@ class ChefServerWebui::Application < Merb::Controller
273
256
  end
274
257
  result
275
258
  end
276
-
259
+
277
260
  def convert_newline_to_br(string)
278
261
  string.to_s.gsub(/\n/, '<br />') unless string.nil?
279
262
  end
@@ -18,21 +18,21 @@
18
18
 
19
19
  require 'chef/api_client'
20
20
 
21
- class ChefServerWebui::Clients < ChefServerWebui::Application
21
+ class Clients < Application
22
22
  provides :json
23
23
  provides :html
24
24
  before :login_required
25
25
 
26
26
  # GET /clients
27
27
  def index
28
- @clients_list = begin
29
- Chef::ApiClient.list()
30
- rescue => e
31
- Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}")
32
- @_message = {:error => "Could not list clients"}
33
- {}
34
- end
35
- render
28
+ begin
29
+ @clients_list = Chef::ApiClient.list().keys.sort
30
+ rescue => e
31
+ Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}")
32
+ @_message = {:error => "Could not list clients"}
33
+ @clients_list = []
34
+ end
35
+ render
36
36
  end
37
37
 
38
38
  # GET /clients/:id
@@ -107,7 +107,7 @@ class ChefServerWebui::Clients < ChefServerWebui::Application
107
107
  begin
108
108
  @client = Chef::ApiClient.load(params[:id])
109
109
  @client.destroy
110
- redirect(absolute_slice_url(:clients), {:message => { :notice => "Client #{params[:id]} deleted successfully" }, :permanent => true})
110
+ redirect(absolute_url(:clients), {:message => { :notice => "Client #{params[:id]} deleted successfully" }, :permanent => true})
111
111
  rescue => e
112
112
  Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}")
113
113
  @_message = {:error => "Could not delete client #{params[:id]}" }
@@ -19,7 +19,7 @@
19
19
 
20
20
  require 'chef' / 'mixin' / 'checksum'
21
21
 
22
- class ChefServerWebui::CookbookAttributes < ChefServerWebui::Application
22
+ class CookbookAttributes < Application
23
23
 
24
24
  provides :html
25
25