How Do You Create a Chef Recipe to Install Java on Linux Chef-Client Nodes?

Problem scenario
You have Linux servers that need Java 1.8 installed on them.  How do you write a Chef recipe to deploy Java?

Solution
Prerequisite
This solution requires that the Chef server must have access to GitHub.  If you want to install Chef server, see this posting.  If you want to install Chef client, see this posting.  You need to have Git installed on the Chef server.

Procedures
1. Log into the Chef server. 

2. Go to the cookbooks directory (e.g., sudo find / -name knife.rb).  Find the "cookbook_path" stanza in the knife.rb file.  If you need to create this file (e.g., you recently configured knife but did not create the path listed in the cookbook_path stanza), manually create the directory path and the file.  Then cd into the directory that cookbook_path (in knife.rb) is set to.

3.  Run this command:
git clone https://github.com/ContinualIntegration/java.git java1.8

4.  a)  If you are not using the ChefDK on the Chef server, do this substep (a).  The command "chef -v" will show you if you are using Chef Development Kit.  From the Chef server if knife has been installed, or from a workstation with knife, run this command:

knife cookbook create java1.8

  b)  If you are using ChefDK (the command "chef -v" will show you if you are using Chef Development Kit), from the Chef server run this command:

chef generate cookbook java1.8

5.  Run this command from the Chef server if knife has been installed or from a workstation with knife:

knife cookbook upload java

6. a) knife node edit <nameOfNode>
    b)  Under the run list, add no commas if it the run list between the [] brackets is currently empty; otherwise put a comma after the last (or single) recipe you find in the run list, then add this stanza after that comma:
"recipe[java]"
       

    c)  Save the changes.

7.  You are done creating the recipe.  You can now run the Chef client service.

FFR
If there is unreliability in the Chef client runs of installing Java, place a duplicate "recipe[java]" stanza with a comma after the top one after you use "knife node edit <nameOfNode>".  It should look like this:
"recipe[java]",
"recipe[java]"

How Do You Troubleshoot the Knife (Chef) Error “You authenticated successfully but you are not authorized … missing read permission”?

Problem scenario
You have installed Chef on Ubuntu.  You run this command:

sudo knife client list

You expect to see a list of Chef client nodes.  But you see an error like this:

"ERROR: You authenticated successfully to https://<FQDN of Chef Server>/organizations/companynickname as <FQDN of Chef client node> but you are not authorized for this action
Response:  missing read permission"

What do you do?

Solution
Run this command:

export EDITOR=vi

Next run this command (without the <> symbols):

knife node create <FQDN of Chef client node>

(You will enter vi text editor.)  Hold shift and tap "z" twice to save the changes

When Using Chef’s Knife Command How Do You Solve The “Error: failed to authenticate … invalid signature for user or client” problem?

Problem scenario
You are trying to use Chef's knife command.  Every time you try to regenerate a key or delete a user, you get an error like this:

"ERROR: Failed to authenticate to https://continualintegration.com/organizations/contintnickname as contint with key /home/ec2-user/.chef/contint.pem
Response:  Invalid signature for user or client 'contint'"

What do you do?

Solution
1.  Log into the GUI for Chef Manage. 
2.  Go to Administration -> Users. 
3.  Find the user referenced in the error message (e.g., contint). 
4.  Highlight the user and go to "Actions" on the right and click on the sprocket/gear icon.  Click "Reset key." 
5.  This will reset the key, but you'll get a private key to place where the client.pem file should be on the Chef server on the back end.  Delete the contents of the client.pem file on the back end and replace it with the content of this newly generated key.

How Do You Create a Recipe or Cookbook to Make a Configuration Change on a Chef Client?

Problem scenario
You have a desired configuration that you want implemented with Chef.  You want a command to execute and a file to transfer via a Chef recipe or cookbook.  You have installed Chef server on one server (see this posting if you want to do this) and Chef client on another (see this posting for installing Chef client).  You want to use Chef for the first time doing something as an example.  How do you get Chef to do two configuration management tasks?

Solution
Hybrid cloud implementations are common.  This solution has been tested to work with a Chef Server in AWS with Chef client nodes in AWS and in Azure.  

Prerequisites
You have Chef server and Chef client already installed on separate servers.  Make sure knife is installed on the Chef server if it is a standalone deployment.  (The knife command does not need to be on a Chef client node.  The knife command does not need to be on the Chef server if you have a workstation with knife.)  Use this to test: "man knife" (with no quotes).  If you see a man page, knife has probably been configured properly and you can skip down to the Procedures section.  Otherwise, go to one of the the Ubuntu or CentOS/RHEL/Fedora sections below.

Ubuntu Prerequisite
If knife is not installed and you are using Ubuntu with a standalone deployment of Chef, run these commands from the Chef server:

sudo apt-get -y update

sudo apt -y install chef

Respond to the prompt for the "URL of Chef Server" with the FQDN of the Chef server.  Go to the "Configure knife" section below.

CentOS/RHEL/Fedora Prerequisite
If knife is not installed and you are using CentOS/RHEL 7.x/Fedora with a standalone deployment of Chef, run these commands from the Chef server:

sudo yum -y update

curl https://packages.chef.io/files/stable/chefdk/2.3.4/el/7/chefdk-2.3.4-1.el7.x86_64.rpm > /tmp/chefdk-2.3.4-1.el7.x86_64.rpm

sudo yum -y localinstall /tmp/chefdk-2.3.4-1.el7.x86_64.rpm

If you are using RHEL 8.x, run these commands from the Chef server:

sudo yum -y update
curl https://packages.chef.io/files/stable/chefdk/4.8.23/el/8/chefdk-4.8.23-1.el7.x86_64.rpm > /tmp/chefdk-4.8.23-1.el7.x86_64.rpm
sudo yum -y localinstall /tmp/chefdk-4.8.23-1.el7.x86_64.rpm

Configure knife Prerequisite

a)  Run this:  knife configure

b)  You will be prompted for a series of questions.  For the first one, accept the default (just press enter) unless you have a preference:  "Where should I put the config file? [/path/to/.chef/knife.rb]"

c)  For the second prompt, "Please enter the chef server URL:", respond with one string with no spaces.   Enter "https://" and then the chef server FQDN, and finally this string "organizations/companynickname/" for the URL with no port number and no quotes.  Replace "companynickname" with the company nickname you provided with the org-create command when you set up the Chef server.  For example:

https://<FQDN of Chef server>/organizations/companynickname/

d)  For the third one, "Please enter an existing username or clientname for the API:" enter "contint" with no quotes where "contint" was entered when you set up Chef with this command:

sudo chef-server-ctl user-create contint Continual Integration dne@doesnotexist.com 'abcd1234' --filename /home/jdoe/contint.pem

e)  For the fourth one, "Please enter the validation clientname:", enter "contint-validator" with no quotes or whichever name you want.

f)  For the fifth prompt, "Please enter the location of the validation key:", enter "/etc/chef/contint-validator.pem" with no quotes where "contint-validator.pem" is the name you want the file to be.  Alternative path locations (from /etc/chef/) could work as well.  This is just an example.

g)  For the sixth prompt, "Please enter the path to a chef repository (or leave blank):", enter "/home/jdoe" with no quotes or a location of your preference.  Your Linux user account should have the ability to create directories and write to files in this location.

h)  1. Note the output like this:

    "You must place your client key in:
      /home/jdoe/.chef/jdoe.pem "

    2.  The source of this file was created when you ran a command this (when setting up Chef server):

    sudo chef-server-ctl user-create contint Continual Integration dne@doesnotexist.com 'abcd1234' --filename /home/jdoe/contint.pem

    The file specified after the "--filename" flag is the source.

    3.  Copy the source file referred to in step h.2 above to the destination as referred to in step h.1.

i)  If you used directions on this site to configure Chef server, you will have already done this step (and its three sub-steps below).
    1.  Note the output that appeared with step g above like this:

    You must place your validation key in:
     /etc/chef/contint-validator.pem"

     2.    Find the file that was created when you set up Chef server.  Assuming the file was named "contint-validator.pem" find it with this command:  sudo find / -name contint-validator.pem

    For background information, this type of command would create such a file:
    sudo chef-server-ctl org-create companynickname 'Continual Integration' --association_user contint --filename contint-validator.pem

    3.  If necessary copy the file from where it was created on the Chef server to the location the output says to.  For example, if the contint-validator.pem file is in /home/jdoe/, copy it to /etc/chef/ (per the output as illustrated in step i.1). 

j)  Run this command: knife ssl fetch

Procedures
1.  From the workstation with knife or the standalone Chef server, run one of the commands below associated with your distribution of Linux (where coolexample is the name of the cookbook you want to create):

# For Ubuntu distributions, run this command:
knife cookbook create coolexample

# For CentOS/RHEL/Fedora distributions of Linux, run this command:
chef generate cookbook coolexample

  •  You will need to be in a directory wherein you have permissions to create subdirectories to run either of the above commands.  Some /etc/chef may not work if you are not root.
  • The home directory of the user may be where you run the above commands.  This is an example for a proof-of-concept.  Your needs may vary; you may want to create your own directory structure.
  • The cookbook_path stanza in the soon-to-be created file named knife.rb will be configured to the directory where the cookbooks will be.  Remember the path where you run one of the above commands.

2.  On the Chef server make sure /etc/chef/client.pem exists.  This file should be a copy of the private key generated from the GUI operation when setting up the client.  (There are other potential locations and names for this file.)

3.  a)  Change directories to the "recipes" directory in the cookbook directory that was just created.  You could run this to find it: sudo find / -name coolexample
     b)  cd /path/found/above

4.  Run this command:  cd recipes

5.  Modify default.rb in this "recipes" directory.  Add theses lines to default.rb (to demonstrate command execution and file transferring in a recipe):

execute "A bash command will run" do
  command "date > /tmp/c.txt"
end

cookbook_file "/tmp/goodfun.txt" do
  source "fun.txt"
  mode "0644"
end

6.  Run these four commands:

cd ..
mkdir files # so "files" is a sibling of "recipes" in the cookbook named "coolexample"
cd files
echo "testing" > fun.txt

7.  Run these two commands (and follow the step below):

export EDITOR=vi
knife node edit <FQDN of chef client server>
  # This command opens the vi text editor.

You will want to go to the run_list section and make it look like these three lines of code (the parentheses portion is for your information and not code):

  "run_list": [
"recipe[coolexample]"
  ]

(Subsequent recipes can be listed provided that the preceding recipe has a comma after it.)*

8.  Run this command:

knife cookbook upload --all

9.  Go to the Chef client node.  From this server run this command:

sudo chef-client -S https://<FQDN of Chef Server>/organizations/companynickname

You are done.

*  To ensure every time you log in you have a text editor exported to an environment variable, thus enabling the "knife node" command, do the following.  (You will not have to worry about running the export command again.)

Run one of the following:

vi ~/.bashrc or vi ~/.bash_profile

(The text is large because the tilde is important.)  Add this single stanza in the file: 
export EDITOR=$(which vi)

Save the changes.

How Do You Troubleshoot the Error “curl: (6) Could not resolve host: Unknown error”?

Problem scenario
You are using RedHat Enterprise Linux in AWS.  curl commands are not working.  DNS names are not resolving accurately.  For example, you try this command:  curl http://icanhazip.com

You get this error:
"curl: (6) Could not resolve host: icanhazip.com; Unknown error"
How do you fix this to get curl commands to work (and make sure that FQDNs resolve properly)?

Solution
Do these four things:

1.  sudo cp /etc/modprobe.d/disableipv6.conf /etc/modprobe.d/bak.disableipv6.conf.bak
2.  sudo su -
3.  echo "install ipv6 /bin/true" >> /etc/modprobe.d/disableipv6.conf
4.  Reboot the server.

How Do You Deploy a Standalone Chef Server to a Linux Server?

Updated 10/13/19

Problem scenario
You want to deploy Chef server to Linux in a standalone fashion.  What do you do?

Solution
This solution has been tested to work with Ubuntu 16.04 Linux in AWS or Azure.  This solution has also been tested to work with RHEL 7.4 in AWS.

#1  For a standalone deployment, you will need a server with 4 CPU cores and 4 GB of RAM according to this link.  But if your server will not be utilized much, our tests were successful with deploying Chef server to VMs with the following characteristics:

  • 2 vCPU cores and 1.75 GB of RAM will work on Ubuntu 16.x in Azure
  • 2 vCPU cores and 3.75 GB of RAM will work on Ubuntu 16.x or 18.x in AWS
  • 2 vCPU cores and 4 GB of RAM will work on RHEL 7.4 in AWS
  • 2 vCPU cores and 4 GB of RAM will work on RHEL 8.2 in AWS (with 4 GB of swap space)

You may want to resize your VM, or upgrade the physical server, to have more RAM.  Click here for AWS resizing directions or here for GCP resizing directions.  If you have ample hard disk space but insufficient memory, you may want to see this posting for directions for adding or configuring virtual memory.

#2 a) Log in. 
      b) If the server is running Ubuntu, run these two commands:
curl https://packages.chef.io/files/stable/chef-server/12.17.5/ubuntu/16.04/chef-server-core_12.17.5-1_amd64.deb > /tmp/chef-server-core_12.17.5-1_amd64.deb

# If you want the most recent .deb file, you may want to go to the official Chef website to check.

sudo dpkg -i /tmp/chef-server-core_*.deb

     c)  If the server is Red Hat 7.x, run these two commands:
curl https://packages.chef.io/files/stable/chef-server/12.17.5/el/7/chef-server-core-12.17.5-1.el7.x86_64.rpm > /tmp/chef-server-core-12.17.5-1.el7.x86_64.rpm

# If you want the most recent .rpm file, you may want to go to the official Chef website to check. 

sudo yum -y localinstall /tmp/chef-server-core-12.17.5-1.el7.x86_64.rpm

d) If the server is RHEL 8.x, do this sub-step d). Run these commands:
curl https://packages.chef.io/files/stable/chef-server/13.2.0/el/8/chef-server-core-13.2.0-1.el7.x86_64.rpm > /tmp/chef-server-core-13.2.0-1.el7.x86_64.rpm

sudo yum -y localinstall /tmp/chef-server-core-13.2.0-1.el7.x86_64.rpm

Skip 3.b. and 3.c. when you get there. This is the end of sub-step d).

#3.a. Run this command:

sudo chef-server-ctl reconfigure

3.b. Run this command:

sudo cp /opt/opscode/embedded/service/omnibus-ctl/spec/fixtures/pivotal.rb /etc/opscode/

3.c. Run this command:

sudo chef-server-ctl reconfigure

#4  Modify this command for your environment, then run it:

sudo chef-server-ctl user-create USER_NAME FIRST_NAME LAST_NAME EMAIL 'PASSWORD' --filename FILE_NAME

# Above command was mostly taken from https://docs.chef.io/install_server.html#standalone

Here is an example of how it may look:
sudo chef-server-ctl user-create contint Continual Integration dne@doesnotexist.com 'abcd1234' --filename /home/ubuntu/contint.pem

#5  Modify this command for your environment, then run it:

sudo chef-server-ctl org-create short_name 'full_organization_name' --association_user user_name --filename ORGANIZATION-validator.pem

# Above command was mostly taken from https://docs.chef.io/install_server.html#standalone

Here is an example of how it may look:

sudo chef-server-ctl org-create companynickname 'Continual Integration' --association_user contint --filename contint-validator.pem

#6  Run these three commands:
sudo chef-server-ctl install chef-manage

sudo chef-server-ctl reconfigure

sudo chef-manage-ctl reconfigure

# Agree to the license for the last command if you can (e.g., it is ok with your employer).  Press 'q" then type "yes" with no quotes and press enter.

#7  If the chef-server-ctl command works, then Chef server was installed.  You may want to try this command as a test:

sudo chef-server-ctl user-list

To see more information about your deployment, run this command:

sudo cat /opt/opscode/version-manifest.txt

FYI
Now would be a good time to install and configure knife.  Chef server is merely installed.  For most purposes, you will need knife. 
If you are not using RHEL 8.x:
To install and configure knife, see this posting, and look at the "Prerequisites" that correspond with your distribution of Linux.

If you are using RHEL 8.x:
Run this command (without installing any other packages to get knife installed): sudo ln -s /opt/opscode/bin/knife /bin/knife
Then go to the posting and view the "Configure knife Prerequisite" section to configure knife. Next run a command like this:
sudo chef-server-ctl user-create contint Continual Integration dne@doesnotexist.com 'abcd1234' --filename /home/jdoe/jdoe.pem

knife configure # You can accept the defaults or change them as desired.

Should You Be Concerned about Surge Protection for Your Laptop If You Use a Hard-Wired Connection with a Network Cable?

Problem scenario
You live in an are that is susceptible to lightning (most of the world).  You use a power strip or UPS with surge protection.  Surge protection is made possible via a MOSFET (metal-oxide semi-conductor field effect transistor) that is destroyed when the power surges to potentially destructive levels.  You do not have surge protection on the coaxial cable to the coaxial modem.  You are concerned that if lightning were to strike, the surge could run through the coaxial cable and into the cable modem thus destroying the cable modem itself and the device(s) that is (are) connected to it via an ethernet patch cable.  Should you be concerned that the spike in current could hurt your laptop from the cable modem over the network cable?

Answer
Yes.  You should be concerned.  Many UPSes have coaxial input and output jacks to protect against these surges.  Luckily in our experience, the speed degradation is negligible.  Your internet performance should not be significantly affected.

How Do You Use scp When You Get A “Permission Denied” Error?

Problem scenario
You want to copy files between RedHat Linux servers with adherence to security best practices.  You try to use scp but you get "Permission denied."  What do you do to copy files in a secure way?

Solution
1.  Verify you can SSH from one server to the other.  For directions for setting up SSH in a cross-cloud environment, you may want to see this posting.  If firewall rules prevent this, then scp will not work either.


2.  Ensure that you can create files in the destination directory.  You may want to use scp to try to copy a file to the /tmp/ directory first then try directory destinations with stricter write permissions.  Local server directory permissions could be the problem. You are done.


3.  This is purely optional and informational. For further information about scp, see this link. If you want to read more about technical security topics, see the many pages of this internal posting. If you are interested in buying a book on I.T. security, see this posting.

How Do You Troublshoot the Error “snappymodule.cc:31:22: fatal error: snappy-c.h: No such file or directory” when Trying to Install Apache Parquet?

Problem scenario
When trying to install Apache Parquet on Ubuntu, you get this error:

Running python-snappy-0.5.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-SIHL_T/python-snappy-0.5.1/egg-dist-tmp-O8UnkU
WARNING: '.' not a valid package name; please use only .-separated package names in setup.py
package init file '__init__.py' not found (or not a regular file)
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
snappymodule.cc:31:22: fatal error: snappy-c.h: No such file or directory
compilation terminated.
error: Setup script exited with error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
ubuntu@ubuntuf1:/opt/parquet-1.2$ find . -name snappymodule.cc
ubuntu@ubuntuf1:/opt/parquet-1.2$ sudo apt-get install python-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
python-dev is already the newest version (2.7.11-1).
0 upgraded, 0 newly installed, 0 to remove and 11 not upgraded.

What should you do?

Solution
Run this command to install libsnappy-dev (a dependency for installing Apache Parquet):
sudo apt-get -y install libsnappy-dev

How Do You Prepopulate Text Fields in a Web Page with Values from a SQL Database?

Problem scenario
You have a web page from an .php file that includes HTML code.  There are fields visible in the web page to the user.  These fields accept text. You want the fields to not be blank; you want the fields to have suggested values of text in them. You want the data in the fields to be taken from the result of a SQL statement.  How do you prepopulate text fields in a LAPP web page with values from SQL statements?

Solution
This assumes have you set up the LAPP stack.  If you do not know how to implement front-end authentication for your LAPP instance, you may want to see one of two blog posts.  This solution assumes you have configured authentication variables that you see in the pg_connect() statement.

Here is an example PHP web page (.php file) that will prepopulate text fields that the user may modify from his/her web browser:

<?php

   $db = pg_connect( "$host $port $dbname $credentials"  );

//The above line assumes the $host, $port, $dbname, and $credentials variables were properly assigned.

//With PHP code compose SQL statements like this:

   $query = 'select col1 from ' . $tn . ' where continual_col = ' . $id . ';';

// This assumes that col1 exists in the table defined in the variable $tn.
// This assumes that $id is the value of exactly one row in the table defined with variable $tn.
// This query will retrieve the value of one field in a table in the database.

//Now invoke Postgres commands via PHP to process the results of the query:

   $selectval = pg_query($query);
   $row1 = pg_fetch_row($selectval);
   $finalval = current($row1);

?>

<html>
<body>

<form action="nextpage.php" method="post">

good_field: <input type="text" name="suggestedval" value="<?php echo $finalval; ?>">

<input type="submit">
</form>

</body>
</html>