How to insert custom facts to PuppetDB - puppet

I'm using the last version of puppet server, and I'm connecting the puppet server to Puppetdb to store catalogs and facts in puppet db.
after hours of installing and configuration. node's facts are now stored in puppet db.
Now after installing PuppetDB I would like to insert custom facts to Puppetdb. here is the following scenario I made :
I added a new node to the puppet server
I used the puppetdb api to add a custom fact :
POST http://puppetserver:8080/pdb/cmd/v1
{
"command":"replace facts",
"version": 5,
"payload": {
"certname":"newnodehostname",
"environment":"production",
"producer_timestamp":"TIMESTAMP",
"producer":"newnodehostname",
"values":{
"newfact":"newfactvalue"
}
}
}
Then when I launch the puppet agent my new fact is deleted, and new facts are saved.
So my question is: why my new fact is deleted when I run the puppet agent on the node ?

PuppetDB stores the most recent set of facts for every node.
So when during puppet run the agent uploads the new set of facts, it overwrites the ones you sent with your one-time PuppetDB API call.
You should consider adding your custom fact as a, well, custom fact so that the fact will be set during each puppet run.
Arguably the simplest way to do that for a single node is:
Create my_fact.sh file in /etc/facter/facts.d/ dir on your node (newnodehostname)
Make it executable
Put something like this into this script:
#!/bin/bash
# ^^^^^^^^^ - note that shebang is REQUIRED for custom fact scripts
# all output in KEY=VALUE format will be treated as custom fact names and their values
echo "newfact=newfactvalue"
For more information, including information how to add custom facts with puppet manifests on your nodes please refer to the full custom facts documentation.

Related

JHipster: How turn prompt optional in my blueprint when executing the "jdl" command

I've observed the following behavior when I generate a new application using JHipster:
When I just call jhipster, it shows a set of prompts to make my choices.
When I call jhipster jdl <myjslfile.jdl>:
2.1. If the JDL has just entities, not declaring a config application section, I've got an error: Database type is required to validate entities.
2.2. If the JDL has the minimum config application like the following, it assumes some defaults and does not show any prompt.
I'm trying to write my own blueprint and I'd like to know how could I tell to Jhipster some default values should be considered when loading a JDL.
I thought that if I just set the prompt attribute default would be the solution, but I did this and have no effect, the prompts are always shown. When there are more than one application declared in the JDL file it's worst because it's not possible to distinguish what is being answered to each application since this processes happen in parallel.
Regards,
application {
config {
baseName microserviceExample,
applicationType microservice,
prodDatabaseType postgresql
}
entities X
}
entity X {
name String required minlength(3)
}
Personally, I don't like depending on default values that could be changed by a new major version (e.g. default for service registry will change in JHipster 8 from Eureka to Consul).
Why is this a problem to explicit these values in your JDL? For me the JDL should be self contained as much as possible.
Alternatively, you could define a .yo-rc.json file in your project directory or in its parent directory if you want to apply to several apps below.
And finally, you could open a feature request on github for the dev team to comment.

Can I omit site.pp to execute one class on all nodes

I habe puppetserver and three nodes. I created on master createuser.pp file with createuser class.
Additionally I created site.pp with following content:
node 'app01','app02,'app03'{
include createuser
}
Now executing from each app server: puppet agent -tv will create user. All work fine.
My question is can I do the same without defining site.pp manifest ?
I can of course add include createuser at the end of class definition in file createuser.pp
but how can i run it from all three app hosts ? Do I need to create a tag ?
Thanks for any tips.
can I do the same without defining site.pp manifest ?
In any version of Puppet still supported, you can do it without a file named site.pp, but not without a "site manifest" in a more general sense. This can be a single file of configurable name (default "site.pp"), or it can be the collective contents of all the files in a specified directory. Either way, the site manifest is the entry point for catalog building. Other manifests are consulted only as needed.
I can of course
add include createuser at the end of class definition in file
createuser.pp
In current Puppet, top-scope code may appear only in the site manifest (though some historic versions were more lax). Your class should be in a module, not in the site manifest, and in that case no, you couldn't use an include statement in the same file with the class definition. You need a class declaration either in the site manifest or in some other class directly or indirectly declared by the site manifest.
but how can i run it from all three app hosts ? Do I
need to create a tag ?
On the agent side, tags are useful only for limiting which classes and resources are applied. Only those already in its catalog are available -- you cannot use tags from that end to apply classes or resources that wouldn't ordinarily be applied.
You ensure that the class is in the node's catalog by declaring it in the site manifest (as you are doing now) or in another class directly or indirectly declared in the site manifest.

Access hiera scope from Puppet custom type

I'm building a custom type and I'm unable to get access to the hiera scope from a defaultto block
module Puppet
require 'puppet/parser/functions/hiera'
newtype(:my_type) do
ensurable
newparam(:myparam) do
defaultto { Puppet::Parser::Functions.hiera('myparam') }
end
newproperty(:value) do
desc "Value of the item."
end
end
end
But I get
Error: undefined method `hiera' for Puppet::Parser::Functions:Module
I'm actually using Puppet 3.8 and future parser
As a workaround, we use
$my_vals = hiera_hash('mytype_vals')
create_resource(my_type, $myvals, {myparam => hiera('myparam')})
That works fine, but my_type objects are expected to be instantiated anywhere in the catalog, an myparam is expected to be the same across all instances. So multiple default value declaration should not be necessary.
Another approach would be to place
My_type{
myparam => hiera('myparam')
}
In the node manifest. That would do the trick, too, but we are developing a module, and main manifest is out of our scope
You can't access hiera data from a provider, because a provider runs agent side and hiera runs master side.
You've mentioned you run masterless in your comments, this is irrelevant as there is still a "master" run which compiles the Puppet catalog and evaluates hiera values and an "agent" run that applies the catalog using providers.
Imagine the Puppet run as a series of steps:
Agent sends master a list of facts
Master compiles the site manifest to find the list of classes to include for the node
Master evaluates all parameters and hiera variables
Master compiles modules into a catalog
Master sends catalog to agent
Agent applies catalog by feeding parameters to providers
So your best bet is to wrap the provider in a define type. Use the define class to get hiera defaults and pass them to the provider, while allowing the default to be overwritten.

Could not retrieve information from environment production source(s) file:///

I've got a puppet class defined like this:
class etchostfile
(
$hostfile
)
file { $hostfile :
ensure => file,
source => "file:///var/www/cobbler/pub/hosts-${hostfile}.txt",
path => '/root/hosts',
}
}
Then I've got a node defined:
node 'hostname.fqdn.com'
{
class { 'etchostfile' :
hostfile => foo,
}
}
I want it to take the file /var/www/cobbler/pub/hosts-foo.txt and install it to /root/hosts. But I'm getting this error:
err: /Stage[main]/Etchostfile/File[foo]: Could not evaluate: Could not
retrieve information from environment production source(s)
file:///var/www/cobbler/pub/hosts-foo.txt
The file exists, is readable, and every directory leading to it is at least r-x.
I saw a number of reasons why this error applies to an incorrect puppet:/// source, but I'm using a file:/// source. I also tried disabling SELinux on both agent and master. No luck.
It worked correctly on my test host, so I presume it's a firewall issue. But the agent can get to the master on port 8140, and I already have a signed certificate, and it appears that I am at least getting a catalog, so I don't understand why I can't get a file too.
Looks like you are trying to source the file from your puppet master? In that case, you need to use the puppet:// resource and not the file:// resource.
Also, ensure that your fileserver setup on master is working.
https://docs.puppetlabs.com/guides/file_serving.html#file-server-configuration
[EDIT]
From the above linked doc first paragraph:
If a file resource declaration contains a puppet: URI in its source
attribute, nodes will retrieve that file from the master’s file server
Also, some more doc talking about file source attribute
https://docs.puppetlabs.com/references/latest/type.html#file-attribute-source
If you are trying to reference a local file (local to the node where the agent is running) you can remove the protocol part and just use:
file { $hostfile :
ensure => file,
source => "/var/www/cobbler/pub/hosts-${hostfile}.txt",
path => '/root/hosts',
}
If you are trying to access a file on the puppet master, you need to use the puppet:/// protocol (and not file). This will bring some additional restrictions : usually you do not configure puppet file serving to serve all files on the master (which would be a security issue) but only to serve files that are part of puppet modules.
Or you could use a template with no logic instead of the file:
file { $hostfile :
ensure => file,
content => template("my_module/hosts-${hostfile}.txt.erb"),
path => '/root/hosts',
}
It is counter intuitive, but using templates with no logic tends to have better performance that trying to use Puppet for file serving.

jenkins: setting root url via Groovy API

I'm trying to update Jenkins' root URL via the Groovy API, so I can script the deployment of a Jenkins master without manual input (aside: why is a tool as popular with the build/devops/automation community as Jenkins so resistant to automation?)
Based on this documentation, I believe I should be able to update the URL using the following script in the Script Console.
import jenkins.model.JenkinsLocationConfiguration
jlc = new jenkins.model.JenkinsLocationConfiguration()
jlc.setUrl("http://jenkins.my-org.com:8080/")
println(jlc.getUrl())
Briefly, this instantiates a JenkinsLocationConfiguration object; calls the setter setUrl with the desired value, http://jenkins.my-org.com:8080/; and prints out the new URL to confirm that it has changed.
The println statement prints what I expect it to, but following this, the value visible through the web interface at "Manage Jenkins" -> "Configure System" -> "Jenkins URL" has not updated as I expected.
I'm concerned that the value hasn't been update properly by Jenkins, which might lead to problems when communicating with external APIs.
Is this a valid way to fix the Jenkins root URL? If not, what is? Otherwise, why isn't the change being reflected in the config page?
You are creating a new JenkinsLocationConfiguration object, and updating the new one, not the existing one being used
use
jlc = JenkinsLocationConfiguration.get()
// ...
jlc.save()
to get the one from the global jenkins configuration, update it and save the config descriptor back.
see : https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java

Resources