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)


124
125
126
# File 'lib/chef/knife/container_docker_build.rb', line 124

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

#build_imageObject

Builds the Docker image



168
169
170
# File 'lib/chef/knife/container_docker_build.rb', line 168

def build_image
  run_command(docker_build_command)
end

#chef_repoString

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

Returns:

  • (String)


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

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

#cleanup_artifactsObject

Cleanup build artifacts



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

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.



232
233
234
235
236
237
238
239
240
# File 'lib/chef/knife/container_docker_build.rb', line 232

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



185
186
187
# File 'lib/chef/knife/container_docker_build.rb', line 185

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

#docker_contextString

Returns the path to the Docker Context

Returns:

  • (String)


206
207
208
# File 'lib/chef/knife/container_docker_build.rb', line 206

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

#node_nameString

Generates a node name for the Docker container

Returns:

  • (String)


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

def node_name
  "#{@name_args[0].gsub('/','-')}-build"
end

#read_and_validate_paramsObject

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



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/chef/knife/container_docker_build.rb', line 72

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
  end
end

#runObject

Run the plugin



60
61
62
63
64
65
66
# File 'lib/chef/knife/container_docker_build.rb', line 60

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



109
110
111
112
113
114
115
116
117
# File 'lib/chef/knife/container_docker_build.rb', line 109

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



131
132
133
# File 'lib/chef/knife/container_docker_build.rb', line 131

def run_berks_install
  run_command("berks install")
end

#run_berks_uploadObject

Upload the cookbooks to the Chef Server



156
157
158
159
160
161
162
163
# File 'lib/chef/knife/container_docker_build.rb', line 156

def run_berks_upload
  run_berks_install
  if config[:force_build]
    run_command("berks upload --force")
  else
    run_command("berks upload")
  end
end

#run_berks_vendorObject

Vendors all the cookbooks into a directory inside the Docker Context



138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/chef/knife/container_docker_build.rb', line 138

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



192
193
194
195
196
197
198
199
# File 'lib/chef/knife/container_docker_build.rb', line 192

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



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/chef/knife/container_docker_build.rb', line 89

def setup_config_defaults
  Chef::Config[:knife][:dockerfiles_path] ||= File.join(Chef::Config[:chef_repo_path], "dockerfiles")
  config[:dockerfiles_path] = Chef::Config[:knife][:dockerfiles_path]

  # 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