Puppet Install specific version of package depending on application version - ruby

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.

Related

Only run another PP file after one has completed

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'],
}

How to disable chunkhash in neutrino.js?

I'm looking for a way to disable chunkhash in neutrino.js when building, but didn't find any documentation about it, anyone could help?
Updated:
As in webpack, I can customize the output.filename, in neutrino.js, it seems the string "[name].[hash].bundle.js" is baked in, and there's no way to remove [hash] as far as I can see.
In your .neutrinorc.js file, you can add an additional override function to change the output filename to not include the chunk hash (using neutrino-preset-react as an example:
module.exports = {
use: [
'neutrino-preset-react',
(neutrino) => {
// the original value of filename is "[name].[chunkhash].js"
neutrino.config.output.filename('[name].js');
}
]
};
If you want to change build targets based on an environment variable:
module.exports = {
use: ['neutrino-preset-react'],
env: {
NEUTRINO_TARGET: {
desktop: {
use: [
(neutrino) => neutrino.config.output.filename('[name].js');
]
},
mobile: {
use: [
(neutrino) => neutrino.config.entry('mobile').add('index.mobile.js');
]
}
}
}
};
Then you can run Neutrino twice with differing environments:
NEUTRINO_TARGET=desktop neutrino build
NEUTRINO_TARGET=mobile neutrino build

Handling Two Puppet Classes with the Same Name

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.

dependency error while running windowsfeature

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.

How to detect the current OS from Gradle

I found this answer about how to do it with Groovy:
Detecting the platform (Window or Linux) by Groovy/Grails:
if (System.properties['os.name'].toLowerCase().contains('windows')) {
println "it's Windows"
} else {
println "it's not Windows"
}
Is there a better way?
Actually, I looked at the Gradle project, and this looks a little cleaner as it uses Ant's existing structure:
import org.apache.tools.ant.taskdefs.condition.Os
task checkWin() << {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
println "*** Windows "
}
}
I found this in the following Gradle branch, and it seems to work nicely. gradle/gradle-core/branches/RB-0.3/build.gradle
Mid 2020 Update:
Still incubating:
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
Early 2019 Update: current() removed.
org.gradle.nativeplatform.platform.OperatingSystem.getDisplayName()
org.gradle.nativeplatform.platform.OperatingSystem.isLinux()
Keep in mind that it's still incubating though.
Mid 2018 Update: just like it was mentioned in comments, now this class moved to a different package, so one should use org.gradle.nativeplatform.platform.OperatingSystem.current()
As of mid 2015, Peter Kahn's answer is still valid. Environment-based profile activation is still something done relatively easier in Maven. But keep in mind that org.apache.tools.ant.taskdefs.condition.Os.isFamily is not exclusive in the sense that if it returns true with one particular parameter it is not necessarily means that it returns false for any other parameter. For instance:
import org.apache.tools.ant.taskdefs.condition.Os
task detect {
doLast {
println(Os.isFamily(Os.FAMILY_WINDOWS))
println(Os.isFamily(Os.FAMILY_MAC))
println(Os.isFamily(Os.FAMILY_UNIX))
}
}
It will return true both for Os.FAMILY_MAC and Os.FAMILY_UNIX on MacOS. Usually it is not something you need in build scripts.
There is though another way to achieve this using Gradle 2+ API, namely:
import org.gradle.internal.os.OperatingSystem;
task detect {
doLast {
println(OperatingSystem.current().isMacOsX())
println(OperatingSystem.current().isLinux())
}
}
Check out the documentation for the org.gradle.nativeplatform.platform.OperatingSystem interface. It is worth to mention that this interface is marked with incubating annotation, that is, "the feature is currently a work-in-progress and may change at any time". The "internal" namespace in the implementation also gives us a hint that we should use this knowing that this can change.
But personally I'd go with this solution. It's just that it's better to write a wrapper class so as not to mess up in case something will change in the future.
One can differentiate the build environment in between Linux, Unix, Windows and OS X - while the Gradle nativeplatform.platform.OperatingSystem differentiates the target environment (incl. FreeBSD and Solaris).
import org.gradle.internal.os.OperatingSystem
OperatingSystem os = OperatingSystem.current();
println "*** Building on ${os.familyName} / ${os.name} / ${os.version} / ${System.getProperty("os.arch")}."
println "*** Building on ${os.toString()}."
if (os.isLinux()) {
// Consider Linux.
} else if (os.isUnix()) {
// Consider UNIX.
} else if (os.isWindows()) {
// Consider Windows.
} else if (os.isMacOsX()) {
// Consider OS X.
} else {
// Unknown OS.
}
One can also use an Ant task (source):
import org.apache.tools.ant.taskdefs.condition.Os
task checkWin() << {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
// Consider Windows.
}
}
Or you can define osName as a string...
import org.gradle.internal.os.OperatingSystem
switch (OperatingSystem.current()) {
case OperatingSystem.LINUX:
project.ext.osName = "Linux";
break;
case OperatingSystem.MAC_OS:
project.ext.osName = "macOS";
break;
case OperatingSystem.WINDOWS:
project.ext.osName = "Windows";
break;
}
... and use it later - to include a native library for example:
run {
systemProperty "java.library.path", "lib/$osName"
}
But it wouldn't change anything since OperatingSystem works exactly like your code:
public static OperatingSystem forName(String os) {
String osName = os.toLowerCase();
if (osName.contains("Windows")) {
return WINDOWS;
} else if (osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx")) {
return MAC_OS;
} else if (osName.contains("sunos") || osName.contains("solaris")) {
return SOLARIS;
} else if (osName.contains("linux")) {
return LINUX;
} else if (osName.contains("freebsd")) {
return FREE_BSD;
} else {
// Not strictly true
return UNIX;
}
}
Source: https://github.com/gradle/gradle/blob/master/subprojects/base-services/src/main/java/org/gradle/internal/os/OperatingSystem.java
Edit:
You can do the same for the architecture:
project.ext.osArch = OperatingSystem.current().getArch();
if ("x86".equals(project.ext.osArch)) {
project.ext.osArch = "i386";
}
and:
run {
systemProperty "java.library.path", "lib/$osName/$osArch"
}
Just be aware that getArch() will return:
"ppc" on PowerPC
"amd64" on 64b
"i386" OR "x86" on 32b.
getArch() will return "x86" on Solaris or "i386" for any other platform.
Edit 2:
Or if you want to avoid any import, you can simply do it yourself:
def getOsName(project) {
final String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("linux")) {
return ("linux");
} else if (osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx")) {
return ("macos");
} else if (osName.contains("windows")) {
return ("windows");
} else if (osName.contains("sunos") || osName.contains("solaris")) {
return ("solaris");
} else if (osName.contains("freebsd")) {
return ("freebsd");
}
return ("unix");
}
def getOsArch(project) {
final String osArch = System.getProperty("os.arch");
if ("x86".equals(osArch)) {
return ("i386");
}
else if ("x86_64".equals(osArch)) {
return ("amd64");
}
else if ("powerpc".equals(osArch)) {
return ("ppc");
}
return (osArch);
}
Gradle doesn't provide a public API for detecting the operating system. Hence the os. system properties are your best bet.
I don't like detecting the OS in Gradle through properties or an Ant task, and the OperatingSystem class no longer contains the current() method.
So, in my opinion, the cleanest way to detect the OS would be:
Import DefaultNativePlatform:
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
Then use DefaultNativePlatform in your task:
if (DefaultNativePlatform.getCurrentOperatingSystem().isWindows()) {
println 'Windows'
}
Mind that this method is not ideal as it is using the Gradle internal API.
It was tested with Gradle 4.10.
Without any imports I got those values from System class like here:
def osName = System.getProperty("os.name").toLowerCase(Locale.ENGLISH)
def osArch = System.getProperty("os.arch").toLowerCase(Locale.ENGLISH)
def osVersion = System.getProperty("os.version").toLowerCase(Locale.ENGLISH)
This worked for me in 2022/2023 with Gradle 7.5
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
OperatingSystem os = DefaultNativePlatform.currentOperatingSystem;
os.isLinux()
os.isWindows()
os.isMacOsX()
According to #shabunc answer, some of your options are:
org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
org.apache.tools.ant.taskdefs.condition.Os
org.gradle.nativeplatform.platform.OperatingSystem
org.gradle.internal.os.OperatingSystem
Number 3 and 4 are basically the same interface, in which OperatingSystem.current() is actually OperatingSystem.isCurrent() (because of Groovy). So it did not work for me.
Number 2 is a viable option but not that elegant IMHO.
So this is how you can use option 1 (as an example was not included):
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
def os = DefaultNativePlatform.currentOperatingSystem
def arch = DefaultNativePlatform.currentArchitecture
def version = "1.0.0"
switch (true) {
case os.windows && arch.i386:
implementation "com.example:example-win32-x86:${version}"
break
case os.windows && arch.amd64:
implementation "com.example:example-win32-x86-amd64:${version}"
break
case os.macOsX && arch.amd64:
implementation "com.example:example-darwin-x86-amd64:${version}"
break
case os.linux && arch.i386:
implementation "com.example:example-linux-x86:${version}"
break
case os.linux && arch.amd64:
implementation "com.example:example-linux-x86-amd64:${version}"
break
default:
println "No suitable driver found for " +
"current OS (${os.displayName}) and " +
"architecture (${arch.displayName})"
}

Resources