sous-chefs / jenkins

Development repository for the jenkins cookbook
https://supermarket.chef.io/cookbooks/jenkins
Apache License 2.0
424 stars 635 forks source link

semi-delayed restart after plug-in installs #574

Open chazzly opened 7 years ago

chazzly commented 7 years ago

Cookbook version

4.2.1

Chef-client version

12.18.31

Platform Details

Oracle Linux Server release 7.2

Expected Result:

Install / update plug-ins, restart jenkins, continue chef run and and configuration.

This is more of a question than an issue. I'm hoping there's a better approach than what I'm doing. I have read through the documentation in this repo and a number of past/present issue, but I'm not seeing what I'm after. In my jenkins wrapper cookbook, I go through the list of plug-ins to be installed:

node['jenkins']['plug_ins'].each` do |p, ver|
  jenkins_plugin p do
     Chef::Log.info("installing #{p} plugin")
     version ver
     retries 1
     action :install
  end
end

In some cases, these plugins must be installed and active for later config changes to work, so jenkins needs to be restarted. I could, of course, add a notify to restart jenkins immediately, but that means jenkins would get restarted with each and every plug-in, which could be dozens, especially on initial install. So, I'm trying to use a global variable as a flag, a ruby block to update that flag if (and only if) any of the plug-ins are installed, then test for that flag and do an immediate service restart:

$updt = false

ruby_block 'plug-in updt' do
  block { $updt = true }
  action :nothing
end

node['jenkins']['plug_ins'].each do |p, ver|
  jenkins_plugin p do
     Chef::Log.info("installing #{p} plugin")
     version ver
     retries 1
     action :install
     notifies :run, 'ruby_block[plug-in updt]', :immediately
  end
end

ruby_block 'immediate restart' do
  block { puts 'restarting Jenkins....'}
  notifies :restart, 'service[jenkins]', :immediately
  only_if lazy { $updt }
end

the "only_if" for the restart ruby_block needs to be lazy because, the ruby_block to update $updt only fires after the notification during execution phase.

Unfortunately, it doesn't work.

The immediate restart block runs every chef run, even if no plug-ins are install / updated. I've tried digging in to it with my tests, but can't seem to accurately test/stub the lazy variable. Anyone know what I'm doing wrong? Any better way to go about this?

StephenKing commented 7 years ago

Yes, this is really a bit annoying. You can find my way around it here, which is to write down all the plugin name/version combinations into a file on the Jenkins master and trigger a restart if that file changes. Could be cleaner, if it would be wrapped by a resource that takes all the plugins+versions to install.

chazzly commented 7 years ago

@StephenKing - Thanks that's a lot cleaner than what I was trying to do. Yeah, there almost needs to be a separate resource to handle all the plug-ins as a whole, then restart.

ehaselwanter commented 7 years ago

I do it like so:

%w( simple-build-for-pipeline=0.2
    github-branch-source=2.0.4
    workflow-api=2.12
..... lllllllloooooong list of all my plugins ....
    token-macro=2.0
    pam-auth=1.3
    workflow-multibranch=2.14
).each do |plugin|
  plugin, version = plugin.split('=')
  jenkins_plugin plugin do
    version version if version
    install_deps false
    notifies :create, 'ruby_block[jenkins_restart_flag]', :immediately
  end
end

# Is notified only when a 'jenkins_plugin' is installed or updated.
ruby_block 'jenkins_restart_flag' do
  block do
    node.run_state['restart_required'] = true
  end
  action :nothing
end

jenkins_command 'restart' do
  only_if { node.run_state['restart_required'] }
end

@chazzly you never ever should use a global var. $updt ... you can use node.run_state to share values (https://docs.chef.io/recipes.html#node-run-state) and it doe not need to be lazy because a guard (https://docs.chef.io/resource_common.html#guards) is executed during the execute phase

grv87 commented 7 years ago

@StephenKing, with your method of plugin installation, have you met the following situation?

After safe-restart converge is failed with

ERROR: Jenkins has not been started, or was already shut down

Either some waiting time is needed or safe-restart is not enough, and we have to restart the service.