I'm trying to pass attributes to my recipe at run-time of chef client.
following is my default.rb attribute file:
if node['os'] == 'windows'
if node.attribute?('temp')
default['param']['name'] = node['temp']['tempname']
else node.attribute?('base')
default['param']['name'] = node['base']['nodename']
end
end
I first ran the chef-client with only the base attribute defined in the node.json file. My node.json looked like :
{
"base": {
"nodename": "John"
}
}
Chef-client run was successfull and the attribute was set accordingly. i.e.
default['param']['name'] = "John"
Than I ran chef-client with both base and temp attribute defined in the node.json.
And here is my node.json file :
{
"base": {
"nodename": "John"
},
"temp": {
"tempname": "Mike"
}
}
Chef-client again ran successfully and the attribute was set accordingly.
default['param']['name'] = "Mike"
The problem is when I run the chef-client again and pass only base attribute from the node.json file(see below for the file), the code doesn't seem to enter the else loop. It just runs the `if' loop with old value for temp attribute(Mike).
{
"base": {
"nodename": "John-2"
}
}
Any ideas to where I'm going wrong.
The second time you ran chef-client, it saved the node[:temp][:nodename] attribute to the node object on the Chef server.
When you ran chef-client again, it loaded the node's attributes back from the server before reaching the attributes/default.rb file, so node[:temp][:nodename] was set when it reached the conditions.
I'm not sure what you're trying to achieve, but it would probably be best to explicitly tell which attribute you want to use through another attribute (and maybe assume a default for it), such as:
default[:name_attribute] = 'temp'
then,
if node['os'] == 'windows'
if node['name_attribute'] == 'temp'
default['param']['name'] = node['temp']['tempname']
else
default['param']['name'] = node['base']['nodename']
end
end
Related
I have a CHEF recipe for package install on windows hosts. We used to use chef13 client; however we have upgraded to chef16, and we are getting some issues with the cookbook migration.
When I run the existing role as-it-is on a win2k16 chef16 kitchen platform, I get this error,
Chef::Exceptions::ImmutableAttributeModification
------------------------------------------------
Node attributes are read-only when you do not specify which precedence level to set. To set an attribute use code like `node.default["key"] = "value"'
and it points out to this section of the recipe
67: guid = guid.gsub(/{/, '').gsub(/}/, '') # remove {}
68: log "[#{role}][#{recipe_name}][#{app_name}]: GUID for installer #{app_name} is #{guid}"
69>> app_params.store('product_guid', guid) # add GUID to the list of parameters
70: end
Hence, what I understand that chef16 dosen't like the hash.store method.
I have tried some other alternate solutions to update the hash, however they do not work.
Using merge method:-
app_params.merge!({ :product_guid => 'guid' })
Using precedence level explicitly:- ( I have used .default, .override as well, however its the same symptom)
node.force_override!['app_params']['product_guid'] = guid
(reff from : https://github.com/chef/chef/issues/6563)
Note that when using the above methods, i do not get any failures, however the hash dosent get updated at all.
I have added few log statements to show this:-
log "[#{role}][#{recipe_name}][#{app_name}]: app_params.keys is #{app_params.keys}"
log "[#{role}][#{recipe_name}][#{app_name}]: app_params is #{JSON.pretty_generate(app_params)}"
* log[[my-role][my-recipe][my-pkgName]: app_params.keys is ["app_name", "full_path", "action"]] action write
* log[[my-role][my-recipe][my-pkgName]: app_params is {
"app_name": "my-pkgName",
"full_path": "https://myArtifactRepo/.../.../../my-pkgName.msi",
"action": "install"
}] action write
## ^^ hash keys and hash values (app_params.keys and app_params) BEFORE the force_override method is used
log "[#{role}][#{recipe_name}][#{app_name}]: app_params.keys is #{app_params.keys}"
log "[#{role}][#{recipe_name}][#{app_name}]: app_params is #{JSON.pretty_generate(app_params)}"
* log[[my-role][my-recipe][my-pkgName]: app_params.keys is ["app_name", "full_path", "action"]] action write
* log[[my-role][my-recipe][my-pkgName]: app_params is {
"app_name": "my-pkgName",
"full_path": "https://myArtifactRepo/.../.../../my-pkgName.msi",
"action": "install"
}] action write
## ^^ hash keys and hash values (app_params.keys and app_params) AFTER the force_override method is used
Note that the hash and hash key values has not been updated it is still,
["app_name", "full_path", "action"];
however we would expect
["app_name", "full_path", "action", "product_guid"]
and the hash itself like,
"app_name": "my-pkgName",
"full_path": "https://myArtifactRepo/.../.../../my-pkgName.msi",
"action": "install",
"product_guid" : XXXXYYY-0WRR-1234-ABCD-3ERDFR234GRT
I have lambda invocation in our terraform-built environment:
data "aws_lambda_invocation" "this" {
count = var.invocation == "true" ? 1 : 0
function_name = aws_lambda_function.this.function_name
input = <<JSON
{
"Name": "Invocation"
}
JSON
}
The problem: the function is invoked not only during creation ("apply") but deletion ("destroy") too. How to invoke it during creation only? I thought about checking environment variables in the lambda (perhaps TF adds name of the process here or something like that) but I hope there's a better way.
Worth checking if you can use the -var 'lambda_xxx=execute' option while running the terraform command to check if the lambda code needs to be executed or not terraform docs
Using that variable lambda_xxx passed in via the command line while executing the command, you can check in the terraform code whether you want to run the lambda code or not.
Below code creates a waf only if the count is 1
resource "aws_waf_rule" "wafrule" {
depends_on = ["aws_waf_ipset.ipset"]
name = "${var.environment}-WAFRule"
metric_name = "${replace(var.environment, "-", "")}WAFRule"
count = "${var.is_waf_enabled == "true" ? 1 : 0}"
predicates {
data_id = "${aws_waf_ipset.ipset.id}"
negated = false
type = "IPMatch"
}
}
Variable declared in variables.tf file
variable "is_waf_enabled" {
type = "string"
default = "false"
description = "String value to indicate if WAF/API KEY is turned on or off (true/any_value)"
}
When you run the command any value other than true is considered false as we are just checking for string true.
Similarly you can do this for your lambda.
There are better alternative solutions for this problem now, which weren't available at the time the question was asked.
Lambda Invocation Resource in AWS provider: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_invocation
Lambda Based Resource in LambdaBased provider: https://registry.terraform.io/providers/thetradedesk/lambdabased/latest/docs/resources/lambdabased_resource
With the disclaimer that I'm the developer of the latter one: If the underlying problem is managing a resource through lambda functions, the lambda based resource has some good features tailored specifically to accomplish that with the obvious drawback of adding another provider dependency.
For various reasons I have a chef recipe that I want to use add multiple groups to a system with. I've defined a data bag with a key / value structure that provides the group name as the key and the guid as the value eg:
{
"id": "default_groups",
"group": {
"sales": "200",
"marketing": "800",
"csr": "1000",
"devel": "9000",
"scientists": "500"
}
}
I was wanting to use the group resource in a for each loop but I don't seem to be referencing the data in the data bag correctly:
user_groups = data_bag_item('groups', 'default_groups')
%w{"#{user_groups['group']}"}.each do |usr|
group "#{usr}.key" do
action :create
gid "#{usr}.value"
end
end
Can anyone explain what I'm doing wrong with my syntax?
The error output from the chef run is as follows:
ERROR: group["#{user_groups['group']}".key] (cookbook_groups::recipe_groups line 10) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '3'
---- Begin output of ["groupadd", "-g", "\"\#{user_groups['group']}\".value", "\"\#{user_groups['group']}\".key"] ----
STDOUT:
STDERR: groupadd: invalid group ID '"#{user_groups['group']}".value'
---- End output of ["groupadd", "-g", "\"\#{user_groups['group']}\".value", "\"\#{user_groups['group']}\".key"] ----
Ran ["groupadd", "-g", "\"\#{user_groups['group']}\".value", "\"\#{user_groups['group']}\".key"] returned 3
You cannot combine string interpolation, word arrays and array/hash access like that.
This might work:
user_groups = data_bag_item('groups', 'default_groups')
user_groups['group'].each do |key, value|
group key do
action :create
gid value
end
end
Apparently, %w does not do what you think:
▶ %w{"#{user_groups['group']}"}
#⇒ ["\"\#{user_groups['group']}\""]
You probably need just:
user_groups['group'].each
or like.
I'm trying to pass some values into chef recipe from the json file.
All I want is to set some values in my recipe from the remote file.
My json file my_conf.json looks like this:
{
"something": {
"listen_port": "81",
"listen_path": "/myapp"
},
"users":{
"user": "me"
}
}
I run my chef-client with this json in params:
chef-client -z run.rb -j my_conf.json
In the recipe I tried:
#test = node[:something][:listen_port]
#test = node['something']['listen_port']
#test = node.default[:something][:listen_port]
But nothing works.
Any ideas?
node['something']['listen_port'] is correct but node[:something][:listen_port] will work as well. More likely assigning to an instance variable (#test =) instead of a normal local variable (test =) is confusing things. Chef does a lot of magic with Ruby scoping internally.
First of all I am new to chef and vagrant.
I already have a working vagrant box based on an open source project at vdd. I am trying to add a chef recipe to it that checks out a git repo into a directory prepared by chef provisioner.
So I added a new recipe to in cookbooks/custom/my_example/default.rb and added an entry "recipe[my_example]" to the run_list in chef/roles/vdd.json. The recipe is supposed to checkout a git repository to a directory document_root which is declared in config.json and prepared with vdd_sites.rb recipe file. My custom chef recipe I have in cookbooks/custom/my_example/default.rb does the follwoing:
git "/var/www/drupal7" do
repository "https://github.com/drupal/drupal.git"
revision "master"
checkout_branch 'master'
action :sync
user 'vagrant'
group 'vagrant'
end
The relevant config json code is:
"vdd": {
"sites": {
"drupal8": {
"account_name": "root",
"account_pass": "root",
"account_mail": "box#example.com",
"site_name": "Drupal 8",
"site_mail": "box#example.com",
"vhost": {
"document_root": "drupal8",
"url": "drupal8.dev",
"alias": ["www.drupal8.dev"]
}
},
"drupal7": {
"account_name": "root",
"account_pass": "root",
"account_mail": "box#example.com",
"site_name": "Drupal 7",
"site_mail": "box#example.com",
"vhost": {
"document_root": "drupal7/docroot",
"url": "drupal7.dev",
"alias": ["www.drupal7.dev"]
}
}
}
}
And the code in vdd_sites.rb is:
if node["vdd"]["sites"]
node["vdd"]["sites"].each do |index, site|
include_recipe "database::mysql"
htdocs = defined?(site["vhost"]["document_root"]) ? site["vhost"]["document_root"] : index
# Avoid potential duplicate slash in docroot path from config.json input.
if htdocs.start_with?("/")
htdocs = htdocs[1..-1]
end
# Create subidrectores, allow for multiple layers deep.
htdocs = "var/www/" + htdocs
htdocs = htdocs.split(%r{\/\s*})
folder = "/"
for i in (0..htdocs.length - 1)
folder = folder + htdocs[i] + "/"
directory folder do
owner "vagrant"
group "vagrant"
mode "0755"
action :create
end
end
mysql_connection_info = {
:host => "localhost",
:username => "root",
:password => node["mysql"]["server_root_password"]
}
mysql_database index do
connection mysql_connection_info
action :create
end
end
end
However, nothing gets cloned in that directory. if I change the target destination to another directory in my recipe file it works fine. i.e. git "/var/www/anotherdir" do ...
I am not sure what's going on, is it the order of recipe execution?
Remove the checkout_branch line, you don't want that. Yes I know it sounds like you do, but you don't. Check the output from chef-client to make sure your recipe is actually running. You seem to be saying both of those snippets of code are vdd_sites?
I suspect your issue is that GIT doesn't much like having files (or directories) in the directories it's creating clones into. It appears to be as if /var/www/drupal7 at the very least has a subdir /docroot, and maybe a lot more files.
Suggest you create the clone first, then add these files.