Guest User

Untitled

a guest
Mar 14th, 2018
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.33 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2.  
  3. require 'rubygems'
  4. require 'thor'
  5. require 'chef'
  6. require 'chef/node'
  7. require 'chef/rest'
  8.  
  9. # Please see the readme for overview documentation.
  10. #
  11. class JsonPrinter
  12. attr_reader :buf, :indent
  13.  
  14. # ==== Arguments
  15. # obj<Object>::
  16. # The object to be rendered into JSON. This object and all of its
  17. # associated objects must be either nil, true, false, a String, a Symbol,
  18. # a Numeric, an Array, or a Hash.
  19. #
  20. # ==== Returns
  21. # <String>::
  22. # The pretty-printed JSON ecoding of the given <i>obj</i>. This string
  23. # can be parsed by any compliant JSON parser without modification.
  24. #
  25. # ==== Examples
  26. # See <tt>JsonPrinter</tt> docs.
  27. #
  28. def self.render(obj)
  29. new(obj).buf
  30. end
  31.  
  32.  
  33. private
  34.  
  35. # Execute the JSON rendering of <i>obj</i>, storing the result in the
  36. # <tt>buf</tt>.
  37. #
  38. def initialize(obj)
  39. @buf = ""
  40. @indent = ""
  41. render(obj)
  42. end
  43.  
  44. # Increase the indentation level.
  45. #
  46. def indent_out
  47. @indent << " "
  48. end
  49.  
  50. # Decrease the indendation level.
  51. #
  52. def indent_in
  53. @indent.slice!(-1, 1)
  54. end
  55.  
  56. # Append the given <i>str</i> to the <tt>buf</tt>.
  57. #
  58. def print(str)
  59. @buf << str
  60. end
  61.  
  62. # Recursive rendering method. Primitive values, like nil, true, false,
  63. # numbers, symbols, and strings are converted to JSON and appended to the
  64. # buffer. Enumerables are treated specially to generate pretty whitespace.
  65. #
  66. def render(obj)
  67. # We can't use a case statement here becuase "when Hash" doesn't work for
  68. # ActiveSupport::OrderedHash - respond_to?(:values) is a more reliable
  69. # indicator of hash-like behavior.
  70. if NilClass === obj
  71. print("null")
  72.  
  73. elsif TrueClass === obj
  74. print("true")
  75.  
  76. elsif FalseClass === obj
  77. print("false")
  78.  
  79. elsif String === obj
  80. print(escape_json_string(obj))
  81.  
  82. elsif Symbol === obj
  83. print("\"#{obj}\"")
  84.  
  85. elsif Numeric === obj
  86. print(obj.to_s)
  87.  
  88. elsif Time === obj
  89. print(obj.to_s)
  90.  
  91. elsif obj.respond_to?(:keys)
  92. print("{")
  93. indent_out
  94. last_key = obj.keys.last
  95. obj.each do |(key, val)|
  96. render(key)
  97. case val
  98. when Hash, Array
  99. indent_out
  100. print(":\n#{indent}")
  101. render(val)
  102. indent_in
  103. else
  104. print(": ")
  105. render(val)
  106. end
  107. print(",\n#{indent}") unless key == last_key
  108. end
  109. indent_in
  110. print("}")
  111.  
  112. elsif Array === obj
  113. print("[")
  114. indent_out
  115. last_index = obj.size - 1
  116. obj.each_with_index do |elem, index|
  117. render(elem)
  118. print(",\n#{indent}") unless index == last_index
  119. end
  120. indent_in
  121. print("]")
  122.  
  123. else
  124. raise "unrenderable object: #{obj.inspect}"
  125. end
  126. end
  127.  
  128. # Special JSON character escape cases.
  129. ESCAPED_CHARS = {
  130. "\010" => '\b',
  131. "\f" => '\f',
  132. "\n" => '\n',
  133. "\r" => '\r',
  134. "\t" => '\t',
  135. '"' => '\"',
  136. '\\' => '\\\\',
  137. '>' => '\u003E',
  138. '<' => '\u003C',
  139. '&' => '\u0026'}
  140.  
  141. # String#to_json extracted from ActiveSupport, using interpolation for speed.
  142. #
  143. def escape_json_string(str)
  144. "\"#{
  145. str.gsub(/[\010\f\n\r\t"\\><&]/) { |s| ESCAPED_CHARS[s] }.
  146. gsub(/([\xC0-\xDF][\x80-\xBF]|
  147. [\xE0-\xEF][\x80-\xBF]{2}|
  148. [\xF0-\xF7][\x80-\xBF]{3})+/nx) do |s|
  149. s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&')
  150. end
  151. }\""
  152. end
  153. end
  154.  
  155. Chef::Config.from_file("/etc/chef/server.rb")
  156.  
  157. API_USERNAME=ENV['CHEF_USERNAME']
  158. API_PASSWORD=ENV['CHEF_PASSWORD']
  159.  
  160. raise StandardError, "Please set CHEF_USERNAME and CHEF_PASSWORD" unless ENV['CHEF_USERNAME'] && ENV['CHEF_PASSWORD']
  161.  
  162. class Knife < Thor
  163.  
  164. desc "register", "Register an openid for an API user"
  165. method_options :username => :required, :password => :required
  166. def register
  167. @rest = Chef::REST.new(Chef::Config[:registration_url])
  168. @rest.register(options[:username], options[:password])
  169. end
  170.  
  171.  
  172. desc "add_recipe", "Add a recipe to a node"
  173. method_options :recipe => :required, :after => :optional, :node => :required
  174. def add_recipe
  175. authenticate
  176. node = @rest.get_rest("nodes/#{expand_node(options[:node])}")
  177. node.recipes << options[:recipe] if !node.recipes.include?(options[:recipe])
  178. @rest.put_rest("nodes/#{expand_node(options[:node])}", node)
  179. list_recipes
  180. end
  181.  
  182. desc "remove_recipe", "Remove a recipe from a node"
  183. method_options :recipe => :required, :node => :required
  184. def remove_recipe
  185. authenticate
  186. node = @rest.get_rest("nodes/#{expand_node(options[:node])}")
  187. node.recipes.delete(options[:recipe]) if node.recipes.include?(options[:recipe])
  188. @rest.put_rest("nodes/#{expand_node(options[:node])}", node)
  189. list_recipes
  190. end
  191.  
  192. desc "show_attr", "Display a node attribute"
  193. method_options :node => :required, :attr => :required
  194. def show_attr
  195. authenticate
  196. node = @rest.get_rest("nodes/#{expand_node(options[:node])}")
  197. puts JsonPrinter.render(node[options[:attr]])
  198. end
  199.  
  200. desc "edit_attr", "Display a node attribute"
  201. method_options :node => :required, :attr => :required
  202. def edit_attr
  203. editor = ENV['EDITOR'] || "vi"
  204. puts "Authenticating..."
  205. authenticate
  206. puts "Fetching node data for #{expand_node(options[:node])}..."
  207. node = @rest.get_rest("nodes/#{expand_node(options[:node])}")
  208. filename = "/tmp/.chef-#{node[:hostname]}"
  209. File.open(filename, "w") {|f| f.write(JsonPrinter.render(node[options[:attr]])) }
  210. system("#{editor} #{filename}") or raise StandardError, "Error communicating with #{editor}"
  211. node[options[:attr]] = JSON.parse(File.read(filename))
  212. puts "Storing node data for #{expand_node(options[:node])}..."
  213. begin
  214. retries = 5
  215. @rest.put_rest("nodes/#{expand_node(options[:node])}", node)
  216. rescue Net::HTTPFatalError
  217. retry if (retries -= 1) > 0
  218. end
  219. puts "Done."
  220. end
  221.  
  222. desc "list_recipes", "List a node's recipes"
  223. method_options :node => :required
  224. def list_recipes
  225. authenticate
  226. node = @rest.get_rest("nodes/#{expand_node(options[:node])}")
  227. puts node.recipes.inspect
  228. end
  229.  
  230. def authenticate
  231. @rest = Chef::REST.new(Chef::Config[:registration_url])
  232. @rest.authenticate(API_USERNAME, API_PASSWORD)
  233. end
  234. end
  235.  
  236. def expand_node(name)
  237. name + "_" + (ENV['CHEF_DOMAIN'] || `hostname -d`.chomp.gsub(".", "_"))
  238. end
  239.  
  240. Knife.start
Add Comment
Please, Sign In to add comment