Skip to content

Instantly share code, notes, and snippets.

@tfitch
Created July 31, 2014 17:00
Show Gist options
  • Save tfitch/778c9557f39bb5958a36 to your computer and use it in GitHub Desktop.
Save tfitch/778c9557f39bb5958a36 to your computer and use it in GitHub Desktop.
converge nodes via API
#!/usr/bin/env ruby
# ASSUMES YOU'VE ALREADY USED single_org_setup.rb to create your nodes
# which will have saved the nodes key files to your machine and make API auth go
require 'fauxhai'
require 'mixlib/cli'
require 'mixlib/config'
require 'chef/rest'
require 'chef/node'
module ConvergeNodesSetup
attr_accessor :config
# This makes config functions available to be called directly
module_function :config=, :config
def self.determine_base_dir
current_dir = Dir.pwd
# Split current dir around the bin directory
# If we're in the bin directory, it will be the 1 index of the array
# and the base dir above it will be in the 0 index of the array
# Even if we're not, the entire dir path will be in the 0 index of the array
# and the rest of the array will be empty, based on how partition works
# Also make sure the dir string ends with a / to make life later easier
partition = current_dir.partition("bin")
if partition[0].end_with?("/")
partition[0]
else
partition[0] + "/"
end
end
def self.extract_org
# split on /, org will be last part of url
config[:chef_server_url].split('/')[-1]
end
class TermFile
TERM_FILE_KEYS = [:node_name, :client_key, :validation_client_name,
:validation_key, :chef_server_url]
def config
ConvergeNodesSetup.config
end
def create_erlang_term_file
puts "Creating chef.config" unless !config[:verbose]
config_dir = config[:base_dir] + "config"
Dir.mkdir(config_dir) unless Dir.exists?(config_dir)
# Assumes we're on a unix system, b/c of mode + perm bits
terms = term_file_hash
File.open("#{config_dir}/chef.config", "w", 0644) do |file|
terms.each do |key, value|
file.write("{#{key}, \"#{value}\"}.\n")
end
file.write("{org_name, \"#{ConvergeNodesSetup.extract_org}\"}.\n")
end
end
def term_file_hash
term_hash = {}
TERM_FILE_KEYS.each do |key|
term_hash[key] = ConvergeNodesSetup.config[key]
end
term_hash
end
end # End TermFile class
class ServerSetup
def config
ConvergeNodesSetup.config
end
def org
@org ||= ConvergeNodesSetup.extract_org
end
def node_json(name)
{
:name => name,
:admin => false
}
end
def clients_endpoint
"clients"
end
def nodes_endpoint
"nodes"
end
def request_body1
'{
"overrides": {},
"name": "latte",
"chef_type": "node",
"json_class": "Chef::Node",
"attributes": {
"hardware_type": "laptop"
}
}'
end
def request_body2
'{
"overrides": {},
"name": "latte",
"chef_type": "node",
"json_class": "Chef::Node",
"attributes": {
"hardware_type": "laptop"
},
"run_list": [],
"defaults": {}
}'
end
def keys_dir
config[:base_dir] + "keys"
end
def config_dir
config[:base_dir] + "config"
end
def rest_client
Chef::REST.new(config[:chef_server_url], config[:node_name],
config[:client_key])
end
def converge_node(node_number)
# org is in the name to namespace keys and configs that all go into same dir
node_name = "testing_node_#{org}_#{node_number}"
puts "Converging node #{nodes_endpoint}/#{node_name}" unless !config[:verbose]
begin
# creating a node consists of creating the client for that node, then the node
node_info = node_json(node_name)
node = Chef::Node.new
node.name(node_name)
# TODO TFITCH: attach Fauxhai attributes here. Then post/save the node
# 400 rest_client.put("#{nodes_endpoint}/#{node_name}", node_info)
# rest_client.put_rest("#{nodes_endpoint}/#{node_name}", request_body1)
# 500 rest_client.put("#{nodes_endpoint}/#{node_name}", Fauxhai.mock(platform: 'ubuntu', version: '12.04'))
# rest_client.put("#{nodes_endpoint}/#{node_name}", request_body2)
rest_client.put("nodes/testing_node_loadtest_0", '{"name": "testing_node_loadtest_0"}')
rescue Net::HTTPServerException => e
if e.message == '409 "Conflict"'
puts "Received 409 Conflict creating node #{node_name}" unless !config[:verbose]
puts "Assuming node already exists and key/config are in place" unless !config[:verbose]
else
# Don't know the cause of the error, so bail
raise
end
end
end
def converge_nodes
node_count = config[:nodes].to_i
node_count.times do |count|
converge_node(count)
end
end
end # End ServerSetup class
end # End ConvergeNodesSetup Module
class ConvergeNodesCli
include Mixlib::CLI
option :help,
:short => "-h",
:long => "--help",
:boolean => true,
:description => "Print usage, which is this message.",
:show_options => true,
:exit => 0
option :verbose,
:short => "-v",
:long => "--verbose",
:boolean => true,
:description => "Verbose mode, give output when the script performs actions."
option :knife_rb,
:short => "-k knife.rb",
:long => "--knife knife.rb",
:required => true,
:description => "The location of knife.rb config to use."
option :nodes,
:short => "-n integer",
:long => "--nodes integer",
:default => 100,
:description => "The number of nodes to create for the test run. Default is 100."
end
class ConvergeNodesConfig
extend Mixlib::Config
end
args = ConvergeNodesCli.new
args.parse_options(ARGV)
ConvergeNodesConfig.from_file(args.config[:knife_rb])
config = args.config.merge!(ConvergeNodesConfig.configuration)
config[:base_dir] = ConvergeNodesSetup.determine_base_dir
puts "Using a base dir of #{config[:base_dir]}" unless !config[:verbose]
ConvergeNodesSetup.config = config
termfile = ConvergeNodesSetup::TermFile.new
termfile.create_erlang_term_file
setup = ConvergeNodesSetup::ServerSetup.new
setup.converge_nodes
puts "Finished" unless !config[:verbose]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment