企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 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。