diff --git a/README.md b/README.md index 5be5471a..6606a2ca 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ If you would prefer to use Hiera then see jira.yaml file for an example. The module can install a package for you using your OS's package manager. Note that there's no smarts here. You need to set javahome correctly. +*Pre JIRA 10* ```puppet # this example works on RHEL class { 'jira': @@ -101,6 +102,15 @@ Note that there's no smarts here. You need to set javahome correctly. } ``` +*Post JIRA 10* +```puppet + # this example works on RHEL + class { 'jira': + java_package => 'java-17-openjdk' + javahome => '/usr/lib/jvm/jre-17-opendjk/', + } +``` + #### Upgrades ##### Upgrades to JIRA @@ -113,7 +123,7 @@ doing large version upgrades. Always backup your database and your home director class { 'jira': java_package => 'java-11-openjdk-headless' javahome => '/usr/lib/jvm/jre-11-opendjk/', - version => '8.16.0', + version => '8.16.0', } ``` @@ -247,6 +257,11 @@ Reverse proxy can be configured as a hash as part of the JIRA resource }, ``` +### notes on secret encryption in dbconfig.xml +The JIRA process will read the dbconfig.xml on startup replace it with the string "{ATL_SECURED}". The password is moved +into `/keys/javax.crypto.spec.SecretKeySpec_`. It is important that this directory +is not located inside of the installation dir as you would lose it in the case of an update. + ## Reference see [REFERENCE.md](REFERENCE.md) diff --git a/REFERENCE.md b/REFERENCE.md index 6b9fe2cf..322f44b6 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -20,6 +20,10 @@ ### Functions +#### Public Functions + +* [`jira::is_installed`](#jira--is_installed): Check if JIRA is already installed + #### Private Functions * `jira::sort_hash`: Sort a hash @@ -388,7 +392,7 @@ Default value: `'jira'` Data type: `Boolean` -Set to true to actually generate a dbconfig.xml with the password - otherwise write "{ATL_SECURED}" +Set to true to actually generate a dbconfig.xml with the password - otherwise write "{ATL_SECURED}" (defaults to true in JIRA versions < 10.3.0) Default value: `false` @@ -1164,6 +1168,26 @@ Deprecated. Has no effect. Default value: `undef` +## Functions + +### `jira::is_installed` + +Type: Ruby 4.x API + +Check if JIRA is already installed + +#### `jira::is_installed(String[1] $homedir)` + +The jira::is_installed function. + +Returns: `Boolean` + +##### `homedir` + +Data type: `String[1]` + + + ## Data types ### `Jira::Jvm_types` diff --git a/examples/jira_mysql_install.pp b/examples/jira_mysql_install.pp index d06ec78a..2a8a274f 100644 --- a/examples/jira_mysql_install.pp +++ b/examples/jira_mysql_install.pp @@ -1,8 +1,7 @@ node default { class { 'mysql::server': - root_password => 'strongpassword', + root_password => 'strongpassword', } - -> mysql::db { 'jira': user => 'jiraadm', password => 'mypassword', diff --git a/examples/jira_mysql_nativessl_install.pp b/examples/jira_mysql_nativessl_install.pp index d6b8943c..772cb5b4 100644 --- a/examples/jira_mysql_nativessl_install.pp +++ b/examples/jira_mysql_nativessl_install.pp @@ -3,7 +3,7 @@ $key = hiera('key') class { 'mysql::server': - root_password => 'strongpassword', + root_password => 'strongpassword', } mysql::db { 'jira': diff --git a/examples/jira_postgres_install.pp b/examples/jira_postgres_install.pp index fe011db8..ed3475cf 100644 --- a/examples/jira_postgres_install.pp +++ b/examples/jira_postgres_install.pp @@ -12,7 +12,7 @@ } -> class { 'jira': - javahome => '/opt/java/latest', + javahome => '/opt/java/latest', } include jira::facts diff --git a/lib/puppet/functions/jira/is_installed.rb b/lib/puppet/functions/jira/is_installed.rb new file mode 100644 index 00000000..2b40deb2 --- /dev/null +++ b/lib/puppet/functions/jira/is_installed.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# @summary Check if JIRA is already installed +Puppet::Functions.create_function(:'jira::is_installed') do + dispatch :default_impl do + # @param homedir The directory for JIRA's runtime data that persists between versions. + # @return [Boolean] install status + param 'String[1]', :homedir + return_type 'Boolean' + end + + def default_impl(homedir) + File.exist? format('%s/dbconfig.xml', homedir) + rescue StandardError + false + end +end diff --git a/manifests/config.pp b/manifests/config.pp index 3f73cbca..039a223e 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -48,8 +48,6 @@ } } - $change_dbpassword = $jira::change_dbpassword - if $jira::dbport { $dbport = $jira::dbport } else { @@ -106,6 +104,7 @@ deprecation('jira::poolsize', 'jira::poolsize is deprecated and simply sets max-pool-size. Please use jira::pool_max_size instead and remove this configuration') } + $change_dbpassword = $jira::change_dbpassword_real $pool_min_size = pick($jira::pool_min_size, 20) $pool_max_size = pick($jira::pool_max_size, $jira::poolsize, 20) $pool_max_wait = pick($jira::pool_max_wait, 30000) diff --git a/manifests/init.pp b/manifests/init.pp index 523b4c16..4fc25bb6 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -69,7 +69,7 @@ # @param dbname # The database name to connect to # @param change_dbpassword -# Set to true to actually generate a dbconfig.xml with the password - otherwise write "{ATL_SECURED}" +# Set to true to actually generate a dbconfig.xml with the password - otherwise write "{ATL_SECURED}" (defaults to true in JIRA versions < 10.3.0) # @param dbuser # Database username # @param dbpassword @@ -484,6 +484,23 @@ fail('You need to specify a value for javahome') } + $is_insalled_deferred = Deferred('jira::is_installed', [$jira::homedir]) + $is_installed = $is_insalled_deferred =~ Deferred ? { + true => jira::is_installed($jira::homedir), + false => $is_insalled_deferred + } + if $is_installed { + # use the parameter if the fact did not run (confine), or the fact shows that there is a dbconfig.xml in place + $change_dbpassword_real = versioncmp($version, '10.3.0') ? { + -1 => true, + default => $change_dbpassword, + } + } + else { + # jira probably not installed + $change_dbpassword_real = true + } + contain jira::install contain jira::config contain jira::service @@ -502,7 +519,7 @@ if $plugin_data['ensure'] == 'absent' { archive { $target: - ensure => 'absent', + ensure => 'absent', } } else { $_target_defaults = { diff --git a/spec/acceptance/default_parameters_jira_10_spec.rb b/spec/acceptance/default_parameters_jira_10_spec.rb new file mode 100644 index 00000000..bc8b9414 --- /dev/null +++ b/spec/acceptance/default_parameters_jira_10_spec.rb @@ -0,0 +1,187 @@ +# frozen_string_literal: true + +require 'spec_helper_acceptance' + +def on_supported_os + family = fact('os.family') + major = fact('os.release.major') + (family == 'Debian' and (major >= '22.04' or (major >= '11' and major <= '20'))) or (family == 'RedHat' and major >= '8') +end + +prepare = <<-EOS + # package {'diffutils': + # ensure => installed + # } + # file_line{'enable show_diff': + # path => '/etc/puppetlabs/puppet/puppet.conf', + # line => 'show_diff = true' + # } +EOS + +pre = <<-EOS + if $facts['os']['family'] == 'RedHat' { + $java_package = 'java-17-openjdk' + $java_home = '/usr/lib/jvm/jre-17-openjdk' + $postgresql_version = '13' + $pgsql_package_name = 'postgresql-server' + $pgsql_data_dir = '/var/lib/pgsql' + $manage_dnf_module = $facts['os']['release']['major'] ? { + '8' => true, + default => false # RHEL-9 has pgsql 13 as a default + } + $autoremove_command = 'dnf --exclude="systemd*" autoremove -y' + } + elsif $facts['os']['family'] == 'Debian' { + $postgresql_version = $facts['os']['release']['major'] ? { + '11' => '13', + default => '14' + } + $java_package = 'openjdk-17-jre' + $java_home = '/usr/lib/jvm/java-17-openjdk-amd64' + $pgsql_package_name = "postgresql-${postgresql_version}" + $pgsql_data_dir = "/var/lib/postgresql/${postgresql_version}/main/" + $manage_dnf_module = false + $autoremove_command = 'apt autoremove -y' + } + $jira_install_dir = '/opt/jira/' + $postgres_service = 'postgresql' + $jira_service = 'jira' +EOS + +pp = <<-EOS + # The output of `systemctl status postgresql` is non ascii which + # breaks the Exec in Postgresql::Server::Instance::Reload + # on rhel based docker containers + # We don't need the output. + class { 'postgresql::globals': + manage_dnf_module => $manage_dnf_module, + version => $postgresql_version, + } + class { 'postgresql::server': + service_status => 'systemctl status postgresql > /dev/null', + needs_initdb => true + } + + postgresql::server::db { 'jira': + user => 'jiraadm', + password => postgresql::postgresql_password('jiraadm', 'mypassword'), + } + + # There is a bug in the check-java.sh that prevents jira from starting on Centos Stream 8 + # https://jira.atlassian.com/browse/JRASERVER-77097 + # Running with script_check_java_manage => true to solve this + class { 'jira': + version => '10.3.2', + java_package => $java_package, + javahome => $java_home, + script_check_java_manage => false, + connection_settings => 'tcpKeepAlive=true', + require => Postgresql::Server::Db['jira'] + } +EOS +pp = pre + pp + +pp_upgrade = <<-EOS + class { 'jira': + version => '10.3.3', + java_package => $java_package, + javahome => $java_home, + connection_settings => 'tcpKeepAlive=true', + script_check_java_manage => false + } +EOS +pp_upgrade = pre + pp_upgrade + +pp_remove = <<-EOS + package {$java_package: + ensure => purged + } + exec {'clear JIRA home': + command => 'rm -Rf ~jira/*', + provider => shell, + } + package {$pgsql_package_name: + ensure => purged + } + if $manage_dnf_module { + exec {"dnf module reset postgresql": + command => 'dnf module reset -y postgresql', + provider => shell, + } + } + exec {"autoremove cleanup": + command => $autoremove_command, + provider => shell, + } + exec {'cleanup pgsql and JIRA install dir': + command => "rm -Rf ${pgsql_data_dir}/* ${$jira_install_dir}/atlassian-jira-software*", + provider => shell, + require => Exec['autoremove cleanup'], + } + service{$postgres_service: + ensure => stopped + } + service{$jira_service: + ensure => stopped + } +EOS +pp_remove = pre + pp_remove + +context 'jira 10 only on RedHat >=8 and Debian-11', if: on_supported_os do + describe 'jira 10 postgresql' do + it 'installs jira 10 with defaults' do + apply_manifest(prepare, catch_failures: true) + # jira just takes *ages* to start up :-( + wget_cmd = 'wget -q --tries=24 --retry-connrefused --read-timeout=10 localhost:8080' + apply_manifest(pp, catch_failures: true) + sleep SLEEP_SECONDS + shell wget_cmd, acceptable_exit_codes: [0, 8] + sleep SLEEP_SECONDS + shell wget_cmd, acceptable_exit_codes: [0, 8] + apply_manifest(pp, catch_changes: true) + + apply_manifest(pp_upgrade, catch_failures: true) + sleep SLEEP_SECONDS + shell wget_cmd, acceptable_exit_codes: [0, 8] + sleep SLEEP_SECONDS + shell wget_cmd, acceptable_exit_codes: [0, 8] + + apply_manifest(pp_upgrade, catch_changes: true) + end + + describe process('java') do + it { is_expected.to be_running } + end + + describe port(8080) do + it { is_expected.to be_listening } + end + + describe service('jira') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe user('jira') do + it { is_expected.to belong_to_group 'jira' } + it { is_expected.to have_login_shell '/bin/true' } + end + + expected_version = '10.3.3' + describe command("wget -q --tries=54 --retry-connrefused --read-timeout=10 -O- localhost:8080 | grep '#{expected_version}'") do + its(:stdout) { is_expected.to include(expected_version) } + end + + # cleanup after this spec to ensure that following tests start without any unmanaged + # packages and data + describe 'shutdown' do + it 'cleans up nicely' do + apply_manifest(pp_remove, catch_failures: true) + end + + it { shell('service jira stop', acceptable_exit_codes: [0, 1]) } + it { shell('pkill -9 -f postgres', acceptable_exit_codes: [0, 1]) } + it { shell('pkill -9 -f jira', acceptable_exit_codes: [0, 1]) } + end + end +end diff --git a/spec/acceptance/default_parameters_spec.rb b/spec/acceptance/default_parameters_spec.rb index 05ecc9ba..f72d7f34 100644 --- a/spec/acceptance/default_parameters_spec.rb +++ b/spec/acceptance/default_parameters_spec.rb @@ -20,7 +20,8 @@ # on rhel based docker containers # We don't need the output. class { 'postgresql::server': - service_status => 'systemctl status postgresql > /dev/null' + service_status => 'systemctl status postgresql > /dev/null', + needs_initdb => true } postgresql::server::db { 'jira': @@ -53,8 +54,7 @@ class { 'jira': version => '8.16.0', java_package => $java_package, javahome => $java_home, - script_check_java_manage => true, - change_dbpassword => true, + script_check_java_manage => true } EOS diff --git a/spec/acceptance/mysql_spec.rb b/spec/acceptance/mysql_spec.rb index 1f821988..9c18e857 100644 --- a/spec/acceptance/mysql_spec.rb +++ b/spec/acceptance/mysql_spec.rb @@ -77,7 +77,6 @@ class { 'jira': dbport => 3306, dbdriver => 'com.mysql.jdbc.Driver', dbtype => 'mysql', - change_dbpassword => true, tomcat_port => 8081, tomcat_native_ssl => true, tomcat_keystore_file => '/tmp/jira.ks', diff --git a/spec/classes/jira_config_spec.rb b/spec/classes/jira_config_spec.rb index 76428c4a..9e381b2c 100644 --- a/spec/classes/jira_config_spec.rb +++ b/spec/classes/jira_config_spec.rb @@ -91,6 +91,42 @@ end end + context 'default params with java install, mysql, and jira > 10.3.0 and change_dbpassword=true' do + let(:params) do + { + version: '10.3.3', + db: 'mysql', + dbpassword: 'test', + change_dbpassword: true, + javahome: '/usr/lib/jvm/jre-11-openjdk', + java_package: 'java-11-openjdk-headless', + } + end + + it do + is_expected.to contain_file(FILENAME_DBCONFIG_XML). + with_content(%r{test}) + end + end + + context 'default params with java install, mysql, and jira > 10.3.0 and change_dbpassword=false (default) and facts that indicate a fresh install' do + let(:params) do + { + version: '10.3.3', + db: 'mysql', + dbpassword: 'test', + change_dbpassword: false, + javahome: '/usr/lib/jvm/jre-11-openjdk', + java_package: 'java-11-openjdk-headless', + } + end + + it do + is_expected.to contain_file(FILENAME_DBCONFIG_XML). + with_content(%r{test}) + end + end + context 'database settings' do let(:params) do super().merge( @@ -172,8 +208,7 @@ dbserver: 'TheSQLServer', dbname: 'TheJiraDB', dbuser: 'TheDBUser', - dbpassword: 'TheDBPassword', - change_dbpassword: true + dbpassword: 'TheDBPassword' ) end @@ -196,8 +231,7 @@ dbserver: 'TheSQLServer', dbname: 'TheJiraDB', dbuser: 'TheDBUser', - dbpassword: 'TheDBPassword', - change_dbpassword: true + dbpassword: 'TheDBPassword' ) end @@ -239,8 +273,7 @@ dbserver: 'TheSQLServer', dbname: 'TheJiraDB', dbuser: 'TheDBUser', - dbpassword: 'TheDBPassword', - change_dbpassword: true + dbpassword: 'TheDBPassword' ) end