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 \#{ChefUtils::Dist::Infra::SHELL} looks for an editor using the following logic\n 1. Looks for an EDITOR set by Shell.editor = \"EDITOR\"\n 2. Looks for an EDITOR configured in your \#{ChefUtils::Dist::Infra::SHELL} config file\n 3. Uses the value of the EDITOR environment variable\n E\n def edit(object)\n unless Shell.editor\n puts \"Please set your editor with Shell.editor = \\\"vim|emacs|mate|ed\\\"\"\n return :failburger\n end\n\n filename = \"\#{ChefUtils::Dist::Infra::SHELL}-edit-\#{object.class.name}-\"\n if object.respond_to?(:name)\n filename += object.name\n elsif object.respond_to?(:id)\n filename += object.id\n end\n\n edited_data = Tempfile.open([filename, \".js\"]) do |tempfile|\n tempfile.sync = true\n tempfile.puts Chef::JSONCompat.to_json(object)\n system(\"\#{Shell.editor} \#{tempfile.path}\")\n tempfile.rewind\n tempfile.read\n end\n\n Chef::JSONCompat.from_json(edited_data)\n end\n\n desc \"Find and edit API clients\"\n explain(<<~E)\n ## 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 E\n subcommands all: \"list all api clients\",\n show: \"load an api client by name\",\n search: \"search for API clients\",\n transform: \"edit all api clients via a code block and save them\"\n def clients\n @clients ||= Shell::ModelWrapper.new(Chef::ApiClient, :client)\n end\n\n desc \"Find and edit cookbooks\"\n subcommands all: \"list all cookbooks\",\n show: \"load a cookbook by name\",\n transform: \"edit all cookbooks via a code block and save them\"\n def cookbooks\n @cookbooks ||= Shell::ModelWrapper.new(Chef::CookbookVersion)\n end\n\n desc \"Find and edit nodes via the API\"\n explain(<<~E)\n ## 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 E\n subcommands all: \"list all nodes\",\n show: \"load a node by name\",\n search: \"search for nodes\",\n transform: \"edit all nodes via a code block and save them\"\n def nodes\n @nodes ||= Shell::ModelWrapper.new(Chef::Node)\n end\n\n desc \"Find and edit roles via the API\"\n explain(<<~E)\n ## 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 E\n subcommands all: \"list all roles\",\n show: \"load a role by name\",\n search: \"search for roles\",\n transform: \"edit all roles via a code block and save them\"\n def roles\n @roles ||= Shell::ModelWrapper.new(Chef::Role)\n end\n\n desc \"Find and edit +databag_name+ via the api\"\n explain(<<~E)\n ## 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:\n databags(: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 E\n subcommands all: \"list all items in the data bag\",\n show: \"load a data bag item by id\",\n search: \"search for items in the data bag\",\n transform: \"edit all items via a code block and save them\"\n def databags(databag_name)\n @named_databags_wrappers ||= {}\n @named_databags_wrappers[databag_name] ||= Shell::NamedDataBagWrapper.new(databag_name)\n end\n\n desc \"Find and edit environments via the API\"\n explain(<<~E)\n ## SUMMARY ##\n +environments+ allows you to query and edit environments 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 E\n subcommands all: \"list all environments\",\n show: \"load an environment by name\",\n search: \"search for environments\",\n transform: \"edit all environments via a code block and save them\"\n def environments\n @environments ||= Shell::ModelWrapper.new(Chef::Environment)\n end\n\n desc \"A REST Client configured to authenticate with the API\"\n def api\n @rest = Chef::ServerAPI.new(Chef::Config[:chef_server_url])\n end\n\nend\n")