Access Puppet built-in variables from a custom provider - ruby

There are built-in global variables, which can be accessed from a manifest or template. Like $serverip for the IP address of the master. I know how to call Facter, but some built-ins are not represented by any Facter's "facts". How can they be accessed from a custom provider?

Yes, the agent transfers fact values to the master, so that during manifest compilations, you can use the values as you described.
The agent itself (and by extension, the types and providers) can access these values directly.
value = Facter.value('serverip')
This should be possible in virtually all contexts on the agent side (including custom facts), because the Puppet agent will always load Facter, making resolution directly available.

With more feedback from the OP it became clear that this is not about master information from global variables, but "implicit facts" with agent configuration instead.
The agent can very simply use its configuration from a global hash.
port = Puppet['masterport']
master_host = Puppet['server']

To wrap it up, the following dumps the 'global' settings into a human-readable commented config-file format, for those wondering which settings are available (those accessible with Puppet['setting']):
irb(main):001:0> require 'puppet'
irb(main):002:0> Puppet.initialize_settings
irb(main):003:0> puts Puppet.settings.to_config

Related

Puppet on WIndows: creating a resource only if a registry entry is (not) present

I need to create a resource (a SCOM agent management group) only if a specific registry setting is not present.
The statement itself is simple but the class doesn't contain any built-in conditional checks (similar to "unless =>" in exec class). The statement fails on SCOM management server because there is no SCOM agent installed. I want to prevent execution of the statement on such servers.
SCOM management server can be identified by presence of specific registry settings. If there any way to check that presence in "if", "unless" or other conditional statements? I know it's possible to write a custom fact and use it along with "if" but I don't know anything about Rubi and have no time to dive in. I need something simpler. Any hints would be highly appreciated.
I need to create a resource (a SCOM agent management group) only if a
specific registry setting is not present.
Well that's part of the problem right there. You ought to know what machine is supposed to host a SCOM management server, and avoid declaring the agent management group based on that machine's identity. You especially ought to know that if you have Puppet managing the management server, too, but even if you don't, this oughtn't to be something that you're figuring out dynamically at runtime.
But since you are ...
The statement itself is simple but the class doesn't contain any
built-in conditional checks (similar to "unless =>" in exec class).
If the resource that you want to apply conditionally does not have any built-in conditional checks that serve the purpose, then Puppet conditional statements such as if and case are the most likely options.
SCOM management server can be identified by presence of specific
registry settings. If there any way to check that presence in "if",
"unless" or other conditional statements?
Puppet conditional statements are evaluated during catalog building, on the Puppet server. What it knows about client nodes is limited to what your node classification, external (Hiera) data, and node facts convey to it.
I know it's possible to write a custom fact and use it along with "if"
but I don't know anything about Rubi and have no time to dive in. I
need something simpler.
Custom facts are not hard to write, but for this purpose, you might find it easier to use an external fact, which on Windows can be implemented via a PowerShell script or batch file. If that's not simple enough for you, then we're back to Puppet needing to know based on node identity. That would manifest as having a different node block for the SCOM server or having different node-specific Hiera data for that node.
Can't comment this due to rep, but writing custom facts is easy, here is a an example. You will obv need to update the registry key to the correct path.
osfamily = Facter.value('osfamily')
case osfamily
when 'windows'
Facter.add('custom_fact') do
setcode do
begin
value = nil
Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\ServerInfo') do |regkey|
value = regkey['value_name'].downcase
end
value
rescue
nil
end
end
end
end
Then in your puppet code you can include or exclude resources based on the value.
if $facts['custom_fact'] {
# Do something
}

Config variables not visible as environment variables in Heroku app

I've set a few custom config variables. I can see them in my application's settings->config variables. I can also see the values with the heroku config command. But when I start my application the environment variables are not there. I use (System/getenv "MY_VARIABLE_NAME") in Clojure to fetch them.
Is it because I try to retrieve them at boot time? Are they only available later? Or is there some twitch which I can get rid of by doing some trick? I've used config variables in Heroku before and they've worked, I don't know what's the problem here...
I was trying to retrieve client ID and secret for oauth authentication with Google from a config variable with System/getenv. I use a library called Friend to do this. Problem is, the set up for oauth parameters in that library is done via macros. And macro expansion happens compile-time. Heroku config variables are not available as environment variables during compilation (for good reasons). They are, however available via filesystem which was my solution to the problem. So instead of:
(System/getenv "MY_APP_GOOGLE_CLIENT_ID")
I'm using this:
(slurp (str (System/getenv "ENV_DIR") "/" "MY_APP_GOOGLE_CLIENT_ID"))
And it works!

Get variable from PuppetMaster config from ruby functions

I wrote simple function for my puppet module. It makes some requests using puppetdb API and I need IP address of puppetdb server. Is there correct way to get settings of connection PuppetMaster to puppetdb to get address of puppetdb server or I should parse puppet.conf by hand?
Parsing puppetdb.conf by hand would be the least desirable way to go about it.
Looking at the code that loads the config, it should be possible to access it using
settings_value = Puppet::Util::Puppetdb.config['main'][setting_name]
for configuration options from the [main] section.
Looking at even more code, you should even be able to use
Puppet::Util::Puppetdb.server
Puppet::Util::Puppetdb.port
I'm not entirely sure whether those APIs are available from parser functions, but it's worth a shot.

Customize Ruby Guardfile per User

I am using guard and therefore I have configured my Guardfile with my host's IP address where notifications should be sent.
How can I do this customization outside of the Guardfile so that only I can see it, not the rest of my team members?
From the shared configurations page in the Guard wiki:
If a .guard.rb is found in your home directory, it will be appended to
the Guardfile in your current directory. This can be used for tasks
you want guard to handle but other users probably don't.
You have several options -- you can either read the address from an environment variable or discern it with code. However, you can probably just use '127.0.0.1' which is the localhost address and should work for anyone to point to their own machine.

How do I get ruby to honor a local hosts file?

I have an rspec testsuite that I use to test our internal and public facing API. Usually all I have to do to test the service is setup my parameters (e.g test urls) and from there the tests connect to the required service and do their thing.
My question is, how to I get ruby to honor my host file entries? In this specific scenario I'm trying to hit our pre-live servers, which use the same urls as our live environment, but obviously are on an entirely different IP cluster.
Unless you are doing some very low-level stuff, Ruby will not perform DNS name resolution by itself, it will simply call the appropriate OS API. So, you need to figure out how to configure your operating system to use a local hosts file.

Resources