Convert puppet manifest config into hiera - yaml

I installed corosync-pacemaker cluster via puppet. Now I would to like keep my data into hiera file. How should I convert cs_primitive section into yaml file?
cs_primitive { 'nfsshare_fs':
primitive_class => 'ocf',
primitive_type => 'Filesystem',
provided_by => 'heartbeat',
parameters => { 'device' => '/dev/disk/lvname', 'directory' =>
'/share', 'fstype' => 'ext4' },
}->
I tried the below code but it didn't work.
corosync::cs_primitive:
'nfsshare_fs':
primitive_class: 'ocf'
primitive_type: 'Filesystem'
provided_by: 'heartbeat'
parameters:
device: '/dev/disk/by-id/lvname'
directory: '/share'
fstype: 'ext4'

It won't work because cs_primitive is a resource type, like, for example, File.
If you want to use it from Hiera, then you could create a class that wraps cs_primitive applying and then connect this class with Hiera.
classes:
- my_class
my_class::param1: value1
my_class::param2: value2
Useful links:
https://puppet.com/docs/puppet/7/lang_defined_types.html
https://puppet.com/docs/puppet/7/lang_classes.html

Related

Puppet file resource require archive resource

I am using Puppet for doing my Vagrant provisioning. I used the archive module at https://forge.puppet.com/puppet/archive/types to download and extract glassfish like this:
archive { '/tmp/glassfish-4.1.1.zip':
ensure => present,
extract => true,
extract_path => '/opt/',
source => 'http://download.java.net/glassfish/4.1.1/release/glassfish-4.1.1.zip',
cleanup => true,
creates => '/opt/glassfish4',
}
After that resource is applied, I want to move a file into the newly created glassfish directory like this
file { 'domain.xml':
ensure => file,
path => '/opt/glassfish4/glassfish/domains/domain1/config/domain.xml',
source => 'puppet:///modules/glassfish/domain.xml',
}
I want to require in the file move resource that the extraction was already done, since the extraction is not creating a file, but rather a directory. Something like
require => FILE['..']
is not working.
You should add a require on the archive task so your file task will be something like
file { 'domain.xml':
ensure => file,
path => '/opt/glassfish4/glassfish/domains/domain1/config/domain.xml',
source => 'puppet:///modules/glassfish/domain.xml',
require => Archive['/tmp/glassfish-4.1.1.zip'],
}
so that the copy of the domain.xml file will be done after the archive task.

nconf.js like gem for ruby configuration

I'm building a cli tool in ruby, and I need to take config from different sources: environment variable, dotfile, arguments or hardcoded values. (with a precedence system)
In node.js I would have used nconf.js, to do this.
Is there some configuration gem in ruby that enable to do such a thing?
The actual answer is this:
updated: 2020-02-26
https://github.com/infochimps-labs/configliere
to quote the author:
Be willing to sit down with the Five Families. Takes settings from (at your option):
Pre-defined defaults from constants
Simple config files
Environment variables
Commandline options and git-style command runners
Ruby block (called when all other options are in place)
put simply. just like nconf.
require 'configliere'
Settings.use :commandline
Settings({
:dest_time => '11-05-1955',
:fluxcapacitor => {
:speed => 88,
},
:delorean => {
:power_source => 'plutonium',
:roads_needed => true,
},
:username => 'marty',
:password => '',
})
#set a value to possibly also come from env
Settings.define :dest_time, :env_var => 'DEST_TIME'
Settings.read "#{__dir__}/config.yml"
Settings.read "#{Dir.pwd()}/config.yml"
Settings.resolve!
old answer:
https://github.com/rubyconfig/config#working-with-environment-variables
it doesn't do argv, but it lets you layer various yaml files and then override with ENV just like nconf lets you.

get ec2 instances with a certain tag using aws sdk

I am trying to figure out what is the best way to get a list of ec2 instances with a certain tag for example "testing" using the ruby aws sdk.
ec2 = AWS::EC2.new(:access_key_id => "XXXXXXXXXXXXX", :secret_access_key => "YYYYYYYYY")
ec2list = ec2.instances.filter("Name", "testing)
This does not seem to work for some reason. It was thinking it will filter out the collection and just give me instances with tag testing. Is there a way to do this using the ruby sdk? thank you.
If you want the tag "Name" with the value of "testing" use:
instances = resource.instances(
filters: [
{
name: 'tag:Name',
values: ["testing"]
}
]
)
For all instances with a tag key of "testing" the following is used.
instances = resource.instances(
filters: [
{
name: 'tag:Key',
values: ["testing"]
}
]
)
See the #instances docs for more filter options.
This worked for me:
ec2.instances.tagged("testing")
None of the above worked, but this one worked for me:
ec2.instances.with_tag("Environment","Integration")
Hi I think you could get what you want using filter on the tags of the instances:
ec2 = AWS::EC2.new(:access_key_id => "XXXXXXXXXXXXX", :secret_access_key => "YYYYYYYYY")
ec2list = ec2.instances.tags.filter("Name", "testing)
CF:
http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/AutoScaling/TagCollection.html#filter-instance_method
http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2.html#tags-instance_method
I am used to doing it this way
require 'aws-sdk'
ec2 = AWS::EC2.new(
:region => cluster_region,
:access_key_id => key_id,
:secret_access_key => access_key)
instances = ec2.instances
instances = instances.filter("filter-key", "filter-value")
One can find the available filters at
http://docs.aws.amazon.com/AWSEC2/latest/CommandLineReference/ApiReference-cmd-DescribeInstances.html

How do I make puppet copy a file only if source exists?

I am trying to provision a vagrant VM to allow users to supply their own bash_profile.local but I don't want this file tracked in the vm's vcs repo. I have a tracked bash_profile.local.dist file that they can rename. How can I tell puppet to only create a file if the source file exists? It is currently working correctly but logs an error during provisioning and this is what I'm trying to avoid.
This is the manifest:
class local
{
file { '.bash_profile.local':
source => 'puppet:///modules/local/bash_profile.local',
path => '/home/vagrant/.bash_profile.local',
replace => false,
mode => 0644,
owner => 'vagrant',
group => 'vagrant',
}
}
You could abuse file in this way :
$a = file('/etc/puppet/modules/local/files/bash_profile.local','/dev/null')
if($a != '') {
file { '.bash_profile.local':
content => $a,
...
}
}
This is not exactly what you asked but you can supply multiple paths in the source, so you can have a default empty file if the user didn't supplied his own.
class local
{
file { '.bash_profile.local':
source => [
'puppet:///modules/local/bash_profile.local',
'puppet:///modules/local/bash_profile.local.default'
],
path => '/home/vagrant/.bash_profile.local',
replace => false,
mode => 0644,
owner => 'vagrant',
group => 'vagrant',
}
}
You can try something like this:
file { 'bash_profile.local':
ensure => present,
source => ['puppet:///modules/local/bash_profile.local', '/dev/null'],
path => '/home/vagrant/.bash_profile.local',
before => Exec['clean-useless-file'],
}
exec { 'clean-useless-file':
command => 'rm .bash_profile.local',
onlyif => 'test -s .bash_profile.local',
cwd => '/home/vagrant',
path => '/bin:/usr/bin',
}
If the admin don't make a copy of ".bash_profile.local" available in "modules/local/bash_profile.local", the file resource will use the second source and then create a blank file. Then, the "onlyif" test fails and the exec will remove the useless blank file.
Used this way this code can be a little cumbersome, but it's better than a provisioning failure. You may evaluate if retaining a blank .bash_profile.local file can be okay in your case. I normally use a variation of this, with wget instead of rm, to get a fresh copy of the file from the internet if it was not already made available as a source.
If you're using puppetmaster, be aware you can use it to provision the own server, presenting two versions of the catalog, according to the .bash_profile.local is present or not.

How do I create a route53 record set using the aws sdk for ruby?

EC2 gives instances a new IP address when they're stopped then restarted, so I need to be able to automatically manage a route53 record set so that I can access things consistently. Sadly the documentation for the route53 portion of the sdk is not nearly as robust as it is for ec2 (understandably) and so I'm a bit stuck. From what I've seen so far, it seems like change_resource_record_sets (link) is the way to go, but I'm confused as to what needs go into :chages since it mentions a Change object but fails to provide a link to a description of said object.
Here's what my code currently looks like for a creation:
r53.client.change_resource_record_sets(:hosted_zone_id => 'MY_ID', :change_batch => {
:changes => 'I DONT KNOW WHAT GOES HERE',
:action => 'CREATE',
:resource_record_set => {
:name => #instance.instance_name,
:type => 'CNAME',
:ttl => 330,
:value => #instance.ip_address
}})
EDIT: Okay, since I haven't had any help either here or on the official forums I've been messing around with it myself. So it turns out that the documentation is just plain awful. All of the values are stored in a Change object, and not given there. So it actually looks more like this:
some_change = AWS::Route53::CreateRequest.new(#instance.instance_name,
'CNAME',
:ttl => 330,
:resource_records => [
{:value => #instance.ip_address}
])
r53.client.change_resource_record_sets(:hosted_zone_id => 'MY_ZONE', :change_batch => {
:changes => [some_change],
})
The documentation is pretty poor, though it does contain a few examples. I initially had the impression that it was necessary to create requests (and use the client object) per your solution, but there are alternatives.
An example of creating a record can be found in the ResourceRecordSetCollection reference, but it's only a little more concise than your answer:
rrsets = AWS::Route53::HostedZone.new(hosted_zone_id).rrsets
rrset = rrsets.create('foo.example.com.', 'A', :ttl => 300, :resource_records => [{:value => '127.0.0.1'}])
I wanted to update an existing record, and didn't have the hosted_zone_id to hand. It took far too long to figure out how best to do this, so I'm offering the following example in the hope it saves someone else some time:
r53 = AWS::Route53.new
domain = "example.com."
fqdn = "host." + domain
zone = r53.hosted_zones.select { |z| z.name == domain }.first
rrset = zone.rrsets[fqdn, 'A']
rrset.resource_records = [ { :value => "1.2.3.4" } ]
rrset.update
Note that that assumes you only have a single zone with that name in Route53.
The method that zts posted seems to be a much better way of updating records. However, if you're updating an alias record then you have to use DeleteRequest/CreateRequest as the alias_target instance attribute on ResourceRecordSet seems to be readonly, even though the docs don't list it as so.
Here's one way to do it. Note that the hosted zone id for the alias target (region in the code below) should not be a personal zone ID, it is actually an encrypted region ID. This doesn't seem to be documented anywhere, and the only reference for these IDs that I could find was in the source of the fog gem.
Edit: This has now moved to a separate module called fog-aws and is more up to date.
{
"ap-northeast-1" => "Z2YN17T5R711GT",
"ap-southeast-1" => "Z1WI8VXHPB1R38",
"ap-southeast-2" => "Z2999QAZ9SRTIC",
"eu-west-1" => "Z3NF1Z3NOM5OY2",
"eu-central-1" => "Z215JYRZR1TBD5",
"sa-east-1" => "Z2ES78Y61JGQKS",
"us-east-1" => "Z3DZXE0Q79N41H",
"us-west-1" => "Z1M58G0W56PQJA",
"us-west-2" => "Z33MTJ483KN6FU",
}
And the code:
change_request = {
hosted_zone_id: zone.id,
change_batch: { changes: [] }
}
alias_target = {
hosted_zone_id: region,
evaluate_target_health: false
}
# Delete the record if it already exists
if rrset.exists?
alias_target[:dns_name] = rrset.alias_target[:dns_name]
delete_request = AWS::Route53::DeleteRequest.new(fqdn, 'A', alias_target: alias_target)
change_request[:change_batch][:changes][0] = delete_request
r53.client.change_resource_record_sets(change_request)
end
# Create the new record
alias_target[:dns_name] = new_alias
create_request = AWS::Route53::CreateRequest.new(fqdn, 'A', alias_target: alias_target)
change_request[:change_batch][:changes][0] = create_request
r53.client.change_resource_record_sets(change_request)
I hacked it until it worked, and here are my results:
Don't look at the ruby route53 documentation for anything but method/object/attribute names. It is misleading, if not outright wrong. Instead, check out the rest documentation since the client just builds up a standard xml request anyway. My example of creating a simple record is as follows:
some_change = AWS::Route53::CreateRequest.new("foo.bar.com",
'CNAME', # the type of the resource record set
:ttl => 330, # The cache time to live for the current resource record set
:resource_records => [
{:value => "0.0.0.0"} # dependent on type
])
r53.client.change_resource_record_sets(:hosted_zone_id => 'MY_ZONE', :change_batch => {
:changes => [some_change],
})
I initially worked with what #slippery John did, but that proved problematic for spot instances that reclaim certain dns names often.
I found a solution I think is better, almost I identical to his:
some_change = AWS::Route53::ChangeRequest.new("UPSERT","foo.bar.com",
'CNAME', # the type of the resource record set
:ttl => 330, # The cache time to live for the current resource record set
:resource_records => [
{:value => "0.0.0.0"} # dependent on type
])
r53.client.change_resource_record_sets(:hosted_zone_id => 'MY_ZONE', :change_batch => {
:changes => [some_change],
})
it is intentionally copied from his solution with a slight modification.
For aws-sdk v2 it is like this:
[72] pry(main)> r53 = Aws::Route53::Client.new
[73] pry(main)> change
=> {:action=>"UPSERT",
:resource_record_set=>
{:name=>"myhost.example.com",
:resource_records=>[{:value=>"192.0.2.44"}],
:ttl=>60,
:type=>"A"}}
[44] pry(main)> res = r53.change_resource_record_sets(hosted_zone_id: my_zone_id, change_batch: {changes: [change]})
=> #<struct Aws::Route53::Types::ChangeResourceRecordSetsResponse
change_info=
#<struct Aws::Route53::Types::ChangeInfo
id="/change/C02195391TWJO1GT9KVRV",
status="PENDING",
submitted_at=2020-11-03 21:39:09.41 UTC,
comment=nil>>
For more info see https://docs.aws.amazon.com/sdk-for-ruby/v2/api/Aws/Route53/Client.html#change_resource_record_sets-instance_method

Resources