mbailey-chef 0.9.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +201 -0
- data/README.rdoc +172 -0
- data/bin/chef-client +26 -0
- data/bin/chef-solo +25 -0
- data/bin/knife +26 -0
- data/bin/shef +34 -0
- data/distro/README +2 -0
- data/distro/common/man/man1/chef-indexer.1 +42 -0
- data/distro/common/man/man1/chef-server-webui.1 +106 -0
- data/distro/common/man/man1/chef-server.1 +107 -0
- data/distro/common/man/man1/chef-solr-indexer.1 +55 -0
- data/distro/common/man/man1/chef-solr.1 +55 -0
- data/distro/common/man/man8/chef-client.8 +63 -0
- data/distro/common/man/man8/chef-solo.8 +57 -0
- data/distro/common/man/man8/chef-solr-rebuild.8 +37 -0
- data/distro/common/man/man8/knife.8 +1349 -0
- data/distro/common/man/man8/shef.8 +45 -0
- data/distro/common/markdown/README +3 -0
- data/distro/common/markdown/knife.mkd +832 -0
- data/distro/debian/etc/default/chef-client +4 -0
- data/distro/debian/etc/default/chef-server +9 -0
- data/distro/debian/etc/default/chef-server-webui +9 -0
- data/distro/debian/etc/default/chef-solr +7 -0
- data/distro/debian/etc/default/chef-solr-indexer +7 -0
- data/distro/debian/etc/init/chef-client.conf +17 -0
- data/distro/debian/etc/init/chef-server-webui.conf +17 -0
- data/distro/debian/etc/init/chef-server.conf +17 -0
- data/distro/debian/etc/init/chef-solr-indexer.conf +17 -0
- data/distro/debian/etc/init/chef-solr.conf +17 -0
- data/distro/debian/etc/init.d/chef-client +175 -0
- data/distro/debian/etc/init.d/chef-server +122 -0
- data/distro/debian/etc/init.d/chef-server-webui +123 -0
- data/distro/debian/etc/init.d/chef-solr +177 -0
- data/distro/debian/etc/init.d/chef-solr-indexer +176 -0
- data/distro/redhat/etc/init.d/chef-client +106 -0
- data/distro/redhat/etc/init.d/chef-server +112 -0
- data/distro/redhat/etc/init.d/chef-server-webui +112 -0
- data/distro/redhat/etc/init.d/chef-solr +104 -0
- data/distro/redhat/etc/init.d/chef-solr-indexer +104 -0
- data/distro/redhat/etc/logrotate.d/chef-client +8 -0
- data/distro/redhat/etc/logrotate.d/chef-server +8 -0
- data/distro/redhat/etc/logrotate.d/chef-server-webui +8 -0
- data/distro/redhat/etc/logrotate.d/chef-solr +8 -0
- data/distro/redhat/etc/logrotate.d/chef-solr-indexer +8 -0
- data/distro/redhat/etc/sysconfig/chef-client +15 -0
- data/distro/redhat/etc/sysconfig/chef-server +14 -0
- data/distro/redhat/etc/sysconfig/chef-server-webui +14 -0
- data/distro/redhat/etc/sysconfig/chef-solr +8 -0
- data/distro/redhat/etc/sysconfig/chef-solr-indexer +7 -0
- data/lib/chef/api_client.rb +264 -0
- data/lib/chef/application/agent.rb +18 -0
- data/lib/chef/application/client.rb +246 -0
- data/lib/chef/application/knife.rb +171 -0
- data/lib/chef/application/solo.rb +215 -0
- data/lib/chef/application.rb +127 -0
- data/lib/chef/applications.rb +4 -0
- data/lib/chef/certificate.rb +194 -0
- data/lib/chef/checksum.rb +182 -0
- data/lib/chef/checksum_cache.rb +173 -0
- data/lib/chef/client.rb +304 -0
- data/lib/chef/config.rb +240 -0
- data/lib/chef/cookbook/cookbook_collection.rb +44 -0
- data/lib/chef/cookbook/file_system_file_vendor.rb +54 -0
- data/lib/chef/cookbook/file_vendor.rb +48 -0
- data/lib/chef/cookbook/metadata/version.rb +87 -0
- data/lib/chef/cookbook/metadata.rb +500 -0
- data/lib/chef/cookbook/remote_file_vendor.rb +87 -0
- data/lib/chef/cookbook/syntax_check.rb +136 -0
- data/lib/chef/cookbook_loader.rb +227 -0
- data/lib/chef/cookbook_site_streaming_uploader.rb +244 -0
- data/lib/chef/cookbook_uploader.rb +103 -0
- data/lib/chef/cookbook_version.rb +930 -0
- data/lib/chef/couchdb.rb +239 -0
- data/lib/chef/daemon.rb +172 -0
- data/lib/chef/data_bag.rb +215 -0
- data/lib/chef/data_bag_item.rb +228 -0
- data/lib/chef/exceptions.rb +66 -0
- data/lib/chef/file_access_control.rb +140 -0
- data/lib/chef/file_cache.rb +218 -0
- data/lib/chef/handler/json_file.rb +58 -0
- data/lib/chef/handler.rb +206 -0
- data/lib/chef/index_queue/amqp_client.rb +113 -0
- data/lib/chef/index_queue/consumer.rb +76 -0
- data/lib/chef/index_queue/indexable.rb +76 -0
- data/lib/chef/index_queue.rb +29 -0
- data/lib/chef/knife/bootstrap/archlinux-gems.erb +44 -0
- data/lib/chef/knife/bootstrap/centos5-gems.erb +41 -0
- data/lib/chef/knife/bootstrap/client-install.vbs +80 -0
- data/lib/chef/knife/bootstrap/fedora13-gems.erb +38 -0
- data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +32 -0
- data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +43 -0
- data/lib/chef/knife/bootstrap/windows-gems.erb +34 -0
- data/lib/chef/knife/bootstrap.rb +181 -0
- data/lib/chef/knife/client_bulk_delete.rb +40 -0
- data/lib/chef/knife/client_create.rb +70 -0
- data/lib/chef/knife/client_delete.rb +45 -0
- data/lib/chef/knife/client_edit.rb +45 -0
- data/lib/chef/knife/client_list.rb +40 -0
- data/lib/chef/knife/client_reregister.rb +56 -0
- data/lib/chef/knife/client_show.rb +50 -0
- data/lib/chef/knife/configure.rb +140 -0
- data/lib/chef/knife/configure_client.rb +52 -0
- data/lib/chef/knife/cookbook_bulk_delete.rb +58 -0
- data/lib/chef/knife/cookbook_create.rb +209 -0
- data/lib/chef/knife/cookbook_delete.rb +143 -0
- data/lib/chef/knife/cookbook_download.rb +130 -0
- data/lib/chef/knife/cookbook_list.rb +41 -0
- data/lib/chef/knife/cookbook_metadata.rb +82 -0
- data/lib/chef/knife/cookbook_metadata_from_file.rb +40 -0
- data/lib/chef/knife/cookbook_show.rb +98 -0
- data/lib/chef/knife/cookbook_site_download.rb +58 -0
- data/lib/chef/knife/cookbook_site_list.rb +56 -0
- data/lib/chef/knife/cookbook_site_search.rb +51 -0
- data/lib/chef/knife/cookbook_site_share.rb +109 -0
- data/lib/chef/knife/cookbook_site_show.rb +57 -0
- data/lib/chef/knife/cookbook_site_unshare.rb +52 -0
- data/lib/chef/knife/cookbook_site_vendor.rb +133 -0
- data/lib/chef/knife/cookbook_test.rb +82 -0
- data/lib/chef/knife/cookbook_upload.rb +95 -0
- data/lib/chef/knife/data_bag_create.rb +59 -0
- data/lib/chef/knife/data_bag_delete.rb +48 -0
- data/lib/chef/knife/data_bag_edit.rb +50 -0
- data/lib/chef/knife/data_bag_from_file.rb +44 -0
- data/lib/chef/knife/data_bag_list.rb +43 -0
- data/lib/chef/knife/data_bag_show.rb +41 -0
- data/lib/chef/knife/ec2_instance_data.rb +46 -0
- data/lib/chef/knife/ec2_server_create.rb +216 -0
- data/lib/chef/knife/ec2_server_delete.rb +90 -0
- data/lib/chef/knife/ec2_server_list.rb +88 -0
- data/lib/chef/knife/exec.rb +52 -0
- data/lib/chef/knife/index_rebuild.rb +51 -0
- data/lib/chef/knife/node_bulk_delete.rb +43 -0
- data/lib/chef/knife/node_create.rb +47 -0
- data/lib/chef/knife/node_delete.rb +44 -0
- data/lib/chef/knife/node_edit.rb +44 -0
- data/lib/chef/knife/node_from_file.rb +42 -0
- data/lib/chef/knife/node_list.rb +41 -0
- data/lib/chef/knife/node_run_list_add.rb +64 -0
- data/lib/chef/knife/node_run_list_remove.rb +45 -0
- data/lib/chef/knife/node_show.rb +54 -0
- data/lib/chef/knife/rackspace_server_create.rb +156 -0
- data/lib/chef/knife/rackspace_server_delete.rb +57 -0
- data/lib/chef/knife/rackspace_server_list.rb +59 -0
- data/lib/chef/knife/recipe_list.rb +32 -0
- data/lib/chef/knife/role_bulk_delete.rb +44 -0
- data/lib/chef/knife/role_create.rb +52 -0
- data/lib/chef/knife/role_delete.rb +44 -0
- data/lib/chef/knife/role_edit.rb +45 -0
- data/lib/chef/knife/role_from_file.rb +46 -0
- data/lib/chef/knife/role_list.rb +40 -0
- data/lib/chef/knife/role_show.rb +51 -0
- data/lib/chef/knife/search.rb +94 -0
- data/lib/chef/knife/slicehost_images_list.rb +53 -0
- data/lib/chef/knife/slicehost_server_create.rb +103 -0
- data/lib/chef/knife/slicehost_server_delete.rb +61 -0
- data/lib/chef/knife/slicehost_server_list.rb +64 -0
- data/lib/chef/knife/ssh.rb +328 -0
- data/lib/chef/knife/status.rb +87 -0
- data/lib/chef/knife/terremark_server_create.rb +152 -0
- data/lib/chef/knife/terremark_server_delete.rb +87 -0
- data/lib/chef/knife/terremark_server_list.rb +77 -0
- data/lib/chef/knife/windows_bootstrap.rb +154 -0
- data/lib/chef/knife.rb +522 -0
- data/lib/chef/log.rb +61 -0
- data/lib/chef/mixin/check_helper.rb +31 -0
- data/lib/chef/mixin/checksum.rb +32 -0
- data/lib/chef/mixin/command/unix.rb +215 -0
- data/lib/chef/mixin/command/windows.rb +72 -0
- data/lib/chef/mixin/command.rb +220 -0
- data/lib/chef/mixin/convert_to_class_name.rb +63 -0
- data/lib/chef/mixin/create_path.rb +56 -0
- data/lib/chef/mixin/deep_merge.rb +225 -0
- data/lib/chef/mixin/deprecation.rb +65 -0
- data/lib/chef/mixin/find_preferred_file.rb +92 -0
- data/lib/chef/mixin/from_file.rb +50 -0
- data/lib/chef/mixin/language.rb +156 -0
- data/lib/chef/mixin/language_include_attribute.rb +61 -0
- data/lib/chef/mixin/language_include_recipe.rb +52 -0
- data/lib/chef/mixin/params_validate.rb +225 -0
- data/lib/chef/mixin/recipe_definition_dsl_core.rb +81 -0
- data/lib/chef/mixin/shell_out.rb +38 -0
- data/lib/chef/mixin/template.rb +95 -0
- data/lib/chef/mixin/xml_escape.rb +140 -0
- data/lib/chef/mixins.rb +16 -0
- data/lib/chef/monkey_patches/dir.rb +36 -0
- data/lib/chef/monkey_patches/string.rb +28 -0
- data/lib/chef/monkey_patches/tempfile.rb +64 -0
- data/lib/chef/node/attribute.rb +465 -0
- data/lib/chef/node.rb +601 -0
- data/lib/chef/openid_registration.rb +187 -0
- data/lib/chef/platform.rb +371 -0
- data/lib/chef/provider/breakpoint.rb +36 -0
- data/lib/chef/provider/cookbook_file.rb +100 -0
- data/lib/chef/provider/cron/solaris.rb +195 -0
- data/lib/chef/provider/cron.rb +186 -0
- data/lib/chef/provider/deploy/revision.rb +73 -0
- data/lib/chef/provider/deploy/timestamped.rb +33 -0
- data/lib/chef/provider/deploy.rb +319 -0
- data/lib/chef/provider/directory.rb +72 -0
- data/lib/chef/provider/env/windows.rb +75 -0
- data/lib/chef/provider/env.rb +152 -0
- data/lib/chef/provider/erl_call.rb +72 -0
- data/lib/chef/provider/execute.rb +58 -0
- data/lib/chef/provider/file.rb +213 -0
- data/lib/chef/provider/git.rb +211 -0
- data/lib/chef/provider/group/dscl.rb +121 -0
- data/lib/chef/provider/group/gpasswd.rb +53 -0
- data/lib/chef/provider/group/groupadd.rb +78 -0
- data/lib/chef/provider/group/pw.rb +84 -0
- data/lib/chef/provider/group/usermod.rb +57 -0
- data/lib/chef/provider/group/windows.rb +79 -0
- data/lib/chef/provider/group.rb +133 -0
- data/lib/chef/provider/http_request.rb +122 -0
- data/lib/chef/provider/ifconfig.rb +132 -0
- data/lib/chef/provider/link.rb +161 -0
- data/lib/chef/provider/log.rb +54 -0
- data/lib/chef/provider/mdadm.rb +91 -0
- data/lib/chef/provider/mount/mount.rb +232 -0
- data/lib/chef/provider/mount/windows.rb +80 -0
- data/lib/chef/provider/mount.rb +117 -0
- data/lib/chef/provider/ohai.rb +41 -0
- data/lib/chef/provider/package/apt.rb +110 -0
- data/lib/chef/provider/package/dpkg.rb +112 -0
- data/lib/chef/provider/package/easy_install.rb +114 -0
- data/lib/chef/provider/package/freebsd.rb +123 -0
- data/lib/chef/provider/package/macports.rb +105 -0
- data/lib/chef/provider/package/pacman.rb +101 -0
- data/lib/chef/provider/package/portage.rb +124 -0
- data/lib/chef/provider/package/rpm.rb +101 -0
- data/lib/chef/provider/package/rubygems.rb +462 -0
- data/lib/chef/provider/package/solaris.rb +127 -0
- data/lib/chef/provider/package/yum-dump.py +128 -0
- data/lib/chef/provider/package/yum.rb +222 -0
- data/lib/chef/provider/package/zypper.rb +133 -0
- data/lib/chef/provider/package.rb +160 -0
- data/lib/chef/provider/remote_directory.rb +140 -0
- data/lib/chef/provider/remote_file.rb +120 -0
- data/lib/chef/provider/route.rb +195 -0
- data/lib/chef/provider/ruby_block.rb +33 -0
- data/lib/chef/provider/script.rb +55 -0
- data/lib/chef/provider/service/arch.rb +109 -0
- data/lib/chef/provider/service/debian.rb +105 -0
- data/lib/chef/provider/service/freebsd.rb +156 -0
- data/lib/chef/provider/service/gentoo.rb +54 -0
- data/lib/chef/provider/service/init.rb +71 -0
- data/lib/chef/provider/service/redhat.rb +60 -0
- data/lib/chef/provider/service/simple.rb +118 -0
- data/lib/chef/provider/service/solaris.rb +85 -0
- data/lib/chef/provider/service/upstart.rb +192 -0
- data/lib/chef/provider/service/windows.rb +129 -0
- data/lib/chef/provider/service.rb +128 -0
- data/lib/chef/provider/subversion.rb +159 -0
- data/lib/chef/provider/template.rb +105 -0
- data/lib/chef/provider/user/dscl.rb +280 -0
- data/lib/chef/provider/user/pw.rb +113 -0
- data/lib/chef/provider/user/useradd.rb +137 -0
- data/lib/chef/provider/user/windows.rb +124 -0
- data/lib/chef/provider/user.rb +187 -0
- data/lib/chef/provider.rb +124 -0
- data/lib/chef/providers.rb +91 -0
- data/lib/chef/recipe.rb +130 -0
- data/lib/chef/resource/apt_package.rb +34 -0
- data/lib/chef/resource/bash.rb +33 -0
- data/lib/chef/resource/breakpoint.rb +35 -0
- data/lib/chef/resource/cookbook_file.rb +45 -0
- data/lib/chef/resource/cron.rb +188 -0
- data/lib/chef/resource/csh.rb +33 -0
- data/lib/chef/resource/deploy.rb +371 -0
- data/lib/chef/resource/deploy_revision.rb +35 -0
- data/lib/chef/resource/directory.rb +76 -0
- data/lib/chef/resource/dpkg_package.rb +34 -0
- data/lib/chef/resource/easy_install_package.rb +41 -0
- data/lib/chef/resource/env.rb +58 -0
- data/lib/chef/resource/erl_call.rb +83 -0
- data/lib/chef/resource/execute.rb +127 -0
- data/lib/chef/resource/file.rb +92 -0
- data/lib/chef/resource/freebsd_package.rb +35 -0
- data/lib/chef/resource/gem_package.rb +49 -0
- data/lib/chef/resource/git.rb +36 -0
- data/lib/chef/resource/group.rb +70 -0
- data/lib/chef/resource/http_request.rb +61 -0
- data/lib/chef/resource/ifconfig.rb +134 -0
- data/lib/chef/resource/link.rb +78 -0
- data/lib/chef/resource/log.rb +62 -0
- data/lib/chef/resource/macports_package.rb +29 -0
- data/lib/chef/resource/mdadm.rb +82 -0
- data/lib/chef/resource/mount.rb +135 -0
- data/lib/chef/resource/ohai.rb +40 -0
- data/lib/chef/resource/package.rb +80 -0
- data/lib/chef/resource/pacman_package.rb +33 -0
- data/lib/chef/resource/perl.rb +33 -0
- data/lib/chef/resource/portage_package.rb +33 -0
- data/lib/chef/resource/python.rb +33 -0
- data/lib/chef/resource/remote_directory.rb +109 -0
- data/lib/chef/resource/remote_file.rb +83 -0
- data/lib/chef/resource/route.rb +135 -0
- data/lib/chef/resource/rpm_package.rb +34 -0
- data/lib/chef/resource/ruby.rb +33 -0
- data/lib/chef/resource/ruby_block.rb +40 -0
- data/lib/chef/resource/scm.rb +146 -0
- data/lib/chef/resource/script.rb +60 -0
- data/lib/chef/resource/service.rb +160 -0
- data/lib/chef/resource/solaris_package.rb +36 -0
- data/lib/chef/resource/subversion.rb +36 -0
- data/lib/chef/resource/template.rb +69 -0
- data/lib/chef/resource/timestamped_deploy.rb +31 -0
- data/lib/chef/resource/user.rb +130 -0
- data/lib/chef/resource/yum_package.rb +43 -0
- data/lib/chef/resource.rb +523 -0
- data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
- data/lib/chef/resource_collection.rb +217 -0
- data/lib/chef/resource_definition.rb +67 -0
- data/lib/chef/resource_definition_list.rb +38 -0
- data/lib/chef/resources.rb +64 -0
- data/lib/chef/rest/auth_credentials.rb +78 -0
- data/lib/chef/rest/cookie_jar.rb +31 -0
- data/lib/chef/rest/rest_request.rb +188 -0
- data/lib/chef/rest.rb +394 -0
- data/lib/chef/role.rb +287 -0
- data/lib/chef/run_context.rb +110 -0
- data/lib/chef/run_list/run_list_expansion.rb +172 -0
- data/lib/chef/run_list/run_list_item.rb +78 -0
- data/lib/chef/run_list.rb +150 -0
- data/lib/chef/run_status.rb +121 -0
- data/lib/chef/runner.rb +107 -0
- data/lib/chef/sandbox.rb +153 -0
- data/lib/chef/search/query.rb +60 -0
- data/lib/chef/shef/ext.rb +568 -0
- data/lib/chef/shef/model_wrapper.rb +120 -0
- data/lib/chef/shef/shef_rest.rb +28 -0
- data/lib/chef/shef/shef_session.rb +271 -0
- data/lib/chef/shef.rb +325 -0
- data/lib/chef/shell_out.rb +413 -0
- data/lib/chef/streaming_cookbook_uploader.rb +201 -0
- data/lib/chef/tasks/chef_repo.rake +256 -0
- data/lib/chef/util/file_edit.rb +122 -0
- data/lib/chef/util/windows/net_group.rb +101 -0
- data/lib/chef/util/windows/net_use.rb +121 -0
- data/lib/chef/util/windows/net_user.rb +198 -0
- data/lib/chef/util/windows/volume.rb +59 -0
- data/lib/chef/util/windows.rb +56 -0
- data/lib/chef/version.rb +21 -0
- data/lib/chef/webui_user.rb +231 -0
- data/lib/chef.rb +39 -0
- metadata +533 -0
data/lib/chef/knife.rb
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
|
3
|
+
# Author:: Christopher Brown (<cb@opscode.com>)
|
|
4
|
+
# Copyright:: Copyright (c) 2009 Opscode, Inc.
|
|
5
|
+
# License:: Apache License, Version 2.0
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require 'chef/version'
|
|
21
|
+
require 'mixlib/cli'
|
|
22
|
+
require 'chef/mixin/convert_to_class_name'
|
|
23
|
+
|
|
24
|
+
require 'pp'
|
|
25
|
+
|
|
26
|
+
class Chef
|
|
27
|
+
class Knife
|
|
28
|
+
include Mixlib::CLI
|
|
29
|
+
extend Chef::Mixin::ConvertToClassName
|
|
30
|
+
|
|
31
|
+
# The "require paths" of the core knife subcommands bundled with chef
|
|
32
|
+
DEFAULT_SUBCOMMAND_FILES = Dir[File.expand_path(File.join(File.dirname(__FILE__), 'knife', '*.rb'))]
|
|
33
|
+
DEFAULT_SUBCOMMAND_FILES.map! { |knife_file| knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/,1] }
|
|
34
|
+
|
|
35
|
+
attr_accessor :name_args
|
|
36
|
+
|
|
37
|
+
def self.msg(msg="")
|
|
38
|
+
puts msg
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.inherited(subclass)
|
|
42
|
+
unless subclass.unnamed?
|
|
43
|
+
subcommands[subclass.snake_case_name] = subclass
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Explicitly set the category for the current command to +new_category+
|
|
48
|
+
# The category is normally determined from the first word of the command
|
|
49
|
+
# name, but some commands make more sense using two or more words
|
|
50
|
+
# ===Arguments
|
|
51
|
+
# new_category::: A String to set the category to (see examples)
|
|
52
|
+
# ===Examples:
|
|
53
|
+
# Data bag commands would be in the 'data' category by default. To put them
|
|
54
|
+
# in the 'data bag' category:
|
|
55
|
+
# category('data bag')
|
|
56
|
+
def self.category(new_category)
|
|
57
|
+
@category = new_category
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.subcommand_category
|
|
61
|
+
@category || snake_case_name.split('_').first unless unnamed?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.snake_case_name
|
|
65
|
+
convert_to_snake_case(name.split('::').last) unless unnamed?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Does this class have a name? (Classes created via Class.new don't)
|
|
69
|
+
def self.unnamed?
|
|
70
|
+
name.nil? || name.empty?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.subcommands
|
|
74
|
+
@@subcommands ||= {}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.subcommands_by_category
|
|
78
|
+
unless @subcommands_by_category
|
|
79
|
+
@subcommands_by_category = Hash.new { |hash, key| hash[key] = [] }
|
|
80
|
+
subcommands.each do |snake_cased, klass|
|
|
81
|
+
@subcommands_by_category[klass.subcommand_category] << snake_cased
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
@subcommands_by_category
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Load all the sub-commands
|
|
88
|
+
def self.load_commands
|
|
89
|
+
DEFAULT_SUBCOMMAND_FILES.each { |subcommand| require subcommand }
|
|
90
|
+
subcommands
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Print the list of subcommands knife knows about. If +preferred_category+
|
|
94
|
+
# is given, only subcommands in that category are shown
|
|
95
|
+
def self.list_commands(preferred_category=nil)
|
|
96
|
+
load_commands
|
|
97
|
+
category_desc = preferred_category ? preferred_category + " " : ''
|
|
98
|
+
msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n"
|
|
99
|
+
|
|
100
|
+
if preferred_category && subcommands_by_category.key?(preferred_category)
|
|
101
|
+
commands_to_show = {preferred_category => subcommands_by_category[preferred_category]}
|
|
102
|
+
else
|
|
103
|
+
commands_to_show = subcommands_by_category
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
commands_to_show.sort.each do |category, commands|
|
|
107
|
+
msg "** #{category.upcase} COMMANDS **"
|
|
108
|
+
commands.each do |command|
|
|
109
|
+
msg subcommands[command].banner if subcommands[command]
|
|
110
|
+
end
|
|
111
|
+
msg
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Run knife for the given +args+ (ARGV), adding +options+ to the list of
|
|
116
|
+
# CLI options that the subcommand knows how to handle.
|
|
117
|
+
# ===Arguments
|
|
118
|
+
# args::: usually ARGV
|
|
119
|
+
# options::: A Mixlib::CLI option parser hash. These +options+ are how
|
|
120
|
+
# subcommands know about global knife CLI options
|
|
121
|
+
def self.run(args, options={})
|
|
122
|
+
load_commands
|
|
123
|
+
subcommand_class = subcommand_class_from(args)
|
|
124
|
+
subcommand_class.options.merge!(options)
|
|
125
|
+
instance = subcommand_class.new(args)
|
|
126
|
+
instance.configure_chef
|
|
127
|
+
instance.run
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.guess_category(args)
|
|
131
|
+
category_words = args.select {|arg| arg =~ /^([[:alnum:]]|_)+$/ }
|
|
132
|
+
matching_category = nil
|
|
133
|
+
while (!matching_category) && (!category_words.empty?)
|
|
134
|
+
candidate_category = category_words.join(' ')
|
|
135
|
+
matching_category = candidate_category if subcommands_by_category.key?(candidate_category)
|
|
136
|
+
matching_category || category_words.pop
|
|
137
|
+
end
|
|
138
|
+
matching_category
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def self.subcommand_class_from(args)
|
|
142
|
+
command_words = args.select {|arg| arg =~ /^([[:alnum:]]|_)+$/ }
|
|
143
|
+
subcommand_class = nil
|
|
144
|
+
|
|
145
|
+
while ( !subcommand_class ) && ( !command_words.empty? )
|
|
146
|
+
snake_case_class_name = command_words.join("_")
|
|
147
|
+
unless subcommand_class = subcommands[snake_case_class_name]
|
|
148
|
+
command_words.pop
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
subcommand_class || subcommand_not_found!(args)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
protected
|
|
155
|
+
|
|
156
|
+
def load_late_dependency(dep, gem_name = nil)
|
|
157
|
+
begin
|
|
158
|
+
require dep
|
|
159
|
+
rescue LoadError
|
|
160
|
+
gem_name ||= dep.gsub('/', '-')
|
|
161
|
+
Chef::Log.fatal "#{gem_name} is not installed. run \"gem install #{gem_name}\" to install it."
|
|
162
|
+
exit 1
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
private
|
|
167
|
+
|
|
168
|
+
# :nodoc:
|
|
169
|
+
# Error out and print usage. probably becuase the arguments given by the
|
|
170
|
+
# user could not be resolved to a subcommand.
|
|
171
|
+
def self.subcommand_not_found!(args)
|
|
172
|
+
unless want_help?(args)
|
|
173
|
+
Chef::Log.fatal("Cannot find sub command for: '#{args.join(' ')}'")
|
|
174
|
+
end
|
|
175
|
+
Chef::Knife.list_commands(guess_category(args))
|
|
176
|
+
exit 10
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# :nodoc:
|
|
180
|
+
# TODO: duplicated with chef/application/knife
|
|
181
|
+
# all logic should be removed from that and Chef::Knife should own it.
|
|
182
|
+
def self.want_help?(args)
|
|
183
|
+
(args.any? { |arg| arg =~ /^(:?(:?\-\-)?help|\-h)$/})
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
public
|
|
187
|
+
|
|
188
|
+
# Create a new instance of the current class configured for the given
|
|
189
|
+
# arguments and options
|
|
190
|
+
def initialize(argv=[])
|
|
191
|
+
super() # having to call super in initialize is the most annoying anti-pattern :(
|
|
192
|
+
|
|
193
|
+
command_name_words = self.class.snake_case_name.split('_')
|
|
194
|
+
|
|
195
|
+
# Mixlib::CLI ignores the embedded name_args
|
|
196
|
+
@name_args = parse_options(argv)
|
|
197
|
+
@name_args.reject! { |name_arg| command_name_words.delete(name_arg) }
|
|
198
|
+
|
|
199
|
+
# knife node run_list add requires that we have extra logic to handle
|
|
200
|
+
# the case that command name words could be joined by an underscore :/
|
|
201
|
+
command_name_words = command_name_words.join('_')
|
|
202
|
+
@name_args.reject! { |name_arg| command_name_words == name_arg }
|
|
203
|
+
|
|
204
|
+
if config[:help]
|
|
205
|
+
msg opt_parser
|
|
206
|
+
exit 1
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def parse_options(args)
|
|
211
|
+
super
|
|
212
|
+
rescue OptionParser::InvalidOption => e
|
|
213
|
+
puts "Error: " + e.to_s
|
|
214
|
+
show_usage
|
|
215
|
+
exit(1)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def ask_question(question, opts={})
|
|
219
|
+
question = question + "[#{opts[:default]}] " if opts[:default]
|
|
220
|
+
|
|
221
|
+
if opts[:default] and config[:defaults]
|
|
222
|
+
|
|
223
|
+
opts[:default]
|
|
224
|
+
|
|
225
|
+
else
|
|
226
|
+
|
|
227
|
+
stdout.print question
|
|
228
|
+
a = stdin.readline.strip
|
|
229
|
+
|
|
230
|
+
if opts[:default]
|
|
231
|
+
a.empty? ? opts[:default] : a
|
|
232
|
+
else
|
|
233
|
+
a
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def configure_chef
|
|
241
|
+
unless config[:config_file]
|
|
242
|
+
full_path = Dir.pwd.split(File::SEPARATOR)
|
|
243
|
+
(full_path.length - 1).downto(0) do |i|
|
|
244
|
+
config_file_to_check = File.join([ full_path[0..i], ".chef", "knife.rb" ].flatten)
|
|
245
|
+
if File.exists?(config_file_to_check)
|
|
246
|
+
config[:config_file] = config_file_to_check
|
|
247
|
+
break
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
# If we haven't set a config yet and $HOME is set, and the home
|
|
251
|
+
# knife.rb exists, use it:
|
|
252
|
+
if (!config[:config_file]) && ENV['HOME'] && File.exist?(File.join(ENV['HOME'], '.chef', 'knife.rb'))
|
|
253
|
+
config[:config_file] = File.join(ENV['HOME'], '.chef', 'knife.rb')
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Don't try to load a knife.rb if it doesn't exist.
|
|
258
|
+
if config[:config_file]
|
|
259
|
+
Chef::Config.from_file(config[:config_file])
|
|
260
|
+
else
|
|
261
|
+
# ...but do log a message if no config was found.
|
|
262
|
+
self.msg("No knife configuration file found")
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
Chef::Config[:log_level] = config[:log_level] if config[:log_level]
|
|
266
|
+
Chef::Config[:log_location] = config[:log_location] if config[:log_location]
|
|
267
|
+
Chef::Config[:node_name] = config[:node_name] if config[:node_name]
|
|
268
|
+
Chef::Config[:client_key] = config[:client_key] if config[:client_key]
|
|
269
|
+
Chef::Config[:chef_server_url] = config[:chef_server_url] if config[:chef_server_url]
|
|
270
|
+
Chef::Log.init(Chef::Config[:log_location])
|
|
271
|
+
Chef::Log.level(Chef::Config[:log_level])
|
|
272
|
+
|
|
273
|
+
Chef::Log.debug("Using configuration from #{config[:config_file]}")
|
|
274
|
+
|
|
275
|
+
if Chef::Config[:node_name].nil?
|
|
276
|
+
raise ArgumentError, "No user specified, pass via -u or specifiy 'node_name' in #{config[:config_file] ? config[:config_file] : "~/.chef/knife.rb"}"
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def pretty_print(data)
|
|
281
|
+
puts data
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def output(data)
|
|
285
|
+
case config[:format]
|
|
286
|
+
when "json", nil
|
|
287
|
+
stdout.puts JSON.pretty_generate(data)
|
|
288
|
+
when "yaml"
|
|
289
|
+
require 'yaml'
|
|
290
|
+
stdout.puts YAML::dump(data)
|
|
291
|
+
when "text"
|
|
292
|
+
# If you were looking for some attribute and there is only one match
|
|
293
|
+
# just dump the attribute value
|
|
294
|
+
if data.length == 1 and config[:attribute]
|
|
295
|
+
stdout.puts data.values[0]
|
|
296
|
+
else
|
|
297
|
+
PP.pp(data, stdout)
|
|
298
|
+
end
|
|
299
|
+
else
|
|
300
|
+
raise ArgumentError, "Unknown output format #{config[:format]}"
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def format_list_for_display(list)
|
|
305
|
+
config[:with_uri] ? list : list.keys.sort { |a,b| a <=> b }
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def format_for_display(item)
|
|
309
|
+
data = item.kind_of?(Chef::DataBagItem) ? item.raw_data : item
|
|
310
|
+
|
|
311
|
+
if config[:attribute]
|
|
312
|
+
config[:attribute].split(".").each do |attr|
|
|
313
|
+
if data.respond_to?(:[])
|
|
314
|
+
data = data[attr]
|
|
315
|
+
elsif data.nil?
|
|
316
|
+
nil # don't get no method error on nil
|
|
317
|
+
else data.respond_to?(attr.to_sym)
|
|
318
|
+
data = data.send(attr.to_sym)
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
{ config[:attribute] => data.kind_of?(Chef::Node::Attribute) ? data.to_hash : data }
|
|
322
|
+
elsif config[:run_list]
|
|
323
|
+
data = data.run_list.run_list
|
|
324
|
+
{ "run_list" => data }
|
|
325
|
+
elsif config[:id_only]
|
|
326
|
+
data.respond_to?(:name) ? data.name : data["id"]
|
|
327
|
+
else
|
|
328
|
+
data
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def edit_data(data, parse_output=true)
|
|
333
|
+
output = JSON.pretty_generate(data)
|
|
334
|
+
|
|
335
|
+
if (!config[:no_editor])
|
|
336
|
+
filename = "knife-edit-"
|
|
337
|
+
0.upto(20) { filename += rand(9).to_s }
|
|
338
|
+
filename << ".js"
|
|
339
|
+
filename = File.join(Dir.tmpdir, filename)
|
|
340
|
+
tf = File.open(filename, "w")
|
|
341
|
+
tf.sync = true
|
|
342
|
+
tf.puts output
|
|
343
|
+
tf.close
|
|
344
|
+
raise "Please set EDITOR environment variable" unless system("#{config[:editor]} #{tf.path}")
|
|
345
|
+
tf = File.open(filename, "r")
|
|
346
|
+
output = tf.gets(nil)
|
|
347
|
+
tf.close
|
|
348
|
+
File.unlink(filename)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
parse_output ? JSON.parse(output) : output
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def confirm(question, append_instructions=true)
|
|
355
|
+
return true if config[:yes]
|
|
356
|
+
|
|
357
|
+
stdout.print question
|
|
358
|
+
stdout.print "? (Y/N) " if append_instructions
|
|
359
|
+
answer = stdin.readline
|
|
360
|
+
answer.chomp!
|
|
361
|
+
case answer
|
|
362
|
+
when "Y", "y"
|
|
363
|
+
true
|
|
364
|
+
when "N", "n"
|
|
365
|
+
self.msg("You said no, so I'm done here.")
|
|
366
|
+
exit 3
|
|
367
|
+
else
|
|
368
|
+
self.msg("I have no idea what to do with #{answer}")
|
|
369
|
+
self.msg("Just say Y or N, please.")
|
|
370
|
+
confirm(question)
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def show_usage
|
|
375
|
+
stdout.puts("USAGE: " + self.opt_parser.to_s)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def load_from_file(klass, from_file, bag=nil)
|
|
379
|
+
relative_path = ""
|
|
380
|
+
if klass == Chef::Role
|
|
381
|
+
relative_path = "roles"
|
|
382
|
+
elsif klass == Chef::Node
|
|
383
|
+
relative_path = "nodes"
|
|
384
|
+
elsif klass == Chef::DataBagItem
|
|
385
|
+
relative_path = "data_bags/#{bag}"
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
relative_file = File.expand_path(File.join(Dir.pwd, relative_path, from_file))
|
|
389
|
+
filename = nil
|
|
390
|
+
|
|
391
|
+
if file_exists_and_is_readable?(from_file)
|
|
392
|
+
filename = from_file
|
|
393
|
+
elsif file_exists_and_is_readable?(relative_file)
|
|
394
|
+
filename = relative_file
|
|
395
|
+
else
|
|
396
|
+
Chef::Log.fatal("Cannot find file #{from_file}")
|
|
397
|
+
exit 30
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
case from_file
|
|
401
|
+
when /\.(js|json)$/
|
|
402
|
+
JSON.parse(IO.read(filename))
|
|
403
|
+
when /\.rb$/
|
|
404
|
+
r = klass.new
|
|
405
|
+
r.from_file(filename)
|
|
406
|
+
r
|
|
407
|
+
else
|
|
408
|
+
Chef::Log.fatal("File must end in .js, .json, or .rb")
|
|
409
|
+
exit 30
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def file_exists_and_is_readable?(file)
|
|
414
|
+
File.exists?(file) && File.readable?(file)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def edit_object(klass, name)
|
|
418
|
+
object = klass.load(name)
|
|
419
|
+
|
|
420
|
+
output = edit_data(object)
|
|
421
|
+
|
|
422
|
+
# Only make the save if the user changed the object.
|
|
423
|
+
#
|
|
424
|
+
# Output JSON for the original (object) and edited (output), then parse
|
|
425
|
+
# them without reconstituting the objects into real classes
|
|
426
|
+
# (create_additions=false). Then, compare the resulting simple objects,
|
|
427
|
+
# which will be Array/Hash/String/etc.
|
|
428
|
+
#
|
|
429
|
+
# We wouldn't have to do these shenanigans if all the editable objects
|
|
430
|
+
# implemented to_hash, or if to_json against a hash returned a string
|
|
431
|
+
# with stable key order.
|
|
432
|
+
object_parsed_again = JSON.parse(object.to_json, :create_additions => false)
|
|
433
|
+
output_parsed_again = JSON.parse(output.to_json, :create_additions => false)
|
|
434
|
+
if object_parsed_again != output_parsed_again
|
|
435
|
+
output.save
|
|
436
|
+
self.msg("Saved #{output}")
|
|
437
|
+
else
|
|
438
|
+
self.msg("Object unchanged, not saving")
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
output(format_for_display(object)) if config[:print_after]
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def create_object(object, pretty_name=nil, &block)
|
|
445
|
+
output = edit_data(object)
|
|
446
|
+
|
|
447
|
+
if Kernel.block_given?
|
|
448
|
+
output = block.call(output)
|
|
449
|
+
else
|
|
450
|
+
output.save
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
pretty_name ||= output
|
|
454
|
+
|
|
455
|
+
self.msg("Created (or updated) #{pretty_name}")
|
|
456
|
+
|
|
457
|
+
output(output) if config[:print_after]
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def delete_object(klass, name, delete_name=nil, &block)
|
|
461
|
+
confirm("Do you really want to delete #{name}")
|
|
462
|
+
|
|
463
|
+
if Kernel.block_given?
|
|
464
|
+
object = block.call
|
|
465
|
+
else
|
|
466
|
+
object = klass.load(name)
|
|
467
|
+
object.destroy
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
output(format_for_display(object)) if config[:print_after]
|
|
471
|
+
|
|
472
|
+
obj_name = delete_name ? "#{delete_name}[#{name}]" : object
|
|
473
|
+
self.msg("Deleted #{obj_name}!")
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
def bulk_delete(klass, fancy_name, delete_name=nil, list=nil, regex=nil, &block)
|
|
477
|
+
object_list = list ? list : klass.list(true)
|
|
478
|
+
|
|
479
|
+
if regex
|
|
480
|
+
to_delete = Hash.new
|
|
481
|
+
object_list.each_key do |object|
|
|
482
|
+
next if regex && object !~ /#{regex}/
|
|
483
|
+
to_delete[object] = object_list[object]
|
|
484
|
+
end
|
|
485
|
+
else
|
|
486
|
+
to_delete = object_list
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
output(format_list_for_display(to_delete))
|
|
490
|
+
|
|
491
|
+
confirm("Do you really want to delete the above items")
|
|
492
|
+
|
|
493
|
+
to_delete.each do |name, object|
|
|
494
|
+
if Kernel.block_given?
|
|
495
|
+
block.call(name, object)
|
|
496
|
+
else
|
|
497
|
+
object.destroy
|
|
498
|
+
end
|
|
499
|
+
output(format_for_display(object)) if config[:print_after]
|
|
500
|
+
self.msg("Deleted #{fancy_name} #{name}")
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def msg(message)
|
|
505
|
+
stdout.puts message
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def stdout
|
|
509
|
+
STDOUT
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
def stdin
|
|
513
|
+
STDIN
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
def rest
|
|
517
|
+
@rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
|