user3558925
user3558925

Reputation: 143

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!

Upvotes: 0

Views: 1367

Answers (2)

Felix Frank
Felix Frank

Reputation: 8223

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';
}

Upvotes: 3

Raul Andres
Raul Andres

Reputation: 3806

You could do this using inline_template:

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

But, as @FelixFrank says, maybe is preferrible a structured way.

That solves the problem of variables inside variables. For the array problem, you could emulate a foreach statement:

$package_name= [ "ant", "maven" ]

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

Upvotes: 1

Related Questions