Class: Chef::Knife::ContainerDockerBuild

Inherits:
Chef::Knife show all
Includes:
Mixin::ShellOut
Defined in:
lib/chef/knife/container_docker_build.rb

Instance Method Summary collapse

Instance Method Details

#berksfile_exists?Boolean

Determines whether a Berksfile exists in the Docker context

Returns:

  • (Boolean)


133
134
135
# File 'lib/chef/knife/container_docker_build.rb', line 133

def berksfile_exists?
  File.exists?(File.join(docker_context, "Berksfile"))
end

#build_imageObject

Builds the Docker image



176
177
178
# File 'lib/chef/knife/container_docker_build.rb', line 176

def build_image
  run_command(docker_build_command)
end

#chef_repoString

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

Returns:

  • (String)


223
224
225
# File 'lib/chef/knife/container_docker_build.rb', line 223

def chef_repo
  File.join(docker_context, "chef")
end

#cleanup_artifactsObject

Cleanup build artifacts



183
184
185
186
187
188
# 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) ⇒ Object

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.



240
241
242
243
244
245
246
247
248
# 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_commandObject

The command to use to build the Docker image



193
194
195
# File 'lib/chef/knife/container_docker_build.rb', line 193

def docker_build_command
  "docker build -t #{@name_args[0]} #{docker_context}"
end

#docker_contextString

Returns the path to the Docker Context

Returns:

  • (String)


214
215
216
# File 'lib/chef/knife/container_docker_build.rb', line 214

def docker_context
  File.join(config[:dockerfiles_path], @name_args[0])
end

#node_nameString

Generates a node name for the Docker container

Returns:

  • (String)


232
233
234
# 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_paramsObject

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



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# 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

#runObject

Run the plugin



63
64
65
66
67
68
69
# 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_berksObject

Execute berkshelf locally



118
119
120
121
122
123
124
125
126
# 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_installObject

Installs all the cookbooks via Berkshelf



140
141
142
# File 'lib/chef/knife/container_docker_build.rb', line 140

def run_berks_install
  run_command("berks install")
end

#run_berks_uploadObject

Upload the cookbooks to the Chef Server



165
166
167
168
169
170
171
# 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_vendorObject

Vendors all the cookbooks into a directory inside the Docker Context



147
148
149
150
151
152
153
154
155
156
157
158
159
160
# 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) ⇒ Object

Run a shell command from the Docker Context directory



200
201
202
203
204
205
206
207
# 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_defaultsObject

Set defaults for configuration values



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# 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