Custom Source能夠理解爲自定義的資源類型,必須使用ruby語言進行書寫,Custom Source主要包含兩個模塊:type和provider。
type和provider是須要配合使用的,type定義了能作什麼,provider定義了怎麼作,type和provider是相互依賴的關係。html
注:學習開發type和provider最好的方法是閱讀現有的type和provider,最好是puppet核心代碼塊。
假如你是初次接觸type和provider的開發,建議閱讀和參考Package和User資源,而不要使用File資源。正則表達式
閱讀本文以前你應該掌握的基本技能:shell
當建立一個type資源時候,應該關注於這個資源能作什麼,而不是如何去作ruby
一般建立type是經過調用Puppet::Type的newtype方法,示例以下:markdown
# lib/puppet/type/database.rb Puppet::Type.newtype(:database) do @doc = "Create a new database." # ... the code ... end
或者開頭使用module Puppetapp
# lib/puppet/type/package.rb module Puppet Type.newtype(:package) do @doc = "Manage a Package." # ... the code ... end
notice: 當建立type時,能夠在名字後面指定參數,而且只有一個參數是可用的:
:self_refresh => true --- 會形成這個資源類型的刷新(相似於這個資源類型經過nogify/subscribe等關聯資源方法收到了刷新的指令),這個最經常使用的是用在mount類型上less
在代碼塊裏建立property和provider以前,一般會對這個資源類型有一個說明,經過@doc方法。字符串使用markdown格式,示例以下:運維
Puppet::Type.newtype(:database) do @doc = %q{Creates a new database. Depending on the provider, this may create relational databases or NoSQL document stores. Example: database {'mydatabase': ensure => present, owner => root } } end
前面咱們說道一個新的type名稱後面是代碼塊,一個代碼塊裏的主要內容就是properties和parameters,它們都能生成資源的屬性。ide
Properties和Parameters又是怎樣的區別呢?它們的區別很微妙並且很重要學習
那麼property是怎麼工做的呢?
假如你定義了一個owner的property,首先property會調用provider的方法去檢測並獲取當前owner的狀態,噹噹前資源狀態與咱們設置的不一致時,property或調用相似於owner=methon的方法將資源狀態改變爲咱們所指望的。
一般咱們定義property是經過"def xxx { ... }"方式定義的,可是有一個特殊的property,由於是比較經常使用的,因此有了簡化的寫法,那就是ensure property。它能夠簡單定義爲ensurable,示例以下:
Puppet::Type.newtype(:database) do ensurable ... end
這個property會調用provider的三個方法:create, destroy, and exists? . 顧名思義,create就是建立(更改)當前的資源狀態,destory就是刪除當前資源,exists?是檢測當前資源是否存在。若是ensure屬性定義爲「不要求同步」,那麼其餘的properties將都不會執行。
其餘property定義方式採用「newproperty(:xxx)do ... end」的形式,示例以下:
Puppet::Type.newtype(:database) do ensurable newproperty(:owner) do desc "The owner of the database." ... end end
其中desc是描述這個property的做用,相似於type類型的@doc方法。
puppet最開始發展時候,properties裏面會有不少代碼,然而通過優化與規範,properties裏面只須要定義可用的參數或者設置validation和munging(後面的parameters講解會說到這兩個方法),若是你定義了一些參數,那麼puppet只會接受這些你定義的參數。一般來說,只須要定義容許的參數,可是這些參數對其餘的property也是生效的。
newproperty(:enable) do newvalue(:true) newvalue(:false) end
validate方法能夠對property設置的參數進行處理,例如,當須要參數是字符串時,能夠這樣寫:
newproperty(:owner) do validate do |value| unless value =~ /^\w+/ raise ArgumentError, "%s is not a valid user name" % value end end end
puppet根據property定義順序執行,因此對一個目標系統資源進行檢查和修復的順序也是根據咱們定義property的順序執行的。
日誌輸出是必不可少的,經過puppet日誌你能夠看到目標系統資源都進行了怎樣的變化,經過以下三個方法能夠實現日誌輸出功能:
示例:
def should_to_s(newvalue) if provider.respond_to?(:package_settings_should_to_s) provider.package_settings_should_to_s(should, newvalue) else super(newvalue) end end def is_to_s(currentvalue) if provider.respond_to?(:package_settings_is_to_s) provider.package_settings_is_to_s(should, currentvalue) else super(currentvalue) end end def change_to_s(currentvalue, newvalue) if provider.respond_to?(:package_settings_change_to_s) provider.package_settings_change_to_s(currentvalue, newvalue) else super(currentvalue,newvalue) end end
當建立一個資源時候,咱們指定的參數會被存儲在每個property的@should方法中,咱們能夠在資源中使用以下方式去調用這些參數:
myval = should(:color)
固然有時候也會調用parameters裏的參數,parameters裏的參數不能使用should方法了,而應該使用value方法。因此當你不肯定你調用的參數是properties裏的仍是parameters裏的時候,使用value方法確定是沒錯的:
myvalue = value(:color)
parameters方法的使用和property大致上是相同的,惟一的不一樣是parameters不會調用providers的方法。
定義一個新的parameter使用newparam方法,後面的語法和property方法同樣。示例以下:
newparam(:name) do desc "The name of the database." end
每一個type都應該有至少一個必有的parameter:namevar。這個parameter是該資源的惟一標識,例如:磁盤上的路徑,用戶名稱,包的名稱等等。
若是聲明的資源裏不指定namevar方法,那麼這個資源的title將會是namevar的默認值。
有三個方法聲明namevar:
newparam(:name) do desc "The name of the database." end
newparam(:path, :namevar => true) do ... end
newparam(:path) do isnamevar ... end
當沒有namevar的定義時候會報錯,puppet2.7和puppet3的報錯信息以下:
puppet 2.7:
$ puppet apply -e "testing { h: }" Error: undefined method `merge' for []:Array
Puppet 3:
$ puppet apply -e "testing { h: }" Error: No set of title patterns matched the title "h".
一次聲明多個變量的方法:
newparam(:color) do newvalues(:red, :green, :blue, :purple) end
聲明變量也可使用正則表達式的形式:
newparam(:color) do desc "Your color, and stuff." newvalues(:blue, :red, /.+/) end
一些parameters是不必定義參數列表的,或者想要對傳進來的參數進行一些處理,那麼咱們可使用validate和munge方法:
newparam(:color) do desc "Your color, and stuff." newvalues(:blue, :red, /.+/) validate do |value| if value == "green" raise ArgumentError, "Everyone knows green databases don't have enough RAM" else super end end munge do |value| case value when :mauve, :violet # are these colors really any different? :purple else super end end end
validate和munge的區別:
validate只會處理使用newvalues定義過的參數,然而munge方法會處理全部傳進來的參數,包括newvalues定義過的和其餘被指定的參數。假如傳遞進來的參數都沒有通過處理,那麼必須使用調用super方法(也就是說else後面必須使用super方法),不然傳進來的數值就因被丟失而失效。super方法的使用能夠參考個人另外一篇博客ruby語法-super用法
通常來說,參數老是先通過validate方法再通過munged方法。
最後要說明的一點:validate和munge方法只會處理傳進來的參數(該參數已是肯定咱們指望的值了),而不會處理方法裏預約義的參數。
由於聲明布爾類型的參數是很常見的,因此爲了定義的方便,可使用下面的方式:
require 'puppet/parameter/boolean' # ... newparam(:force, :boolean => true, :parent => Puppet::Parameter::Boolean)
其中:parent => Puppet::Parameter::Boolean會配置parameter接受許多的名稱(變量等),並判斷其真假,返回true或false。:boolean => true部分會建立一個布爾方法並返回parameter的最終參數,在上面的例子中,等同於:boolean => true建立了一個force?的方法。
一個type資源能夠指定要自動關聯的資源,經過使用autorequire,autobefore,autonotify和autosubscribe方法,這些方法須要一個資源類型的名字做爲參數,而且會返回一個資源列表,這個資源列表可能會與你定義的type方法有某些關聯。示例:
autorequire(:user) do self[:user] end
須要注意的一點:當使用這四個方法時,即便調用的資源名稱(例如上例中的user)並非一個有效的資源,也不會報錯。
這是一個發生在agent端的事情,在agent端有時咱們須要設置一些先決條件,當先決條件不被知足時,就會跳出部署catalog。這個先決條件的定義就是pre_run_check方法了。
若是type資源裏面定義了pre_run_check方法,在Puppet agent或puppet apply部署catalog以前,首先會運行全部資源裏的pre_run_check方法,一旦有錯誤產生,就會將錯誤信息打印出來告知使用者並中止部署catalog。