Customize CFEngine3 temporary downloaded files location - linux

I am facing a issue while trying configuring something with CFENGINE3.5, I have created a policy to install some package from source, which download tar balls from some url and then untar it and further digs it with make and make install, everything working fine except while it download tar balls it keeps at "/etc" location, I want cfengine to put this file at /tmp.
Is there any way to customize this default behavior of cfengine to keep all temporary downloaded files at "/tmp" instead of "/etc".
Here is the Policy snippet:
bundle agent install
{
vars:
"packages" slist => {
"Algorithm-Diff-1.1902",
"Apache-DB-0.13",
"Apache-DBI-1.06",
"Apache-Session-1.83",
"Apache-SessionX-2.01",
"AppConfig-1.65",
"Archive-Tar-1.32",
};
commands:
"/usr/bin/wget http://10.X.X.X/downloads/perl-modules/$(packages).tar.gz;
/usr/bin/gunzip $(packages).tar.gz;
tar -xf $(packages).tar;
cd $(packages);
/usr/bin/perl Makefile.PL;
/usr/bin/make;
/usr/bin/make install;"
contain => standard,
classes => satisfied(canonify("$(packages)-installed"));
}
body contain standard
{
useshell => "true";
exec_owner => "root";
}
Thanks in advance.

You can add the directory in which the commands should be executed to the contain body, like this:
body contain standard
{
useshell => "true";
exec_owner => "root";
chdir => "/tmp";
}
Please note there are already a few contain bodies in the standard library (lib/3.5/commands.cf), maybe one of those can be used so you don't have to write your own. Note that CFEngine already executes as root, so exec_owner => "root" is not strictly necessary.

Related

How to include multiple values under a section in inifile

I am trying to create a puppet manifest using inifile. This would be for a configuration file where I need to have the following format.
[safe]
directory = /home/foo
directory = /home/test
directory = /home/something
I know that there is a way to use directory1, and directory2 but I was wondering if there is a way to do it without changing the directory since it needs that specific attribute. This implementation is meant for puppet manifest.
Also, I was thinking puppetlabs/inifile module but if there is another option to achieve this would be great too.
Thanks for the help in advance
So far, I have an implementation like:
ini_setting { 'procedure cache size':
ensure => present,
path => '/var/lib/somethning/test.config',
section => 'safe',
setting => 'directory',
value => '/home/foo',
indent_char => "\t",
}
This is for each directory. The purpose for this implementation is to address the new git configuration for safe.repository in the recent update. My understanding is that for multiple directories, it adds a new value as directory = <directory> I don't believe that it likes directories separate by commas.
First I thought about file_line, but this is not idempotent for multi-line settings (you get problems when you run again). You can try:
Sample puppet code dir.pp
$safe_directories="directory = /home/foo
directory = /home/test
directory = /home/something"
notice "Testing\n${safe_directories}"
file { "/tmp/result.ini":
ensure => present,
content => template('/tmp/layout.erb'),
}
notice "Check /tmp/result.ini"
Sample template /tmp/layout.erb
[unsafe]
directory=/unsafe
[safe]
<%=#safe_directories%>
otherfield=secure
[header3]
nothing = here
Now run command from commandline
puppet apply dir.pp

How can I install binary file into NixOS

I'm trying to install external binary inside NixOS, using declarative ways. Inside nix-pkg manual, I found such way of getting external binary inside NixOS
{ pkgs ? import <nixpkgs> {} }:
pkgs.stdenv.mkDerivation {
name = "goss";
src = pkgs.fetchurl {
url = "https://github.com/aelsabbahy/goss/releases/download/v0.3.13/goss-linux-amd64";
sha256 = "1q0kfdbifffszikcl0warzmqvsbx4bg19l9a3vv6yww2jvzj4dgb";
};
phases = ["installPhase"];
installPhase = ''
'';
But I'm wondering, what should I add inside InstallPhase, to make this binary being installed inside the system?
This seems to be an open source Go application, so it's preferable to use Nixpkgs' Go support instead, which may be more straightforward than patching a binary.
That said, installPhase is responsible creating the $out path; typically mkdir -p $out/bin followed by cp, make install or similar commands.
So that's not actually installing it into the system; after all Nix derivations are not supposed to have side effects. "Installing" it into the system is the responsibility of NixOS's derivations, as configured by you.
You could say that 'installation' is the combination of modifying the NixOS configuration + switching to the new NixOS. I tend to think about the modification to the configuration only; the build and switch feel like implementation details, even though nixos-rebuild is usually a manual operation.
Example:
installPhase = ''
install -D $src $out/bin/goss
chmod a+x $out/bin/goss
'';
Normally chmod would be done to a local file by the build phase, but we don't really need that phase here.
I have no idea why this was so hard to figure out. Having robust configuration systems is fine, but at the end of the day sometimes you just need to be able to download and expose a single flipping file on the $PATH.
The result of fetchurl is "the unaltered contents of the URL within the Nix store", which is being used for the src. So in installPhase, $src points to the downloaded data, and you just have to copy/install/link that into $out/…..
pkgs.stdenv.mkDerivation {
name = "hello_static";
src = pkgs.fetchurl {
name = "hello_static";
url = "https://raw.githubusercontent.com/ruanyf/simple-bash-scripts/6e837f949010e0f5e9305e629da946de12cc63e8/scripts/hello-world.sh";
sha256 = "sha256:somE27ajbm0TtWv9tyeqTWDW3gbIs6xvlcFS9QS1ZJ0=";
};
phases = [ "installPhase" ];
installPhase = ''
install -D $src $out/bin/hello_static
'';
};

Custom fact should run after a package is installed

I have a small custom fact in a my php module
Facter.add('php_extension_version') do
setcode do
Facter::Core::Execution.exec("php -i | awk '/^PHP Extension =>/ { print $4}'") || nil
end
end
This obviously requires the php binary to be installed. However, I noticed that all facts are run once before applying the catalog, so this fact is invalid before php installed.
Is there any way of gathering the information after the module is installed? Is there perhaps another way of exposing this information except facter?
Update
I'm using the two facts to determine which of multiple .so files is the right one to install:
if $php_zts_enabled {
$so_name = "newrelic-$php_extension_version.so"
} else {
$so_name = "newrelic-$php_extension_version-zts.so"
}
file {"/usr/lib64/php5/extensions/newrelic.so":
source => "file:///opt/newrelic-php5-$version-linux/agent/x64/$so_name",
owner => root,
group => root,
mode => 0644,
notify => Service['apache'],
require => Exec["extract-php-agent-$version"]
}
The files that are located in the agent/x64 directory can be
newrelic-20060613.so newrelic-20090626-zts.so newrelic-20121212.so newrelic-20131226-zts.so
newrelic-20060613-zts.so newrelic-20100525.so newrelic-20121212-zts.so
newrelic-20090626.so newrelic-20100525-zts.so newrelic-20131226.so
You essentially have only two opportunities to execute code on the node:
As part of a Facter fact. As you are aware, this happens before puppet applies a catalog, so any facts dependent on the results of the puppet run will not be useful until the next run.
As part of a custom provider. You can create a custom type and provider for installing the extensions that checks the node state before deciding what to do. Providers execute on the node, and as long as you know the overall provider lifecycle you can make this happen after the PHP install. However, this is incredibly complex compared to normal puppet modules.
Outside of those options, the normal way of doing this would be to enforce the version and configuration of php within your own manifests, and then pass that information to here. You should already know the version of PHP and its extensions based on what packages you have installed.
I would modify the fact so that it's present only when the binary is present (hence it won't be present at the very first run).
Facter.add('php_extension_version') do
setcode do
if system("which php > /dev/null 2>&1")
Facter::Core::Execution.exec("php -i | awk '/^PHP Extension =>/ { print $4}'") || nil
end
end
end
and then in your manifest you'd wrap the original code in the if
if $php_extension_version {
if $php_zts_enabled {
$so_name = "newrelic-$php_extension_version.so"
} else {
$so_name = "newrelic-$php_extension_version-zts.so"
}
file {"/usr/lib64/php5/extensions/newrelic.so":
source => "file:///opt/newrelic-php5-$version-linux/agent/x64/$so_name",
owner => root,
group => root,
mode => 0644,
notify => Service['apache'],
require => Exec["extract-php-agent-$version"]
}
}

Puppet unzip file always into read only folder

I am using following script part to unzip my zip file. But the problem is it unzips the file always into a readonly folder. How can this be fixed.
exec { "install appliction server to pc":
command => 'unzip wso2as-5.2.1.zip',
cwd => '/home/malintha/adikari3/',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
logoutput => true,
timeout => 3600,
require => File['/home/malintha/adikari3/wso2as-5.2.1.zip'],
}
There are three parameters to the exec type, of which you should use at least one, to control when and when not to run
onlyif
unless
creates
The unzipping of an archive typically lends itself to a creates solution
exec { "unzip-file":
cwd => "/path/for/extraction",
creates => "/path/for/extraction/software-x.y",
...
}
assuming that the zip extracts into a directory tree rooted at software-x.y.
For more details, see the reference documentation.

CFENGINE: policy to perform bunch of commands on bunch of packages

I have to create one CFENGINE 3 Policy which should take input from defined input list and then want to perform some bunch of commands on that set one by one.
For Eg:
For only one Package here I have the example:
bundle agent test_tester_install
{
commands:
"/usr/bin/wget http://something.example.com/perl-modules/Test-Tester-0.104.tar.gz;
/usr/bin/gunzip Test-Tester-0.104.tar.gz;
tar -xf Test-Tester-0.104.tar;
cd Test-Tester-0.104;
/usr/bin/perl Makefile.PL;
/usr/bin/make;
/usr/bin/make install"
contain => standard,
classes => satisfied("Test-Tester Installed");
}
body contain standard
{
useshell => "true";
exec_owner => "root";
}
body classes satisfied(new_class)
{
promise_repaired => { "$(new_class)" };
}
But I am not sure that how to do it if I want to do the same for 100 packages. I think "slist would do this but how exactly i need to draft that policy i am not sure"
This is very similar to applying "for" loop in bash shell where we iterate input one by one and perform some operations
Experts Please help
The way to do something like this is to use CFEngine's implicit looping. You store the values in a list, and then iterate over them in the promises. For your example, it would be something like this:
bundle agent install
{
vars:
"packages" slist => { "Test-Tester-0.104", "Foo-Bar-1.001" }; # etc.
commands:
"/usr/bin/wget http://something.example.com/perl-modules/$(packages).tar.gz;
/usr/bin/gunzip $(packages).tar.gz;
tar -xf $(packages).tar;
cd $(packages);
/usr/bin/perl Makefile.PL;
/usr/bin/make;
/usr/bin/make install"
contain => standard,
classes => satisfied(canonify("$(packages)-installed"));
}
Note that I'm using $(package) whenever you previously had Test-Tester-0.104. Of course this only works if all the names are consistent in this respect. To add more, you'd only need to add the names to the packages variable. Not also that I used canonify() to make the string that gets passed to the satisfied() body a valid class name.
Now, if you are going to be doing a lot of installs like this, what I would suggest is defining a new package_method definition, which takes care of following the right steps internally, so that in your policy you can have something much cleaner, like this:
vars:
"packages" slist => { "Test-Tester-0.104", "Foo-Bar-1.001" }; # etc.
packages:
"$(packages)"
package_policy => "add",
package_method => perlsrcpkg; # or whatever you call your new package_method
You can find the documentation for packages promises here: http://cfengine.com/docs/3.5/reference-promise-types-packages.html#packages, and a bunch of package_method definition examples in the CFEngine Standard Library: https://github.com/cfengine/masterfiles/blob/master/lib/3.5/packages.cf
Finally, if the packages you are installing are from CPAN, you could just use the Packages::Installed::cpanm sketch from the Design Center: https://cfengine.com/cfengine-design-center/sketches/packages-cpan-cpanm

Resources