set default shell linux

Execute: sudo chsh -s /bin/bash username


Using “${a:-b}” for variable assignment in scripts

This technique allows for a variable to be assigned a value if another variable is either empty or is undefined. NOTE: This “other variable” can be the same or another variable.


    If parameter is unset or null, the expansion of word is substituted. 
    Otherwise, the value of parameter is substituted.

NOTE: This form also works, ${parameter-word}. If you’d like to see a full list of all forms of parameter expansion available within Bash then I highly suggest you take a look at this topic in the Bash Hacker’s wiki titled: “Parameter expansion“.


variable doesn’t exist

$ echo "$VAR1"

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
default value

variable exists

$ VAR1="has value"
$ echo "$VAR1"
has value

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
has value

The same thing can be done by evaluating other variables, or running commands within the default value portion of the notation.

$ VAR2="has another value"
$ echo "$VAR2"
has another value
$ echo "$VAR1"


$ VAR1="${VAR1:-$VAR2}"
$ echo "$VAR1"
has another value

More Examples

You can also use a slightly different notation where it’s just VARX=${VARX-<def. value>.

$ echo "${VAR1-0}"
has another value
$ echo "${VAR2-0}"
has another value
$ echo "${VAR3-0}"

In the above $VAR1 & $VAR2 were already defined with the string “has another value” but $VAR3was undefined, so the default value was used instead, 0.

Another Example

$ VARX="${VAR3-0}"
$ echo "$VARX"

Checking and assigning using := notation

Lastly I’ll mention the handy operator, :=. This will do a check and assign a value if the variable under test is empty or undefined.


Notice that $VAR1 is now set. The operator := did the test and the assignment in a single operation.

$ unset VAR1
$ echo "$VAR1"

$ echo "${VAR1:=default}"
$ echo "$VAR1"

However if the value is set prior, then it’s left alone.

$ VAR1="some value"
$ echo "${VAR1:=default}"
some value
$ echo "$VAR1"
some value

Handy Dandy Reference Table

ss of table


Helm: Creating first chart

We will be creating a helm chart for sonatype nexus.

Helm provides several tools to streamline the chart authoring experience.

To get things started, you can create a chart scaffold, like so:

$ helm create helm-nexus

Created helm-nexus/

This will create a number of required files and directories for you. Charts may also include optional files like a LICENSE file or a file. Check the docs for more info on what you can include.

As you author charts, Helm provides a linting feature that can help you find issues with your chart’s formatting or templates:

$ helm lint helm-nexus

No issues found

The Chart File Structure

A chart is organized as a collection of files inside of a directory. The directory name is the name of the chart (without versioning information). Thus, a chart describing helm-nexus would be stored in the helm-nexus/ directory.

Inside of this directory, Helm will expect a structure that matches this:

  Chart.yaml          # A YAML file containing information about the chart
  LICENSE             # OPTIONAL: A plain text file containing the license for the chart           # OPTIONAL: A human-readable README file
  requirements.yaml   # OPTIONAL: A YAML file listing dependencies for the chart
  values.yaml         # The default configuration values for this chart
  charts/             # OPTIONAL: A directory containing any charts upon which this chart depends.
  templates/          # OPTIONAL: A directory of templates that, when combined with values,
                      # will generate valid Kubernetes manifest files.
  templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes

Helm reserves use of the charts/ and templates/ directories, and of the listed file names. Other files will be left as they are.

  1. Charts.yaml

apiVersion: v1
description: A Helm chart for Sonatype Nexus
name: helm-nexus
version: 0.1.0
appVersion: 3.5.1
description: Sonatype Nexus
  - dependency
  - management
  - sonatype
  - repository
  - htpps://
  - name: arati

Make sure that the directory name and chart name are the same, otherwise helm lint will give an error.

2. Values.yaml

# Default values for sonatype-nexus.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
  repository: clearent/nexus
  tag: 3.5.1-02
  pullPolicy: IfNotPresent
  name: nexus
  type: LoadBalancer
  externalPort: 8081
  internalPort: 8081
    initialDelaySeconds: 30
    periodSeconds: 30
    failureThreshold: 6
    initialDelaySeconds: 30
    periodSeconds: 30
  enabled: false
  # Used to create an Ingress record.
  #  - chart-example.local
    # nginx
    # "true"
    # Secrets must be manually created in the namespace.
    # - secretName: chart-example-tls
    #   hosts:
    #     - chart-example.local
  enabled: true
  accessMode: ReadWriteOnce
  size: 8Gi
  mountPath: /nexus-data  # This is the local host machine's path 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
  storageClassName: generic
resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #  cpu: 100m
  #  memory: 128Mi
  # requests:
  #  cpu: 100m
  #  memory: 128Mi

3. templates/deployment.yaml

apiVersion: extensions/v1beta1
kind: Deployment
  name: {{ template "fullname" . }}
    app: {{ template "name" . }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
      app: {{ template "name" . }}
      release: {{ .Release.Name }}
  replicas: {{ .Values.replicaCount }}
        app: {{ template "name" . }}
        chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
        release: {{ .Release.Name }}
        heritage: {{ .Release.Service }}
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
            - containerPort: {{ .Values.service.internalPort }}
              path: /
              port: {{ .Values.service.internalPort }}
            initialDelaySeconds: {{ .Values.service.livenessProbe.initialDelaySeconds }}
            periodSeconds: {{ .Values.service.livenessProbe.periodSeconds }}
              path: /
              port: {{ .Values.service.internalPort }}
            initialDelaySeconds: {{ .Values.service.readinessProbe.initialDelaySeconds }}
            periodSeconds: {{ .Values.service.readinessProbe.periodSeconds }}
            failureThreshold: {{ .Values.service.readinessProbe.failureThreshold }}
            - mountPath: /nexus-data
              name: nexus-data-volume
      - name: nexus-data-volume
        {{- if .Values.persistence.enabled }}
          claimName: {{ .Values.persistence.existingClaim | default (include "fullname" .) }}
        {{- else }}
          emptyDir: {}
        {{- end -}}

mountPath is the location where the pv will be mounted inside the container.

If there is an existing pvc then that will be used otherwise a new one with the same name as the helm service will be created.

4. templates/pv-create.yaml

{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
kind: PersistentVolume
apiVersion: v1
  name: {{ template "fullname" . }}
    app: {{ template "name" . }}
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
    release: "{{ .Release.Name }}"
    heritage: "{{ .Release.Service }}"
    type: local
  storageClassName: {{ .Values.persistence.storageClassName | quote }}
    storage: {{ .Values.persistence.size | quote }}
    - ReadWriteOnce
    path: {{ .Values.persistence.mountPath | quote }}
{{- end }}

5. templates/pvc-create.yaml

{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
kind: PersistentVolumeClaim
apiVersion: v1
  name: {{ template "fullname" . }}
    app: {{ template "name" . }}
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
    release: "{{ .Release.Name }}"
    heritage: "{{ .Release.Service }}"
    type: local
  storageClassName: "generic"
    - {{ .Values.persistence.accessMode | quote }}
      storage: {{ .Values.persistence.size | quote }}
{{- end }}

6. templates/service.yaml

apiVersion: v1
kind: Service
  name: {{ template "fullname" . }}
    app: {{ template "name" . }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
  type: {{ .Values.service.type }}
    - port: {{ .Values.service.externalPort }}
      targetPort: {{ .Values.service.internalPort }}
      protocol: TCP
      name: {{ }}
    app: {{ template "name" . }}
    release: {{ .Release.Name }}

The code can be found here:
You can clone it. Then execute helm lint helm-nexus to check if there are any syntactical errors.
Then execute helm install helm-nexus/ to install a chart.

You will get an output as follows:
NAME: knobby-cheetah
LAST DEPLOYED: Tue Oct 24 05:22:16 2017
NAMESPACE: default

==> v1/PersistentVolumeClaim
knobby-cheetah-helm-nexus Bound knobby-cheetah-helm-nexus 8Gi RWO generic 1s

==> v1/Service
knobby-cheetah-helm-nexus 8081:31647/TCP 1s

==> v1beta1/Deployment
knobby-cheetah-helm-nexus 1 1 1 0 1s

==> v1/PersistentVolume
knobby-cheetah-helm-nexus 8Gi RWO Retain Bound default /knobby-cheetah-helm-nexus generic 1s

1. Get the application URL by running these commands:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running ‘kubectl get svc -w knobby-che etah-helm-nexus’
export SERVICE_IP=$(kubectl get svc –namespace default knobby-cheetah-helm-ne xus -o jsonpath='{.status.loadBalancer.ingress[0].ip}’)
echo http://$SERVICE_IP:8081

The helm release name is: knobby-cheetah
It will be available from the same instance on {cluster-ip}:8081
The cluster-ip can be retrieved with command: kubectl get svc
The resources and chart can be deleted with command: helm delete {chart-name}
The chart name can be obtained by helm ls

Git: Push a new repository

create a new repository on the command line

echo "# helm-nexus" >>
git init
git add
git commit -m "first commit"
git remote add origin{username}/helm-nexus.git
git push -u origin master

…or push an existing repository from the command line

git remote add origin{username}/helm-nexus.git
git push -u origin master

Chef: Local Cookbook Development



  1. Execute the command as follows:
    chef generate cookbook test_cookbook
    cd test_cookbook
    Take a look at some of the default files like, spec-helper.rb, default.rb file
  2. We will now create a generator that we will use to create cookbook with our customization:
    mkdir generator
    chef generate generator generator/lcd_origin
    cd generator/lcd_origin/templates/default
    vi insert text of your choice. Save and close.
  3. Edit kitchen.yml.erb change the contents to match the following, as we will be using docker driver and centos 7.2 image:
      name: docker
      privileged: true
      use_sudo: false
      name: chef_zero
      # You may wish to disable always updating cookbooks in CI or other testing environments.
      # For example:
      #   always_update_cookbooks: &amp;amp;amp;amp;amp;amp;lt;%%= !ENV['CI'] %&amp;amp;amp;amp;amp;amp;gt;
      always_update_cookbooks: true
      name: inspec
      - name: centos-7.2
          run_command: /usr/lib/systemd/systemd
      - name: default
          - recipe[&amp;amp;amp;amp;amp;amp;lt;%= cookbook_name %&amp;amp;amp;amp;amp;amp;gt;::default]
            - test/smoke/default
    &amp;amp;amp;amp;amp;amp;lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;lt;/span&amp;amp;amp;amp;amp;amp;gt;

    Make sure you are not adding any tabs as they are invalid in ymls.

  4. Edit ../../files/default/spec_helper.rb Add the following lines:
    RSpec.configure do |config|
      config.platform = 'centos'
      config.version = '7.2.1511'
    end&amp;amp;amp;amp;amp;amp;lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;lt;/span&amp;amp;amp;amp;amp;amp;gt;
  5. So to tell chef to use our generator when generating cookbooks:
    goto the lcd_origin directory
    mkdir ~/.chef
    vi ~/.chef/config.rb Add the contents as below:

    cookbook_path ['~/chef/cookbooks']
    local_mode true
    if File.basename($PROGRAM_NAME).eql?('chef') &amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp; ARGV[0].eql?('generate')
      chefdk.generator.license = "all_rights"
      chefdk.generator.copyright_holder = "Student Name"
      chefdk.generator_cookbook = "/root/cookbooks/lcd_origin" = ""
      chefdk.generator_cookbook = "~/generator/lcd_origin"
    &amp;amp;amp;amp;amp;amp;lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;lt;/span&amp;amp;amp;amp;amp;amp;gt;

    Create directory chef/cookbooks
    mkdir -p ~/chef/cookbooks
    And then generate a cookbook
    cd ~/chef
    chef generate cookbook cookbooks/lcd_web
    If you check the README vi cookbooks/lcd_web/ You will see the text we added previously.
    We can generate attributes by following command:
    chef generate attribute cookbooks/lcd_web default
    We can genrate recipe by:
    chef generate recipe cookbooks/lcd_web users

  6. These attributes can be checked here in lcd_origin/attributes/default.rb
    The recipe can be checked with lcd_origin/recipes/users.rb

Test Driven Development




    1. You can check the chefspec default file  spec/unit/recipes/default_spec.rb
    2. Now let’s run the default_spec
      chef exec rspec
      If you get any warning about platform and platform_version then change the following in your code:
      runner = ‘centos’, version: ‘7.2.1511’)
      For some of you the platform and the platform_version might be already added. It might be ubuntu and 16.04 change it to centos and 7.2.1511 resp.
      Then execute the rspec again. This will give an output similar to below:
      Finished in 0.48374 seconds (files took 1.83 seconds to load)
      2 examples, 0 failures
    3. Now change the default_spec.rb to match the following to check if httpd package is installed or not:
      # Cookbook:: lcd_web
      # Spec:: default
      # Copyright:: 2017, Student Name, All Rights Reserved.
      require 'spec_helper'
      describe 'lcd_web::default' do
        context 'CentOS' do
          let(:chef_run) do
            # for a complete list of available platforms and versions see:
            runner = 'centos', version: '7.2.1511')
          it 'converges successfully' do
            expect { chef_run }.to_not raise_error
          it 'installs httpd' do
            expect(chef_run).to install_package('httpd')

      Then run chef exec rspec You will get an error as below:



      1) lcd_web::default CentOS installs httpd
      Failure/Error: expect(chef_run).to install_package(‘httpd’)

      expected “package[httpd]” with action :install to be in Chef run. Other p ackage resources:

      # ./spec/unit/recipes/default_spec.rb:23:in `block (3 levels) in ‘

      Finished in 0.63225 seconds (files took 1.68 seconds to load)
      3 examples, 1 failure

      Failed examples:

      rspec ./spec/unit/recipes/default_spec.rb:22 # lcd_web::default CentOS installs httpd

      It failed because there was no httpd package present in the system because our cookbook doesn’t do so. Let’s add httpd installation to our default recipe.

      package ‘httpd’ do
      As the default action is install we do not need to specify anything.
      Now let’s execute the rspec: chef exec rspec
      Now the output will be as follows:

      Finished in 0.73318 seconds (files took 1.67 seconds to load)
      3 examples, 0 failures

    4. Add the following below installs httpd task:
          it 'enables the httpd service' do
            expect(chef_run).to enable_service('httpd')
          it 'starts the service' do
            expect(chef_run).to start_service('httpd')
      Add the following in default.rb recipe:
      service 'httpd' do
        action [:start, :enable]
      &amp;amp;amp;amp;amp;amp;lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;lt;/span&amp;amp;amp;amp;amp;amp;gt;

      Then run: chef exec rspec

    5. Now what if I add something in the default recipe that might break my cookbook:
      add the line in default.rb
      include_recipe ‘something’
      Then run rspec you will get error as below:
      Failure/Error: runner.converge(described_recipe)Chef::Exceptions::CookbookNotFound:
      Cookbook something not found. If you’re loading something from another cookbook, make sure you configure the dependency in your metadata
      # /tmp/chefspec20170918-4764-5svx8rfile_cache_path/cookbooks/lcd_web/recipes/default.rb:7:in `from_file’
      # ./spec/unit/recipes/default_spec.rb:15:in `block (3 levels) in ‘
      # ./spec/unit/recipes/default_spec.rb:31:in `block (3 levels) in ‘Finished in 0.81827 seconds (files took 1.71 seconds to load)
      5 examples, 4 failuresFailed examples:rspec ./spec/unit/recipes/default_spec.rb:18 # lcd_web::default CentOS converges successfully
      rspec ./spec/unit/recipes/default_spec.rb:22 # lcd_web::default CentOS installs httpd
      rspec ./spec/unit/recipes/default_spec.rb:26 # lcd_web::default CentOS enables the httpd service
      rspec ./spec/unit/recipes/default_spec.rb:30 # lcd_web::default CentOS starts the service

So you can see the test will fail if the cookbook dependency failes as well. You can remove the include_recipe line and re execute the rspec.

Test Kitchen Configuration


  1. Edit .kitchen.yml to match the following:
      name: docker
      privileged: true
      use_sudo: false
      name: chef_zero
      # You may wish to disable always updating cookbooks in CI or other testing environments.
      # For example:
      #   always_update_cookbooks: &amp;amp;amp;amp;amp;amp;lt;%= !ENV['CI'] %&amp;amp;amp;amp;amp;amp;gt;
      always_update_cookbooks: true
      name: inspec
      - name: centos-7.2
      - name: centos-6.8
      - name: dev
          run_command: /usr/sbin/init
          - recipe[la_java::default]
        attributes: { 'java': { 'jdk_version': '7' } }
            - 8080:80
        excludes: centos-6.8
      - name: prod
          run_command: /sbin/init
          - recipe[la_java::default]
        attributes: { 'java': { 'jdk_version': '6' } }
            - 8081:80
        includes: centos-6.8
    &amp;amp;amp;amp;amp;amp;lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;lt;/span&amp;amp;amp;amp;amp;amp;gt;

    Execute the command kitchen list
    If you get error as follows:
    >>>>>> ——Exception——-
    >>>>>> Class: Kitchen::ClientError
    >>>>>> Message: Could not load the ‘docker’ driver from the load path. Please en sure that your driver is installed as a gem or included in your Gemfile if using Bundler.
    >>>>>> ———————-
    >>>>>> Please see .kitchen/logs/kitchen.log for more details
    >>>>>> Also try running `kitchen diagnose –all` for configuration

    Then install the chef gem kitchen-docker with:  chef gem install kitchen-docker
    Then the kitchen list output will be as follows:
    [root@arati7111 lcd_web]# kitchen list
    Instance Driver Provisioner Verifier Transport Last Action Last Error
    dev-centos-72 Docker ChefZero Inspec Ssh
    prod-centos-68 Docker ChefZero Inspec Ssh
    Then run: kitchen converge
    Then kitchen verify
    Thus java 7 will be installed in centos 7 and java 6 on centos 6

  2. If you comment the includes and excludes statements from .kitchen.yml then we will have 4 test cases.
  3. You can download the java cookbook with
    knife cookbook site download
    and add it to the run_list

Using Test Kitchen


Execute the following commands

  1. mkdir test_kitchen
  2. cd test_kitchen
  3. kitchen init
    If you get the following error while executing kitchen init:Successfully installed kitchen-vagrant-1.2.1
    Fetching: mixlib-install-3.6.0.gem (100%)
    Successfully installed mixlib-install-3.6.0
    Fetching: ffi-1.9.18.gem (100%)
    Building native extensions. This could take a while…
    ERROR: Error installing kitchen-vagrant:
    ERROR: Failed to build gem native extension./usr/bin/ruby extconf.rb
    mkmf.rb can’t find header files for ruby at /usr/share/include/ruby.h

Gem files will remain installed in /home/user/.gem/ruby/gems/ffi-1.9.18 for inspection.
Results logged to /home/user/.gem/ruby/gems/ffi-1.9.18/ext/ffi_c/gem_make.out

Then execute the kitchen init command with sudo rights

  • If even then the issue is not resolved execute the following command:
    chef gem list kitchen-vagrant
    Then you will have output as follows:  kitchen-vagrant (1.2.1)
    chef gem uninstall kitchen-vagrant -v 1.2.1
    Then rerun kitchen init with sudo rights
  • chef generate cookbook my_cookbook
    You can see that the test/integration/default directory
    In the cookbook you can see the test/smoke/default directory
  • Execute kitchen list
    If you get an error as follows:
    >>>>>> ——Exception——-
    >>>>>> Class: Kitchen::UserError
    >>>>>> Message: Vagrant 1.1.0 or higher is not installed. Please download a package from
    >>>>>> ———————-
    That means you will have to install vagrant. you can use the following command:
    rpm -ivh again execute kitchen list  you will get an output as below:
    Instance Driver Provisioner Verifier Transport Last Action Last Error
    default-ubuntu-1404 Vagrant ChefSolo Busser Ssh
    default-centos-72 Vagrant ChefSolo Busser Ssh
  • Execute kitchen create
    You will get an error as follows: The provider ‘virtualbox’ that was requested to back the machine ‘default’
    You will need to install virtualbox first: Follow this tutorial for the same:
    If you are not able to install vbox then just change the driver name from vagrant to docker in .kitchen.yml

Then execute kitchen converge
Then execute kitchen setup
Then you can execute kitchen destroy to delete the created instances


Create a cookbook with chef generate cookbook lcd_web. Edit the following file test/smoke/default/default_test.rb. Add the following lines
[ ‘net-tools’, ‘httpd’ ].each do |pkg|
describe package(pkg) do
it { should be_installed }

Then execute kitchen verify it will fail the test as below:

System Package
∅ net-tools should be installed
expected that `System Package net-tools` is installed
System Package
∅ httpd should be installed
expected that `System Package httpd` is installed

Now lets add the chef code to install these packages
Add the following lines in recipes/default.rb
[ ‘net-tools’, ‘httpd’].each do |pkg|
package pkg do
action :install

Then execute kitchen converge
Then run kitchen verify
The output should be somthing as below:
System Package
✔ net-tools should be installed
System Package
✔ httpd should be installed

Static Code Analysis

foodcritic -l
FC001: Use strings in preference to symbols to access node attributes
FC002: Avoid string interpolation where not required
FC004: Use a service resource to start and stop services
FC005: Avoid repetition of resource declarations
FC006: Mode should be quoted or fully specified when setting file permissions
FC007: Ensure recipe dependencies are reflected in cookbook metadata
FC008: Generated cookbook metadata needs updating
FC009: Resource attribute not recognised
FC010: Invalid search syntax
FC011: Missing README in markdown format
FC012: Use Markdown for README rather than RDoc
FC013: Use file_cache_path rather than hard-coding tmp paths
FC014: Consider extracting long ruby_block to library
FC015: Consider converting definition to a Custom Resource
FC016: LWRP does not declare a default action
FC017: LWRP does not notify when updated
FC018: LWRP uses deprecated notification syntax

Now cd to lcd_web cookbook
execute: foodcritic .
output: Checking 2 files
FC008: Generated cookbook metadata needs updating: ./metadata.rb:3
FC064: Ensure issues_url is set in metadata: ./metadata.rb:1
FC065: Ensure source_url is set in metadata: ./metadata.rb:1
FC067: Ensure at least one platform supported in metadata: ./metadata.rb:1
FC078: Ensure cookbook shared under an OSI-approved open source license: ./metadata.rb:1

Lets check our metadata.rb file
For error FC067 add the line in metadata.rb: supports ‘centos’
The other errors are not of our concern so we will exclude them with:
foodcritic . -t ~FC008 -t ~FC064 -t ~FC065 -t ~FC078
There should be no errors.

Now we want to persist these exclusion so we will create .foodcritic file:
vi .foodcritic and add the following lines:




Save and close. Then execute foodcritic .

Lets have a look at rubocop. To install rubocop execute gem install rubocop

You can have a look at it’s help with command rubocop –help

If you run rubocop in lcd_we cookbook you might get output as follows:

init_test/lcd_web/recipes/default.rb:7:2: C: Space inside square brackets detected.
[ ‘net-tools’, ‘httpd’].each do |pkg|
bin/mixlib-install:11:11: C: Prefer single-quoted strings when you don’t need string interpolation or special symbols.
version = “>= 0”
bin/mixlib-install:15:32: C: Prefer single-quoted strings when you don’t need string interpolation or special symbols.
str = str.dup.force_encoding(“BINARY”) if str.respond_to? :force_encoding
bin/mixlib-install:17:15: C: Avoid the use of Perl-style backrefs.
version = $1

32 files inspected, 53 offenses detected

You might have errors like “line too long” etc. By default the line length specified in 80, Now let’s see if we can override that setting.
We will be needing todo file for that let’s generate it by the command:
rubocop –auto-gen-config
Then edit the file .rubocop.yml and add the line: inherit_from: .rubocop_todo.yml
Then execute rubocop you will see that all of our offenses have been masked.
Let’s have a look at the .rubocop_todo.yml file.
Now in the code you will see code blocks like follows:

# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
    - 'generator/lcd_origin/recipes/recipe.rb'

This denotes that there i an indentation issue with recipe.rb file.
rubocop has the feature to auto-correct small issues, you will need to comment code block one by one and then execute rubocop –auto-correct
Output will be something like: generator/lcd_origin/metadata.rb:5:1: C: [Corrected] 1 trailing blank lines detected.

So in this way we can correct some issues with rubocop. You can repeat the same for rest of the issues.
For the other issues which cannot be correct with rubo-cop you can add rules for the same in .rubocop.yml

We will change the LineLength rule. Add the following in .rubocop.yml file:
Max: 200
Then comment the LineLength block in .rubocop_todo.yml file.

Then execute rubocop You will see there are no offenses.


Edit file recipes/default.rb. Comment everything and add the following:

lazy_message = "Hello World"

file 'lazy_message' do
  path '/tmp/lazy.txt'
  content "#{lazy_message}"

execute 'yum-makecache' do
  command 'yum makecache'
  notifies :create, 'file[message]', :immediately
  action :nothing

package 'bind-utils' do
  action :install
  notifies :run, 'execute[yum-makecache]', :before

file 'message' do
  path '/tmp/message.txt'
  content lazy { "#{lazy_message}" }

lazy_message = "Goodbye World"

In this code firstly value of lazy_meesage will be set to Hello World. Then file /tmp/lazy.txt will get generated then makecache block will ge executed which in turn will call the file “message” block. But the file content will be wriiten at last due to lazy tag. Then package bind-utils will be installed but before that yum makecache will be called.
Then execute kitchen converge
kitchen login
lazy.txt will contain “Hello World” and message.txt will contain “Goodbye world”


Install ruby on centos with rvm


Whether you are preparing your VPS to try out a new application, or find yourself in need of a solid and isolated Ruby installation, getting your system ready-for-work (inline with CentOS design ideologies of stability, along with its incentives of minimalism) can get you feeling a little bit lost.

In this DigitalOcean article, we are focusing on the simplest and quickest rock-solid way to get the latest Ruby interpreter (version 2.1.0) installed on a VPS running CentOS 6.5 using the Ruby Version Manager – RVM.


1. Ruby Version Manager (RVM)

2. Understanding CentOS

3. Getting Started With Installation

  1. Preparing The System
  2. Downloading And Installing RVM
  3. Installing Ruby 2.1.0 On CentOS 6.5 Using RVM
  4. Setting Up Any Ruby Version As The Default Interpreter
  5. Working With Different Ruby Installations
  6. Working With RVM gemsets

Ruby Version Manager (RVM)

Ruby Version Manager, or RVM (and rvm as a command) for short, lets developers and system administrators quickly get started using Ruby and/or developing applications with a Ruby interpreter.

Not only does RVM support multiple versions of Ruby simultaneously, but also it comes with built-in tools to create and work with virtual environments called gemsets. With the help of RVM, it is possible to create any number of perfectly isolated – and self-contained – gemsets where dependencies, packages, and the default Ruby installation are crafted to match your needs and kept accordingly between different stages of deployment — guaranteed to work the same way regardless of where.

RVM gemsets

The power of RVM is its ability to create fully isolated Ruby containers which act like a completely different (and a new) environment. Any application running inside the environment can access (and function) only within its reach.

Understanding CentOS

CentOS operating system is derived from RHEL – Red Hat Enterprise Linux. The target users of these distributions are usually businesses, which require their systems to be running the most stable way for a long time.

The main incentives of CentOS, therefore, is the desire for stability, which is achieved by supplying tested, stable versions of applications.

All the default applications that are shipped with CentOS remain to be used by the system (and its supportive applications such as the package manager YUM) alone. It is neither recommended nor easy to try to work with them.

That is why we are going to prepare our CentOS 6.5 running droplet with necessary tools and continue with installing a Ruby interpreter targeted to run your applications.

Getting Started With Installation

Preparing The System

CentOS distributions are very lean. They do not come with many of the popular applications and tools that you are likely to need – and this is an intentional design choice as we have seen.

For our installations, however, we are going to need some libraries and tools (i.e. development [related] tools) that are not shipped by default. Therefore, we need to get them downloaded and installed before we continue.

For this purpose we will download various development tools using YUM software groups which consist of bunch of commonly used tools (applications) bundled together, ready to download.

As the first step, in order to get necessary development tools, run the following:

yum groupinstall -y development


yum groupinstall -y 'development tools'

Note: The former (shorter) version might not work on older distributions of CentOS.

Downloading And Installing RVM

After arming our system with tools needed for development (and deployment) of applications, such as a generic compiler, we are ready to get RVM downloaded installed.

RVM is designed from the ground up to make the whole process of getting Ruby and managing environments easy. It is no surprise that getting RVM itself is simplified as well.

In order to download and install RVM, run the following:

curl -L | bash -s stable

And to create a system environment using RVM shell script:

source /etc/profile.d/

Installing Ruby 2.1.0 On CentOS 6.5 Using RVM

All that is needed from now on to work with Ruby 2.1.0 (or any other version), after downloading RVM and configuring a system environment is the actual installation of Ruby from source – which is to be handled by RVM.

In order to install Ruby 2.1.0 from source using RVM, run the following:

rvm reload
To find available ruby versions execute rvm list known
It will display ruby versions
rvm install 2.1.0 

Setting Up Any Ruby Version As The Default Interpreter

If you are working with multiple applications which are already in production, it is a highly likely scenario that at some point you will need to use a different version of Ruby for a certain application.

However, for most situations, you will probably be using the latest version as the interpreter to run all others.

One of RVM’s excellent features is its ability to help you set a default Ruby version to be used generally and switch between them when necessary.

To check your current default interpreter, run the following:

ruby --version
# ruby command is linked to the selected version of Ruby Interpreter (i.e. 2.1.0)

To see all the installed Ruby versions, use the following command:

rvm list rubies

To set a Ruby version as the default, run the following:

# Usage: rvm use [version] --default
rvm use 2.1.0 --default