Chef : Pass parameters to a ruby_block in Chef - ruby

How do you pass parameters to a ruby_block in chef.
If I have
notifies :create, "ruby_block[createErb]", :immediately
and I want pass a parameter (fileToConvert) to this ruby_block (createErb) at the time that I notify.
ruby_block "createErb" do
block do
ErbCreator.new(fileToConvert)
end
action :nothing
end
How would I do this?

Short answer - you can't.
RubyBlock is a Chef resource, so it does not accept arbitrary parameters. In your example, I would recommend creating a Chef Extension (LWRP or HWRP):
In your resource:
# resources/erb_create.rb
actions :create
default_action :create
attribute :filename, name_attribute: true
# more attributes
And in your provider:
# providers/erb_create.rb
action(:create) do
ErbCreator.new(new_resource.filename)
# ... etc
end
Then in a recipe:
# recipes/default.rb
cookbook_erb_create 'filename'
You can read more about LWRPs on the Chef Docs.

Related

Chef custom resource action properties not working

I'm having an issue with a custom resource I created in a new cookbook i'm working on. When I do a kitchen converge on the following setup I get the following error:
error: NoMethodError: undefined method `repository_url' for PoiseApplicationGit::Resource
Info about my development machine:
Chef Development Kit Version: 2.1.11
chef-client version: 13.2.20
delivery version: master (73ebb72a6c42b3d2ff5370c476be800fee7e5427)
berks version: 6.3.0
kitchen version: 1.17.0
inspec version: 1.33.1
Here's my custom resource under resources/deploy.rb:
resource_name :opsworks_deploy
property :app_path, String, name_property: true
property :app_name, String, required: true
property :repository_url, String, required: true
property :repository_key, String, required: true
property :short_name, String, required: true
property :app_type, String, required: true
property :app, Object, required: true
property :permission, String, required: true
action :deploy do
apt_update 'update'
# Install NGinx
package 'nginx' do
not_if { ::File.exist?("/etc/init.d/nginx") }
end
# Setup the app directory
directory my_app_path do
owner 'www-data'
group 'www-data'
mode '0755'
recursive true
end
slack_notify "notify_deployment_end" do
message "App #{app_name} deployed successfully"
action :nothing
end
slack_notify "notify_nginx_reload" do
message "Nginx has reloaded"
action :nothing
end
slack_notify "notify_nginx_config" do
message "Nginx site config has been updated for #{app_name}"
action :nothing
end
slack_notify "notify_git_deploy" do
message "App #{app_name} has been checkout out from git"
action :nothing
end
slack_notify "notify_file_permissions" do
message "App #{app_name} has been given proper file permissions"
action :nothing
end
# Deploy git repo from opsworks app
application app_path do
owner 'www-data'
group 'www-data'
git do
user 'root'
group 'root'
repository my_repo_url
deploy_key my_repo_key
notifies :notify, "slack_notify[notify_git_deploy]", :immediately
end
execute "chown-data-www" do
command "chown -R www-data:www-data #{my_app_path}"
user "root"
action :run
notifies :notify, "slack_notify[notify_file_permissions]", :immediately
end
# Setup the nginx config file for the site
template "/etc/nginx/sites-enabled/#{my_short_name}" do
source "#{my_app_type}.erb"
owner "root"
group "root"
mode 0644
variables( :app => my_app )
notifies :notify, "slack_notify[notify_nginx_config]", :immediately
end
# Reload nginx
service "nginx" do
supports :status => true, :restart => true, :reload => true, :stop => true, :start => true
action :reload
notifies :notify, "slack_notify[notify_nginx_reload]", :immediately
end
end
end
Here's my recipe under recipes/default.rb (all variables are set properly and to the proper types, i'm using test data bags and they are correctly passing):
command = search(:aws_opsworks_command).first
deploy_app = command[:args][:app_ids].first
app = search(:aws_opsworks_app, "app_id:#{deploy_app}").first
app_path = "/var/www/" + app[:shortname]
opsworks_deploy app_path do
app_name app[:name]
app_type app[:environment][:APP_TYPE]
repository_url app[:app_source][:url]
repository_key app[:app_source][:ssh_key]
short_name app[:shortname]
app app
permission '0755'
end
The only way I can get it working is if I add this at the top of the action declaration and update the properties within to match:
action :deploy do
my_repo_url = repository_url.dup
my_repo_key = repository_key.dup
my_app_path = app_path.dup
my_app_type = app_type.dup
my_short_name = short_name.dup
my_app = app.dup
...
Any reason why this is the case? Should I have to redeclare them like that in the action?
Use new_resource.repository_url and similar. The magic aliasing doesn't work correctly in a lot of circumstances and we've formally deprecated it as of 13.1 (though it's been not recommended for a while).

Chef: Can a variable set within one ruby_block be used later in a recipe?

Let's say I have one variable, directory_list, which I define and set in a ruby_block named get_directory_list. Can I use directory_list later on in my recipe, or will the compile/converge processes prevent this?
Example:
ruby_block "get_file_list" do
block do
transferred_files = Dir['/some/dir/*']
end
end
transferred_files.each do |file|
file "#{file}" do
group "woohoo"
user "woohoo"
end
end
Option 1: You could also put your file resource inside the ruby_block.
ruby_block "get_file_list" do
block do
files = Dir['/some/dir/*']
files.each do |f|
t = Chef::Resource::File.new(f)
t.owner("woohoo")
t.group("woohoo")
t.mode("0600")
t.action(:create)
t.run_context=(rc)
t.run_action(:create)
end
end
end
Option 2: You could use node.run_state to pass data around.
ruby_block "get_file_list" do
block do
node.run_state['transferred_files'] = Dir['/some/dir/*']
end
end
node.run_state['transferred_files'].each do |file|
file "#{file}" do
group "woohoo"
user "woohoo"
end
end
Option 3: If this were just one file, you could declare a file resource with action :nothing, look up the resource from within the ruby_block, and set the filename, and then notify the file resource when the ruby_block runs.
Option 4: If this is the example from IRC today, just place your rsync and the recursive chown inside a single bash resource. rsync and chown are already idempotent, so I don't think it's objectionable in this particular case.

How do I use a Chef Resource in a Library

How do I include a Chef Directory resource in a library? When executing the recipe below, the variables are assigned but the directories aren't created. I don't receive any error messages.
This is a simplified example. Trying to create multiple directories by passing the directory name to a library.
# create directories
# /var/www/domain
# /var/www/domain/production
# /var/www/domain/staging
The library
# directory library
class DirectoryStructure
attr_accessor :domain, :production, :staging
def initialize(domain)
#domain = "/var/www/#{domain}"
#staging = "##domain/staging"
#production = "##domain/production"
end
def create(dir_type,directory_path,username,group)
dir = Chef::Resource::Directory.new(:create)
dir.name(directory_path)
dir.owner(username)
dir.group(group)
dir.mode(2750)
dir
end
end
The recipe
web_dirs = DirectoryStructure.new(domain)
site_dirs.create(web_dirs.domain,username,deploy_group)
site_dirs.create(web_dirs.production,username,deploy_group)
site_dirs.create(web_dirs.staging,username,deploy_group)
I have tried to use this example but I am obviously missing something.
enter link description herehttps://docs.chef.io/lwrp_custom_resource_library.html
This looks like you should be creating a resource, either an LWRP or a normal Ruby class. In most cases the LWRP will be simpler and is probably what you want in this case.
cookbooks/mycook/resources/directory_structure.rb:
default_action :create
attribute :domain, name_attribute: true
attribute :owner
attribute :group
cookbooks/mycook/providers/directory_structure.rb:
action :create do
directory "/var/www/#{#new_resource.domain}" do
owner new_resource.owner
group new_resource.group
end
directory "/var/www/#{#new_resource.domain}/production" do
owner new_resource.owner
group new_resource.group
end
directory "/var/www/#{#new_resource.domain}/staging" do
owner new_resource.owner
group new_resource.group
end
end
cookbooks/mycook/providers/directory_structure.rb:
mycook_directory_structure 'example.com' do
owner 'me'
group 'mygroup'
end

How can you access Chef LWRP attributes in a recipe

With some of the default chef resources, it is possible to access some of their attributes after they have been called
# recipes/default.rb
f = file "/tmp/file_resource" do
owner "root"
group "root"
mode "0755"
action :create
end
log "Path to my file is #{f.path}" # outputs "/tmp/file_resource"
How can this be achieved in a custom LWRP (here is an example)
# resources/default.rb
actions :create
default_action :create
attribute :relative_path, :kind_of => String, :name_attribute => true
attribute :full_path, :kind_of => String
In this provider, I am trying to update the property of new_resource.full_path to be equal to the path of the file resource
# providers/default.rb
action :create do
f = file "/path/to/my/resource/#{new_resource.relative_path}" do
owner "root"
group "root"
mode "0755"
action :create
end
new_resource.full_path(f.path)
new_resource.updated_by_last_action(f.updated_by_last_action?)
end
However when I try to access resource.full_path in the recipe, it is nil rather than the expected /path/to/my/resource/relative/path
# recipes/default.rb
resource = my_awesome_lwrp "relative/path" do
action :create
end
log "Full path for my resource: #{resource.full_path}" # outputs "Full path for my resource:"
This example is rather contrived I know, the real world application/reason for this can be seen in the default resource/provider here https://github.com/peterjmit/chef-ssl-cert

heroku: ActionController::RoutingError (No route matches [GET] "/newrelic")

ERROR
ActionController::RoutingError (No route matches [GET] "/newrelic")
# and I am getting error page for both staging and production heroku servers
Documentation
https://devcenter.heroku.com/articles/newrelic
GEM
https://github.com/newrelic/rpm
# ruby 2.1.0p0
# rails 4.0.1
Both environment variables NEW_RELIC_LICENSE_KEY and NEW_RELIC_APP_NAME are set to heroku config variable
Gemfile
gem "newrelic_rpm", "~> 3.5.7.59"
config/newrelic.yml
common: &default_settings
license_key: <%= ENV['NEW_RELIC_LICENSE_KEY'] %>
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %>
monitor_mode: true
developer_mode: false
log_level: info
browser_monitoring:
auto_instrument: true
audit_log:
enabled: false
capture_params: false
transaction_tracer:
enabled: true
transaction_threshold: apdex_f
record_sql: obfuscated
stack_trace_threshold: 0.500
error_collector:
enabled: true
capture_source: true
ignore_errors: "ActionController::RoutingError,Sinatra::NotFound"
development:
<<: *default_settings
monitor_mode: true
developer_mode: true
test:
<<: *default_settings
monitor_mode: false
production:
<<: *default_settings
monitor_mode: true
staging:
<<: *default_settings
monitor_mode: true
app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> (Staging)
[NOTE: I have two application hosted to heroku:]
(staging).herokuapp.com
(production).herokuapp.com
And I want to configure new-relic for both environments/servers.
Also, Note that this configuration is working fine in development(localhost) environmet.
EDITED
config/routes.rb
Demo::Application.routes.draw do
root :to => "home#index"
devise_for :users,:controllers => {:sessions => "sessions",:omniauth_callbacks => "omniauth_callbacks" }
post '/tinymce_assets' => 'tinymce_assets#create'
resources :home
namespace :admin do
resources :dashboards
resources :users do
member do
get :reset
put :reset_pw
put :delete_record
put :restore_user
end
end
end
resources :drives do
member do
put :destroy_drive
post :add_consolidation
put :delete_consolidation
post :add_driveorganizer
put :delete_drive_organizer
put :restore_drirve
end
collection do
get :recalculate_consolidation
end
resources :drive_details do
resources :images
end
end
resources :products do
member do
post :add_category
put :destroy_pc
put :delete_product
put :restore_products
end
end
resources :stores do
member do
put :delete_store
end
end
resources :store_products do
member do
put :delete_storeproduct
post :add_package_items
put :delete_package_item
put :restore_store_product
get :get_product_price
end
collection do
get :autocomplete_others
end
end
resources :orders do
member do
put :delete_order
put :restore_order
get :charge_stripe
end
resources :order_items do
collection do
post :display_price
end
member do
put :delete_record
end
end
end
resources :categories do
member do
put :delete_category
put :restore_category
end
collection do
get :move
end
end
namespace :user do
resources :campaigns do
member do
get :single_campaign
end
resources :stores
resources :carts do
collection do
post :carts_update
get :checkout_final
get :payment
post :payment
get :update_payment
get :update_payment_and_redirect
get :confirmation
post :confirmation
get :finish
post :confirmation_update
put :empty_cart
post :shelter_survey
end
member do
put :destroy_oi
put :checkout
end
end
end
end
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
end
Thanks
Based on the error you're getting, it looks like you're trying to access the route to the New Relic Ruby agent's developer mode in your staging and production environments. Developer mode installs a middleware in your app that responds to any URL prepended with /newrelic. Because you've enabled Developer mode in your development (localhost) environment (the developer_mode key is set to true in your newrelic.yml under development), accessing this route succeeds there, but it fails in staging and production because you don't have developer mode enabled in those environments.
Your current configuration is usually desirable, since Developer mode introduces a large amount of overhead that is generally unacceptable in production. Rather than attempt to access the route in staging or production, use it during development only.
You may also want to consider upgrading the version of the agent you are using, since version 3.5.7 does not fully support Ruby 2.0 or Rails 4. More information on releases can be found at https://docs.newrelic.com/docs/releases/ruby.

Resources