class Chef::Knife::ContainerDockerBuild

Public Instance Methods

berksfile_exists?() click to toggle source

Determines whether a Berksfile exists in the Docker context

@returns [TrueClass, FalseClass]

# File lib/chef/knife/container_docker_build.rb, line 133
def berksfile_exists?
  File.exists?(File.join(docker_context, "Berksfile"))
end
build_image() click to toggle source

Builds the Docker image

# File lib/chef/knife/container_docker_build.rb, line 176
def build_image
  run_command(docker_build_command)
end
chef_repo() click to toggle source

Returns the path to the chef-repo inside the Docker Context

@return [String]

# File lib/chef/knife/container_docker_build.rb, line 223
def chef_repo
  File.join(docker_context, "chef")
end
cleanup_artifacts() click to toggle source

Cleanup build artifacts

# File lib/chef/knife/container_docker_build.rb, line 183
def cleanup_artifacts
  unless config[:local_mode]
    destroy_item(Chef::Node, node_name, "node")
    destroy_item(Chef::ApiClient, node_name, "client")
  end
end
destroy_item(klass, name, type_name) click to toggle source

Extracted from Chef::Knife.delete_object, because it has a confirmation step built in… By not specifying the '–no-cleanup' flag the user is already making their intent known. It is not necessary to make them confirm two more times.

# File lib/chef/knife/container_docker_build.rb, line 240
def destroy_item(klass, name, type_name)
  begin
    object = klass.load(name)
    object.destroy
    ui.warn("Deleted #{type_name} #{name}")
  rescue Net::HTTPServerException
    ui.warn("Could not find a #{type_name} named #{name} to delete!")
  end
end
docker_build_command() click to toggle source

The command to use to build the Docker image

# File lib/chef/knife/container_docker_build.rb, line 193
def docker_build_command
  "docker build -t #{@name_args[0]} #{docker_context}"
end
docker_context() click to toggle source

Returns the path to the Docker Context

@return [String]

# File lib/chef/knife/container_docker_build.rb, line 214
def docker_context
  File.join(config[:dockerfiles_path], @name_args[0])
end
node_name() click to toggle source

Generates a node name for the Docker container

@return [String]

# File lib/chef/knife/container_docker_build.rb, line 232
def node_name
  File.read(File.join(chef_repo, ".node_name")).strip
end
read_and_validate_params() click to toggle source

Reads the input parameters and validates them. Will exit if it encounters an error

# File lib/chef/knife/container_docker_build.rb, line 75
def read_and_validate_params
  if @name_args.length < 1
    show_usage
    ui.fatal("You must specify a Dockerfile name")
    exit 1
  end

  # if berkshelf isn't installed, set run_berks to false
  if config[:run_berks]
    ver = shell_out("berks -v")
    config[:run_berks] = ver.stdout.match(/\d+\.\d+\.\d+/) ? true : false

    if config[:berks_config]
      unless File.exists?(config[:berks_config])
        ui.fatal("No Berksfile configuration found at #{config[:berks_config]}")
        exit 1
      end
    end
  end
end
run() click to toggle source

Run the plugin

# File lib/chef/knife/container_docker_build.rb, line 63
def run
  read_and_validate_params
  setup_config_defaults
  run_berks if config[:run_berks]
  build_image
  cleanup_artifacts if config[:cleanup]
end
run_berks() click to toggle source

Execute berkshelf locally

# File lib/chef/knife/container_docker_build.rb, line 118
def run_berks
  if File.exists?(File.join(docker_context, "Berksfile"))
    if File.exists?(File.join(chef_repo, "zero.rb"))
      run_berks_vendor
    elsif File.exists?(File.join(chef_repo, "client.rb"))
      run_berks_upload
    end
  end
end
run_berks_install() click to toggle source

Installs all the cookbooks via Berkshelf

# File lib/chef/knife/container_docker_build.rb, line 140
def run_berks_install
  run_command("berks install")
end
run_berks_upload() click to toggle source

Upload the cookbooks to the Chef Server

# File lib/chef/knife/container_docker_build.rb, line 165
def run_berks_upload
  run_berks_install
  berks_upload_cmd = "berks upload"
  berks_upload_cmd << " --force" if config[:force_build]
  berks_upload_cmd << " --config=#{File.expand_path(config[:berks_config])}" if config[:berks_config]
  run_command(berks_upload_cmd)
end
run_berks_vendor() click to toggle source

Vendors all the cookbooks into a directory inside the Docker Context

# File lib/chef/knife/container_docker_build.rb, line 147
def run_berks_vendor
  if File.exists?(File.join(chef_repo, "cookbooks"))
    if config[:force_build]
      FileUtils.rm_rf(File.join(chef_repo, "cookbooks"))
    else
      show_usage
      ui.fatal("A `cookbooks` directory already exists. You must either remove this directory from your dockerfile directory or use the `force` flag")
      exit 1
    end
  end

  run_berks_install
  run_command("berks vendor #{chef_repo}/cookbooks")
end
run_command(cmd) click to toggle source

Run a shell command from the Docker Context directory

# File lib/chef/knife/container_docker_build.rb, line 200
def run_command(cmd)
  Open3.popen2e(cmd, chdir: docker_context) do |stdin, stdout_err, wait_thr|
    while line = stdout_err.gets
      puts line
    end
    wait_thr.value.to_i
  end
end
setup_config_defaults() click to toggle source

Set defaults for configuration values

# File lib/chef/knife/container_docker_build.rb, line 99
def setup_config_defaults
  config[:dockerfiles_path] ||= Chef::Config[:knife][:dockerfiles_path] || File.join(Chef::Config[:chef_repo_path], 'dockerfiles')

  # Determine if we are running local or server mode
  case
  when File.exists?(File.join(config[:dockerfiles_path], @name_args[0], 'chef', 'zero.rb'))
    config[:local_mode] = true
  when File.exists?(File.join(config[:dockerfiles_path], @name_args[0], 'chef', 'client.rb'))
    config[:local_mode] = false
  else
    show_usage
    ui.fatal("Can not find a Chef configuration file in #{config[:dockerfiles_path]}/#{@name_args[0]}/chef")
    exit 1
  end
end