Skip to content

Commit

Permalink
add onlyif && unless features
Browse files Browse the repository at this point in the history
lint

remove debug

fixe check_all_attributes

lint
  • Loading branch information
Zarne committed Aug 13, 2024
1 parent 1abd3c1 commit beafb0f
Show file tree
Hide file tree
Showing 11 changed files with 988 additions and 34 deletions.
40 changes: 39 additions & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2023-08-17 21:26:09 UTC using RuboCop version 1.50.2.
# on 2024-08-06 17:00:26 UTC using RuboCop version 1.50.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand All @@ -12,6 +12,44 @@ Lint/NonAtomicFileOperation:
Exclude:
- 'lib/puppet/provider/archive/ruby.rb'

# Offense count: 1
Naming/AccessorMethodName:
Exclude:
- 'lib/puppet/type/archive.rb'

# Offense count: 1
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
Naming/MethodParameterName:
Exclude:
- 'spec/lib/puppet_spec/files.rb'

# Offense count: 9
# Configuration parameters: AssignmentOnly.
RSpec/InstanceVariable:
Exclude:
- 'spec/unit/puppet/provider/archive/ruby_spec.rb'
- 'spec/unit/puppet/type/archive_spec.rb'

# Offense count: 1
# Configuration parameters: EnforcedStyle.
# SupportedStyles: have_received, receive
RSpec/MessageSpies:
Exclude:
- 'spec/lib/puppet_spec/compiler.rb'

# Offense count: 4
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
RSpec/VerifiedDoubles:
Exclude:
- 'spec/unit/puppet/type/archive_spec.rb'

# Offense count: 4
# Configuration parameters: AllowedVariables.
Style/GlobalVars:
Exclude:
- 'spec/lib/puppet_spec/files.rb'

# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowComments.
Expand Down
88 changes: 88 additions & 0 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -632,13 +632,19 @@ Parameters
Examples
--------

#### Examples

#####

```puppet
archive::nexus { '/tmp/jtstand-ui-0.98.jar':
url => 'https://oss.sonatype.org',
gav => 'org.codehaus.jtstand:jtstand-ui:0.98',
repository => 'codehaus-releases',
packaging => 'jar',
extract => false,
}
```

#### Parameters

Expand Down Expand Up @@ -895,6 +901,72 @@ whether archive file should be present/absent (default: present)

Default value: `present`

##### `onlyif`

A test command that checks the state of the target system and restricts
when the `archive` can run. If present, Puppet runs this test command
first, and only runs the main command if the test has an exit code of 0
(success). For example:

```
archive { '/tmp/jta-1.1.jar':
ensure => present,
extract => true,
extract_path => '/tmp',
source => 'http://central.maven.org/maven2/javax/transaction/jta/1.1/jta-1.1.jar',
onlyif => 'test `java -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{sub("^$", "0", $2); print $1$2}'` -gt 15',
cleanup => true,
env_path => ["/bin", "/usr/bin", "/sbin", "/usr/sbin"],
}
```

Since this command is used in the process of determining whether the
`archive` is already in sync, it must be run during a noop Puppet run.

This parameter can also take an array of commands. For example:

onlyif => ['test -f /tmp/file1', 'test -f /tmp/file2'],

or an array of arrays. For example:

onlyif => [['test', '-f', '/tmp/file1'], 'test -f /tmp/file2']

This `archive` would only run if every command in the array has an
exit code of 0 (success).

##### `unless`

A test command that checks the state of the target system and restricts
when the `archive` can run. If present, Puppet runs this test command
first, then runs the main command unless the test has an exit code of 0
(success). For example:

```
archive { '/tmp/jta-1.1.jar':
ensure => present,
extract => true,
extract_path => '/tmp',
source => 'http://central.maven.org/maven2/javax/transaction/jta/1.1/jta-1.1.jar',
unless => 'test `java -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{sub("^$", "0", $2); print $1$2}'` -gt 15',
cleanup => true,
env_path => ["/bin", "/usr/bin", "/sbin", "/usr/sbin"],
}
```

Since this command is used in the process of determining whether the
`archive` is already in sync, it must be run during a noop Puppet run.

This parameter can also take an array of commands. For example:

unless => ['test -f /tmp/file1', 'test -f /tmp/file2'],

or an array of arrays. For example:

unless => [['test', '-f', '/tmp/file1'], 'test -f /tmp/file2']

This `archive` would only run if every command in the array has a
non-zero exit code.

#### Parameters

The following parameters are available in the `archive` type.
Expand All @@ -910,6 +982,8 @@ The following parameters are available in the `archive` type.
* [`digest_type`](#-archive--digest_type)
* [`digest_url`](#-archive--digest_url)
* [`download_options`](#-archive--download_options)
* [`env_path`](#-archive--env_path)
* [`environment`](#-archive--environment)
* [`extract`](#-archive--extract)
* [`extract_command`](#-archive--extract_command)
* [`extract_flags`](#-archive--extract_flags)
Expand Down Expand Up @@ -998,6 +1072,20 @@ archive file checksum source (instead of specifying checksum)

provider download options (affects curl, wget, gs, and only s3 downloads for ruby provider)

##### <a name="-archive--env_path"></a>`env_path`

The search path used for check execution.
Commands must be fully qualified if no path is specified. Paths
can be specified as an array or as a '

##### <a name="-archive--environment"></a>`environment`

An array of any additional environment variables you want to set for a
command, such as `[ 'HOME=/root', '[email protected]']`.
Note that if you use this to set PATH, it will override the `path`
attribute. Multiple environment variables should be specified as an
array.

##### <a name="-archive--extract"></a>`extract`

Valid values: `true`, `false`
Expand Down
136 changes: 122 additions & 14 deletions lib/puppet/provider/archive/ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

require 'securerandom'
require 'tempfile'
require 'puppet/util/execution'

# This provider implements a simple state-machine. The following attempts to #
# document it. In general, `def adjective?` implements a [state], while `def
Expand Down Expand Up @@ -59,6 +60,7 @@
#

Puppet::Type.type(:archive).provide(:ruby) do
include Puppet::Util::Execution
optional_commands aws: 'aws'
optional_commands gsutil: 'gsutil'
defaultfor feature: :microsoft_windows
Expand Down Expand Up @@ -95,18 +97,6 @@ def tempfile_name
end
end

def creates
if resource[:extract] == :true
extracted? ? resource[:creates] : 'archive not extracted'
else
resource[:creates]
end
end

def creates=(_value)
extract
end

def checksum
resource[:checksum] || (resource[:checksum] = remote_checksum if resource[:checksum_url])
end
Expand All @@ -127,7 +117,7 @@ def remote_checksum
# returns boolean
def checksum?(store_checksum = true)
return false unless File.exist? archive_filepath
return true if resource[:checksum_type] == :none
return true if resource[:checksum_type] == :none

archive = PuppetX::Bodeco::Archive.new(archive_filepath)
archive_checksum = archive.checksum(resource[:checksum_type])
Expand Down Expand Up @@ -156,7 +146,7 @@ def extract
end

def extracted?
resource[:creates] && File.exist?(resource[:creates])
resource.check_all_attributes
end

def transfer_download(archive_filepath)
Expand Down Expand Up @@ -258,4 +248,122 @@ def optional_switch(value, option)
[]
end
end

# Verify that we have the executable
def checkexe(command)
exe = extractexe(command)
if Facter.value(:osfamily) == 'windows'
if absolute_path?(exe)
if !Puppet::FileSystem.exist?(exe)
raise ArgumentError, format(_("Could not find command '%{exe}'"), exe: exe)
elsif !File.file?(exe)
raise ArgumentError, format(_("'%{exe}' is a %{klass}, not a file"), exe: exe, klass: File.ftype(exe))
end
end
elsif File.expand_path(exe) == exe
if !Puppet::FileSystem.exist?(exe)
raise ArgumentError, format(_("Could not find command '%{exe}'"), exe: exe)
elsif !File.file?(exe)
raise ArgumentError, format(_("'%{exe}' is a %{klass}, not a file"), exe: exe, klass: File.ftype(exe))
elsif !File.executable?(exe)
raise ArgumentError, format(_("'%{exe}' is not executable"), exe: exe)
end
end

if resource[:env_path]
Puppet::Util.withenv PATH: resource[:env_path].join(File::PATH_SEPARATOR) do
return if which(exe)
end
end

# 'which' will only return the command if it's executable, so we can't
# distinguish not found from not executable
raise ArgumentError, format(_("Could not find command '%{exe}'"), exe: exe)
end

def environment
env = {}

if (path = resource[:env_path])
env[:PATH] = path.join(File::PATH_SEPARATOR)
end

return env unless (envlist = resource[:environment])

envlist = [envlist] unless envlist.is_a? Array
envlist.each do |setting|
unless (match = %r{^(\w+)=((.|\n)*)$}.match(setting))
warning "Cannot understand environment setting #{setting.inspect}"
next
end
var = match[1]
value = match[2]

warning "Overriding environment setting '#{var}' with '#{value}'" if env.include?(var) || env.include?(var.to_sym)

if value.nil? || value.empty?
msg = "Empty environment setting '#{var}'"
Puppet.warn_once('undefined_variables', "empty_env_var_#{var}", msg, resource.file, resource.line)
end

env[var] = value
end

env
end

def run(command, check = false)
checkexe(command)

debug "Executing#{check ? ' check' : ''} #{command}"

cwd = resource[:extract] ? resource[:extract_path] : File.dirname(resource[:path])
# It's ok if cwd is nil. In that case Puppet::Util::Execution.execute() simply will not attempt to
# change the working directory, which is exactly the right behavior when no cwd parameter is
# expressed on the resource. Moreover, attempting to change to the directory that is already
# the working directory can fail under some circumstances, so avoiding the directory change attempt
# is preferable to defaulting cwd to that directory.

# NOTE: that we are passing "false" for the "override_locale" parameter, which ensures that the user's
# default/system locale will be respected. Callers may override this behavior by setting locale-related
# environment variables (LANG, LC_ALL, etc.) in their 'environment' configuration.
output = Puppet::Util::Execution.execute(
command,
failonfail: false,
combine: true,
cwd: cwd,
uid: resource[:user],
gid: resource[:group],
override_locale: false,
custom_environment: environment,
sensitive: false
)
# The shell returns 127 if the command is missing.
raise ArgumentError, output if output.exitstatus == 127

# Return output twice as processstatus was returned before, but only exitstatus was ever called.
# Output has the exitstatus on it so it is returned instead. This is here twice as changing this
# would result in a change to the underlying API.
[output, output]
end

def extractexe(command)
if command.is_a? Array
command.first
else
match = %r{^"([^"]+)"|^'([^']+)'}.match(command)
if match
# extract whichever of the two sides matched the content.
match[1] or match[2]
else
command.split(%r{ })[0]
end
end
end

def validatecmd(command)
exe = extractexe(command)
# if we're not fully qualified, require a path
self.fail "'#{exe}' is not qualified and no path was specified. Please qualify the command or specify a path." if !absolute_path?(exe) && resource[:path].nil?
end
end
Loading

0 comments on commit beafb0f

Please sign in to comment.