# Chef Server WebUI
WebUI的組織結構和Rails基礎講的類似。 唯一的區別就是:
Chef Server WebUI 沒有直接操作數據庫,所以config下面沒有相關數據庫配置。
因為都是通過erchef提供的 restful api來和數據庫通信。
### node示例
拿我們在第二章應用中創建的node2來示例。 打開chef server webui: [http://local.chef.com](http://local.chef.com) (這是我本地/etc/hosts里設置的測試域名)

在登陸之后,我們點擊nodes。默認的日志在「/var/log/chef-server/chef-server-webui/current」目錄下面:
~~~
$ sudo tail -f /var/log/chef-server/chef-server-webui/current
~~~
你可以觀察日志,當導航欄nodes被點擊的時候:
~~~
Started GET "/nodes" for 127.0.0.1
...
...
~~~
日志中我們看到,是對/nodes發起了GET請求, 這個/nodes是啥呢? 我們之前Rails基礎里講過了, 這個是resources,我們去controller里面去找,根據Rails基礎中提過的約定大于配置,就應該是在app/controllers/nodes_controller.rb中定義的。
~~~
require 'chef/node'
class NodesController < ApplicationController
respond_to :html
before_filter :require_login
before_filter :require_admin, :only => [:destroy]
def index
node_hash = if session[:environment]
client_with_actor.get("environments/#{session[:environment]}/nodes")
else
client_with_actor.get("nodes")
end
@node_list = node_hash.keys.sort
rescue => e
log_and_flash_exception(e, "Could not list nodes")
@node_list = {}
end
# ...
end
~~~
我們只摘出了nodes controller的部分代碼, index action,就是GET /nodes所響應的那個action方法。可以通過config/routes.rb文件得到印證:
~~~
ChefServerWebui::Application.routes.draw do
resources :nodes, :id => /[^\/]+/
# ...
end
~~~
可以回頭參考我們講的Rails基礎,就知道當我們GET /nodes的時候,就是響應index action。這就是restful。
回到我們的index action中:
這個action,要獲取注冊到這個chef server的所有nodes信息。這里最關鍵的方法是這個:
~~~
client_with_actor.get
~~~
而client_with_actor這是一個方法,被定義在lib / chef_server_webui / api_client_helper.rb文件中:
~~~
require 'chef_server/rest_client'
module ChefServerWebui
module ApiClientHelper
#
# We customize the behavior of Chef::REST in two important ways:
#
# 1. Set the 'x-ops-request-source' request header so all requests are
# authenticated as the webui user.
# 2. Set the client_name of *some* requests to that of the logged-in user
# so these requests are effectively authorized as said user.
#
DEFAULT_REQUEST_HEADERS = {
:headers => ChefServerWebui::Application.config.rest_client_custom_http_headers.merge({'x-ops-request-source' => 'web'})
}.freeze
# Returns an instance of ChefServer::RestClient with the 'actor' set to the
# webui client.
def client
client_with_actor(ChefServerWebui::Application.config.chef_server_url,
ChefServerWebui::Application.config.rest_client_name,
ChefServerWebui::Application.config.rest_client_key)
end
# Returns an instance of ChefServer::RestClient with the 'actor' set to the
# current logged in user. The current user is set in
# Thread.current[:current_user_id] by the Rails appliction using an
# around_filter
def client_with_actor(url=Rails.configuration.chef_server_url,
actor=Thread.current[:current_user_id],
signing_key_filename=ChefServerWebui::Application.config.rest_client_key)
ChefServer::RestClient.new(url, actor, signing_key_filename, DEFAULT_REQUEST_HEADERS)
end
end
end
~~~
這個文件代碼很短,我就復制了全部在這里,我們可以看出來, 這個helper方法,是用于跟erchef核心api來交互的。client_with_actor方法最終返回的是一個ChefServer::RestClient對象。
我們再去看看這個ChefServer::RestClient類,在lib / chef_server / rest_client.rb里面被定義:
~~~
require 'chef/log'
require 'chef/rest'
require 'chef/run_list'
require 'forwardable'
module ChefServer
class RestClient
extend Forwardable
attr_reader :rest_client
def_delegator :@rest_client, :get_rest
def_delegator :@rest_client, :post_rest
def_delegator :@rest_client, :put_rest
def_delegator :@rest_client, :delete_rest
def_delegator :@rest_client, :fetch
def initialize(chef_server_url,
client_name,
signing_key_filename,
options={})
@rest_client = Chef::REST.new(chef_server_url,
client_name,
signing_key_filename,
options)
end
[:get, :post, :put, :delete].each do |method|
define_method method do |*args|
begin
@rest_client.send("#{method}_rest".to_sym, *args)
rescue => e
Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}")
raise e
end
end
end
end
end
~~~
可以看得出來:
client_with_actor.get方法,實際就是ChefServer::RestClient.get, 而ChefServer::RestClient.get,實際是調用了Chef::REST.get,也就是我們前面所講的chef gem里的chef/rest.rb里定義的方法。
### 小結
client_with_actor和erchef api交互,來獲取nodes的相關信息。
這里只是用nodes作為示例,實際上webui中其他導航欄的信息,道理都是一樣的,大家可以自己思考。
而重點在于erchef的核心api。
- 序
- Chapter 1: 初識Chef
- 一些背景
- Chef vs Puppet
- Chapter 2: Chef應用
- Chef架構
- Chef能做什么
- Chef組件
- Chef環境安裝
- chef-server
- opscode-chef
- chef-solo
- Chef實戰
- 實戰前的必修理論
- 使用Chef
- Chapter 3: Ruby基礎
- 對象與方法
- 標識符
- 類與模塊
- 數據類型
- 真與假
- 控制語句
- 代碼塊
- Chapter 4: Chef源碼架構
- Rubygems與gem
- bundler
- Chef源碼組織
- Chapter 5: Rails基礎
- Rails是什么
- MVC架構
- Restful
- Rails組成與項目結構
- Chapter 6: Chef Server WebUI
- Chef Server Webui組織結構
- Chef Rest API
- 參考