How to Check if a File or Directory Exists in Puppet Using Conditional Statements


1 views

Many Puppet users encounter this common frustration: you want to check whether a file or directory actually exists on the filesystem, but Puppet's native resource references don't provide this functionality. The File resource type in Puppet is declarative - it describes what the system should look like, not what it currently looks like.

These common attempts don't work as expected:

if File['/some/path'] {
  # This always returns true because it's checking resource definition
}

if defined(File['/some/path']) {
  # Only checks if the resource is declared in Puppet code
}

Puppet provides a file() function that can read file contents during catalog compilation. We can leverage its behavior when files don't exist:

$file_exists = file('/some/path', '/dev/null') != '/dev/null'

if $file_exists {
  notify { 'File exists': }
} else {
  fail('The specified file does not exist')
}

For directories, we need a slightly different approach:

define directory_exists($path) {
  $check = generate('/bin/sh', '-c', "test -d ${path} && echo exists || echo missing")
  
  if $check == 'missing' {
    fail("Directory ${path} does not exist")
  }
}

directory_exists { 'check_my_dir':
  path => '/some/directory'
}

For more complex scenarios, consider creating a custom fact:

# In module/lib/facter/file_exists.rb
Facter.add('file_exists') do
  setcode do
    File.exist?('/some/path').to_s
  end
end

Then use it in your manifest:

if $facts['file_exists'] == 'true' {
  # Your code here
}

Remember that these checks happen during catalog compilation. For frequently changing filesystems, consider:

  • Using exported resources
  • Implementing the check in an exec resource with onlyif
  • Creating a custom provider

Here's a complete example that checks multiple paths:

class check_paths {
  $paths_to_check = ['/etc/puppetlabs', '/tmp/nonexistent']
  
  $paths_to_check.each |$path| {
    $check = generate('/bin/sh', '-c', "test -e ${path} && echo exists || echo missing")
    
    if $check == 'missing' {
      notify { "${path} does not exist": }
      # Or fail() if you want to stop execution
    } else {
      notify { "${path} exists": }
    }
  }
}

When working with Puppet manifests, you might need to verify whether a file or directory exists on the target system before proceeding with certain operations. The naive approach of using if File["/some/path"] doesn't work as expected because it checks for resource declaration in the catalog, not actual filesystem existence.

Puppet doesn't provide a direct way to check filesystem existence in its DSL, but we can achieve this through several methods:

# Method 1: Using the find_file function (Puppet 4.8+)
if find_file('/some/path') != undef {
  # Path exists
} else {
  fail("Required path /some/path does not exist")
}

# Method 2: Using a custom fact
# Add this to your custom fact library
Facter.add('path_exists') do
  setcode do
    File.exist?('/some/path')
  end
end

# Then in your manifest:
if $facts['path_exists'] {
  # Proceed
}

For older Puppet versions, you can use the generate function to call external commands:

$path_exists = generate('/usr/bin/test', '-e', '/some/path')
if $path_exists.empty {
  fail("Path /some/path does not exist")
}

When implementing these checks:

  • Prefer custom facts for performance (they're evaluated once per run)
  • Use absolute paths for all file operations
  • Consider adding descriptive fail messages
  • Test edge cases (symlinks, permissions, etc.)

Here's a complete example that creates a directory only if a prerequisite path exists:

# In custom fact (e.g., modules/custom/lib/facter/prerequisite_exists.rb)
Facter.add('prerequisite_exists') do
  setcode do
    File.directory?('/important/prerequisite')
  end
end

# In your manifest
if $facts['prerequisite_exists'] {
  file { '/dependent/directory':
    ensure => directory,
    owner  => 'root',
    group  => 'root',
    mode   => '0755',
  }
} else {
  notify { 'prerequisite-warning':
    message => "Skipping creation: /important/prerequisite not found",
    loglevel => 'warning',
  }
}

When troubleshooting file existence checks:

  • Run puppet facts to verify custom fact values
  • Check system logs for permission issues
  • Test commands manually on target nodes
  • Use puppet apply --debug for detailed execution tracing