構成管理

トピックは人間の怠inessを引き起こしました:)

繰り返し、複数の構成に現れるパラメーター(例えば、インターフェースのIPアドレス)を変更する必要がある場合に対処する必要がありました。 また、推測するのが論理的であるため、どのようなファイルが「すぐに」思い出すことは困難であることが判明しました。

このアイデアは新しいものではなく、テンプレートの使用に基づいています。 言語はルビーです。



初期構成ファイルのタイプとしてXMLを選択することにしましたが、これは非常に適しています。 YAMLなどに目を向けることができます。

  <xml>
   <構成名= 'rc.conf'>
   <インターフェース>
     <iface name = 're0' tag = 'internal'>
     <ip> 172.16.0.1 </ ip>
     <netmask> 255.255.255.240 </ netmask>
     <media> 1000baseTX </ media>
     <mediaopt>全二重</ mediaopt>
     <opts>ポーリング</ opts>
     </ iface>
     <iface name = 're1' tag = 'external'>
       <ip> 172.16.0.17 </ ip>
       <netmask> 255.255.255.228 </ netmask>
     </ iface>
     <iface name = 'fxp0'>
       <dhcp> true </ dhcp>
       <opts>ポーリング</ opts>
     </ iface>
     <エイリアスiface = 're0' num = '0'>
       <ip> 10.0.0.1 </ ip>
       <netmask> 255.255.255.0 </ netmask>
     </エイリアス>
     <クローン>
       vlan101
       vlan110
       vlan111
     </ cloned>
   </ interfaces>
   </ config>
 </ xml> 


LibXMLを使用してより速く解析し、それを選択しました。 類似として、 REXML、またはXMLファイルからハッシュを作成するXmlSimpleの既製の代替手段を検討できますが、より遅くなります。この点については以下で説明します。

テンプレートでの作業には、 erubisを選択しました

テストによると ERBerubyよりも速いようです



実際にはコード自体:

  「rubygems」が必要
 「エルビス」が必要
 「xml」が必要

 def xml2hash(xml = nil)
   xml.nilの場合、「missed 'xml' param」を発生しますか?

   v = [];  h = {}

  ループする
     xml.read
     break if(xml.node_type == XML :: Reader :: TYPE_END_ELEMENT || xml.empty_element?)
     if(xml.node_type == XML :: Reader :: TYPE_ELEMENT)
      名前= xml.name
       h [名前] || = []
       attrib = {}
       if(xml.attribute_count> 0)then
        カウント= xml.attribute_count
         while(count> 0)do
          カウント-= 1
           xml.move_to_attribute(カウント)
           attrib.merge!({xml.name => xml.value})
        終わり
      終わり
       r = xml2hash(xml)
      ケースr
        ハッシュするとき
           r.merge!(attrib)attrib.emptyでない限り?
           h [名前] .push(r)
        とき配列
           h [name] .push(attrib)attrib.emptyでない限り?
           h [名前] .push(* r)
        他に
           h [name] .push(attrib)attrib.emptyでない限り?
           h [名前] .push(r)
       r.nilでない限り終了しますか?
     elsif(xml.node_type == XML :: Reader :: TYPE_TEXT &&!xml.value.nil?)
       xml.value.split( "\ n")。各{| i |  i.gsub!(/ ^ \ s *?(\ S +)\ s * $ /、 '\ 1');  v.push(i)except(i.empty?|| i =〜/ ^ \ s * $ /);  }
    終わり
  終わり

   r = []
   r.push(h)(h.nil?|| h.empty?)でない限り
   r.push(* v)(v.nil?|| v.empty?)以外
  リターン* r

  レスキュー=> e
     puts "#{e.class}:#{e}(method:xml2hash)"

終わり

始める
   xml = XML :: Reader.file( 'params.xml')
   r = xml2hash(xml)
   xml.close

   r ['xml']。最初の['config']。各do | i |
    テンプレート= File.read(i ['name'] + ".eruby")
     eruby = Erubis :: Eruby.new(テンプレート)
     File.open(i ['name']、 "w"){| file |  file.puts eruby.evaluate({:list => i})}
  終わり
	
  レスキュー=> e
     puts "#{e.class}:#{e}(method:main)"
終わり 


コードの詳細は説明しません。xml2hashメソッドの再帰呼び出しが使用されているとだけ言います。ブロックの始まりであれば、さらに深く、ブロックの終わりまたは空の要素/ブロックであれば、上に戻ります。

テンプレートファイルはxml + '.eruby'のconfig_nameです。 私の場合、rc.conf.eruby。

出力はconfig_name(rc.conf)にあります。



テンプレートコンテンツ:

<% for item in @list['interfaces'].first['iface'] %>

ifconfig_<%= item['name'] %>="<% unless item['dhcp'] %>inet <%= item['ip'].first %> netmask <%= item['netmask'].first %><% else %>DHCP<% end %><% unless (item['media'].nil? || item['media'].empty?) %> media <%= item['media'].first %><% end %><% unless (item['mediaopt'].nil? || item['mediaopt'].empty?) %> mediaopt <%= item['mediaopt'].first %><% end %><% unless (item['opts'].nil? || item['opts'].empty?) %> <%= item['opts'].first %><% end %>"

<% end %>

<% for item in @list['interfaces'].first['alias'] %>

ifconfig_<%= item['iface'] %>_alias<%= item['num'] %>="inet <%= item['ip'].first %> netmask <%= item['netmask'].first %>"

<% end %>

<% if @list['interfaces'].first.key?('cloned') && !@list['interfaces'].first['cloned'].empty? %>cloned_interfaces="<%= @list['interfaces'].first['cloned'].join(' ') %>"<% end %>






はい、それはやや読めないように見えますが、これは一見しただけです:)



約束どおり、「上記のコード」とXmlSimpleのテストに移りましょう。

xml_test.rb:

  「rubygems」が必要
 「xml」が必要
 「ベンチマーク」が必要

 def xml2hash(xml = nil)
   #メソッド定義上記参照
終わり

始める
   xml = ''
   Benchmark.bm do | x |
     x.report {100.times do
       xml_read = XML :: Reader.file( 'params.xml')
       xml = xml2hash(xml_read)
       xml_read.close 
    終了}
  終わり
   p xml

  レスキュー=> e
     puts "#{e.class}:#{e}(method:main)"
終わり 




  ezhik @ pollux:〜$ time ruby​​ xml_test.rb 
      ユーザーシステムの総実数
   0.210000 0.010000 0.220000(0.253391)
 {"xml" => [{"config" => [{"name" => "rc.conf"、 "interfaces" => [{"alias" => [{"netmask" => ["255.255.255.0 "]、" num "=>" 0 "、" ip "=> [" 10.0.0.1 "]、" iface "=>" re0 "}]、" iface "=> [{" name "=>" re0 "、" netmask "=> [" 255.255.255.240 "]、" opts "=> [" polling "]、" tag "=>" internal "、" mediaopt "=> ["全二重 "]、"メディア"=> [" 1000baseTX "]、" ip "=> [" 172.16.0.1 "]}、{" name "=>" re1 "、" netmask "=> [" 255.255.255.228 "]、" tag "= > "external"、 "ip" => ["172.16.0.17"]}、{"name" => "fxp0"、 "opts" => ["polling"]、 "dhcp" => ["true"] }]、 "クローン" => ["vlan101"、 "vlan110"、 "vlan111"]}]}}}}]}}

実数0m0.447s
ユーザー0m0.344s
 sys 0m0.036s 




xml_simple.rb:

  「rubygems」が必要
 「xmlsimple」が必要
 「ベンチマーク」が必要

 xml = ''
 Benchmark.bm do | x |
   x.report {100.times do
     xml = XmlSimple.xml_in( 'params.xml')
  終了}
終わり
 p xml 




  ezhik @ pollux:〜$ time ruby​​ xml_simple.rb 
      ユーザーシステムの総実数
   1.770000 0.100000 1.870000(1.956282)
 {"config" => [{"name" => "rc.conf"、 "interfaces" => [{"alias" => [{"netmask" => ["255.255.255.0"]、 "num" = > "0"、 "ip" => ["10.0.0.1"]、 "iface" => "re0"}]、 "iface" => [{"netmask" => ["255.255.255.240"]、 " name "=>" re0 "、" opts "=> [" polling "]、" tag "=>" internal "、" mediaopt "=> ["全二重 "]、"メディア "=> [" 1000baseTX " ]、 "ip" => ["172.16.0.1"]}、{"netmask" => ["255.255.255.228"]、 "name" => "re1"、 "tag" => "external"、 "ip "=> [" 172.16.0.17 "]}、{" name "=>" fxp0 "、" opts "=> [" polling "]、" dhcp "=> [" true "]}]、" clone "= > ["\ n vlan101 \ n vlan110 \ n vlan111 \ n"]}]}]}}

実際の0m2.279s
ユーザー0m2.012s
 sys 0m0.124s 




はい、それはまさにxmlを解析した後のハッシュの外観です。

時間差はありますが、このタスクにはそれほど重要ではないと思うので、選択はあなた次第です。



その結果、私は得た:

  ifconfig_re0 = "inet 172.16.0.1ネットマスク255.255.255.240メディア1000baseTX mediaopt全二重ポーリング"
 ifconfig_re1 = "inet 172.16.0.17 netmask 255.255.255.228"
 ifconfig_fxp0 = "DHCPポーリング"
 ifconfig_re0_alias0 = "inet 10.0.0.1 netmask 255.255.255.0"
 clone_interfaces = "vlan101 vlan110 vlan111" 




終わり。



All Articles