Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use native Puppet instead of the retries Gem in the CLI provider, replacing try_sleep parameter by exponential backoff #904

Merged
merged 1 commit into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .sync.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
---
Gemfile:
optional:
':test':
- gem: 'retries'
.rubocop.yml:
unmanaged: true
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ group :test do
gem 'coveralls', :require => false
gem 'simplecov-console', :require => false
gem 'puppet_metadata', '~> 3.5', :require => false
gem 'retries', :require => false
end

group :development do
Expand Down
9 changes: 0 additions & 9 deletions NATIVE_TYPES_AND_PROVIDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,6 @@ class { '::jenkins':
include ::jenkins::cli_helper
```

The ruby gem `retries` is presently required by all providers.

### `puppetserver`

There is a known issue with `puppetserver` being unable to load code from
Expand All @@ -141,13 +139,6 @@ jruby-puppet: {

See [SERVER-973](https://tickets.puppetlabs.com/browse/SERVER-973)

Additionally, the `retries` gem is required. This may be installed on the master by running:

```
/opt/puppetlabs/bin/puppetserver gem install retries
```


Types
--

Expand Down
5 changes: 0 additions & 5 deletions lib/puppet/feature/retries.rb

This file was deleted.

1 change: 0 additions & 1 deletion lib/puppet/x/jenkins/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class UnknownConfig < ArgumentError; end
ssh_private_key: nil,
puppet_helper: '/usr/share/java/puppet_helper.groovy',
cli_tries: 30,
cli_try_sleep: 2,
cli_username: nil,
cli_password: nil,
cli_password_file: '/tmp/jenkins_credentials_for_puppet',
Expand Down
17 changes: 4 additions & 13 deletions lib/puppet/x/jenkins/provider/cli.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'puppet/provider'
require 'puppet/util/retry_action'
require 'facter'

require 'json'
Expand Down Expand Up @@ -31,7 +32,6 @@ def self.inherited(subclass) # rubocop:todo Lint/MissingSuper
initvars

commands java: 'java'
confine feature: :retries
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is that feature now gone?
does the below function not provide that feature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously the feature was provided by the gem. Now it uses functionality built into Puppet itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean Ruby?
retry is a Ruby keyword (that i only learned about yesterday)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I did.


# subclasses should inherit this value once it has been determined that
# jenkins requires authorization, it shortens the run time be elemating the
Expand Down Expand Up @@ -170,7 +170,6 @@ def self.execute_with_retry(command, options = {}, cli_pre_cmd = [])
url = config[:url]
ssh_private_key = config[:ssh_private_key]
cli_tries = config[:cli_tries]
cli_try_sleep = config[:cli_try_sleep]
cli_username = config[:cli_username]
cli_password = config[:cli_password]
cli_password_file = config[:cli_password_file]
Expand Down Expand Up @@ -202,16 +201,7 @@ def self.execute_with_retry(command, options = {}, cli_pre_cmd = [])
# retry on "unknown" execution errors but don't catch AuthErrors. If an
# AuthError has bubbled up to this level it means either an ssh_private_key
# is required and we don't have one or that one we have was rejected.
handler = proc do |exception, attempt_number, total_delay|
Puppet.debug("#{sname} caught #{exception.class.to_s.match(%r{::([^:]+)$})[1]}; retry attempt #{attempt_number}; #{total_delay.round(3)} seconds have passed")
end
with_retries(
max_tries: cli_tries,
base_sleep_seconds: 1,
max_sleep_seconds: cli_try_sleep,
rescue: [UnknownError, NetError],
handler: handler
) do
Puppet::Util::RetryAction.retry_action(retries: cli_tries, retry_exceptions: [UnknownError, NetError]) do
result = execute_with_auth(cli_cmd, auth_cmd, options)
Puppet.debug("#{sname} command stdout:\n#{result}") unless result == ''
return result
Expand Down Expand Up @@ -262,7 +252,8 @@ def self.execute_exceptionify(cmd, options)
'SEVERE: I/O error in channel CLI connection',
'java.net.SocketException: Connection reset',
'java.net.ConnectException: Connection refused',
'java.io.IOException: Failed to connect'
'java.io.IOException: Failed to connect',
'java.io.IOException: Server returned HTTP response code: 503'
]

if options.key?(:tmpfile_as_param)
Expand Down
18 changes: 0 additions & 18 deletions manifests/cli/config.pp
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,10 @@
Boolean $cli_password_file_exists = false,
Optional[String] $ssh_private_key_content = undef,
) {
if str2bool($facts['is_pe']) {
$gem_provider = 'pe_gem'
# lint:ignore:legacy_facts
} elsif $facts['rubysitedir'] and ('/opt/puppetlabs/puppet/lib/ruby' in $facts['rubysitedir']) {
# lint:endignore
# AIO puppet
$gem_provider = 'puppet_gem'
} else {
$gem_provider = 'gem'
}

# lint:ignore:legacy_facts
$is_root = $facts['id'] == 'root'
# lint:endignore

# required by PuppetX::Jenkins::Provider::Clihelper base
if ! defined(Package['retries']) {
package { 'retries':
provider => $gem_provider,
}
}

if $ssh_private_key and $ssh_private_key_content {
file { $ssh_private_key:
ensure => 'file',
Expand Down
20 changes: 0 additions & 20 deletions spec/classes/cli/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,26 +126,6 @@
end
end
end

describe 'package gem provider' do
context 'is_pe fact' do
context 'true' do
let :facts do
super().merge(is_pe: true)
end

it { is_expected.to contain_package('retries').with(provider: 'pe_gem') }
end

context 'false' do
let :facts do
super().merge(is_pe: false)
end

it { is_expected.to contain_package('retries').with(provider: 'gem') }
end
end
end
end
end
end
7 changes: 2 additions & 5 deletions spec/unit/puppet/x/jenkins/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
url: 'http://localhost:8080',
ssh_private_key: nil,
puppet_helper: '/usr/share/java/puppet_helper.groovy',
cli_tries: 30,
cli_try_sleep: 2
cli_tries: 30
}.freeze

shared_context 'facts' do
Expand All @@ -21,7 +20,6 @@
Facter.add(:jenkins_ssh_private_key) { setcode { 'fact.id_rsa' } }
Facter.add(:jenkins_puppet_helper) { setcode { 'fact.groovy' } }
Facter.add(:jenkins_cli_tries) { setcode { 22 } }
Facter.add(:jenkins_cli_try_sleep) { setcode { 33 } }
end
end

Expand Down Expand Up @@ -126,8 +124,7 @@
url: 'http://localhost:111',
ssh_private_key: 'cat.id_rsa',
puppet_helper: 'cat.groovy',
cli_tries: 222,
cli_try_sleep: 333
cli_tries: 222
)

catalog.add_resource jenkins
Expand Down
104 changes: 11 additions & 93 deletions spec/unit/puppet/x/jenkins/provider/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
require 'spec_helper'
require 'unit/puppet/x/spec_jenkins_providers'

# we need to make sure retries is always loaded or random test ordering can
# cause failures when a side effect hasn't yet caused the lib to be loaded
require 'retries'
require 'puppet/x/jenkins/provider/cli'

describe Puppet::X::Jenkins::Provider::Cli do
Expand Down Expand Up @@ -38,7 +35,6 @@
Facter.add(:jenkins_puppet_helper) { setcode { 'fact.groovy' } }
Facter.add(:jenkins_cli_username) { setcode { 'myuser' } }
Facter.add(:jenkins_cli_tries) { setcode { 22 } }
Facter.add(:jenkins_cli_try_sleep) { setcode { 33 } }
end
end

Expand Down Expand Up @@ -316,13 +312,6 @@
end

describe '::cli' do
before do
# disable with_retries sleeping to [vastly] speed up testing
#
# we are relying the side effects of ::suitable? from a previous example
Retries.sleep_enabled = false
end

shared_examples 'uses default values' do
it 'uses default values' do
expect(described_class.superclass).to receive(:execute).with(
Expand Down Expand Up @@ -400,8 +389,7 @@
url: 'http://localhost:111',
ssh_private_key: 'cat.id_rsa',
cli_username: 'myuser',
cli_tries: 222,
cli_try_sleep: 333
cli_tries: 222
)

catalog.add_resource jenkins
Expand All @@ -423,10 +411,8 @@
context 'without ssh_private_key' do
CLI_AUTH_ERRORS.each do |error|
it 'does not retry cli on AuthError exception' do
expect(described_class.superclass).to receive(:execute).with(
'java -jar /usr/share/java/jenkins-cli.jar -s http://localhost:8080 -logger WARNING foo',
failonfail: true, combine: true
).and_raise(AuthError, error)
expect(described_class).to receive(:execute_with_auth).once.and_raise(AuthError, error)
expect(Puppet::Util::RetryAction).not_to receive(:sleep)

expect { described_class.cli('foo') }.
to raise_error(AuthError)
Expand Down Expand Up @@ -490,14 +476,12 @@
context 'network failure' do
context 'without ssh_private_key' do
CLI_NET_ERRORS.each do |error|
it 'does not retry cli on AuthError exception' do
expect(described_class.superclass).to receive(:execute).with(
'java -jar /usr/share/java/jenkins-cli.jar -s http://localhost:8080 -logger WARNING foo',
failonfail: true, combine: true
).exactly(30).times.and_raise(NetError, error)
it 'retries cli on NetError exception' do
expect(described_class).to receive(:execute_with_auth).exactly(31).times.and_raise(NetError, error)
expect(Puppet::Util::RetryAction).to receive(:sleep).exactly(30).times

expect { described_class.cli('foo') }.
to raise_error(NetError)
to raise_error(Puppet::Util::RetryAction::RetryException::RetriesExceeded)
end
end
end
Expand All @@ -514,10 +498,7 @@
)
catalog.add_resource jenkins

expect(described_class.superclass).to receive(:execute).with(
'java -jar /usr/share/java/jenkins-cli.jar -s http://localhost:8080 -logger WARNING foo',
failonfail: true, combine: true
).exactly(30).times.and_raise(UnknownError, 'foo')
expect(Puppet::Util::RetryAction).to receive(:retry_action).with(retries: 30, retry_exceptions: [UnknownError, NetError]).and_raise(UnknownError, 'foo')

expect { described_class.cli('foo', catalog: catalog) }.
to raise_error(UnknownError, 'foo')
Expand All @@ -530,10 +511,7 @@
)
catalog.add_resource jenkins

expect(described_class.superclass).to receive(:execute).with(
'java -jar /usr/share/java/jenkins-cli.jar -s http://localhost:8080 -logger WARNING foo',
failonfail: true, combine: true
).twice.and_raise(UnknownError, 'foo')
expect(Puppet::Util::RetryAction).to receive(:retry_action).with(retries: 2, retry_exceptions: [UnknownError, NetError]).and_raise(UnknownError, 'foo')

expect { described_class.cli('foo', catalog: catalog) }.
to raise_error(UnknownError, 'foo')
Expand All @@ -547,10 +525,7 @@
)
catalog.add_resource jenkins

expect(described_class.superclass).to receive(:execute).with(
'java -jar /usr/share/java/jenkins-cli.jar -s http://localhost:8080 -logger WARNING foo',
failonfail: true, combine: true
).exactly(3).times.and_raise(UnknownError, 'foo')
expect(Puppet::Util::RetryAction).to receive(:retry_action).with(retries: 3, retry_exceptions: [UnknownError, NetError]).and_raise(UnknownError, 'foo')

expect { described_class.cli('foo', catalog: catalog) }.
to raise_error(UnknownError, 'foo')
Expand All @@ -565,69 +540,12 @@
)
catalog.add_resource jenkins

expect(described_class.superclass).to receive(:execute).with(
'java -jar /usr/share/java/jenkins-cli.jar -s http://localhost:8080 -logger WARNING foo',
failonfail: true, combine: true
).twice.and_raise(UnknownError, 'foo')
expect(Puppet::Util::RetryAction).to receive(:retry_action).with(retries: 2, retry_exceptions: [UnknownError, NetError]).and_raise(UnknownError, 'foo')

expect { described_class.cli('foo', catalog: catalog) }.
to raise_error(UnknownError, 'foo')
end
end

context 'waiting up to n seconds' do
# this isn't behavioral testing because we don't want to either wait
# for the wallclock delay timeout or attempt to accurate time examples
it 'by default' do
jenkins = Puppet::Type.type(:component).new(
name: 'jenkins::cli::config'
)
catalog.add_resource jenkins

expect(described_class).to receive(:with_retries).with(hash_including(max_sleep_seconds: 2))

described_class.cli('foo', catalog: catalog)
end

it 'from catalog value' do
jenkins = Puppet::Type.type(:component).new(
name: 'jenkins::cli::config',
cli_try_sleep: 3
)
catalog.add_resource jenkins

expect(described_class).to receive(:with_retries).with(hash_including(max_sleep_seconds: 3))

described_class.cli('foo', catalog: catalog)
end

it 'from fact' do
Facter.add(:jenkins_cli_try_sleep) { setcode { 4 } }

jenkins = Puppet::Type.type(:component).new(
name: 'jenkins::cli::config'
)
catalog.add_resource jenkins

expect(described_class).to receive(:with_retries).with(hash_including(max_sleep_seconds: 4))

described_class.cli('foo', catalog: catalog)
end

it 'from catalog overriding fact' do
Facter.add(:jenkins_cli_try_sleep) { setcode { 4 } }

jenkins = Puppet::Type.type(:component).new(
name: 'jenkins::cli::config',
cli_try_sleep: 3
)
catalog.add_resource jenkins

expect(described_class).to receive(:with_retries).with(hash_including(max_sleep_seconds: 3))

described_class.cli('foo', catalog: catalog)
end
end
end

context 'options with :stdinjson' do
Expand Down
13 changes: 0 additions & 13 deletions spec/unit/puppet/x/spec_jenkins_providers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,6 @@
described_class.confine_collection.instance_variable_get(:@confines)
end

it 'has no matched confines' do
expect(described_class.confine_collection.summary).to eq({})
end

context 'feature :retries' do
it do
expect(confines).to include(
be_a(Puppet::Confine::Feature).
and(have_attributes(values: [:retries]))
)
end
end

context 'commands :java' do
it do
expect(confines).to include(
Expand Down
Loading