Module: Source::Install

Defined in:
lib/source_install.rb

Overview

This module implements helpers that are used for resources

Constant Summary collapse

VERSION =
'1.0.1'

Instance Method Summary collapse

Instance Method Details

#archive_file_name(_new_resource) ⇒ Object



20
21
22
23
24
# File 'lib/source_install.rb', line 20

def archive_file_name(_new_resource)
  # noinspection RubyExpressionInStringInspection
  raise NotImplementedError('Client must indicate the filename of the what the archive file \
that will be downloaded, e.g. "#{base_name(new_resource)}-#{new_resource.version}.tar.gz"')
end

#archive_root_directory(_new_resource) ⇒ Object



31
32
33
34
35
# File 'lib/source_install.rb', line 31

def archive_root_directory(_new_resource)
  # noinspection RubyExpressionInStringInspection
  raise NotImplementedError('Client must indicate the directory created by extraction, \
e.g. "#{base_name(new_resource)}-#{new_resource.version}". This will be used as the build directory.')
end

#base_name(_new_resource) ⇒ Object

Hooks for install



11
12
13
14
# File 'lib/source_install.rb', line 11

def base_name(_new_resource)
  raise NotImplementedError('Client must define base application name e.g. "Python". \
This is frequently used to build e.g. archive file name and will be used to define default directories.')
end

#build_binary(build_directory, new_resource) ⇒ Object



328
329
330
331
332
333
# File 'lib/source_install.rb', line 328

def build_binary(build_directory, new_resource)
  ensure_install_directory(new_resource)
  configure_build(build_directory, new_resource)
  compile_and_install(build_directory, new_resource)
  post_install_logic(new_resource)
end

#build_permission_command(new_resource) ⇒ Object



284
285
286
287
288
289
290
291
292
293
# File 'lib/source_install.rb', line 284

def build_permission_command(new_resource)
  ruby_block 'Build Children' do
    block do
      files = iterate_install_directory(new_resource)
      node.run_state['build_permission_command'] = files
    end
    action :nothing
    subscribes :run, 'bash[Install]', :immediate
  end
end

#check_build_directory(build_directory, new_resource) ⇒ Object



228
229
230
231
232
233
# File 'lib/source_install.rb', line 228

def check_build_directory(build_directory, new_resource)
  checksum_file 'Source Checksum' do
    source_path build_directory
    target_path "/var/chef/cache/#{base_name(new_resource).downcase}-#{new_resource.version}-src-checksum"
  end
end

#clear_source_directory(build_directory, new_resource) ⇒ Object



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

def clear_source_directory(build_directory, new_resource)
  dir = build_directory
  bash 'Clear Archive' do
    code "rm -rf #{dir}\nmkdir #{dir}\nchown #{new_resource.owner}:#{new_resource.group} #{dir}"
    # Run as root so we blow it away if the owner changes
    action :nothing
    subscribes :run, 'checksum_file[Download Checksum]', :immediate
  end
end

#code_for_extraction(download_file, build_directory, new_resource) ⇒ Object



146
147
148
149
150
151
152
# File 'lib/source_install.rb', line 146

def code_for_extraction(download_file, build_directory, new_resource)
  code = <<~CODE
    #{extract_command(download_file)} #{download_file}
    chown -R #{new_resource.owner}:#{new_resource.group} #{build_directory}
  CODE
  return code
end

#command_for_file(filename, new_resource) ⇒ Object



268
269
270
271
272
# File 'lib/source_install.rb', line 268

def command_for_file(filename, new_resource)
  path = File.join(new_resource.install_directory, filename)
  recurse = recurse_command(path)
  return "\nchown#{recurse} #{new_resource.owner}:#{new_resource.group} #{path}"
end

#compile_and_install(build_directory, new_resource) ⇒ Object



321
322
323
324
325
326
# File 'lib/source_install.rb', line 321

def compile_and_install(build_directory, new_resource)
  check_build_directory(build_directory, new_resource)
  bin_file = File.join(new_resource.install_directory, install_creates_file(new_resource))
  manage_bin_file(bin_file)
  make_build(build_directory, bin_file, new_resource)
end

#configuration_command(_new_resource) ⇒ Object



42
43
44
45
# File 'lib/source_install.rb', line 42

def configuration_command(_new_resource)
  raise NotImplementedError('Client must define the configuration command to be run before build, \
e.g. "./config shared --prefix..."')
end

#configure_build(build_directory, new_resource) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
# File 'lib/source_install.rb', line 216

def configure_build(build_directory, new_resource)
  code = configuration_command(new_resource)
  makefile = manage_make_file(build_directory, code, new_resource)
  bash 'Configure Build' do
    code code
    cwd build_directory
    user new_resource.owner
    group new_resource.group
    creates makefile
  end
end

#create_default_directoriesObject



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/source_install.rb', line 75

def create_default_directories
  directory '/var/chef' do
    mode 0o755
    owner 'root'
    group 'root'
  end
  directory '/var/chef/cache' do
    mode 0o755
    owner 'root'
    group 'root'
  end
end

#create_install(new_resource) ⇒ Object



335
336
337
338
339
340
# File 'lib/source_install.rb', line 335

def create_install(new_resource)
  ensure_version(new_resource)
  build_directory = path_to_build_directory(new_resource)
  extract_archive(build_directory, new_resource)
  build_binary(build_directory, new_resource)
end

#create_opt_directories(new_resource) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/source_install.rb', line 176

def create_opt_directories(new_resource)
  directory "/opt/#{base_name(new_resource).downcase}" do
    mode 0o755
    owner 'root'
    group 'root'
  end
  directory default_install_directory(new_resource) do
    mode 0o755
    owner 'root'
    group 'root'
  end
end

#default_install_directory(new_resource) ⇒ Object



172
173
174
# File 'lib/source_install.rb', line 172

def default_install_directory(new_resource)
  return "/opt/#{base_name(new_resource).downcase}/#{new_resource.version}"
end

#default_version(_new_resource) ⇒ Object



16
17
18
# File 'lib/source_install.rb', line 16

def default_version(_new_resource)
  raise NotImplementedError('Client must provide a default version string e.g. "1.1.4".')
end

#download_archive(new_resource) ⇒ Object



101
102
103
104
105
106
107
108
109
110
# File 'lib/source_install.rb', line 101

def download_archive(new_resource)
  download_file = path_to_download_file(new_resource)
  url = download_url(new_resource)
  remote_file download_file do
    source url
    owner new_resource.owner
    group new_resource.group
  end
  return download_file
end

#download_base_url(_new_resource) ⇒ Object



26
27
28
29
# File 'lib/source_install.rb', line 26

def download_base_url(_new_resource)
  raise NotImplementedError('Client must indicate the URL at which the archive file is located, \
e.g. "https://www.oss-project.org/source"')
end

#download_url(new_resource) ⇒ Object



68
69
70
71
72
73
# File 'lib/source_install.rb', line 68

def download_url(new_resource)
  url = download_base_url(new_resource)
  url += '/' unless url.match?(%r{/$})
  url += archive_file_name(new_resource)
  return url
end

#ensure_install_directory(new_resource) ⇒ Object



189
190
191
192
193
194
# File 'lib/source_install.rb', line 189

def ensure_install_directory(new_resource)
  return if new_resource.install_directory

  create_opt_directories(new_resource)
  new_resource.install_directory = default_install_directory(new_resource)
end

#ensure_version(new_resource) ⇒ Object

Common install code



62
63
64
65
66
# File 'lib/source_install.rb', line 62

def ensure_version(new_resource)
  return if new_resource.version

  new_resource.version = default_version(new_resource)
end

#execute_build(build_directory, bin_file, new_resource) ⇒ Object



243
244
245
246
247
248
249
250
251
# File 'lib/source_install.rb', line 243

def execute_build(build_directory, bin_file, new_resource)
  bash 'Compile' do
    code 'make'
    cwd build_directory
    user new_resource.owner
    group new_resource.group
    creates bin_file
  end
end

#execute_install(build_directory, bin_file, new_resource) ⇒ Object



253
254
255
256
257
258
259
260
# File 'lib/source_install.rb', line 253

def execute_install(build_directory, bin_file, new_resource)
  bash 'Install' do
    code install_command(new_resource)
    cwd build_directory
    # Run as root in case it is installing in directory without write access
    creates bin_file
  end
end

#extract_archive(build_directory, new_resource) ⇒ Object



166
167
168
169
170
# File 'lib/source_install.rb', line 166

def extract_archive(build_directory, new_resource)
  download_file = download_archive(new_resource)
  manage_source_directory(download_file, build_directory, new_resource)
  extract_download(download_file, build_directory, new_resource)
end

#extract_command(filename) ⇒ Object



138
139
140
141
142
143
144
# File 'lib/source_install.rb', line 138

def extract_command(filename)
  return 'unzip -q' if filename.match?(/\.zip/)

  return 'tar xzf' if filename.match?(/\.(:?tar\.gz|tgz)/)

  raise "Archive not supported: #{filename}"
end

#extract_creates_file(_new_resource) ⇒ Object



37
38
39
40
# File 'lib/source_install.rb', line 37

def extract_creates_file(_new_resource)
  raise NotImplementedError('Client must indicate a relative path to a file that is created by extraction, \
e.g. "README.md"')
end

#extract_download(download_file, build_directory, new_resource) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
# File 'lib/source_install.rb', line 154

def extract_download(download_file, build_directory, new_resource)
  # Built-in archive_file requires Chef 15 and poise_archive is failing to exhibit idempotence on zip files
  parent = File.dirname(build_directory)
  code = code_for_extraction(download_file, build_directory, new_resource)
  bash 'Extract Archive' do
    code code
    cwd parent
    # Run as root in case it is installing in directory without write access
    creates File.join(build_directory, extract_creates_file(new_resource))
  end
end

#install_command(_new_resource) ⇒ Object



52
53
54
# File 'lib/source_install.rb', line 52

def install_command(_new_resource)
  raise NotImplementedError('Client must define the command for installation, e.g. "make install"')
end

#install_creates_file(_new_resource) ⇒ Object



47
48
49
50
# File 'lib/source_install.rb', line 47

def install_creates_file(_new_resource)
  raise NotImplementedError('Client must indicate a relative path to a file that is created by installation, \
e.g. "bin/my_app"')
end

#iterate_install_directory(new_resource) ⇒ Object



274
275
276
277
278
279
280
281
282
# File 'lib/source_install.rb', line 274

def iterate_install_directory(new_resource)
  command = ''
  Dir.foreach(new_resource.install_directory) do |filename|
    next if ['.', '..'].include?(filename)

    command += command_for_file(filename, new_resource)
  end
  return command
end

#make_build(build_directory, bin_file, new_resource) ⇒ Object



315
316
317
318
319
# File 'lib/source_install.rb', line 315

def make_build(build_directory, bin_file, new_resource)
  execute_build(build_directory, bin_file, new_resource)
  execute_install(build_directory, bin_file, new_resource)
  set_install_permissions(build_directory, new_resource)
end

#manage_bin_file(bin_file) ⇒ Object



235
236
237
238
239
240
241
# File 'lib/source_install.rb', line 235

def manage_bin_file(bin_file)
  file bin_file do
    action :nothing
    manage_symlink_source false
    subscribes :delete, 'checksum_file[Source Checksum]', :immediate
  end
end

#manage_make_file(build_directory, code, new_resource) ⇒ Object



206
207
208
209
210
211
212
213
214
# File 'lib/source_install.rb', line 206

def manage_make_file(build_directory, code, new_resource)
  save_config(code, new_resource)
  makefile = File.join(build_directory, 'Makefile')
  file makefile do
    action :nothing
    subscribes :delete, 'file[Config File]', :immediate
  end
  return makefile
end

#manage_source_directory(download_file, build_directory, new_resource) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/source_install.rb', line 130

def manage_source_directory(download_file, build_directory, new_resource)
  checksum_file 'Download Checksum' do
    source_path download_file
    target_path "/var/chef/cache/#{base_name(new_resource).downcase}-#{new_resource.version}-dl-checksum"
  end
  clear_source_directory(build_directory, new_resource)
end

#path_to_build_directory(new_resource) ⇒ Object



112
113
114
115
116
117
118
# File 'lib/source_install.rb', line 112

def path_to_build_directory(new_resource)
  base = archive_root_directory(new_resource)
  return File.join(new_resource.build_directory, base) if new_resource.build_directory

  create_default_directories
  return File.join('/var/chef/cache', base)
end

#path_to_download_directory(new_resource) ⇒ Object



88
89
90
91
92
93
# File 'lib/source_install.rb', line 88

def path_to_download_directory(new_resource)
  return new_resource.download_directory if new_resource.download_directory

  create_default_directories
  return '/var/chef/cache'
end

#path_to_download_file(new_resource) ⇒ Object



95
96
97
98
99
# File 'lib/source_install.rb', line 95

def path_to_download_file(new_resource)
  directory = path_to_download_directory(new_resource)
  file = File.join(directory, archive_file_name(new_resource))
  return file
end

#post_install_logic(_new_resource) ⇒ Object



56
57
58
# File 'lib/source_install.rb', line 56

def post_install_logic(_new_resource)
  raise NotImplementedError('Client must define logic to run after installation, for example to creating symlinks')
end

#recurse_command(path) ⇒ Object



262
263
264
265
266
# File 'lib/source_install.rb', line 262

def recurse_command(path)
  return ' -R' if File.directory?(path)

  return ''
end

#save_config(code, new_resource) ⇒ Object



196
197
198
199
200
201
202
203
204
# File 'lib/source_install.rb', line 196

def save_config(code, new_resource)
  file 'Config File' do
    path "/var/chef/cache/#{base_name(new_resource).downcase}-#{new_resource.version}-config"
    content code
    mode 0o644
    owner 'root'
    group 'root'
  end
end

#set_install_permissions(build_directory, new_resource) ⇒ Object



304
305
306
307
308
309
310
311
312
313
# File 'lib/source_install.rb', line 304

def set_install_permissions(build_directory, new_resource)
  build_permission_command(new_resource)
  bash 'Change Install Permissions' do
    code(lazy { node.run_state['build_permission_command'] })
    cwd new_resource.install_directory
    action :nothing
    subscribes :run, 'bash[Install]', :immediate
  end
  set_src_permissions(build_directory, new_resource)
end

#set_src_permissions(build_directory, new_resource) ⇒ Object

Some install scripts create artifacts in the source directory



296
297
298
299
300
301
302
# File 'lib/source_install.rb', line 296

def set_src_permissions(build_directory, new_resource)
  bash 'Set Config Permissions' do
    code "chown -R #{new_resource.owner}:#{new_resource.group} #{build_directory}"
    action :nothing
    subscribes :run, 'bash[Install]', :immediate
  end
end