diff --git a/documentation/resources/openjdk_install.md b/documentation/resources/openjdk_install.md index b9185b15..a9ad46d7 100644 --- a/documentation/resources/openjdk_install.md +++ b/documentation/resources/openjdk_install.md @@ -31,6 +31,7 @@ Introduced: v8.0.0 | pkg_names | Array | | List of packages to install | | | pkg_version | String | | Package version to install | | | install_type | String | | Installation type | `package` `source` | +| source_install_dir | String | | Source install directory | | ## Examples @@ -47,3 +48,17 @@ openjdk_install '11' do alternatives_priority 2 end ``` + +To install a source archive from an internal mirror: + +```ruby +openjdk_install '17' do + install_type 'source' + url 'https://artifacts.example.com/java/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz' + checksum 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +end +``` + +For source installs, custom URLs install into a directory derived from the archive name unless +`java_home` or `source_install_dir` is set. Source archives must contain a single top-level +directory because the source installer strips one leading path component during extraction. diff --git a/documentation/resources/openjdk_source_install.md b/documentation/resources/openjdk_source_install.md index 7032ba8d..e8dcb9d8 100644 --- a/documentation/resources/openjdk_source_install.md +++ b/documentation/resources/openjdk_source_install.md @@ -20,6 +20,7 @@ Introduced: v8.0.0 | url | String | `default_openjdk_url(version)` | The URL to download from | | checksum | String | `default_openjdk_checksum(version)` | The checksum for the downloaded file | | java_home | String | Based on the version | Set to override the java_home | +| source_install_dir | String | Based on the archive name | Source install directory | | java_home_mode | Integer, String | `0755` | The permission for the Java home directory | | java_home_owner | String | `root` | Owner of the Java Home | | java_home_group | String | `node['root_group']` | Group for the Java Home | @@ -44,3 +45,28 @@ openjdk_source_install '11' do alternatives_priority 2 end ``` + +To install a custom OpenJDK archive from an internal mirror: + +```ruby +openjdk_source_install '17' do + url 'https://artifacts.example.com/java/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz' + checksum 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +end +``` + +This installs to `/usr/lib/jvm/java-17-openjdk/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9` +and configures alternatives from that Java home. + +To choose a stable install directory for a custom archive: + +```ruby +openjdk_source_install '17' do + url 'https://artifacts.example.com/java/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz' + checksum 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + source_install_dir 'jdk-17.0.9+9' +end +``` + +Source archives must contain a single top-level directory. The resource extracts archives with +one leading path component stripped so the archive contents land directly in `java_home`. diff --git a/metadata.rb b/metadata.rb index 999bf085..55d8fa99 100644 --- a/metadata.rb +++ b/metadata.rb @@ -5,7 +5,7 @@ description 'Recipes and resources for installing Java and managing certificates' source_url 'https://github.com/sous-chefs/java' issues_url 'https://github.com/sous-chefs/java/issues' -chef_version '>= 16.0' +chef_version '>= 17.5' version '14.0.1' supports 'almalinux', '>= 8.0' diff --git a/resources/alternatives.rb b/resources/alternatives.rb index f67e7c44..2def88b3 100644 --- a/resources/alternatives.rb +++ b/resources/alternatives.rb @@ -34,7 +34,7 @@ action :set do bin_cmds_to_setup = parse_java_alternatives set_alternatives(bin_cmds_to_setup) do |cmd, alt_path| - alternative_exists = ::File.exist?("/var/lib/alternatives/#{cmd}") && + alternative_exists = ::File.exist?(alternative_file_path(cmd)) && alternatives_display(cmd).stdout.include?(alt_path) Chef::Log.debug("Alternative for #{cmd} exists with correct path? #{alternative_exists}") alternative_exists @@ -58,6 +58,14 @@ def alternatives_display(cmd) shell_out(alternatives_cmd, '--display', cmd) end + def alternative_file_path(cmd) + if platform_family?('debian') + "/var/lib/dpkg/alternatives/#{cmd}" + else + "/var/lib/alternatives/#{cmd}" + end + end + def parse_java_alternatives bin_cmds_to_setup = [] new_resource.bin_cmds.each do |cmd| @@ -101,12 +109,12 @@ def set_alternatives(bin_cmds) end end - alternative_file_exists = ::File.exist?("/var/lib/alternatives/#{cmd}") + alternative_file_exists = ::File.exist?(alternative_file_path(cmd)) if !our_alternative_exists || !alternative_file_exists converge_by("Add alternative for #{cmd}") do if new_resource.reset_alternatives && alternative_file_exists - ::FileUtils.rm_f("/var/lib/alternatives/#{cmd}") + ::FileUtils.rm_f(alternative_file_path(cmd)) end shell_out!(alternatives_cmd, '--install', bin_path, cmd, alt_path, priority.to_s) end diff --git a/resources/openjdk_install.rb b/resources/openjdk_install.rb index e5c9ce9e..e119b717 100644 --- a/resources/openjdk_install.rb +++ b/resources/openjdk_install.rb @@ -22,6 +22,10 @@ String, description: 'Set to override the java_home' +property :source_install_dir, + String, + description: 'Directory under the versioned parent path where the source archive is installed' + property :bin_cmds, Array, description: 'A list of bin_cmds based on the version and variant' @@ -59,7 +63,9 @@ url new_resource.url checksum new_resource.checksum java_home new_resource.java_home + source_install_dir new_resource.source_install_dir java_home_mode new_resource.java_home_mode + java_home_owner new_resource.java_home_owner java_home_group new_resource.java_home_group default new_resource.default bin_cmds bin_cmds @@ -93,7 +99,9 @@ url new_resource.url checksum new_resource.checksum java_home new_resource.java_home + source_install_dir new_resource.source_install_dir java_home_mode new_resource.java_home_mode + java_home_owner new_resource.java_home_owner java_home_group new_resource.java_home_group default new_resource.default bin_cmds bin_cmds diff --git a/resources/openjdk_source_install.rb b/resources/openjdk_source_install.rb index dae97036..0b07ecb7 100644 --- a/resources/openjdk_source_install.rb +++ b/resources/openjdk_source_install.rb @@ -19,6 +19,9 @@ property :java_home, String, description: 'Set to override the java_home' +property :source_install_dir, String, + description: 'Directory under the versioned parent path where the source archive is installed' + property :bin_cmds, Array, description: 'A list of bin_cmds based on the version and variant' @@ -30,13 +33,11 @@ action :install do url = new_resource.url || default_openjdk_url(new_resource.version, new_resource.variant) checksum = new_resource.checksum || default_openjdk_checksum(new_resource.version) - java_home = new_resource.java_home || "/usr/lib/jvm/java-#{new_resource.version}-openjdk/jdk-#{new_resource.version}" + java_home = resolved_java_home(url) bin_cmds = new_resource.bin_cmds || default_bin_cmds(new_resource.version) - extract_dir = java_home.split('/')[0..-2].join('/') - parent_dir = java_home.split('/')[0..-3].join('/') tarball_name = url.split('/').last - directory parent_dir do + directory java_home do owner new_resource.java_home_owner group new_resource.java_home_group mode new_resource.java_home_mode @@ -52,7 +53,13 @@ end archive_file "#{Chef::Config[:file_cache_path]}/#{tarball_name}" do - destination extract_dir + destination java_home + strip_components 1 + overwrite true + owner new_resource.java_home_owner + group new_resource.java_home_group + mode new_resource.java_home_mode + not_if { ::File.exist?(::File.join(java_home, 'bin', 'java')) } end java_alternatives 'set-java-alternatives' do @@ -74,22 +81,22 @@ end action :remove do - java_home = new_resource.java_home || "/usr/lib/jvm/java-#{new_resource.version}-openjdk/jdk-#{new_resource.version}" + url = new_resource.url || default_openjdk_url(new_resource.version, new_resource.variant) + java_home = resolved_java_home(url) bin_cmds = new_resource.bin_cmds || default_bin_cmds(new_resource.version) - extract_dir = java_home.split('/')[0..-2].join('/') java_alternatives 'unset-java-alternatives' do java_location java_home bin_cmds bin_cmds - only_if { ::File.exist?(extract_dir) } + only_if { ::File.exist?(java_home) } not_if { new_resource.skip_alternatives } action :unset end - directory "Removing #{extract_dir}" do - path extract_dir + directory "Removing #{java_home}" do + path java_home recursive true - only_if { ::File.exist?(extract_dir) } + only_if { ::File.exist?(java_home) } action :delete end @@ -97,3 +104,25 @@ action :delete end end + +action_class do + def resolved_java_home(url) + return new_resource.java_home if new_resource.java_home + + install_dir = + if new_resource.source_install_dir + new_resource.source_install_dir + elsif new_resource.url + source_install_dir_from_url(url) + else + "jdk-#{new_resource.version}" + end + + "/usr/lib/jvm/java-#{new_resource.version}-openjdk/#{install_dir}" + end + + def source_install_dir_from_url(url) + ::File.basename(::URI.parse(url).path) + .sub(/\.(?:tar\.(?:gz|bz2|xz)|tgz|tbz2|zip)\z/i, '') + end +end diff --git a/spec/resources/alternatives_spec.rb b/spec/resources/alternatives_spec.rb index cdc5ad20..3d4953d8 100644 --- a/spec/resources/alternatives_spec.rb +++ b/spec/resources/alternatives_spec.rb @@ -16,4 +16,30 @@ expect { runner.converge('test::alternatives_unset_spec') }.not_to raise_error end + + it 'does not reinstall an existing Debian alternative' do + allow(::File).to receive(:exist?).and_call_original + allow(::File).to receive(:exist?).with('/opt/java/bin/java').and_return(true) + allow(::File).to receive(:exist?).with('/var/lib/dpkg/alternatives/java').and_return(true) + allow(::File).to receive(:exist?).with('/var/lib/alternatives/java').and_return(false) + + stubs_for_provider('java_alternatives[test-existing-alternatives]') do |provider| + display = <<~OUTPUT + java - auto mode + link best version is /opt/java/bin/java + link currently points to /opt/java/bin/java + link java is /usr/bin/java + /opt/java/bin/java - priority 1062 + OUTPUT + + allow(provider).to receive(:shell_out) + .with('update-alternatives', '--display', 'java') + .and_return(instance_double(Mixlib::ShellOut, stdout: display, exitstatus: 0)) + allow(provider).to receive(:shell_out!) do |*args| + raise "unexpected shell_out!: #{args.join(' ')}" + end + end + + expect { runner.converge('test::alternatives_existing_spec') }.not_to raise_error + end end diff --git a/spec/resources/openjdk_install_spec.rb b/spec/resources/openjdk_install_spec.rb index 6451c4fe..8bb387fe 100644 --- a/spec/resources/openjdk_install_spec.rb +++ b/spec/resources/openjdk_install_spec.rb @@ -32,6 +32,8 @@ url: 'https://example.test/openjdk.tar.gz', checksum: 'a' * 64, java_home: '/usr/lib/jvm/java-17-openjdk/jdk-17', + source_install_dir: 'jdk-17.0.9+9', + java_home_owner: 'javauser', bin_cmds: %w(java javac), skip_alternatives: true ) diff --git a/spec/resources/openjdk_source_install_spec.rb b/spec/resources/openjdk_source_install_spec.rb index ba4e723e..efcef1af 100644 --- a/spec/resources/openjdk_source_install_spec.rb +++ b/spec/resources/openjdk_source_install_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'openjdk_source_install' do + let(:cache_path) { Chef::Config[:file_cache_path] } + context 'install' do let(:runner) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '24.04', step_into: ['openjdk_source_install']) } let(:converge) { runner.converge('test::openjdk_source_direct_spec') } @@ -19,6 +21,68 @@ expect(resource.content).to eq("export JAVA_HOME=/usr/lib/jvm/java-17-openjdk/jdk-17\n") expect(resource.mode).to eq('0644') end + + it 'extracts the archive into the final java_home' do + archive = converge.resource_collection.find(archive_file: ::File.join(cache_path, 'openjdk.tar.gz')) + + expect(archive.destination).to eq('/usr/lib/jvm/java-17-openjdk/jdk-17') + expect(archive.strip_components).to eq(1) + expect(archive.overwrite).to be true + expect(archive.not_if).not_to be_empty + end + end + + context 'custom source URL' do + let(:runner) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '24.04', step_into: ['openjdk_source_install']) } + let(:converge) { runner.converge('test::openjdk_source_custom_url_spec') } + let(:java_home) { '/usr/lib/jvm/java-17-openjdk/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9' } + + it 'derives java_home from the archive file name' do + resource = converge.resource_collection.find(file: '/etc/profile.d/java.sh') + + expect(resource.content).to eq("export JAVA_HOME=#{java_home}\n") + end + + it 'sets alternatives to the derived java_home' do + expect(converge).to set_java_alternatives('set-java-alternatives').with( + java_location: java_home, + bin_cmds: %w(java javac) + ) + end + + it 'extracts the archive into the derived java_home' do + archive = converge.resource_collection.find(archive_file: ::File.join(cache_path, 'OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz')) + + expect(archive.destination).to eq(java_home) + expect(archive.strip_components).to eq(1) + expect(archive.overwrite).to be true + expect(archive.owner).to eq('root') + expect(archive.group).to eq('root') + expect(archive.mode).to eq('0755') + expect(archive.not_if).not_to be_empty + end + end + + context 'custom source URL with explicit java_home' do + let(:runner) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '24.04', step_into: ['openjdk_source_install']) } + let(:converge) { runner.converge('test::openjdk_source_explicit_java_home_spec') } + + it 'uses the explicit java_home' do + resource = converge.resource_collection.find(file: '/etc/profile.d/java.sh') + + expect(resource.content).to eq("export JAVA_HOME=/opt/java/custom-openjdk\n") + end + end + + context 'custom source URL with source_install_dir' do + let(:runner) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '24.04', step_into: ['openjdk_source_install']) } + let(:converge) { runner.converge('test::openjdk_source_install_dir_spec') } + + it 'uses source_install_dir under the versioned parent directory' do + resource = converge.resource_collection.find(file: '/etc/profile.d/java.sh') + + expect(resource.content).to eq("export JAVA_HOME=/usr/lib/jvm/java-17-openjdk/jdk-17.0.9+9\n") + end end context 'remove' do diff --git a/test/fixtures/cookbooks/test/recipes/alternatives_existing_spec.rb b/test/fixtures/cookbooks/test/recipes/alternatives_existing_spec.rb new file mode 100644 index 00000000..b714fd5e --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/alternatives_existing_spec.rb @@ -0,0 +1,5 @@ +java_alternatives 'test-existing-alternatives' do + java_location '/opt/java' + bin_cmds ['java'] + priority 1062 +end diff --git a/test/fixtures/cookbooks/test/recipes/openjdk_source_custom_url_spec.rb b/test/fixtures/cookbooks/test/recipes/openjdk_source_custom_url_spec.rb new file mode 100644 index 00000000..8ac6fcf7 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/openjdk_source_custom_url_spec.rb @@ -0,0 +1,5 @@ +declare_resource(:openjdk_source_install, '17') do + url 'https://artifacts.example.test/java/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz' + checksum 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + bin_cmds %w(java javac) +end diff --git a/test/fixtures/cookbooks/test/recipes/openjdk_source_explicit_java_home_spec.rb b/test/fixtures/cookbooks/test/recipes/openjdk_source_explicit_java_home_spec.rb new file mode 100644 index 00000000..4fc8a521 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/openjdk_source_explicit_java_home_spec.rb @@ -0,0 +1,6 @@ +declare_resource(:openjdk_source_install, '17') do + url 'https://artifacts.example.test/java/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz' + checksum 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + java_home '/opt/java/custom-openjdk' + bin_cmds %w(java javac) +end diff --git a/test/fixtures/cookbooks/test/recipes/openjdk_source_install_dir_spec.rb b/test/fixtures/cookbooks/test/recipes/openjdk_source_install_dir_spec.rb new file mode 100644 index 00000000..dab3492d --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/openjdk_source_install_dir_spec.rb @@ -0,0 +1,6 @@ +declare_resource(:openjdk_source_install, '17') do + url 'https://artifacts.example.test/java/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz' + checksum 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + source_install_dir 'jdk-17.0.9+9' + bin_cmds %w(java javac) +end diff --git a/test/fixtures/cookbooks/test/recipes/openjdk_source_spec.rb b/test/fixtures/cookbooks/test/recipes/openjdk_source_spec.rb index b4a6227a..80b2f26e 100644 --- a/test/fixtures/cookbooks/test/recipes/openjdk_source_spec.rb +++ b/test/fixtures/cookbooks/test/recipes/openjdk_source_spec.rb @@ -3,6 +3,8 @@ url 'https://example.test/openjdk.tar.gz' checksum 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' java_home '/usr/lib/jvm/java-17-openjdk/jdk-17' + source_install_dir 'jdk-17.0.9+9' + java_home_owner 'javauser' bin_cmds %w(java javac) skip_alternatives true end