7

I'd like to use a chef-shell session on an aws opsworks ec2 server so I can test some environment and instance specific code I'd like to include in a custom recipe. For example, I'd like to see the output of instance attributes such as node[:opsworks][:instance][:layers] or node[:opsworks][:instance][:public_dns_name] as well as data I have passed to the opsworks stack using custom json.

I can start chef-shell, I just don't know how to use it to access opsworks attributes.

If I ssh into the opsworks ec2 instance I can access attributes like node['ec2']['instance_id'] but no opsworks specific ones like node['opsworks']['instance']['layers']

root@mongodb1:/opt/aws/opsworks/current/bin# ./chef-shell
loading configuration: none (standalone session)
Session type: standalone
Loading......done.

This is the chef-shell.
 Chef Version: 11.10.4
 http://www.opscode.com/chef
 http://docs.opscode.com/

run `help' for help, `exit' or ^D to quit.

Ohai2u [email protected]!
chef > attributes_mode
chef:attributes > node['ec2']['instance_id']
 => "i-c1a98f2c"
chef:attributes > node['opsworks']['instance']['layers']
NoMethodError: undefined method `[]' for nil:NilClass
        from (irb#1):4
chef:attributes >

2 Answers 2

10

The Custom JSON and the Stack's state are pushed to the instance in a JSON struct when an OpsWorks event (setup, configure, deploy, undeploy, shutdown) occurs. If you want your recipe to see the up-to-the-minute state of the OpsWorks Stack then you need to run your recipe from the OpsWorks UI via the Deploy -> Run Command -> Execute Recipes form.

The JSON sent by OpsWorks is stored on the instance. If you're willing to use potentially-stale Stack state info which is only as fresh as the last time this instance ran an OpsWorks event, you can look for the most recent *.json file on the instance in /var/lib/aws/opsworks/chef, and parse it via Ruby code.

You can also use the opsworks-agent-cli utility on the instance to (re-)run the recipes from an OpsWorks event directly from the command-line on the instance. This utility will re-run OpsWorks events - it won't initiate new events, and it does not pull in a fresh copy of the stack state or the Custom JSON, rather it reuses the .json file that OpsWorks sent to the instance when that event was run originally. For example, in order to rerun the setup event on your instance (because the setup event was definitely run already):

sudo opsworks-agent-cli run_command setup

In order to rerun the same set of recipes you executed last time you ran Execute Recipes from the UI:

sudo opsworks-agent-cli run_command execute_recipes

This kind of sucks, because you need to run the event via the UI first. So if you want to run a custom recipe, or if you want to update custom cookbooks, you first need to run that event from the UI. But, the second, third, and subsequent times you can rerun those events via opsworks-agent-cli.

See here for more about the opsworks-agent-cli.

9

Using advice from @schlomoswidler about the location of the custom json on the ec2 instance file in his answer above I ran the following to get an interactive chef-shell that includes the custom opsworks attributes I was looking for:

root@mongodb1:/opt/aws/opsworks/current/bin# /opt/aws/opsworks/current/bin/chef-shell -j /var/lib/aws/opsworks/chef/2014-10-27-13-46-53-01.json
loading configuration: none (standalone session)
Session type: standalone
Loading.....done.

This is the chef-shell.
 Chef Version: 11.10.4
 http://www.opscode.com/chef
 http://docs.opscode.com/

run `help' for help, `exit' or ^D to quit.

Ohai2u [email protected]!
chef > node['opsworks']['instance']['layers']
 => ["mongodb"]
chef >

You obviously need to replace the json in /var/lib/aws/opsworks/chef folder with an appropriate file on your system.

Update for Chef 12 Linux OpsWorks Stacks (2016)

Chef 12 Linux based OpsWorks stacks work differently than Chef 11 stacks. One difference is that chef search is now the proper way to access data provided by OpsWorks within a recipe. On the instance, attribute data is now exposed through data bags (stack migration & reference). You can get an overview of available data bags by inspecting the directory for one of your Chef runs. Each data bag has its own sub-directory below /var/chef/runs/<ID>/data_bags/.

[root@asd1 ~]# ll /var/chef/runs/c7f67e3e-c15d-4159-bb14-5bde07751543/data_bags/
total 36
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_app
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_command
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_ecs_cluster
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_elastic_load_balancer
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_instance
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_layer
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_rds_db_instance
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_stack
drwxr-xr-x 2 root root 4096 Nov 23 21:19 aws_opsworks_user
[root@asd1 ~]#

You can't use the same chef-shell technique as I used above for Chef 11 stacks.

The best way that I know of to experiment with search is by using a Pry session to get access to the runtime environment of the second chef run which is dedicated to clients.

Examply Pry Session

In the following example I first trigger the "Execute Recipes" lifecycle event from the UI and use "opsworks_cookbook_demo::foo" as the recipe to run. Then I SSH into my instance and edit /var/chef/cookbooks/opsworks_cookbook_demo/recipes/foo.rb, adding the following two lines.

require "pry"
binding.pry

Then I run opsworks-agent-cli run to repeat the latest run. Unless the latest run was of type "Update Custom Cookbooks", this will leave the local changes in place.

The recipe will be run again, but now we have an interactive shell to experiment. Here's how you can perform two searches:

[root@asd1 ~]# opsworks-agent-cli run
[2015-11-23 21:46:35]  INFO [opsworks-agent(3396)]: About to re-run 'execute_recipes' from 2015-11-23T21:43:15
... lots more output ...
From: /var/chef/runs/76ff2d58-ab8f-4cf6-8744-9562025321fd/local-mode-cache/cache/cookbooks/opsworks_cookbook_demo/recipes/foo.rb @ line 4 Chef::Mixin::FromFile#from_file:

    1: Chef::Log.info "foo"
    2:
    3: require "pry"
 => 4: binding.pry

search(:aws_opsworks_stack)
=> [{"data_bag_item('aws_opsworks_stack', 'f24bd5ea-3ff2-4a1a-a4e4-9298495ae263')"=>
   {"arn"=>"arn:aws:opsworks:us-west-2:153700967203:stack/f24bd5ea-3ff2-4a1a-a4e4-9298495ae263/",
    "custom_cookbooks_source"=>{"type"=>"s3", "url"=>"redacted", "username"=>nil, "password"=>nil, "ssh_key"=>nil, "revision"=>nil},
    "name"=>"susan",
    "region"=>"us-west-2",
    "stack_id"=>"f24bd5ea-3ff2-4a1a-a4e4-9298495ae263",
    "use_custom_cookbooks"=>true,
    "vpc_id"=>nil,
    "id"=>"f24bd5ea-3ff2-4a1a-a4e4-9298495ae263",
    "chef_type"=>"data_bag_item",
    "data_bag"=>"aws_opsworks_stack"}}]

search(:aws_opsworks_instance, "self:true")
=> [{"data_bag_item('aws_opsworks_instance', 'asd1')"=>
   {"ami_id"=>"ami-d93622b8",
    "architecture"=>"x86_64",
    "auto_scaling_type"=>nil,
    "availability_zone"=>"us-west-2a",
    "created_at"=>"2015-11-20T12:48:29+00:00",
    "ebs_optimized"=>false,
    "ec2_instance_id"=>"i-be823867",
    "elastic_ip"=>nil,
    "hostname"=>"asd1",
    "instance_id"=>"42d28e39-29a8-4fdf-a327-afdc23668ff1",
    "instance_type"=>"c3.large",
    "layer_ids"=>["f08fb7e2-9278-498a-8c0d-7d1c1bae22aa"],
… lots more data …

The aws blog post Quickly Explore the Chef Environment in AWS OpsWorks has other examples of using pry on an OpsWorks instance.

1
  • For some reason this throws me into [1] pry(#<Chef::CookbookVersion>)> from where I can't access anything. A step will bring me into [1] pry(#<Chef::RunContext::CookbookCompiler>):1> which isn't helpful. Another step into [1] pry(#<Chef::EventDispatch::Dispatcher>)> where pry crashes with Error: Cannot find local context. Did you use binding.pry? - anyone has experienced this? Jun 12, 2017 at 16:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .