Search code examples
puppet

Puppet: variables inside variables


Hopefully a simple question, is there a way I can put variables inside other variables? In my particular use case, I am trying to get tricky to have puppet install a whole bunch of binaries (ant, maven, jdk's etc)

Let's say I have the following manifest:

$package_name = [ 'ant', 'maven' ]
$package_ant_versions = [ '1.7.1', '1.8.4', '1.9.4' ]
$package_ant_prefix = 'apache-ant-'
$package_ant_suffix = '-src.tar.gz'
$package_maven_versions = [ '3.0.4' ]
$package_maven_prefix = 'apache-maven-'
$package_maven_suffix = '.tgz'
$path = 'repo.domain.com/software'

So there are my variables. Now I am trying to write an exec statement that will iterate through all packages and variables and download them locally, so I may install them.

Here is my attempt at the command:

exec { 'download-packages': 
    command => "/usr/bin/aws s3 cp ${path}/${package_name}/${package_${package_name}_prefix}/{package_${package_name}_versions}/${package_${package_name}_suffix} /tmp"
}

The way I had hoped it would work was that it would iterate through all variables. For example, with the defined variables the commands that would be run are:

/usr/bin/aws s3 cp repo.domain.com/software/ant/apache-ant-1.7.1-src.tar.gz /tmp
/usr/bin/aws s3 cp repo.domain.com/software/ant/apache-ant-1.8.4-src.tar.gz /tmp
/usr/bin/aws s3 cp repo.domain.com/software/ant/apache-ant-1.9.4-src.tar.gz /tmp
/usr/bin/aws s3 cp repo.domain.com/software/maven/apache-maven-3.0.4.tgz /tmp

The end result is that I simply want to add/change versions in the manifest (e.g. I could go in and add ant version 1.9.3 simply by changing:

$package_ant_versions = [ '1.7.1', '1.8.4', '1.9.4' ]

to

$package_ant_versions = [ '1.7.1', '1.8.4', '1.9.3', '1.9.4' ]

And have puppet do the rest (assuming the file is available in the location it is trying to download from).

I am sure I am doing this all wrong, but I hope the end result I am trying to get to is clear. It seems to break when I try and put variables inside variables:

${package_${package_name}_prefix}
${package_${package_name}_versions}
${package_${package_name}_suffix}

Any help to get this working or achieve something similar would be really helpful.

Thanks!


Solution

  • First, as was noted, use a structure like the following.

    $packages = { 
        'ant' => { 
            'versions' => [ '1.7.1', '1.8.4', '1.9.4', ], 
            'prefix' => 'apache-ant-', 
            'suffix' => '-src.tar.gz',
        },
        'maven' => { 
            'versions' => [ '3.0.4', ],
            'prefix' => 'apache-maven-', 
            'suffix' => '-bin.tar.gz',
        }
    }
    

    Note that the array of versions cannot be sensibly used in a single exec resource. I think you want this:

    define software_download($versions, $prefix, $suffix) {
        software_version_download { $versions:
            software => $name,
            prefix => $prefix,
            suffix => $suffix,
        }
    }
    
    define software_version_download($software, $prefix, $suffix) {
        $version = $name
        exec { "download-$software-$version": 
            command => "/usr/bin/aws s3 cp ${path}/${software}/${prefix}${version}${suffix} /tmp",
        }
    }
    

    The define software_download accepts your data and multiplexes it to the software_version_download define, passing each distinct version as the resource $name. From that, the final command is constructed.

    If your data is in the hash, you can create_resources('software_download', $packages), or less magically via manifest code:

    software_download { 
        'ant': 
            'versions' => [ '1.7.1', '1.8.4', '1.9.4', ], 
            'prefix' => 'apache-ant-', 
            'suffix' => '-src.tar.gz';
        'maven':
            'versions' => [ '3.0.4', ],
            'prefix' => 'apache-maven-', 
            'suffix' => '-bin.tar.gz';
    }