Skip to content

Instantly share code, notes, and snippets.

@gmr
Last active April 12, 2020 22:06
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gmr/5339326 to your computer and use it in GitHub Desktop.
Save gmr/5339326 to your computer and use it in GitHub Desktop.
Chef + Cobbler Integration files

Note: These work for us with Cobbler 2.2.3 and Chef 11.4.0 on CentOS

Quick Install

These are our install steps on CentOS 6:

mkdir -p ~/.chef/plugins/knife/
curl -o ~/.chef/plugins/knife/set_environment.rb https://gist.github.com/gmr/5339326/raw/5bd498d25bc2f4d17f029cdc4a34ed38e461fec2/set_environment.rb
curl -o /usr/lib/python2.6/site-packages/cobbler/modules/install_pre_chef.py https://gist.github.com/gmr/5339326/raw/0b248a8b40e5bac5673bd7df7cfd60185af778bc/install_pre_chef.py
curl -o /usr/lib/python2.6/site-packages/cobbler/modules/delete_post_chef.py  https://gist.github.com/gmr/5339326/raw/ae71362ae721c0391f0be2f4b2166f3806e90a91/delete_post_chef.py
service cobblerd restart

install_pre_chef.py

Pre-install trigger for chef to add a node to chef so that it is available when chef-client starts int the post install process. Place install_pre_chef.py in your Python site-packages/modules/cobbler/modules directory... really :-(

Using the knife set_environment plugin at https://gist.github.com/nstielau/961827/, it sets the environment in chef to match the status. Run the following two commands to enable it:

mkdir -p ~cobbler/.chef/plugins/knife/
curl -o ~cobbler/.chef/plugins/knife/set_environment.rb https://gist.github.com/gmr/5339326/raw/5bd498d25bc2f4d17f029cdc4a34ed38e461fec2/set_environment.rb

It will take the status field in Cobbler (aka "development" or "production") and set the Chef environment to the title case for the status: "Development" or "Production" etc.

Aside from this trigger, make sure you have cobbler install chef, copy out the init.d and sysconfig from chef's resources (https://github.com/opscode/chef/tree/master/distro/redhat/etc) in our case, and make it a service that runs on boot.

delete_post_chef.py

This is a modified script from the install_pre_chef.py and will remove nodes from chef when they are removed from cobbler. This too goes into your Python site-packages/modules/cobbler/modules directory

#!/usr/bin/env python
"""
(C) 2010 Pragmatic Source
Farzad FARID <ffarid@pragmatic-source.com>
delete_post_chef.py: Delete the profile from Chef on delete from Cobbler
Check https://fedorahosted.org/cobbler/wiki/CobblerTriggers for
documentation on Cobbler's triggers and API.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
"""
from cobbler import utils
import sys
import os
# Configuration settings
# ----------------------
# * home:
# The HOME environment variable is undefined in the cobblerd process, we
# have to set it here for 'knife' to be able to find its configuration
# file, '~/.chef/knife.rb'.
# * knife_config_path:
# If the 'knife.rb' configuration file is in an unusual place, define the
# full path here.
# * chef_roles:
# List of compulsory Chef Roles to prepend to the management classes extracted
# from the Cobbler configuration.
# Only the 'home' setting is compulsory.
CHEF_CONFIG = {
#'home': '/root',
'knife_config_path': '/root/.chef/knife.rb',
'chef_roles': [ 'Base' ]
}
def register():
# this pure python trigger acts as if it were a legacy shell-trigger, but is much faster.
# the return of this method indicates the trigger type
return "/var/lib/cobbler/triggers/delete/profile/post/*"
def run(api, args, logger):
objtype = args[0] # "system" or "profile"
name = args[1] # name of system or profile
boot_ip = args[2] # ip or "?"
# Handle only systems, not profiles
if objtype != "system":
return 0
# Lookup the node in Cobbler's database
node = api.find_system(name)
# Find its fully qualified hostname and the management classes, to which we
# add "Linux" unconditionnaly. We directly map cobbler's Management Classes to
# Chef Roles' names.
hostname = node.hostname
roles = node.mgmt_classes
roles = CHEF_CONFIG.get('chef_roles', []) + roles
logger.info("Removing %s (%s) in Chef" % (name, hostname))
# Note: "knife node delete" does not destroy the node's RSA key. We don't
# need to delete it as it will be recreated by chef-client on the first
# run.
if CHEF_CONFIG.has_key('home'):
os.environ['HOME'] = CHEF_CONFIG['home']
knife_opts = ''
if CHEF_CONFIG.has_key('knife_config_path'):
knife_opts = '--config ' + CHEF_CONFIG['knife_config_path']
# Delete the node
# Ignore stderr too, as usually this command should fail.
rc = utils.subprocess_call(logger,
"knife node delete %(hostname)s --yes %(knife_opts)s >> /var/log/cobbler/knife.log" % { 'hostname': hostname, 'knife_opts': knife_opts },
shell=True)
if rc != 0:
logger.warning("Failed to delete node %s in Chef" % hostname)
#!/usr/bin/env python
"""
(C) 2010 Pragmatic Source
Farzad FARID <ffarid@pragmatic-source.com>
register_chef.py: Register the server being installed on the Chef server
We assume that the 'knife' is installed locally on the Cobbler server.
Check https://fedorahosted.org/cobbler/wiki/CobblerTriggers for
documentation on Cobbler's triggers and API.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
"""
from cobbler import utils
import sys
import os
# Configuration settings
# ----------------------
# * home:
# The HOME environment variable is undefined in the cobblerd process, we
# have to set it here for 'knife' to be able to find its configuration
# file, '~/.chef/knife.rb'.
# * knife_config_path:
# If the 'knife.rb' configuration file is in an unusual place, define the
# full path here.
# * chef_roles:
# List of compulsory Chef Roles to prepend to the management classes extracted
# from the Cobbler configuration.
# Only the 'home' setting is compulsory.
CHEF_CONFIG = {
#'home': '/root',
'knife_config_path': '/root/.chef/knife.rb',
'chef_roles': [ 'Base' ]
}
def register():
# this pure python trigger acts as if it were a legacy shell-trigger, but is much faster.
# the return of this method indicates the trigger type
return "/var/lib/cobbler/triggers/install/pre/*"
def run(api, args, logger):
objtype = args[0] # "system" or "profile"
name = args[1] # name of system or profile
boot_ip = args[2] # ip or "?"
# Handle only systems, not profiles
if objtype != "system":
return 0
# Lookup the node in Cobbler's database
node = api.find_system(name)
# Find its fully qualified hostname and the management classes, to which we
# add "Linux" unconditionnaly. We directly map cobbler's Management Classes to
# Chef Roles' names.
hostname = node.hostname
roles = node.mgmt_classes
roles = CHEF_CONFIG.get('chef_roles', []) + roles
logger.info("Registering %s (%s) in Chef" % (name, hostname))
# Create the node in Chef, deleting it first if necessary, and
# add roles one by one.
# Note: "knife node delete" does not destroy the node's RSA key. We don't
# need to delete it as it will be recreated by chef-client on the first
# run.
if CHEF_CONFIG.has_key('home'):
os.environ['HOME'] = CHEF_CONFIG['home']
knife_opts = ''
if CHEF_CONFIG.has_key('knife_config_path'):
knife_opts = '--config ' + CHEF_CONFIG['knife_config_path']
# Delete the node
# Ignore stderr too, as usually this command should fail.
rc = utils.subprocess_call(logger,
"knife node delete %(hostname)s --yes %(knife_opts)s >> /var/log/cobbler/knife.log" % { 'hostname': hostname, 'knife_opts': knife_opts },
shell=True)
if rc != 0:
logger.warning("Failed to delete node %s in Chef" % hostname)
# Remove the client
rc = utils.subprocess_call(logger,
"knife client delete %(hostname)s --yes %(knife_opts)s >> /var/log/cobbler/knife.log" % { 'hostname': hostname, 'knife_opts': knife_opts },
shell=True)
if rc != 0:
logger.warning("Failed to delete client %s in Chef" % hostname)
# Add the node
logger.info("Setting environment to %s" % node.status.title())
rc = utils.subprocess_call(logger, "knife node create %(hostname)s --disable-editing %(knife_opts)s >> /var/log/cobbler/knife.log" %
{ 'hostname': hostname, 'knife_opts': knife_opts},
shell=True)
if rc != 0:
logger.error("Failed to create node %s in Chef" % hostname)
# Set the environment using the plugin from the README
logger.info("Setting environment to %s" % node.status.title())
rc = utils.subprocess_call(logger, "knife node set_environment %(hostname)s environment %(environment)s %(knife_opts)s >> /var/log/cobbler/knife.log" %
{ 'hostname': hostname, 'knife_opts': knife_opts, 'environment': node.status.title()},
shell=True)
if rc != 0:
logger.error("Failed to set environment for node %s in Chef" % hostname)
# Add roles to the node
for role in roles:
rc = utils.subprocess_call(logger,
"knife node run_list add %(hostname)s \"role[%(role)s]\" %(knife_opts)s >> /var/log/cobbler/knife.log" % { 'hostname': hostname, 'knife_opts': knife_opts, 'role': role },
shell=True)
if rc != 0:
logger.error("Failed to add role %(role)s to node %(hostname)s in Chef" % { 'hostname': hostname, 'role': role })
return 0
## Knife plugin to set node environment
# See http://wiki.opscode.com/display/chef/Environments
#
## Install
# Place in .chef/plugins/knife/set_environment.rb
#
## Usage
# Nick-Stielaus-MacBook-Pro:chef-repo nstielau$ knife node set_environment mynode.net my_env
# Looking for mynode.net
# Setting environment to my_env
# 1 items found
#
# Node Name: mynode.net
# Environment: my_env
# FQDN: mynode.net
# IP: 66.111.39.46
# Run List: role[base], role[web_app]
# Roles: base, web_app
# Recipes timezone::default, hosts::default, sudo::default, web_app::default
# Platform: ubuntu 10.04
require 'chef/knife'
module SomeNamespace
class NodeSetEnvironment < Chef::Knife
deps do
require 'chef/search/query'
require 'chef/knife/search'
end
banner "knife node set_environment NODE ENVIRONMENT"
def run
unless @node_name = name_args[1]
ui.error "You need to specify a node"
exit 1
end
unless @environment = name_args[2]
ui.error "You need to specify an environment"
exit 1
end
puts "Looking for #{@node_name}"
searcher = Chef::Search::Query.new
result = searcher.search(:node, "name:#{@node_name}")
knife_search = Chef::Knife::Search.new
node = result.first.first
if node.nil?
puts "Could not find a node named #{@node_name}"
exit 1
end
puts "Setting environment to #{@environment}"
node.chef_environment(@environment)
node.save
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment