How to edit a file and pass values into it through Puppet - linux

I want to pass limit values in /etc/security/limits.conf in all servers available in environment through puppet. Need to be automated this process whenever i create new instance, this limit values directly append to new boxes

There's an official puppet module for modifying limits.
You could also use file_line for this.
file_line { 'append_limits_conf':
path => '/etc/security/limits.conf',
match => 'variable_name',
line => 'vriable_name = foobar',
}
The match will be used to determine if the variable is already declared within the file. If yes - it will change the value to whatever you define at line. If it's not in there it will just append the line.
More sophisticated file editing can be done with augeas - but might be overkill for you case right now.

Related

Terraform: Is there a way to ignore whitepace changes when generating a plan?

I wanted to ask if there is a way to ignore whitespace changes when creating a terraform plan.
This question is related to this one, I created a new one because I wanted to give a new example of the issue.
Terraform shows unnecessary changes due to whitespace
For example, when running
terraform plan
I get the following change for a helm provider resource
# helm_release.cert-manager will be updated in-place
~ resource "helm_release" "cert-manager" {
id = "cert-manager"
name = "cert-manager"
~ values = [
- <<-EOT
installCRDs: true
EOT,
+ <<-EOT
installCRDs: true
EOT,
]
# (27 unchanged attributes hidden)
}
I found out that the change was due to line endings. Deployed was CRLF and my local source file had LF as line ending.
Is there an option to ignore whitespaces and/or line ending characters?
It's typically the responsibility of the provider itself to determine whether the prior value and the new value are equivalent despite not being exactly equal, and so making this work automatically would require a change to the provider itself to notice that this argument is defined as being YAML and YAML doesn't ascribe any meaning to the decision between CRLF and just LF. The provider would ideally perform this check itself and thus avoid you needing to worry about it, and I would suggest opening a feature request with the provider developer to see if they would be interested in handling that.
However, if a provider isn't performing that job correctly itself then you can potentially work around it by doing your own normalization of the value using Terraform language features, so that the value passed to the provider is always the same when the meaning is the same.
One straightforward way to achieve that in this case would be to round-trip the value through both yamldecode and yamlencode, thereby normalizing the input to be in the style that yamlencode produces:
values = [yamlencode(yamldecode(var.something))]
If you want to be more surgical about it and only normalize the line endings, you could use replace to remove the CR character from any CRLF pair:
values = [replace(var.something, "\r\n", "\n")]
The above solution assumes that the difference in whitespace is being caused by something in your module, such as if you're storing your Terraform configuration in a misconfigured Git repository that's rewriting LF to CRLF when you clone it on a Windows system. This config-based normalization can undo that sort of transformation so that the provider will always see the value in the same way.
This solution cannot address problems that are caused by the provider itself misbehaving. Unfortunately some providers have bugs where they will silently rewrite the stored values for some arguments during the "refresh" step, regardless of how you wrote it in the configuration. In that case the only recourse is to fix the provider, because that incorrect value is originating inside the provider itself and isn't under the control of the module author.

Is there a way to input variable values from outside to terraform main file?

Is there a way I can input variable values from outside to terraform main file. It can be a excel sheet or sql db. Is it possible to do so ?
What you can't currently do is point you cmdline at a db i.e. to replace a tfvars file, but what you can set up in Terraform is to use a number of different key value stores:
consul
https://www.terraform.io/intro/examples/consul.html
aws parameter store (using a resource or data)
https://www.terraform.io/docs/providers/aws/d/ssm_parameter.html
There are quite a number of other key/value stores to choose from but there's no zero code solution and you will end up with lots of these statements:
Setup a key in Consul to provide inputs
data "consul_keys" "input" {
key {
name = "size"
path = "tf_test/size"
default = "m1.small"
}
}
There are many ways to do that;
You can use a tfvars file with all your inputs and you can use one file customer, user, environment
You can pass the variables to terraform executable on the command line
You can define environment files prefixed wit TF_VAR_[variable]
You can use https://www.terraform.io/docs/providers/aws/d/ssm_parameter.html as suggested above
You can even store variables in DynamoDB or any other database
You can use Consult+Vault as well

Puppet - remove ini_setting completely

I am using puppet 4.5.3 and ini_setting module version 1.4.2. I need to be able to remove a stanza in an ini file. For example:
[header]
ip = '1.1.1.1'
hostname = 'myserver'
port = 80
I am able to remove each section of the ini file using the ensure => absent parameter but I cannot find a way to remove the stanza header, or preferably the whole thing in one command.
What I have left is
[header]
Does anyone know how this can be done? Unfortunately there are other stanzas in the same file that I need to keep so I cannot simply delete the file.
thanks,
Using the Augeas type:
augeas { 'remove_ini_header':
incl => '/etc/example.ini',
lens => 'IniFile.lns_loose',
changes => 'rm section[. = "header"]',
}
To break this down a bit, first I used the built-in IniFile.lns_loose lens (i.e. a "generic" loose parsing of INI files) and augtool to see the current state of the tree:
$ augtool -t "IniFile.lns_loose incl /etc/example.ini"
augtool> print /files/etc/example.ini
/files/etc/example.ini
/files/etc/example.ini/section = "header"
/files/etc/example.ini/section/ip = "'1.1.1.1'"
/files/etc/example.ini/section/hostname = "'myserver'"
/files/etc/example.ini/section/port = "80"
The entire section is in one part of the tree, so calling rm for that section will delete the entire subtree.
To match the header section, you need to search for nodes called section where the value (the right hand side) is header. The [. = "header"] part of the command is a path expression that filters for nodes with the value header.

How to get non standard tags in rpm query

I wanted to add things such as Size, BuildHost, BuildDate etc in rpm query but adding this thing in spec file results in unknown tag?? How can I do this so that these things are reflected when i give the rpm query command?
These tags are determined when the package is built; they cannot be forced to specific values.
For example BuildHost is hardcoded in rpmbuild and cannot be changed. There is RFE https://bugzilla.redhat.com/show_bug.cgi?id=1309367 to allow it modify from command line. But right now you cannot change it by any tag in spec file nor by passing some option on command line to rpmbuild.
I assume it will be very similar to other values you specified.
RPM5 permits arbitrary unique tag names to be added to header metadata.
The tag names are configured in a colon separated list in a macro. Then the new tags can be used in spec files and can be extracted using --queryformat.
All arbitrary tags are string (or string array) valued.

Puppet: Can $hostname be checked against a master file before running manifest head?

I've seen someone doing a check on whether an agent's MAC address is on a specific regular expression before it runs the specified stuff below. The example is something like this:
if $is_virtual == "true" and $kernel == "Linux" and $macaddress =~ /^02:00:0A/ {
include nmonitor
include rootsh
include checkmk-agent
include backuppcacc
include onecontext
include sysstatpkg
include ensurekvmsudo
include cronntpdate
}
That's just it in that particular manifest file. Similarly another manifest example but via regular expression below:
node /^mi-cloud-(dev|stg|prd)-host/ {
if $is_virtual == 'false' {
include etchosts
include checkmk-agent
include nmonitor
include rootsh
include sysstatpkg
include cronntpdate
include fstab-ds-dev
}
}
I've been asked of whether can that similar concept be applied upon checking the agent's hostname with a master file of hostnames allowed to be run or otherwise.
I am not sure whether it can be done, but the rough idea goes around something like:
file { 'hostmasterfile.ini'
ensure => present,
source => puppet:///test/hostmaster.ini,
content => $hostname
}
$coname = content
#Usually the start / head of the manifest
if $hostname == $coname {
include <a>
include <b>
}
Note: $fqdn is out of the question.
To my knowledge, I have not seen any such sample manifest that matches the request. Whats more, it goes against a standard practice of keeping things easier to manage and not putting all eggs in a basket.
An ex-colleague of mine claims that idea above is about self-provisioning. However that concept is non-existent in Puppet (he posed that question at a workshop a few months back). I am not sure how true is that though.
If that thing above can be done, any suggestion of how can it be done? Or is it best to go back to the standard one manifest per node for easy maintenance?
Thanks very much.
M
Well, you can replace your node blocks with if constructs.
if $hostname == 'host1' {
# manifest for host1 here
}
You can combine this with some sort of inifile (e.g., using the generate) function. If the <a> and <b> for the include statements are then fetched from your ini file as well, you have constructed a crude ENC.
Note that this has security implications - any agent can claim to have any host name. It's even very simple to do:
FACTER_hostname=kerberos01 puppet agent --test
Any node can receive the catalog for kerberos01 this way. (node blocks rely on $certname instead, which cannot be forged.)
I could not decipher your precise intent from your question, but I suspect that you really want an ENC or a Hiera based approach.
Edit after feedback from your first comment:
To make the master read contents from local files, you should
get rid of the file { 'hostmasterfile.ini': } - it only allows you to set contents, not retrieve them
initialize the variable content using the file function (this will make all nodes fail if the file is not readable)
The code could look like this (assuming that there can be multiple host names in the ini file).
$ini_data = file('/etc/puppet/files/test/hostmaster.ini')
Next step would be a regex lookup like this:
if $ini_data =~ /name=$hostname/ {
Unfortunately, this does not work! Puppet will not expand variable values in regular expressions, apparently.
You can use this (kind of silly) workaround:
$ini_lookup = regsubst($ini_data, "name=$hostname", '__FOUND__')
if $ini_lookup =~ /__FOUND__/ {
...
}
Final remark about security: If your team is adamant about not using $certname for this lookup (although it should be easy to map host names to cert names), you should consider adding the host name to your trusted facts.

Resources