class Chef::Knife::CookbookUpload

Constants

CHECKSUM
MATCH_CHECKSUM

Public Instance Methods

cookbook_repo() click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 187
def cookbook_repo
  @cookbook_loader ||= begin
    Chef::Cookbook::FileVendor.fetch_from_disk(config[:cookbook_path])
    Chef::CookbookLoader.new(config[:cookbook_path])
  end
end
cookbooks_to_upload() click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 164
def cookbooks_to_upload
  @cookbooks_to_upload ||=
    if config[:all]
      cookbook_repo.load_cookbooks_without_shadow_warning
    else
      upload_set = {}
      @name_args.each do |cookbook_name|
        begin
          if ! upload_set.has_key?(cookbook_name)
            upload_set[cookbook_name] = cookbook_repo[cookbook_name]
            if config[:depends]
              upload_set[cookbook_name].metadata.dependencies.each_key { |dep| @name_args << dep }
            end
          end
        rescue Exceptions::CookbookNotFoundInRepo => e
          ui.error("Could not find cookbook #{cookbook_name} in your cookbook path, skipping it")
          Log.debug(e)
        end
      end
      upload_set
    end
end
environment() click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 201
def environment
  @environment ||= config[:environment] ? Environment.load(config[:environment]) : nil
end
run() click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 77
def run
  # Sanity check before we load anything from the server
  unless config[:all]
    if @name_args.empty?
      show_usage
      ui.fatal("You must specify the --all flag or at least one cookbook name")
      exit 1
    end
  end

  config[:cookbook_path] ||= Chef::Config[:cookbook_path]

  if @name_args.empty? && ! config[:all]
    show_usage
    ui.fatal("You must specify the --all flag or at least one cookbook name")
    exit 1
  end

  assert_environment_valid!
  warn_about_cookbook_shadowing
  version_constraints_to_update = {}
  upload_failures = 0
  upload_ok = 0

  # Get a list of cookbooks and their versions from the server
  # to check for the existence of a cookbook's dependencies.
  @server_side_cookbooks = Chef::CookbookVersion.list_all_versions
  justify_width = @server_side_cookbooks.map { |name| name.size }.max.to_i + 2
  if config[:all]
    cookbook_repo.load_cookbooks_without_shadow_warning
    cookbooks_for_upload = []
    cookbook_repo.each do |cookbook_name, cookbook|
      cookbooks_for_upload << cookbook
      cookbook.freeze_version if config[:freeze]
      version_constraints_to_update[cookbook_name] = cookbook.version
    end
    if cookbooks_for_upload.any?
      begin
        upload(cookbooks_for_upload, justify_width)
      rescue Exceptions::CookbookFrozen
        ui.warn("Not updating version constraints for some cookbooks in the environment as the cookbook is frozen.")
      end
      ui.info("Uploaded all cookbooks.")
    else
      cookbook_path = config[:cookbook_path].respond_to?(:join) ? config[:cookbook_path].join(", ") : config[:cookbook_path]
      ui.warn("Could not find any cookbooks in your cookbook path: #{cookbook_path}. Use --cookbook-path to specify the desired path.")
    end
  else
    if @name_args.empty?
      show_usage
      ui.error("You must specify the --all flag or at least one cookbook name")
      exit 1
    end

    cookbooks_to_upload.each do |cookbook_name, cookbook|
      cookbook.freeze_version if config[:freeze]
      begin
        upload([cookbook], justify_width)
        upload_ok += 1
        version_constraints_to_update[cookbook_name] = cookbook.version
      rescue Exceptions::CookbookNotFoundInRepo => e
        upload_failures += 1
        ui.error("Could not find cookbook #{cookbook_name} in your cookbook path, skipping it")
        Log.debug(e)
        upload_failures += 1
      rescue Exceptions::CookbookFrozen
        ui.warn("Not updating version constraints for #{cookbook_name} in the environment as the cookbook is frozen.")
        upload_failures += 1
      end
    end

    if upload_failures == 0
      ui.info "Uploaded #{upload_ok} cookbook#{upload_ok == 1 ? "" : "s"}."
    elsif upload_failures > 0 && upload_ok > 0
      ui.warn "Uploaded #{upload_ok} cookbook#{upload_ok == 1 ? "" : "s"} ok but #{upload_failures} " +
        "cookbook#{upload_failures == 1 ? "" : "s"} upload failed."
    elsif upload_failures > 0 && upload_ok == 0
      ui.error "Failed to upload #{upload_failures} cookbook#{upload_failures == 1 ? "" : "s"}."
      exit 1
    end
  end

  unless version_constraints_to_update.empty?
    update_version_constraints(version_constraints_to_update) if config[:environment]
  end
end
update_version_constraints(new_version_constraints) click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 194
def update_version_constraints(new_version_constraints)
  new_version_constraints.each do |cookbook_name, version|
    environment.cookbook_versions[cookbook_name] = "= #{version}"
  end
  environment.save
end
warn_about_cookbook_shadowing() click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 205
      def warn_about_cookbook_shadowing
        # because cookbooks are lazy-loaded, we have to force the loader
        # to load the cookbooks the user intends to upload here:
        cookbooks_to_upload

        unless cookbook_repo.merged_cookbooks.empty?
          ui.warn "* " * 40
          ui.warn(<<-WARNING)
The cookbooks: #{cookbook_repo.merged_cookbooks.join(', ')} exist in multiple places in your cookbook_path.
A composite version of these cookbooks has been compiled for uploading.

#{ui.color('IMPORTANT:', :red, :bold)} In a future version of Chef, this behavior will be removed and you will no longer
be able to have the same version of a cookbook in multiple places in your cookbook_path.
WARNING
          ui.warn "The affected cookbooks are located:"
          ui.output ui.format_for_display(cookbook_repo.merged_cookbook_paths)
          ui.warn "* " * 40
        end
      end

Private Instance Methods

assert_environment_valid!() click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 227
def assert_environment_valid!
  environment
rescue Net::HTTPServerException => e
  if e.response.code.to_s == "404"
    ui.error "The environment #{config[:environment]} does not exist on the server, aborting."
    Log.debug(e)
    exit 1
  else
    raise
  end
end
check_for_dependencies!(cookbook) click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 267
def check_for_dependencies!(cookbook)
  # for all dependencies, check if the version is on the server, or
  # the version is in the cookbooks being uploaded. If not, exit and warn the user.
  missing_dependencies = cookbook.metadata.dependencies.reject do |cookbook_name, version|
    check_server_side_cookbooks(cookbook_name, version) || check_uploading_cookbooks(cookbook_name, version)
  end

  unless missing_dependencies.empty?
    missing_cookbook_names = missing_dependencies.map { |cookbook_name, version| "'#{cookbook_name}' version '#{version}'" }
    ui.error "Cookbook #{cookbook.name} depends on cookbooks which are not currently"
    ui.error "being uploaded and cannot be found on the server."
    ui.error "The missing cookbook(s) are: #{missing_cookbook_names.join(', ')}"
    exit 1
  end
end
check_server_side_cookbooks(cookbook_name, version) click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 283
def check_server_side_cookbooks(cookbook_name, version)
  if @server_side_cookbooks[cookbook_name].nil?
    false
  else
    versions = @server_side_cookbooks[cookbook_name]["versions"].collect { |versions| versions["version"] }
    Log.debug "Versions of cookbook '#{cookbook_name}' returned by the server: #{versions.join(", ")}"
    @server_side_cookbooks[cookbook_name]["versions"].each do |versions_hash|
      if Chef::VersionConstraint.new(version).include?(versions_hash["version"])
        Log.debug "Matched cookbook '#{cookbook_name}' with constraint '#{version}' to cookbook version '#{versions_hash['version']}' on the server"
        return true
      end
    end
    false
  end
end
check_uploading_cookbooks(cookbook_name, version) click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 299
def check_uploading_cookbooks(cookbook_name, version)
  if (! cookbooks_to_upload[cookbook_name].nil?) && Chef::VersionConstraint.new(version).include?(cookbooks_to_upload[cookbook_name].version)
    Log.debug "Matched cookbook '#{cookbook_name}' with constraint '#{version}' to a local cookbook."
    return true
  end
  false
end
upload(cookbooks, justify_width) click to toggle source
# File lib/chef/knife/cookbook_upload.rb, line 239
def upload(cookbooks, justify_width)
  cookbooks.each do |cb|
    ui.info("Uploading #{cb.name.to_s.ljust(justify_width + 10)} [#{cb.version}]")
    check_for_broken_links!(cb)
    check_for_dependencies!(cb)
  end
  Chef::CookbookUploader.new(cookbooks, :force => config[:force], :concurrency => config[:concurrency]).upload_cookbooks
rescue Chef::Exceptions::CookbookFrozen => e
  ui.error e
  raise
end