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



135
136
137
# File 'lib/chef/knife/container_docker_build.rb', line 135

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

#build_imageObject

Builds the Docker image



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

def build_image
  run_command(docker_build_command)
end

#chef_repoString

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



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

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

#cleanup_artifactsObject

Cleanup build artifacts



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

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.



242
243
244
245
246
247
248
249
250
# File 'lib/chef/knife/container_docker_build.rb', line 242

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



195
196
197
# File 'lib/chef/knife/container_docker_build.rb', line 195

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

#docker_contextString

Returns the path to the Docker Context



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

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

#node_nameString

Generates a node name for the Docker container



234
235
236
# File 'lib/chef/knife/container_docker_build.rb', line 234

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



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/chef/knife/container_docker_build.rb', line 76

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



64
65
66
67
68
69
70
# File 'lib/chef/knife/container_docker_build.rb', line 64

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



120
121
122
123
124
125
126
127
128
# File 'lib/chef/knife/container_docker_build.rb', line 120

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



142
143
144
# File 'lib/chef/knife/container_docker_build.rb', line 142

def run_berks_install
  run_command("berks install")
end

#run_berks_uploadObject

Upload the cookbooks to the Chef Server



167
168
169
170
171
172
173
# File 'lib/chef/knife/container_docker_build.rb', line 167

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



149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/chef/knife/container_docker_build.rb', line 149

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



202
203
204
205
206
207
208
209
# File 'lib/chef/knife/container_docker_build.rb', line 202

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



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/chef/knife/container_docker_build.rb', line 100

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