# 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里设置的测试域名)
![webui-demo-node](https://box.kancloud.cn/2015-08-23_55d9d7aede8ee.png)
在登陆之后,我们点击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
- 参考