add if statment into puppet class manifest - puppet

I am very new to Puppet programming.
I have the following class which configures the resolv.conf file correctly:
class dnsclient (
$nameservers = [ 'ns1 ip',
'ns2 ip' ,
'ns3 ip' ],
$options = [ 'rotate',
'timeout:5',
'attempts:3' ],
$search = [ 'example.com',
'example2.com' ],
$domain = 'UNSET',
$sortlist = ['UNSET'],
$resolver_config_file = '/etc/resolv.conf',
$resolver_config_file_ensure = 'file',
$resolver_config_file_owner = 'root',
$resolver_config_file_group = 'root',
$resolver_config_file_mode = '0644',
) {
# Validates domain
if is_domain_name($domain) != true {
fail("Domain name, ${domain}, is invalid.")
}
# Validates $resolver_config_file_ensure
case $resolver_config_file_ensure {
'file', 'present', 'absent': {
# noop, these values are valid
}
default: {
fail("Valid values for \$resolver_config_file_ensure are \'absent\', \'file\', or \'present\'. Specified value is ${resolver_config_file_ensure}")
}
}
file { 'dnsclient_resolver_config_file':
ensure => $resolver_config_file_ensure,
content => template('dnsclient/resolv.conf.erb'),
path => $resolver_config_file,
owner => $resolver_config_file_owner,
group => $resolver_config_file_group,
mode => $resolver_config_file_mode,
}
}
I created a custom fact default_gateway which should find the client default gateway, and according to that I want to then assign different name servers.
I tried to enter the condition at the beginning of the dnsclient class:
class dnsclient
if $default_gateway == 'DG ip' {
$nameservers = [ 'ns1 ip',
'ns2 ip' ,
'ns3 ip' ],
}
But I am getting a syntax error on the client, please advise. Where do I place the if statement to assign different name servers if the default gateway is different.

I assume you need to also remove the $nameservers class parameter, so you would change the beginning of the file to:
class dnsclient (
# This parameter is no longer required?
# $nameservers = [ 'ns1 ip',
# 'ns2 ip' ,
# 'ns3 ip' ],
$options = [ 'rotate',
'timeout:5',
'attempts:3' ],
$search = [ 'example.com',
'example2.com' ],
$domain = 'UNSET',
$sortlist = ['UNSET'],
$resolver_config_file = '/etc/resolv.conf',
$resolver_config_file_ensure = 'file',
$resolver_config_file_owner = 'root',
$resolver_config_file_group = 'root',
$resolver_config_file_mode = '0644',
) {
# Your code goes here:
if $default_gateway == 'DG ip' {
$nameservers = ['ns1 ip', 'ns2 ip', 'ns3 ip'],
}
...

Related

reason: actual value has 1 more key(s) than expected:

I am running karate tests.
I am posting a request object and i recieve a response object . however in the response object i have one extra field populated .How will i handle the scenario ?
the following is my test
#NFRSubscription.feature
Feature: NFR Subscription API Tests
Background:
* url __arg.test_service.url
* configure ssl = false
* configure httpVersion = 'http2'
Scenario: Create/Patch/Delete NRF subscription by nfInstanceId subscription condition
* def subscriptionId = ''
* def createSubscriptionByNfInstanceIdRequest = read('subscription/subscriptionCreateRequest.json')
* def patchSubscriptionByNfInstanceIdResponse = read('subscription/subscriptionPatchResponse.json')
* def createSubscriptionByNfInstanceIdResponse = createSubscriptionByNfInstanceIdRequest
# Create the NRF subscription by nfInstanceId
Given path '/nnrf-nfm/v1/subscriptions/'
And header Content-Type = 'application/json; charset=utf-8'
And print createSubscriptionByNfInstanceIdRequest
And request createSubscriptionByNfInstanceIdRequest
When method post
Then status 201
And match response == createSubscriptionByNfInstanceIdResponse
And match response.subscriptionId == '#present'
And print response
the content of subscription/subscriptionCreateRequest.json is as follows.
{
"nfStatusNotificationUri": "http://localhost:8080/ip/test",
"reqNfInstanceId": "9c79364e-99e1-42a8-ada1-86c31ad1fa76",
"subscrCond": {
"nfInstanceId": "9c79364e-99e1-42a8-ada1-86c31ad1fa76"
},
"validityTime": "2022-02-18T10:15:15Z",
"reqNotifEvents": [
"NF_REGISTERED"
],
"plmnId": {"mcc": "454", "mnc" : "93" },
"nid": "2465aEB5ff1",
"notifCondition": {
"monitoredAttributes": [
"testattri"
]
},
"reqNfType": "NRF",
"reqNfFqdn": "com.openet.com",
"reqSnssais": [
{ "sst": 10, "sd": "aA82a7" }
],
"reqPlmnList": [
{"mcc": "454", "mnc" : "93" }
],
"reqSnpnList": [
{"mcc": "454", "mnc" : "93" }
],
"servingScope": [
"any string"
],
"nrfSupportedFeatures": "CBAdEd1bef9B118EAd8d5bAfc66B59c1D292fD821d"
}
the content of the file subscription/subscriptionPatchResponse.json is as follows.
{
"nfStatusNotificationUri": "http://localhost:8080/ip/test",
"reqNfInstanceId": "9c79364e-99e1-42a8-ada1-86c31ad1fa76",
"subscrCond": {
"nfInstanceId": "9c79364e-99e1-42a8-ada1-86c31ad1fa76"
},
"validityTime": "2023-03-07T23:20:50Z",
"reqNotifEvents": [
"NF_REGISTERED"
],
"plmnId": {"mcc": "454", "mnc" : "93" },
"nid": "2465aEB5ff1",
"notifCondition": {
"monitoredAttributes": [
"testattri"
]
},
"reqNfType": "NRF",
"reqNfFqdn": "com.openet.com",
"reqSnssais": [
{ "sst": 10, "sd": "aA82a7" }
],
"reqPlmnList": [
{"mcc": "454", "mnc" : "93" }
],
"reqSnpnList": [
{"mcc": "454", "mnc" : "93" }
],
"servingScope": [
"any string"
],
"nrfSupportedFeatures": "CBAdEd1bef9B118EAd8d5bAfc66B59c1D292fD821d"
}
in the response I would expect a new field called subscriptionId .
my test fails at the moment with the following error .
16:00:57 com.intuit.karate.exception.KarateException: NFRSubscription.feature:24 - path: $, actual: {nfStatusNotificationUri=http://localhost:8080/ip/test, reqNfInstanceId=9c79364e-99e1-42a8-ada1-86c31ad1fa76, subscrCond={nfInstanceId=9c79364e-99e1-42a8-ada1-86c31ad1fa76}, subscriptionId=608425, validityTime=2022-02-18T10:15:15Z, reqNotifEvents=["NF_REGISTERED"], plmnId={mcc=454, mnc=93}, nid=2465aEB5ff1, notifCondition={monitoredAttributes=["testattri"]}, reqNfType=NRF, reqNfFqdn=com.openet.com, reqSnssais=[{"sst":10,"sd":"aA82a7"}], reqPlmnList=[{"mcc":"454","mnc":"93"}], reqSnpnList=[{"mcc":"454","mnc":"93"}], servingScope=["any string"], nrfSupportedFeatures=CBAdEd1bef9B118EAd8d5bAfc66B59c1D292fD821d}, expected: {nfStatusNotificationUri=http://localhost:8080/ip/test, reqNfInstanceId=9c79364e-99e1-42a8-ada1-86c31ad1fa76, subscrCond={nfInstanceId=9c79364e-99e1-42a8-ada1-86c31ad1fa76}, validityTime=2022-02-18T10:15:15Z, reqNotifEvents=["NF_REGISTERED"], plmnId={mcc=454, mnc=93}, nid=2465aEB5ff1, notifCondition={monitoredAttributes=["testattri"]}, reqNfType=NRF, reqNfFqdn=com.openet.com, reqSnssais=[{"sst":10,"sd":"aA82a7"}], reqPlmnList=[{"mcc":"454","mnc":"93"}], reqSnpnList=[{"mcc":"454","mnc":"93"}], servingScope=["any string"], nrfSupportedFeatures=CBAdEd1bef9B118EAd8d5bAfc66B59c1D292fD821d}, reason: actual value has 1 more key(s) than expected: {subscriptionId=608425}
any idea how should i formulate createSubscriptionByNfInstanceIdResponse object to handle an extra dynamically generated field . in other words how can i do the following
add response.subscriptionId into createSubscriptionByNfInstanceIdResponse and then compare response and
createSubscriptionByNfInstanceIdResponse object .
And match response == createSubscriptionByNfInstanceIdResponse
I have changed the test to add the subscriptionId field in the response object and then asserted it .
# Create the NRF subscription by nfInstanceId
Given path '/nnrf-nfm/v1/subscriptions/'
And header Content-Type = 'application/json; charset=utf-8'
And print createSubscriptionByNfInstanceIdRequest
And request createSubscriptionByNfInstanceIdRequest
When method post
Then status 201
And match response.subscriptionId == '#present'
And print response
And set createSubscriptionByNfInstanceIdResponse.subscriptionId = response.subscriptionId
And match response == createSubscriptionByNfInstanceIdResponse

Terraform: nested for loop from yaml

I am trying to run nested for loop on terraform.
I have the following Yaml file:
Employees:
- Department:
- Dev:
- name: "danielf"
role: developer
details:
email : danielf#example.com
firstname : daniel
lastname : folsik
- name: "johnb"
role: developer
details:
email : johnb#example.com
firstname : john
lastname : belk
- Ops:
- name: "benol"
role: devops
details:
email : benol#example.com
firstname : ben
lastname : olkin
- name: "pauld"
role: devops
details:
email : pauld#example.com
firstname : paul
lastname : dempler
I am using locals to get the yaml data:
locals {
ou_config = yamldecode(file("employees.yaml"))
}
I want to run into the list of objects on "Dev" and "Ops" lists using for_each.
for example, I want to run on the "Dev" list to get the following list of objects in the first iteration:
[
{
key = "email"
value = "danielf#example.com"
},
{
key = "firstname"
value = "daniel"
},
{
key = "lastname"
value = "folskin"
}
]
The next run on the for_each will be:
[
{
key = "email"
value = "johnb#example.com"
},
{
key = "firstname"
value = "john"
},
{
key = "lastname"
value = "belk"
}
]
etc.
How can I do it on terraform?
If I understand correctly, all you are trying to extract is the details portion of that yaml file ...
Here is what I would do to get all:
locals {
ou_config = yamldecode(file("employees.yaml"))
expanded_names = flatten([
for e in local.ou_config.Employees : [
for d in e.Department : [
for key, person in d : [
for key, value in person : [
value.details
]
]
]
]
])
}
output "test" {
value = local.expanded_names
}
And if we want to filter we add an if key == "Dev"
locals {
ou_config = yamldecode(file("employees.yaml"))
expanded_names = flatten([
for e in local.ou_config.Employees : [
for d in e.Department : [
for key, person in d : [
for key, value in person : [
value.details
]
] if key == "Dev"
]
]
])
}
output "test" {
value = local.expanded_names
}
A terraform plan on that will look like:
Changes to Outputs:
+ test = [
+ {
+ email = "danielf#example.com"
+ firstname = "daniel"
+ lastname = "folsik"
},
+ {
+ email = "johnb#example.com"
+ firstname = "john"
+ lastname = "belk"
},
]
That format should be easier to loop in the final resource than the key value you suggested

Is it possible to perform nested iterations in HCL resulting in a flat list without calling flatten?

Is it possible with HCL to have nested iterations returning a flat list(map) without resorting to flatten?
I have this:
locals {
mappings = flatten([
for record_type in var.record_types : [
for host in var.hosts : {
type = record_type,
host = host
}
]
])
}
I would like to remove the need for flatten like this:
locals {
mappings = [
for record_type in var.record_types :
for host in var.hosts : {
type = record_type,
host = host
}
]
}
But it seems like each for .. in must return data.
One alternative I could think of to only have a single for-loop is using setproduct():
variable "record_types" {
default = ["type1", "type2"]
}
variable "hosts" {
default = ["host1", "host2"]
}
locals {
mappings = [
for i in setproduct(var.record_types, var.hosts) : {
type = i[0],
host = i[1],
}
]
}
output "mappings" {
value = local.mappings
}
after terraform apply resulting in:
Outputs:
mappings = [
{
"host" = "host1"
"type" = "type1"
},
{
"host" = "host2"
"type" = "type1"
},
{
"host" = "host1"
"type" = "type2"
},
{
"host" = "host2"
"type" = "type2"
},
]
Of course, the two variables need to be independent sets here.
If you want to support duplicates or have dependent inputs, flatten() with two loops is the way.

Puppet Error: You cannot specify more than one of content, source, target

I am trying to create one file and one symbolic link via Puppet (with Hiera). I'm running on Ubuntu 16.04, and I am using all latest modules.
The file is called "a" and the link is called "b". These files are not related directly.
I have a init.pp file for the node:
define hiera::files (
$ensure,
$content= "",
$target="/./.",
$mode = "",
$owner = "root",
$force = "false" ) {
file { $title:
ensure => $ensure,
owner => $owner,
force => $force,
content => $content,
mode => $mode,
target => $target,
}
}
create_resources('hiera::files', hiera_hash('files', {}))
node "default" {
hiera_include('classes')
}
There is also a node.yaml file containing the corresponding data:
files:
/etc/a.txt:
ensure: "present"
mode: "2770"
owner: "simon"
content: "[d] \n type = sss \n resource = samba_1"
/etc/b:
ensure: "link"
target: "/usr/share/b"
mode: "777"
I have tried other variations, but I always get an error that I cannot specify more than one of content, source, target. Is it possible to have both? Not for the same file, but for separate files like I am trying to do?
The hiera::files defaults are the issue here, as even if you're not specifying content and target in your Hiera hash, they're being set:
define hiera::files ( $ensure, $content= "", $target="/./.", $mode = "", $owner = "root", $force = "false" ){
Change the $content and $target defaults to undef so they must be specified if you're going to use them.
define hiera::files ( $ensure, $content = undef, $target = undef, $mode = "", $owner = "root", $force = "false" ){
If you really need these default values, then you need a way to avoid setting target on a file with content, and content on a file/symlink with target, e.g.
define hiera::files ( $ensure, $content = undef, $target = undef, $mode = "", $owner = "root", $force = "false" ){
# Provide a default empty content value when ensure => present, and no content is given
$real_content = $ensure ? {
"present" => $content ? {
undef => "",
default => $content,
},
default => undef,
}
# Provide a default /./. target value when ensure => link, and no target is given
$real_target = $ensure ? {
"link" => $target ? {
undef => "/./.",
default => $target,
},
default => undef,
}
file { $title:
ensure => $ensure,
owner => $owner,
force => $force,
content => $real_content,
mode => $mode,
target => $real_target,
}
}
Or perhaps preferably, use separate defines to make the behaviour clear.

Cannot parse array into defined type

I am using following puppet class
class myclass{
$foo = [{"id" => "bar", "ip" => "1.1.1.1"}, {"id" => "baz", "ip" => "2.2.2.2"}]
map {$foo:}
define map () { notify {$name['id']: } }
}
But this gives me
err: Could not retrieve catalog from remote server: Could not intern from pson: Could not convert from pson: Could not find relationship target "Change_config::Map[ip1.1.1.1idbar]"
warning: Not using cache on failed catalog
err: Could not retrieve catalog; skipping run
What is the reason for this ?
Regards,
Malintha Adikari
Your array contains hashes. The resource declaration syntax works only for arrays of strings.
$foo = ["bar", "baz"]
map {$foo:}
define map () { notify {$name: } }
If you want to pass data with each resource title, you need to
build a hash of your data, not an array of hashes
use the create_resources function
Untested example code:
$foo = {
"bar" => { "ip" => "1.1.1.1" },
"baz" => { "ip" => "2.2.2.2" },
}
create_resources('map', $foo)
define map ($ip="") { notify { "$name has ip $ip": } }

Resources