Proc.new do
desc "edit an object in your EDITOR"
explain("## SUMMARY ##\n +edit(object)+ allows you to edit any object that can be converted to JSON.\n When finished editing, this method will return the edited object:\n\n new_node = edit(existing_node)\n\n## EDITOR SELECTION ##\n Shef looks for an editor using the following logic\n 1. Looks for an EDITOR set by Shef.editor = \"EDITOR\"\n 2. Looks for an EDITOR configured in your shef config file\n 3. Uses the value of the EDITOR environment variable\n")
def edit(object)
unless Shef.editor
puts "Please set your editor with Shef.editor = \"vim|emacs|mate|ed\""
return :failburger
end
filename = "shef-edit-#{object.class.name}-"
if object.respond_to?(:name)
filename += object.name
elsif object.respond_to?(:id)
filename += object.id
end
edited_data = Tempfile.open([filename, ".js"]) do |tempfile|
tempfile.sync = true
tempfile.puts Chef::JSONCompat.to_json(object)
system("#{Shef.editor.to_s} #{tempfile.path}")
tempfile.rewind
tempfile.read
end
Chef::JSONCompat.from_json(edited_data)
end
desc "Find and edit API clients"
explain("## SUMMARY ##\n +clients+ allows you to query you chef server for information about your api\n clients.\n\n## LIST ALL CLIENTS ##\n To see all clients on the system, use\n\n clients.all #=> [<Chef::ApiClient...>, ...]\n\n If the output from all is too verbose, or you're only interested in a specific\n value from each of the objects, you can give a code block to +all+:\n\n clients.all { |client| client.name } #=> [CLIENT1_NAME, CLIENT2_NAME, ...]\n\n## SHOW ONE CLIENT ##\n To see a specific client, use\n\n clients.show(CLIENT_NAME)\n\n## SEARCH FOR CLIENTS ##\n You can also search for clients using +find+ or +search+. You can use the\n familiar string search syntax:\n\n clients.search(\"KEY:VALUE\")\n\n Just as the +all+ subcommand, the +search+ subcommand can use a code block to\n filter or transform the information returned from the search:\n\n clients.search(\"KEY:VALUE\") { |c| c.name }\n\n You can also use a Hash based syntax, multiple search conditions will be \n joined with AND.\n\n clients.find :KEY => :VALUE, :KEY2 => :VALUE2, ...\n\n## BULK-EDIT CLIENTS ##\n **BE CAREFUL, THIS IS DESTRUCTIVE**\n You can bulk edit API Clients using the +transform+ subcommand, which requires\n a code block. Each client will be saved after the code block is run. If the\n code block returns +nil+ or +false+, that client will be skipped:\n\n clients.transform(\"*:*\") do |client|\n if client.name =~ /borat/i\n client.admin(false)\n true\n else\n nil\n end\n end\n\n This will strip the admin privileges from any client named after borat.\n")
subcommands :all => "list all api clients",
:show => "load an api client by name",
:search => "search for API clients",
:transform => "edit all api clients via a code block and save them"
def clients
@clients ||= Shef::ModelWrapper.new(Chef::ApiClient, :client)
end
desc "Find and edit cookbooks"
subcommands :all => "list all cookbooks",
:show => "load a cookbook by name",
:transform => "edit all cookbooks via a code block and save them"
def cookbooks
@cookbooks ||= Shef::ModelWrapper.new(Chef::CookbookVersion)
end
desc "Find and edit nodes via the API"
explain("## SUMMARY ##\n +nodes+ Allows you to query your chef server for information about your nodes.\n\n## LIST ALL NODES ##\n You can list all nodes using +all+ or +list+\n\n nodes.all #=> [<Chef::Node...>, <Chef::Node...>, ...]\n\n To limit the information returned for each node, pass a code block to the +all+\n subcommand:\n\n nodes.all { |node| node.name } #=> [NODE1_NAME, NODE2_NAME, ...]\n\n## SHOW ONE NODE ##\n You can show the data for a single node using the +show+ subcommand:\n\n nodes.show(\"NODE_NAME\") => <Chef::Node @name=\"NODE_NAME\" ...>\n\n## SEARCH FOR NODES ##\n You can search for nodes using the +search+ or +find+ subcommands:\n\n nodes.find(:name => \"app*\") #=> [<Chef::Node @name=\"app1.example.com\" ...>, ...]\n\n Similarly to +all+, you can pass a code block to limit or transform the\n information returned:\n\n nodes.find(:name => \"app#\") { |node| node.ec2 } \n\n## BULK EDIT NODES ##\n **BE CAREFUL, THIS OPERATION IS DESTRUCTIVE**\n\n Bulk edit nodes by passing a code block to the +transform+ or +bulk_edit+\n subcommand. The block will be applied to each matching node, and then the node\n will be saved. If the block returns +nil+ or +false+, that node will be \n skipped.\n\n nodes.transform do |node|\n if node.fqdn =~ /.*\\\\.preprod\\\\.example\\\\.com/\n node.set[:environment] = \"preprod\"\n end\n end\n\n This will assign the attribute to every node with a FQDN matching the regex.\n")
subcommands :all => "list all nodes",
:show => "load a node by name",
:search => "search for nodes",
:transform => "edit all nodes via a code block and save them"
def nodes
@nodes ||= Shef::ModelWrapper.new(Chef::Node)
end
desc "Find and edit roles via the API"
explain("## SUMMARY ##\n +roles+ allows you to query and edit roles on your Chef server.\n\n## SUBCOMMANDS ##\n * all (list)\n * show (load)\n * search (find)\n * transform (bulk_edit)\n\n## SEE ALSO ##\n See the help for +nodes+ for more information about the subcommands.\n")
subcommands :all => "list all roles",
:show => "load a role by name",
:search => "search for roles",
:transform => "edit all roles via a code block and save them"
def roles
@roles ||= Shef::ModelWrapper.new(Chef::Role)
end
desc "Find and edit +databag_name+ via the api"
explain("## SUMMARY ##\n +databags(DATABAG_NAME)+ allows you to query and edit data bag items on your\n Chef server. Unlike other commands for working with data on the server, \n +databags+ requires the databag name as an argument, for example:\ndatabags(:users).all\n\n## SUBCOMMANDS ##\n * all (list)\n * show (load)\n * search (find)\n * transform (bulk_edit)\n\n## SEE ALSO ##\n See the help for +nodes+ for more information about the subcommands.\n\n")
subcommands :all => "list all items in the data bag",
:show => "load a data bag item by id",
:search => "search for items in the data bag",
:transform => "edit all items via a code block and save them"
def databags(databag_name)
@named_databags_wrappers ||= {}
@named_databags_wrappers[databag_name] ||= Shef::NamedDataBagWrapper.new(databag_name)
end
desc "A REST Client configured to authenticate with the API"
def api
@rest = Shef::ShefREST.new(Chef::Config[:chef_server_url])
end
end