A chocolatey provider is required, to install packages this will work but only works once another pp file finishes executing.
The problem is that puppet evaluates both files under the node statement and errors on invalid provider; the problem is I run the first pp file by commenting the other out , then let it run & uncomment it then rerun with puppet agent --test it all works.
I have tried tags and used an if statement with the tag , but this doesn't seem to work either.
class windows::chocolatey {
exec { 'set_executionpolicy':
command => "set-executionpolicy unrestricted -force -scope process;
(iex((new-object
net.webclient).DownloadString('https://chocolatey.org/install.ps1')))>\$null
2>&1",
provider => 'powershell',
creates => 'C:/ProgramData/chocolatey',
}
node "web-iis-02" {
class { 'windows':} #chocolatey installing to allow atom.pp to work
class { 'atom': } # init.pp below install using chocolatey
#installs package
class atom {
if tagged(windows) {
include atom::pakages
notify { "Calling Pakagepp script": }
}
}
#if tagged init.pp above calls this:
class atom::pakages {
include chocolatey
package { 'Atom':
ensure => 'latest',
provider => 'chocolatey',
}
I get this from pakages.pp:
Error: Failed to apply catalog: Parameter provider failed on
Package[Atom]: Invalid package provider 'chocolatey' (file:
/etc/puppetlabs/code/environments/production/modules/atom/manifests/pakages.pp, line: 3)
Try adding a require dependency, so the atom class is declared after the windows class:
class { 'windows': }
class { 'atom':
require => Class['windows'],
}
or quick and dirty:
class { 'windows': }
-> class { 'atom': }
You'll need to remove that tagged condition as it isn't needed.
I can't quite tell from your question which classes depend on which, but I'm pretty sure it is require you need. You may need to add a require for the chocolatey class:
class { 'atom':
require => Class['windows', 'chocolatey'],
}
Related
I'm working with Puppet 4.5 in masterless configuration and am trying to create a Puppet function to read a simple config file that assigns roles and environments. I don't have any integration with hiera/facter that I can change.
The file format is:
host1::java_app_node::qa
host2::nodejs_app_node::prod
The Puppet function that will read this file is in a module called homebase. I want to function to return a hash or array of hashes that split the config values. This will let me use them in templates.
In modules/homebase/manifests/init.pp I define:
$role_file = 'puppet://role.lst'
I then created modules/homebase/functions/get_roles.pp as follows:
function homebase::get_roles() {
$func_name = 'homebase::get_roles()'
if ! File.exists?($::homebase::role_file) {
fail("Could not find #{$::homebase::role_file}")
}
hosts = { }
File.open($::homebase::role_file).each |line| {
parts = line.split(/::/)
hosts[parts[0]] = { 'host' => parts[0], 'role' => parts[1], 'env' => parts[2] }
}
return hosts
}
In other classes, I then want to call:
class myapp {
$servers = homebase::get_roles().each | k, v | {
$v['host'] if $v['role'] =~ /myapp/ && $v['env'] == $environment
}
file { 'myapp.cfg':
ensure => file,
path => '/opt/myapp/myapp.cfg',
source => template("/myapp/myapp.cfg.erb"),
mode => '0644',
owner => myuser,
group => myuser,
}
}
Seems like there would be a better way to do this. Am I completely off base?
There turned out to be a much easier way to this rather than try to create a function to read a non-standard configuration file. Instead, I used a site.pp file to create node {} entries. I also parameterized the myapp class to take inputs based on the node.
So my site.pp looks like:
node 'server1.mydomain', 'server2.mydomain' {
$myvar = [ 'val1', 'val2' ]
class { 'myapp':
values => $myvar
}
}
This could probably be improved. One of the issues is with a non-Puppet configuration file I was able to also able to control execution in my bash wrapper script. Much of the need for that went away when, though, with the node definitions.
I have a module which installs my Application.
To install system packages i'm using virtual resource:
#package {[
'unzip',
'wget',
'htop',
'xorg-x11-server-Xvfb']:
ensure => installed,
}
define myapp1_packages {
realize(
Package['unzip'],
Package['fontconfig'],
Package['libfreetype.so.6'])
}
#myapp1_packages{ 'myapp1_packages': }
Then I use realize in my manifest to install the above packages:
realize(myapp1_packages['myapp1_packages'])
But for each version of my application I also need appropriate versions of system packages.
I need something like that:
if $app_version == '1.0' {
"install unzip-1xx"
"install fontconfig-1-xx"
"install libfreetype.so.6-1-x-xx"
elseif $app_version == '2.0'
"install unzip-2xx"
"install fontconfig-2-xx"
"install libfreetype.so.6-2-x-xx"
What is most elegant way to do this? And is it possible to keep virtual resources in that case? I'm looking to use ensure_packages but i worried about resource duplication. Thanks for the help!
The best thing to do here is to make $app_version a parameter for your module: https://docs.puppet.com/puppet/4.10/lang_classes.html#class-parameters-and-variables. Note an example from the documentation here: https://docs.puppet.com/puppet/4.10/lang_classes.html#appendix-smart-parameter-defaults.
For your situation, the class would look like:
myclass($app_version = 'default version') {
if $app_version == '1.0' {
#package { 'unzip': ensure => '1xx' }
#package { 'fontconfig': ensure => '1-xx' }
#package { 'libfreetype': ensure => '6-1-xx' }
}
elsif $app_version == '2.0' {
#package { 'unzip': ensure => '2xx' }
#package { 'fontconfig': ensure => '2-xx' }
#package { 'libfreetype': ensure => '6-2-xx' }
}
}
thus also allowing you to retain your virtual resources.
You can then pass parameters to this class by declaring it like:
class { 'myclass': app_version => '2.0' }
or using automatic data bindings with hieradata:
# puppet manifest
include myclass
# hieradata
myclass::app_version: 2.0
Your collector elsewhere will then realize the correct versions for your packages.
I want to use the elasticsearch/elasticsearch module in my own module called rehan. The elasticsearch/elasticsearch module provides a class called elasticsearch. If I also want to create a class in my module that makes use of the one in elasticsearch/elasticsearch, how can I achieve this? I have tried:
class rehan::elasticsearch {
class { 'elasticsearch':
manage_repo => true,
repo_version => '2.2',
require => Class['java']
}
elasticsearch::instance { 'es-01':
require => Package['elasticsearch'],
}
}
The above code errors with:
Error: Duplicate declaration: Class[Rehan::Elasticsearch] is already declared; cannot redeclare at..
In Puppet 3 (even with the future parser!), you need to use:
class { '::elasticsearch':
manage_repo => true,
repo_version => '2.2',
require => Class['java']
}
In Puppet 4, the resolution rules for types, classes and variables changed (it doens't try to resolve them contextually), so your code is valid.
This is how my manifest looks like:
class dotNetCore
{
notify { 'Installing NET-Framework-Core': }
windowsfeature { 'NET-Framework-Core': }
notify { 'Finished Installing NET-Framework-Core': }
}
class installIIS{
require dotNetCore
notify { 'Installing IIS': }
windowsfeature { 'IIS':
feature_name => [
'Web-Server',
'Web-WebServer',
'Web-Asp-Net45',
'Web-ISAPI-Ext',
'Web-ISAPI-Filter',
'NET-Framework-45-ASPNET',
'WAS-NET-Environment',
'Web-Http-Redirect',
'Web-Filtering',
'Web-Mgmt-Console',
'Web-Mgmt-Tools'
]
}
notify { 'Finished Installing IIS': }
}
class serviceW3SVC {
require installIIS
notify { 'Setting serviceW3SVC': }
service { 'W3SVC':
ensure => 'running',
enable => 'true',
}
notify { 'Finished Setting serviceW3SVC': }
}
class stopDefaultWebsite
{
require serviceW3SVC
notify { 'Stopping Default Web Site': }
iis::manage_site_state { 'Default Web Site':
ensure => 'stopped',
site_name => 'Default Web Site'
}
notify { 'Finished Stopping Default Web Site': }
}
class includecoreandiis
{
contain dotNetCore
contain installIIS
contain serviceW3SVC
contain stopDefaultWebsite
}
On the agent node, i am getting dependency error in the event viewer:
Failed to apply catalog: Parameter provider failed on Exec[add-feature-NET-Framework-Core]: Invalid exec provider 'powershell' at /etc/puppetlabs/puppet/environments/production/modules/windowsfeature/manifests/init.pp:111
Wrapped exception:
Invalid exec provider 'powershell'
After restarting the Puppet Agent service on the client node couple of times, it fetches the rest of the files and it works.
How do i make it wait for all the required files to be downloaded before installing the mentioned windows features?
You need to install the PowerShell provider module.
Additionally you may want to look at the windowsfeature module and anything that is available in the puppetlabs/windows module pack.
Sounds like a plugin sync issue after rereading, plus waiting for a suitable provider.
As part of my project, I need to read files from a directory and do some operations all these in build script. For each file, the operation is the same(reading some SQL queries and execute it). I think its a repetitive task and better to write inside a method. Since I'm new to Gradle, I don't know how it should be. Please help.
One approach given below:
ext.myMethod = { param1, param2 ->
// Method body here
}
Note that this gets created for the project scope, ie. globally available for the project, which can be invoked as follows anywhere in the build script using myMethod(p1, p2) which is equivalent to project.myMethod(p1, p2)
The method can be defined under different scopes as well, such as within tasks:
task myTask {
ext.myMethod = { param1, param2 ->
// Method body here
}
doLast {
myMethod(p1, p2) // This will resolve 'myMethod' defined in task
}
}
If you have defined any methods in any other file *.gradle - ext.method() makes it accessible project wide. For example here is a
versioning.gradle
// ext makes method callable project wide
ext.getVersionName = { ->
try {
def branchout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
standardOutput = branchout
}
def branch = branchout.toString().trim()
if (branch.equals("master")) {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--tags'
standardOutput = stdout
}
return stdout.toString().trim()
} else {
return branch;
}
}
catch (ignored) {
return null;
}
}
build.gradle
task showVersion << {
// Use inherited method
println 'VersionName: ' + getVersionName()
}
Without ext.method() format , the method will only be available within the *.gradle file it is declared. This is the same with properties.
You can define methods in the following way:
// Define an extra property
ext.srcDirName = 'src/java'
// Define a method
def getSrcDir(project) {
return project.file(srcDirName)
}
You can find more details in gradle documentation Chapter 62. Organizing Build Logic
An example with a root object containing methods.
hg.gradle file:
ext.hg = [
cloneOrPull: { source, dest, branch ->
if (!dest.isDirectory())
hg.clone(source, dest, branch)
else
hg.pull(dest)
hg.update(dest, branch)
},
clone: { source, dest, branch ->
dest.mkdirs()
exec {
commandLine 'hg', 'clone', '--noupdate', source, dest.absolutePath
}
},
pull: { dest ->
exec {
workingDir dest.absolutePath
commandLine 'hg', 'pull'
}
},
]
build.gradle file
apply from: 'hg.gradle'
hg.clone('path/to/repo')
Somehow, maybe because it's five years since the OP, but none of the
ext.someMethod = { foo ->
methodBody
}
approaches are working for me. Instead, a simple function definition seems to be getting the job done in my gradle file:
def retrieveEnvvar(String envvar_name) {
if ( System.getenv(envvar_name) == "" ) {
throw new InvalidUserDataException("\n\n\nPlease specify environment variable ${envvar_name}\n")
} else {
return System.getenv(envvar_name)
}
}
And I call it elsewhere in my script with no prefix, ie retrieveEnvvar("APP_PASSWORD")
This is 2020 so I'm using Gradle 6.1.1.
#ether_joe the top-voted answer by #InvisibleArrow above does work however you must define the method you call before you call it - i.e. earlier in the build.gradle file.
You can see an example here. I have used this approach with Gradle 6.5 and it works.
With Kotlin DSL (build.gradle.kts) you can define regular functions and use them.
It doesn't matter whether you define your function before the call site or after it.
println(generateString())
fun generateString(): String {
return "Black Forest"
}
tasks.create("MyTask") {
println(generateString())
}
If you want to import and use a function from another script, see this answer and this answer.
In my react-native in build.gradle
def func_abc(y){return "abc"+y;}
then
def x = func_abc("y");
If you want to check:
throw new GradleException("x="+x);
or
println "x="+x;