chake-0.92/ 0000755 0000041 0000041 00000000000 14756133274 012563 5 ustar www-data www-data chake-0.92/.manifest 0000644 0000041 0000041 00000004224 14756133274 014374 0 ustar www-data www-data .ackrc
.gitignore
.gitlab-ci.yml
.manifest
.rubocop.yml
.rubocop_todo.yml
ChangeLog.md
Gemfile
LICENSE.txt
README.chef.md
README.itamae-remote.md
README.itamae.md
README.md
README.shell.md
Rakefile
activate.sh
bin/chake
chake.gemspec
chake.spec.erb
examples/test/.ssh_config
examples/test/Rakefile
examples/test/Vagrantfile
examples/test/config.rb
examples/test/cookbooks/basics/recipes/default.rb
examples/test/cookbooks/example/files/default/test
examples/test/cookbooks/example/files/host-lemur/test.asc
examples/test/cookbooks/example/recipes/default.rb
lib/chake.rb
lib/chake/bootstrap/00_set_hostname.sh
lib/chake/bootstrap/chef/01_installed.sh
lib/chake/bootstrap/chef/02_debian.sh
lib/chake/bootstrap/chef/99_unsupported.sh
lib/chake/bootstrap/itamae-remote/01_installed.sh
lib/chake/bootstrap/itamae-remote/02_debian.sh
lib/chake/bootstrap/itamae-remote/99_unsupported.sh
lib/chake/config.rb
lib/chake/config_manager.rb
lib/chake/config_manager/chef.rb
lib/chake/config_manager/itamae.rb
lib/chake/config_manager/itamae_remote.rb
lib/chake/config_manager/shell.rb
lib/chake/config_manager/skel/chef/Rakefile
lib/chake/config_manager/skel/chef/config.rb
lib/chake/config_manager/skel/chef/cookbooks/basics/recipes/default.rb
lib/chake/config_manager/skel/chef/nodes.yaml
lib/chake/config_manager/skel/itamae/Rakefile
lib/chake/config_manager/skel/itamae/cookbooks/basics/default.rb
lib/chake/config_manager/skel/itamae/nodes.yaml
lib/chake/config_manager/skel/itamae/roles/basic.rb
lib/chake/config_manager/skel/shell/Rakefile
lib/chake/config_manager/skel/shell/nodes.yaml
lib/chake/connection.rb
lib/chake/connection/local.rb
lib/chake/connection/ssh.rb
lib/chake/node.rb
lib/chake/readline.rb
lib/chake/tmpdir.rb
lib/chake/version.rb
lib/chake/wipe.rb
lib/chake/yaml.rb
man/.gitignore
man/Rakefile
man/readme2man.sed
spec/chake/backend/local_spec.rb
spec/chake/backend/ssh_spec.rb
spec/chake/backend_spec.rb
spec/chake/config_manager/chef_spec.rb
spec/chake/config_manager/itamae_remote_spec.rb
spec/chake/config_manager/itamae_spec.rb
spec/chake/config_manager/shell_spec.rb
spec/chake/config_manager_spec.rb
spec/chake/node_spec.rb
spec/integration_tests_spec.rb
spec/spec_helper.rb
chake-0.92/bin/ 0000755 0000041 0000041 00000000000 14756133274 013333 5 ustar www-data www-data chake-0.92/bin/chake 0000755 0000041 0000041 00000001415 14756133274 014335 0 ustar www-data www-data #!/usr/bin/env ruby
require 'rake'
rakefiles = %w[rakefile Rakefile rakefile.rb Rakefile.rb]
if rakefiles.none? { |f| File.exist?(f) } && !ARGV.include?('-f') && !ARGV.include?('--rakefile')
require 'tmpdir'
require 'fileutils'
# syntethize a Rakefile
tmpdir = Dir.mktmpdir
rakefile = File.join(tmpdir, 'Rakefile')
File.open(rakefile, 'w') do |f|
f.puts 'require "chake"'
end
ARGV.unshift << '--rakefile' << rakefile
# cleanup after finishing
at_exit do
FileUtils.rm_rf tmpdir
end
end
class Rake::Application
alias orig_thread_pool thread_pool
def thread_pool # :nodoc:
if Chake.respond_to?(:nodes)
@thread_pool ||= Rake::ThreadPool.new(Chake.nodes.size + 1)
else
orig_thread_pool
end
end
end
Rake.application.run
chake-0.92/.ackrc 0000644 0000041 0000041 00000000047 14756133274 013650 0 ustar www-data www-data --ignore-dir=coverage
--ignore-dir=pkg
chake-0.92/.gitlab-ci.yml 0000644 0000041 0000041 00000000637 14756133274 015225 0 ustar www-data www-data image: debian:testing
.install: &install
- apt-get update && apt-get install -qy ruby asciidoctor ruby-bundler ruby-rspec rubocop ruby-simplecov codespell ronn
tests:
before_script: *install
script:
- rake test
manpages:
before_script: *install
script:
- rake man
style:
before_script: *install
script:
- rake style
codespell:
before_script: *install
script:
- rake codespell
chake-0.92/.gitignore 0000644 0000041 0000041 00000000330 14756133274 014547 0 ustar www-data www-data *.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
/examples/test/nodes.yaml
/examples/test/.tmp
.*.html
*.1
*.7
chake-0.92/README.chef.md 0000644 0000041 0000041 00000003414 14756133274 014750 0 ustar www-data www-data chake-chef(7) -- configure chake nodes with chef-solo
=====================================================
## Description
This configuration manager will allow you to manage nodes by running
**chef-solo(1)** on each remote node.
When `chake init` runs, the following chef-specific files will be created:
A brief explanation of the created files that are specific to **chef**:
* `config.rb`: contains the chef-solo configuration. You can modify it, but
usually you won't need to.
* `config/roles`: directory is where you can put your role definitions.
* `cookbooks`: directory where you will store your cookbooks. A sample cookbook
called "basics" is created, but feel free to remove it and add actual
cookbooks.
## Configuration
Nodes can be configured to be managed with chef by having a `run_list` key in
their configuration:
```yaml
host1.mycompany.com:
run_list:
- role[server]
- recipe[service1]
service1:
option1: "here we go"
```
Any extra configuration under `host1.mycompany.com` will be saved to a JSON file
and given to the chef-solo --node-json option in the command line. For example,
the above configuration will produce a JSON file that looks like this:
```json
{
"run_list": [
"role[server]",
"recipe[service1]"
]
,
"service1": {
"option1": "here we go"
}
}
```
Inside Chef recipes, you can access those values by using the `node` object.
For example:
```ruby
template "/etc/service1.conf.d/option1.conf" do
variables option1: node["option1"]
end
```
## Bootstrapping
The bootstrap process for _chef_ involves getting chef-solo installed. The
node hostname will also be set based on the hostname informed in the
configuration file.
## See also
* **chake(1)**
*
*
chake-0.92/README.itamae-remote.md 0000644 0000041 0000041 00000003206 14756133274 016573 0 ustar www-data www-data chake-itamae-remote(7) -- configure chake nodes with a remote itamae
====================================================================
## Description
This configuration manager will run **itamae(1)** on each remote node. This is
different from the _itamae_ configuration manager, which runs itamae on your
workstation (the host running chake). _itamae-remote_ will run itamae
individually on each node, which is one order of magnitude faster. This
requires itamae to be installed on each node, and that will be taken care of
automatically by the bootstrapping process.
## Configuration
The _itamae-remote_ configuration manager requires one key called
`itamae-remote`, and the value must be a list of strings representing the list
of recipes to apply to the node when converging.
```yaml
host1.mycompany.com:
itamae-remote:
- cookbooks/basic/default.rb
- roles/server.rb
service1:
option1: "here we go"
```
Any extra configuration under `host1.mycompany.com` will be saved to a JSON file
and given to the itamae --node-json option in the command line. For example,
the above configuration will produce a JSON file that looks like this:
```json
{
"itamae": [
"cookbooks/basic.rb",
"roles/server.rb"
]
,
"service1": {
"option1": "here we go"
}
}
```
Inside itamae recipes, you can access those values by using the `node` object.
For example:
```ruby
template "/etc/service1.conf.d/option1.conf" do
variables option1: node["option1"]
end
```
## Bootstrapping
The bootstrapping process will make sure itamae is installed. The node hostname
will be set according to your chake configuration.
## See also
* **chake(1)**
chake-0.92/lib/ 0000755 0000041 0000041 00000000000 14756133274 013331 5 ustar www-data www-data chake-0.92/lib/chake.rb 0000644 0000041 0000041 00000020762 14756133274 014740 0 ustar www-data www-data require 'yaml'
require 'json'
require 'tmpdir'
require 'chake/config'
require 'chake/version'
require 'chake/readline'
require 'chake/wipe'
desc 'Initializes current directory with sample structure'
task init: 'init:itamae'
Chake::ConfigManager.all.map do |cfgmgr|
desc "Initializes current directory for #{cfgmgr.short_name}"
task "init:#{cfgmgr.short_name}" do
cfgmgr.init
end
end
desc 'list nodes'
task :nodes do
fields = %i[hostname connection config_manager]
lengths = fields.map do |f|
[f.length, Chake.nodes.map { |n| n.send(f).to_s.length }.max].max
end
columns = lengths.map { |l| "%-#{l}s" }.join(' ')
puts(columns % fields)
puts(columns % lengths.map { |l| '-' * l })
Chake.nodes.each do |node|
puts(columns % fields.map { |f| node.send(f) })
end
end
def encrypted_for(node)
encrypted_files = Array(node.data['encrypted'])
if encrypted_files.empty?
encrypted_files = Dir.glob("**/files/{default,host-#{node.hostname}}/*.{asc,gpg}") + Dir.glob('**/files/*.{asc,gpg}')
end
encrypted_files.each_with_object({}) do |key, hash|
hash[key] = key.sub(/\.(asc|gpg)$/, '')
end
end
desc 'list encrypted files per node'
task :encrypted do
Chake.nodes.each do |node|
puts "#{node.hostname}: #{Array(encrypted_for(node).keys).join(', ')}"
end
end
def maybe_decrypt(node)
if node.needs_upload?
return yield
end
files = encrypted_for(node)
files.each do |encrypted, target|
sh "gpg --use-agent --quiet --decrypt --output #{target} #{encrypted}"
end
begin
yield
ensure
files.each do |_, target|
Chake::Wipe.instance.wipe(target)
end
end
end
def if_files_changed(node, group_name, files)
return if files.empty?
hash_io = IO.popen(%w[xargs sha1sum], 'w+')
hash_io.puts(File.join(Chake.tmpdir, "#{node}.bootstrap"))
files.sort.each { |f| hash_io.puts(f) }
hash_io.close_write
current_hash = hash_io.read
hash_file = File.join(Chake.tmpdir, "#{node}.#{group_name}.sha1sum")
hash_on_disk = nil
hash_on_disk = File.read(hash_file) if File.exist?(hash_file)
yield if current_hash != hash_on_disk
FileUtils.mkdir_p(File.dirname(hash_file))
File.write(hash_file, current_hash)
end
def write_json_file(file, data)
File.chmod(0o600, file) if File.exist?(file)
File.open(file, 'w', 0o600) do |f|
f.write(JSON.pretty_generate(data))
f.write("\n")
end
end
desc 'Executed before bootstrapping'
task bootstrap_common: :connect_common
desc 'Executed before uploading'
task upload_common: :connect_common
desc 'Executed before uploading'
task converge_common: :connect_common
desc 'Executed before connecting to any host'
task :connect_common
Chake.nodes.each do |node|
node.silent = Rake.application.options.silent
hostname = node.hostname
bootstrap_script = File.join(Chake.tmpdir, "#{hostname}.bootstrap")
bootstrap_steps = node.bootstrap_steps
bootstrap_code = (["#!/bin/sh\n", "set -eu\n"] + bootstrap_steps.map { |f| File.read(f) }).join
desc "bootstrap #{hostname}"
task "bootstrap:#{hostname}" => :bootstrap_common do
mkdir_p Chake.tmpdir unless File.directory?(Chake.tmpdir)
if !File.exist?(bootstrap_script) || File.read(bootstrap_script) != bootstrap_code
# create bootstrap script
File.write(bootstrap_script, bootstrap_code)
chmod 0o755, bootstrap_script
# copy bootstrap script over
scp = node.scp
target = "/tmp/.chake-bootstrap.#{Etc.getpwuid.name}"
sh *scp, bootstrap_script, node.scp_dest + target
# run bootstrap script
node.run_as_root("#{target} #{hostname}")
end
# overwrite config with current contents
config = File.join(Chake.tmpdir, "#{hostname}.json")
write_json_file(config, node.data)
end
desc "upload data to #{hostname}"
task "upload:#{hostname}" => ["bootstrap:#{hostname}", :upload_common] do
next unless node.needs_upload?
encrypted = encrypted_for(node)
rsync_excludes = (encrypted.values + encrypted.keys).map { |f| ['--exclude', f] }.flatten
rsync_excludes << '--exclude' << '.git/'
rsync_excludes << '--exclude' << 'cache/'
rsync_excludes << '--exclude' << 'nodes/'
rsync_excludes << '--exclude' << 'local-mode-cache/'
rsync = node.rsync + ['-ap'] + ENV.fetch('CHAKE_RSYNC_OPTIONS', '').split
rsync_logging = (Rake.application.options.trace && '--verbose') || '--quiet'
hash_files = Dir.glob(File.join(Chake.tmpdir, '*.sha1sum'))
files = Dir.glob('**/*').reject { |f| File.directory?(f) } - encrypted.keys - encrypted.values - hash_files
if_files_changed(hostname, 'plain', files) do
sh *rsync, '--delete', rsync_logging, *rsync_excludes, './', node.rsync_dest
end
if_files_changed(hostname, 'enc', encrypted.keys) do
Dir.mktmpdir do |tmpdir|
encrypted.each do |encrypted_file, target_file|
target = File.join(tmpdir, target_file)
mkdir_p(File.dirname(target))
rm_f target
File.open(target, 'w', 0o400) do |output|
IO.popen(['gpg', '--quiet', '--batch', '--use-agent', '--decrypt', encrypted_file]) do |data|
output.write(data.read)
end
end
puts "#{target} (decrypted)"
end
sh *rsync, rsync_logging, "#{tmpdir}/", node.rsync_dest
end
end
end
converge_dependencies = [:converge_common, "bootstrap:#{hostname}", "upload:#{hostname}"]
desc "converge #{hostname}"
task "converge:#{hostname}" => converge_dependencies do
maybe_decrypt(node) do
node.converge
end
end
desc 'apply on #{hostname}'
task "apply:#{hostname}", [:recipe] => [:recipe_input, :connect_common, "connect:#{hostname}"] do |_task, _args|
maybe_decrypt(node) do
node.apply($recipe_to_apply)
end
end
task "apply:#{hostname}" => converge_dependencies
desc "run a command on #{hostname}"
task "run:#{hostname}", [:command] => [:run_input, :connect_common, "connect:#{hostname}"] do
node.run($cmd_to_run)
end
desc "Logs in to a shell on #{hostname}"
task "login:#{hostname}" => [:connect_common, "connect:#{hostname}"] do
node.run_shell
end
desc 'checks connectivity and setup on all nodes'
task "check:#{hostname}" => [:connect_common, "connect:#{hostname}"] do
node.run('sudo echo OK')
end
# needs to be overridden in user projects
task "connect:#{hostname}"
end
task :run_input, :command do |_task, args|
$cmd_to_run = args[:command]
unless $cmd_to_run
puts '# Enter command to run (use arrow keys for history):'
$cmd_to_run = Chake::Readline::Commands.readline
end
if !$cmd_to_run || $cmd_to_run.strip == ''
puts
puts 'I: no command provided, operation aborted.'
exit(1)
end
end
task :recipe_input, :recipe do |_task, args|
$recipe_to_apply = args[:recipe]
unless $recipe_to_apply
recipes = Dir['**/*/recipes/*.rb'].map do |f|
f =~ %r{(.*/)?(.*)/recipes/(.*).rb$}
cookbook = Regexp.last_match(2)
recipe = Regexp.last_match(3)
recipe = nil if recipe == 'default'
[cookbook, recipe].compact.join('::')
end.sort
puts 'Available recipes:'
IO.popen('column', 'w') do |column|
column.puts(recipes)
end
$recipe_to_apply = Chake::Readline::Recipes.readline
if !$recipe_to_apply || $recipe_to_apply.empty?
puts
puts 'I: no recipe provided, operation aborted.'
exit(1)
end
unless recipes.include?($recipe_to_apply)
abort "E: no such recipe: #{$recipe_to_apply}"
end
end
end
desc 'upload to all nodes'
multitask upload: Chake.nodes.map { |node| "upload:#{node.hostname}" }
desc 'bootstrap all nodes'
multitask bootstrap: Chake.nodes.map { |node| "bootstrap:#{node.hostname}" }
desc 'converge all nodes (default)'
multitask 'converge' => Chake.nodes.map { |node| "converge:#{node.hostname}" }
desc 'Apply on all nodes'
multitask 'apply', [:recipe] => Chake.nodes.map { |node| "apply:#{node.hostname}" }
desc 'run on all nodes'
multitask :run, [:command] => Chake.nodes.map { |node| "run:#{node.hostname}" }
task default: :converge
desc 'checks connectivity and setup on all nodes'
multitask check: (Chake.nodes.map { |node| "check:#{node.hostname}" }) do
puts '✓ all hosts OK'
puts ' - ssh connection works'
puts ' - password-less sudo works'
end
desc 'runs a Ruby console in the chake environment'
task :console do
require 'irb'
IRB.setup('__FILE__', argv: [])
workspace = IRB::WorkSpace.new(self)
puts 'chake - interactive console'
puts '---------------------------'
puts 'all node data in available in Chake.nodes'
puts
IRB::Irb.new(workspace).run(IRB.conf)
end
chake-0.92/lib/chake/ 0000755 0000041 0000041 00000000000 14756133274 014404 5 ustar www-data www-data chake-0.92/lib/chake/yaml.rb 0000644 0000041 0000041 00000000347 14756133274 015677 0 ustar www-data www-data require 'yaml'
module Chake
module YAML
def self.load_file(filename)
if RUBY_VERSION >= '3.1'
::YAML.load_file(filename, aliases: true)
else
::YAML.load_file(filename)
end
end
end
end
chake-0.92/lib/chake/node.rb 0000644 0000041 0000041 00000003430 14756133274 015656 0 ustar www-data www-data require 'uri'
require 'etc'
require 'forwardable'
require 'chake/connection'
require 'chake/config_manager'
module Chake
class Node
extend Forwardable
attr_reader :hostname, :port, :username, :remote_username, :data
attr_accessor :silent
def self.max_node_name_length
@max_node_name_length ||= 0
end
class << self
attr_writer :max_node_name_length
end
def initialize(hostname, data = {})
uri = parse_uri(hostname)
@connection_name = uri.scheme
@hostname = uri.host
@port = uri.port
@username = uri.user || Etc.getpwuid.name
@remote_username = uri.user
@path = uri.path
@data = data
set_max_node_length
end
def connection
@connection ||= Chake::Connection.get(@connection_name).new(self)
end
def_delegators :connection, :run, :run_as_root, :run_shell, :rsync, :rsync_dest, :scp, :scp_dest, :skip?
def config_manager
@config_manager ||= Chake::ConfigManager.get(self)
end
def_delegators :config_manager, :converge, :apply, :path, :bootstrap_steps, :needs_upload?
def path
@path ||= config_manager.path
end
def log(msg)
return if silent
puts("%#{Node.max_node_name_length}s: %s\n" % { host: hostname, msg: msg })
end
private
def parse_uri(hostname)
uri = URI.parse(hostname)
if incomplete_uri(uri)
uri = URI.parse("ssh://#{hostname}")
end
uri.path = nil if uri.path.empty?
uri
end
def incomplete_uri(uri)
!uri.host && ((!uri.scheme && uri.path) || (uri.scheme && uri.opaque))
end
def set_max_node_length
return if @hostname.length <= self.class.max_node_name_length
self.class.max_node_name_length = @hostname.length
end
end
end
chake-0.92/lib/chake/config.rb 0000644 0000041 0000041 00000001313 14756133274 016174 0 ustar www-data www-data require 'chake/node'
require 'chake/yaml'
module Chake
class << self
attr_accessor :nodes
end
end
nodes_file = ENV['CHAKE_NODES'] || 'nodes.yaml'
nodes_directory = ENV['CHAKE_NODES_D'] || 'nodes.d'
nodes = (File.exist?(nodes_file) && Chake::YAML.load_file(nodes_file)) || {}
nodes.values.each do |node|
node['chake_metadata'] = { 'definition_file' => nodes_file }
end
Dir.glob(File.join(nodes_directory, '*.yaml')).sort.each do |f|
file_nodes = Chake::YAML.load_file(f)
file_nodes.values.each do |node|
node['chake_metadata'] = { 'definition_file' => f }
end
nodes.merge!(file_nodes)
end
Chake.nodes = nodes.map { |node, data| Chake::Node.new(node, data) }.reject(&:skip?).uniq(&:hostname)
chake-0.92/lib/chake/connection/ 0000755 0000041 0000041 00000000000 14756133274 016543 5 ustar www-data www-data chake-0.92/lib/chake/connection/local.rb 0000644 0000041 0000041 00000000462 14756133274 020164 0 ustar www-data www-data require 'socket'
module Chake
class Connection
class Local < Connection
def command_runner
['sh', '-c']
end
def shell_command
ENV.fetch('SHELL', Etc.getpwuid.shell)
end
def skip?
node.hostname != Socket.gethostname
end
end
end
end
chake-0.92/lib/chake/connection/ssh.rb 0000644 0000041 0000041 00000003021 14756133274 017661 0 ustar www-data www-data module Chake
class Connection
class Ssh < Connection
def scp
['scp', ssh_config, scp_options].flatten.compact
end
def scp_dest
"#{ssh_target}:"
end
def rsync
[ssh_prefix, 'rsync', rsync_ssh].flatten.compact
end
def rsync_dest
[ssh_target, "#{node.path}/"].join(':')
end
def command_runner
[ssh_prefix, 'ssh', ssh_config, ssh_options, ssh_target].flatten.compact
end
def shell_command
command_runner
end
private
def rsync_ssh
@rsync_ssh ||=
begin
ssh_command = 'ssh'
if File.exist?(ssh_config_file)
ssh_command += " -F #{ssh_config_file}"
end
ssh_command += " -p #{node.port}" if node.port
if ssh_command == 'ssh'
[]
else
['-e', ssh_command]
end
end
end
def ssh_config
(File.exist?(ssh_config_file) && ['-F', ssh_config_file]) || []
end
def ssh_config_file
@ssh_config_file ||= ENV.fetch('CHAKE_SSH_CONFIG', '.ssh_config')
end
def ssh_prefix
@ssh_prefix ||= ENV.fetch('CHAKE_SSH_PREFIX', '').split
end
def ssh_target
[node.remote_username, node.hostname].compact.join('@')
end
def ssh_options
(node.port && ['-p', node.port.to_s]) || []
end
def scp_options
(node.port && ['-P', node.port.to_s]) || []
end
end
end
end
chake-0.92/lib/chake/readline.rb 0000644 0000041 0000041 00000002701 14756133274 016514 0 ustar www-data www-data require 'etc'
require 'readline'
require 'chake/tmpdir'
module Chake
class Readline
class << self
def history_file
raise NotImplementedError
end
def history
@history ||= []
end
def prompt
raise NotImplementedError
end
def init
return unless File.exist?(history_file)
@history = File.readlines(history_file).map(&:strip)
end
def finish
return if !File.writable?(File.dirname(history_file)) || history.empty?
File.open(history_file, 'w') do |f|
history.last(500).each do |line|
f.puts(line)
end
end
end
def readline
::Readline::HISTORY.clear
history.each do |cmd|
::Readline::HISTORY.push(cmd)
end
input = ::Readline.readline(prompt)
history.push(input) if input && input.strip != '' && input != @last
input
end
end
class Commands < Readline
def self.history_file
File.join(Chake.tmpdir, '.commands_history')
end
def self.prompt
'$ '
end
end
class Recipes < Readline
def self.history_file
File.join(Chake.tmpdir, '.recipes_history')
end
def self.prompt
'> '
end
end
end
end
Chake::Readline.constants.each do |subclass|
subclass = Chake::Readline.const_get(subclass)
subclass.init
at_exit do
subclass.finish
end
end
chake-0.92/lib/chake/bootstrap/ 0000755 0000041 0000041 00000000000 14756133274 016421 5 ustar www-data www-data chake-0.92/lib/chake/bootstrap/itamae-remote/ 0000755 0000041 0000041 00000000000 14756133274 021152 5 ustar www-data www-data chake-0.92/lib/chake/bootstrap/itamae-remote/99_unsupported.sh 0000644 0000041 0000041 00000000446 14756133274 024423 0 ustar www-data www-data echo "---------------------"
echo "Unsupported platform: Installing itamae with rubygems"
echo "---------------------"
echo
for file in /etc/os-release /etc/issue; do
if [ -f $file ]; then
cat $file
break
fi
done
if ! which itamae >/dev/null ; then
gem install itamae
exit
fi
chake-0.92/lib/chake/bootstrap/itamae-remote/02_debian.sh 0000644 0000041 0000041 00000000211 14756133274 023223 0 ustar www-data www-data if [ -x /usr/bin/apt-get ]; then
apt-get update
export DEBIAN_FRONTEND=noninteractive
apt-get -q -y install rsync itamae
exit
fi
chake-0.92/lib/chake/bootstrap/itamae-remote/01_installed.sh 0000644 0000041 0000041 00000000113 14756133274 023760 0 ustar www-data www-data # itamae already installed
if which itamae >/dev/null 2>&1; then
exit
fi
chake-0.92/lib/chake/bootstrap/chef/ 0000755 0000041 0000041 00000000000 14756133274 017326 5 ustar www-data www-data chake-0.92/lib/chake/bootstrap/chef/99_unsupported.sh 0000644 0000041 0000041 00000000724 14756133274 022576 0 ustar www-data www-data echo "---------------------"
echo "Unsupported platform: Installing chef-solo with omnibus package"
echo "---------------------"
echo
for file in /etc/os-release /etc/issue; do
if [ -f $file ]; then
cat $file
break
fi
done
if ! which chef-solo >/dev/null ; then
# Install chef-solo via omnibus package that chef provides
# This script should install chef-solo in any Linux distribution
wget -O- https://opscode.com/chef/install.sh | bash
exit
fi
chake-0.92/lib/chake/bootstrap/chef/02_debian.sh 0000644 0000041 0000041 00000000304 14756133274 021402 0 ustar www-data www-data if [ -x /usr/bin/apt-get ]; then
apt-get update
export DEBIAN_FRONTEND=noninteractive
apt-get -q -y install rsync chef
update-rc.d chef-client disable
service chef-client stop
exit
fi
chake-0.92/lib/chake/bootstrap/chef/01_installed.sh 0000644 0000041 0000041 00000000121 14756133274 022133 0 ustar www-data www-data # chef-solo already installed
if which chef-solo >/dev/null 2>&1; then
exit
fi
chake-0.92/lib/chake/bootstrap/00_set_hostname.sh 0000644 0000041 0000041 00000001261 14756133274 021745 0 ustar www-data www-data hostname="$1"
if [ "$(hostname)" != "${hostname}" ]; then
echo "$hostname" > /etc/hostname
hostname --file /etc/hostname
fi
fqdn=$(hostname --fqdn || true)
if [ "$fqdn" != "$hostname" ]; then
# if hostname is bar.example.com, we also want `bar` to be in /etc/hosts
short_hostname=$(echo "$hostname" | cut -d . -f 1)
if [ "$short_hostname" != "$hostname" ] && ! grep -q "\s${short_hostname}" /etc/hosts; then
hostname="$hostname $short_hostname"
fi
printf "127.0.1.1\t%s\n" "$hostname" >> /etc/hosts
fi
# Stop cloud-init from resetting the hostname
if [ -f /etc/cloud/cloud.cfg ]; then
sed -i -e '/^\s*-\s*\(set_hostname\|update_hostname\)/d' /etc/cloud/cloud.cfg
fi
chake-0.92/lib/chake/version.rb 0000644 0000041 0000041 00000000053 14756133274 016414 0 ustar www-data www-data module Chake
VERSION = '0.92'.freeze
end
chake-0.92/lib/chake/wipe.rb 0000644 0000041 0000041 00000000575 14756133274 015704 0 ustar www-data www-data require 'singleton'
module Chake
class Wipe
include Singleton
if system('which', 'wipe', out: '/dev/null', err: :out)
def wipe(file)
system('wipe', '-rfs', file)
end
else
warn 'W: please install the \`wipe\` program for secure deletion, falling back to unlink(2)'
def wipe(file)
File.unlink(file)
end
end
end
end
chake-0.92/lib/chake/tmpdir.rb 0000644 0000041 0000041 00000000124 14756133274 016225 0 ustar www-data www-data module Chake
def self.tmpdir
ENV.fetch('CHAKE_TMPDIR', 'tmp/chake')
end
end
chake-0.92/lib/chake/config_manager/ 0000755 0000041 0000041 00000000000 14756133274 017343 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/shell.rb 0000644 0000041 0000041 00000001210 14756133274 020771 0 ustar www-data www-data require 'shellwords'
require 'chake/config'
module Chake
class ConfigManager
class Shell < ConfigManager
def converge
commands = node.data['shell'].join(' && ')
node.run_as_root sh(commands)
end
def apply(config)
node.run_as_root sh(config)
end
def self.accept?(node)
node.data.key?('shell')
end
private
def sh(command)
if node.path
command = "cd #{node.path} && " + command
end
if node.silent
"sh -ec '#{command}' >/dev/null"
else
"sh -xec '#{command}'"
end
end
end
end
end
chake-0.92/lib/chake/config_manager/itamae_remote.rb 0000644 0000041 0000041 00000001566 14756133274 022513 0 ustar www-data www-data require 'shellwords'
require 'chake/config'
require 'chake/tmpdir'
module Chake
class ConfigManager
class ItamaeRemote < ConfigManager
def converge
recipes = node.data['itamae-remote']
return if recipes.empty?
run_itamae(*recipes)
end
def apply(config)
run_itamae(config)
end
def needs_upload?
true
end
def self.accept?(node)
node.data.key?('itamae-remote')
end
private
def run_itamae(*recipes)
cmd = ['itamae', 'local', "--node-json=#{json_config}"]
if node.silent
cmd << '--log-level=warn'
end
cmd += recipes.map { |r| File.join(node.path, r) }
node.run_as_root(Shellwords.join(cmd))
end
def json_config
File.join(node.path, Chake.tmpdir, "#{node.hostname}.json")
end
end
end
end
chake-0.92/lib/chake/config_manager/chef.rb 0000644 0000041 0000041 00000001603 14756133274 020575 0 ustar www-data www-data require 'chake/config'
require 'chake/tmpdir'
module Chake
class ConfigManager
class Chef < ConfigManager
CONFIG = ENV['CHAKE_CHEF_CONFIG'] || 'config.rb'
def converge
node.run_as_root "sh -c 'rm -f #{node.path}/nodes/*.json && chef-solo -c #{node.path}/#{CONFIG} #{logging} -j #{json_config}'"
end
def apply(config)
node.run_as_root "sh -c 'rm -f #{node.path}/nodes/*.json && chef-solo -c #{node.path}/#{CONFIG} #{logging} -j #{json_config} --override-runlist recipe[#{config}]'"
end
priority 99
def self.accept?(_node)
true # this is the default, but after everything else
end
private
def json_config
parts = [node.path, Chake.tmpdir, "#{node.hostname}.json"].compact
File.join(parts)
end
def logging
(node.silent && '-l fatal') || ''
end
end
end
end
chake-0.92/lib/chake/config_manager/skel/ 0000755 0000041 0000041 00000000000 14756133274 020301 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/shell/ 0000755 0000041 0000041 00000000000 14756133274 021410 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/shell/Rakefile 0000644 0000041 0000041 00000000020 14756133274 023045 0 ustar www-data www-data require 'chake'
chake-0.92/lib/chake/config_manager/skel/shell/nodes.yaml 0000644 0000041 0000041 00000000067 14756133274 023407 0 ustar www-data www-data host1.mycompany.com:
shell:
- echo "HELLO WORLD"
chake-0.92/lib/chake/config_manager/skel/itamae/ 0000755 0000041 0000041 00000000000 14756133274 021541 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/itamae/roles/ 0000755 0000041 0000041 00000000000 14756133274 022665 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/itamae/roles/basic.rb 0000644 0000041 0000041 00000000045 14756133274 024272 0 ustar www-data www-data include_recipe '../cookbooks/basics'
chake-0.92/lib/chake/config_manager/skel/itamae/cookbooks/ 0000755 0000041 0000041 00000000000 14756133274 023532 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/itamae/cookbooks/basics/ 0000755 0000041 0000041 00000000000 14756133274 024776 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/itamae/cookbooks/basics/default.rb 0000644 0000041 0000041 00000000031 14756133274 026741 0 ustar www-data www-data package 'openssh-server'
chake-0.92/lib/chake/config_manager/skel/itamae/Rakefile 0000644 0000041 0000041 00000000020 14756133274 023176 0 ustar www-data www-data require 'chake'
chake-0.92/lib/chake/config_manager/skel/itamae/nodes.yaml 0000644 0000041 0000041 00000000064 14756133274 023535 0 ustar www-data www-data host1.mycompany.com:
itamae:
- roles/basic.rb
chake-0.92/lib/chake/config_manager/skel/chef/ 0000755 0000041 0000041 00000000000 14756133274 021206 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/chef/config.rb 0000644 0000041 0000041 00000000200 14756133274 022770 0 ustar www-data www-data root = __dir__
file_cache_path "#{root}/cache"
cookbook_path "#{root}/cookbooks"
role_path "#{root}/config/roles"
chake-0.92/lib/chake/config_manager/skel/chef/cookbooks/ 0000755 0000041 0000041 00000000000 14756133274 023177 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/chef/cookbooks/basics/ 0000755 0000041 0000041 00000000000 14756133274 024443 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/chef/cookbooks/basics/recipes/ 0000755 0000041 0000041 00000000000 14756133274 026075 5 ustar www-data www-data chake-0.92/lib/chake/config_manager/skel/chef/cookbooks/basics/recipes/default.rb 0000644 0000041 0000041 00000000031 14756133274 030040 0 ustar www-data www-data package 'openssh-server'
chake-0.92/lib/chake/config_manager/skel/chef/Rakefile 0000644 0000041 0000041 00000000020 14756133274 022643 0 ustar www-data www-data require 'chake'
chake-0.92/lib/chake/config_manager/skel/chef/nodes.yaml 0000644 0000041 0000041 00000000066 14756133274 023204 0 ustar www-data www-data host1.mycompany.com:
run_list:
- recipe[basics]
chake-0.92/lib/chake/config_manager/itamae.rb 0000644 0000041 0000041 00000002770 14756133274 021136 0 ustar www-data www-data require 'shellwords'
require 'chake/config'
require 'chake/tmpdir'
module Chake
class ConfigManager
class Itamae < ConfigManager
def converge
recipes = node.data['itamae']
return if recipes.empty?
run_itamae(*recipes)
end
def apply(config)
run_itamae(config)
end
def needs_upload?
false
end
def self.accept?(node)
node.data.key?('itamae')
end
private
def run_itamae(*recipes)
cmd = ['itamae']
case node.connection
when Chake::Connection::Ssh
cmd << 'ssh' << "--user=#{node.username}" << "--host=#{node.hostname}"
cmd += ssh_config
when Chake::Connection::Local
if node.username == 'root'
cmd.prepend 'sudo'
end
cmd << 'local'
else
raise NotImplementedError, "Connection type #{node.connection.class} not supported for itamee"
end
cmd << "--node-json=#{json_config}"
if node.silent
cmd << '--log-level=warn'
end
cmd += recipes
node.log("$ #{cmd.join(' ')}")
io = IO.popen(cmd, 'r', err: %i[child out])
node.connection.read_output(io)
end
def json_config
File.join(Chake.tmpdir, "#{node.hostname}.json")
end
def ssh_config
ssh_config = node.connection.send(:ssh_config_file) # FIXME
File.exist?(ssh_config) ? ["--ssh-config=#{ssh_config}"] : []
end
end
end
end
chake-0.92/lib/chake/connection.rb 0000644 0000041 0000041 00000003107 14756133274 017071 0 ustar www-data www-data require 'English'
module Chake
Connection = Struct.new(:node)
class Connection
class CommandFailed < RuntimeError
end
def scp
['scp']
end
def scp_dest
''
end
def rsync
['rsync']
end
def rsync_dest
"#{node.path}/"
end
def run(cmd)
node.log('$ %s' % { command: cmd })
io = IO.popen(command_runner + ['/bin/sh'], 'w+', err: %i[child out])
io.write(cmd)
io.close_write
read_output(io)
end
def read_output(io)
io.each_line do |line|
node.log(line.gsub(/\s*$/, ''))
end
io.close
if $CHILD_STATUS
status = $CHILD_STATUS.exitstatus
if status != 0
raise CommandFailed, [node.hostname, 'FAILED with exit status %d' % { status: status }].join(': ')
end
end
end
def run_shell
system(*shell_command)
end
def run_as_root(cmd)
if node.remote_username == 'root'
run(cmd)
else
run("sudo #{cmd}")
end
end
def to_s
self.class.connection_name
end
def skip?
false
end
def self.connection_name
name.split('::').last.downcase
end
def self.inherited(subclass)
super
@connections ||= []
@connections << subclass
end
def self.get(name)
connection = @connections.find { |b| b.connection_name == name }
raise ArgumentError, "Invalid connection name: #{name}" unless connection
connection
end
end
end
require 'chake/connection/ssh'
require 'chake/connection/local'
chake-0.92/lib/chake/config_manager.rb 0000644 0000041 0000041 00000004033 14756133274 017670 0 ustar www-data www-data require 'pathname'
module Chake
class ConfigManager
attr_reader :node
def initialize(node)
@node = node
end
def converge; end
def apply(config); end
def path
"/var/tmp/#{name}.#{node.username}"
end
def name
self.class.short_name
end
def to_s
name
end
def bootstrap_steps
base = File.join(File.absolute_path(File.dirname(__FILE__)), 'bootstrap')
steps = Dir[File.join(base, '*.sh')] + Dir[File.join(base, name, '*.sh')]
steps.sort_by { |f| File.basename(f) }
end
def needs_upload?
true
end
def self.short_name
name.split('::').last.gsub(/([[:lower:]])([[:upper:]])/) do
first = Regexp.last_match(1)
last = Regexp.last_match(2).downcase
"#{first}-#{last}"
end.downcase
end
def self.priority(new_priority = nil)
@priority ||= new_priority || 50
end
def self.inherited(klass)
super
@subclasses ||= []
@subclasses << klass
end
def self.get(node)
available = @subclasses.sort_by(&:priority)
manager = available.find { |c| c.short_name == node.data['config_manager'] }
manager ||= available.find { |c| c.accept?(node) }
raise ArgumentError, "Can't find configuration manager class for node #{node.hostname}. Available: #{available}.join(', ')}" unless manager
manager.new(node)
end
def self.accept?(_node)
false
end
def self.all
@subclasses
end
def self.init
skel = Pathname(__FILE__).parent / 'config_manager' / 'skel' / short_name
skel.glob('**/*').each do |source|
target = source.relative_path_from(skel)
if target.exist?
puts "exists: #{target}"
else
if source.directory?
FileUtils.mkdir_p target
else
FileUtils.cp source, target
end
puts "create: #{target}"
end
end
end
end
end
Dir["#{File.dirname(__FILE__)}/config_manager/*.rb"].sort.each do |f|
require f
end
chake-0.92/README.shell.md 0000644 0000041 0000041 00000001440 14756133274 015147 0 ustar www-data www-data chake-shell(7) -- configure chake nodes with shell
==================================================
## Description
This configuration manager is a simpler wrapper for running a list of shell
commands on the nodes.
## Configuration
The _shell_ configuration manager requires one key called `shell`, and the
value must be a list of strings representing the list of commands to run on the
node when converging.
```yaml
host1.mycompany.com:
shell:
- echo "HELLO WORLD"
```
## Bootstrapping
Very little bootstrapping is required for this configuration manager, as we
hope every node you could possibly want to manage with it already has a POSIX
shell as `/bin/sh`. During bootstrapping, only the node hostname will be set
according to your chake configuration.
## See also
* **chake(1)**
chake-0.92/activate.sh 0000644 0000041 0000041 00000000143 14756133274 014715 0 ustar www-data www-data base=$(dirname $BASH_SOURCE)
export RUBYLIB=${base}/lib:${RUBYLIB}
export PATH=${base}/bin:${PATH}
chake-0.92/LICENSE.txt 0000644 0000041 0000041 00000002106 14756133274 014405 0 ustar www-data www-data Copyright (c) 2014 Antonio Terceiro
The Expat License (a.k.a. "MIT")
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
chake-0.92/spec/ 0000755 0000041 0000041 00000000000 14756133274 013515 5 ustar www-data www-data chake-0.92/spec/spec_helper.rb 0000644 0000041 0000041 00000003210 14756133274 016327 0 ustar www-data www-data begin
require 'simplecov'
SimpleCov.start do
minimum_coverage 35.3
track_files 'lib/**/*.rb'
add_filter %r{^/spec/}
add_filter %r{^/lib/chake/config_manager/skel/}
end
rescue LoadError
puts "W: simplecov not installed, we won't have a coverage report"
end
require 'chake/node'
require 'chake/connection'
require 'rspec/version'
if RSpec::Version::STRING < '2.14'
puts 'Skipping tests, need RSpec >= 2.14'
exit
end
shared_examples 'Chake::Connection' do |connection_class|
let(:connection) { connection_class.new(node) }
it('runs commands') do
io = StringIO.new("line 1\n line 2\n")
expect(IO).to receive(:popen).with(connection.command_runner + ['/bin/sh'], 'w+', Hash).and_return(io)
expect(io).to receive(:write).with('something').ordered
expect(io).to receive(:close_write).ordered
expect(node).to receive(:log).with('$ something')
expect(node).to receive(:log).with('line 1')
expect(node).to receive(:log).with(' line 2')
connection.run('something')
end
it('runs as root') do
expect(connection).to receive(:run).with('sudo something')
connection.run_as_root('something')
end
it('does not use sudo if already root') do
allow(connection.node).to receive(:remote_username).and_return('root')
expect(connection).to receive(:run).with('something')
connection.run_as_root('something')
end
end
module Helpers
def silence(stream)
orig_stream = stream.clone
begin
File.open('/dev/null', 'w') do |f|
stream.reopen(f)
yield
end
ensure
stream.reopen(orig_stream)
end
end
end
RSpec.configure do |c|
c.include Helpers
end
chake-0.92/spec/chake/ 0000755 0000041 0000041 00000000000 14756133274 014570 5 ustar www-data www-data chake-0.92/spec/chake/config_manager_spec.rb 0000644 0000041 0000041 00000001177 14756133274 021074 0 ustar www-data www-data require 'pathname'
require 'chake/node'
require 'chake/config_manager'
describe Chake::ConfigManager do
subject { Chake::ConfigManager.new(Chake::Node.new('ssh://user@hostname.tld')) }
it 'provides a path' do
allow(subject).to receive(:name).and_return('xyz')
expect(subject.path).to eq('/var/tmp/xyz.user')
end
it 'provides bootstrap scripts' do
bootstrap_steps = subject.bootstrap_steps
expect(bootstrap_steps).to_not be_empty
bootstrap_steps.each do |path|
expect(Pathname(path)).to exist
end
end
it 'requires uploading by default' do
expect(subject.needs_upload?).to eq(true)
end
end
chake-0.92/spec/chake/node_spec.rb 0000644 0000041 0000041 00000005403 14756133274 017056 0 ustar www-data www-data require 'chake/node'
describe Chake::Node do
before do
ent = double
allow(ent).to receive(:name).and_return('jonhdoe')
allow(Etc).to receive(:getpwuid).and_return(ent)
end
let(:simple) { Chake::Node.new('hostname') }
it('has a name') { expect(simple.hostname).to eq('hostname') }
it('uses ssh by default') { expect(simple.connection).to be_an_instance_of(Chake::Connection::Ssh) }
it('user current username by default') {
expect(simple.username).to eq('jonhdoe')
}
it('writes to specified path') {
node = Chake::Node.new('ssh://host.tld/path/to/config')
expect(node.path).to eq('/path/to/config')
}
let(:with_username) { Chake::Node.new('username@hostname') }
it('accepts username') { expect(with_username.username).to eq('username') }
it('uses ssh') { expect(with_username.connection).to be_an_instance_of(Chake::Connection::Ssh) }
let(:with_connection) { Chake::Node.new('local://hostname') }
it('accepts connection as URI scheme') { expect(with_connection.connection).to be_an_instance_of(Chake::Connection::Local) }
it('wont accept any connection') do
expect { Chake::Node.new('foobar://bazqux').connection }.to raise_error(ArgumentError)
end
let(:with_data) { Chake::Node.new('local://localhost', 'run_list' => ['recipe[common]']) }
it('takes data') do
expect(with_data.data).to be_a(Hash)
end
let(:with_port) { Chake::Node.new('ssh://foo.bar.com:2222') }
it('accepts a port specification') do
expect(with_port.port).to eq(2222)
end
let(:with_port_but_no_scheme) { Chake::Node.new('foo.bar.com:2222') }
it('accepts a port specification without a scheme') do
expect(with_port_but_no_scheme.port).to eq(2222)
expect(with_port_but_no_scheme.connection.to_s).to eq('ssh')
end
%i[run run_as_root rsync_dest].each do |method|
it("delegates #{method} to connection") do
node = simple
connection = double
args = Object.new
allow(node).to receive(:connection).and_return(connection)
expect(connection).to receive(method).with(args)
node.send(method, args)
end
end
it 'delegates converge to config_manager' do
node = simple
expect(node.config_manager).to receive(:converge)
node.converge
end
it 'delegates apply to config_manager' do
node = simple
expect(node.config_manager).to receive(:apply).with('myrecipe')
node.apply('myrecipe')
end
it 'falls back to writing to path specified by config manager' do
expect(simple.path).to eq(simple.config_manager.path)
end
it 'calculates max node name length' do
Chake::Node.max_node_name_length = 0
Chake::Node.new('foobar')
expect(Chake::Node.max_node_name_length).to eq(6)
Chake::Node.new('foobarbaz')
expect(Chake::Node.max_node_name_length).to eq(9)
end
end
chake-0.92/spec/chake/backend_spec.rb 0000644 0000041 0000041 00000000033 14756133274 017512 0 ustar www-data www-data require 'chake/connection'
chake-0.92/spec/chake/backend/ 0000755 0000041 0000041 00000000000 14756133274 016157 5 ustar www-data www-data chake-0.92/spec/chake/backend/local_spec.rb 0000644 0000041 0000041 00000001031 14756133274 020603 0 ustar www-data www-data require 'spec_helper'
describe Chake::Connection::Local do
include_examples 'Chake::Connection', Chake::Connection::Local
let(:node) { Chake::Node.new('local://myusername@myhost/srv/chake') }
it('runs commands with sh -c') { expect(connection.command_runner).to eq(['sh', '-c']) }
it('rsyncs locally') { expect(connection.rsync_dest).to eq('/srv/chake/') }
it('skips if hostname is not the local hostname') do
allow(Socket).to receive(:gethostname).and_return('otherhost')
expect(node.skip?).to eq(true)
end
end
chake-0.92/spec/chake/backend/ssh_spec.rb 0000644 0000041 0000041 00000002162 14756133274 020314 0 ustar www-data www-data require 'spec_helper'
describe Chake::Connection::Ssh do
include_examples 'Chake::Connection', Chake::Connection::Ssh
let(:node) { Chake::Node.new('ssh://myuser@myhost/srv/chake') }
it('runs commands with ssh') { expect(connection.command_runner).to eq(['ssh', 'myuser@myhost']) }
it('rsyncs over ssh') { expect(connection.rsync_dest).to eq('myuser@myhost:/srv/chake/') }
it 'uses no remote username if none was passed' do
node = Chake::Node.new('theserver')
expect(node.username).to eq(Etc.getpwuid.name)
expect(node.remote_username).to be_nil
end
it 'uses username is passwd' do
expect(node.username).to eq('myuser')
expect(node.remote_username).to eq('myuser')
end
context 'with a custom port' do
let(:node) { Chake::Node.new('ssh://myhost:2222') }
it 'uses port with ssh' do
expect(connection.command_runner).to eq(['ssh', '-p', '2222', 'myhost'])
end
it 'uses port with scp' do
expect(connection.scp).to eq(['scp', '-P', '2222'])
end
it 'uses port with rsync' do
expect(connection.send(:rsync_ssh)).to eq(['-e', 'ssh -p 2222'])
end
end
end
chake-0.92/spec/chake/config_manager/ 0000755 0000041 0000041 00000000000 14756133274 017527 5 ustar www-data www-data chake-0.92/spec/chake/config_manager/itamae_remote_spec.rb 0000644 0000041 0000041 00000002206 14756133274 023701 0 ustar www-data www-data require 'spec_helper'
require 'chake/node'
require 'chake/config_manager/itamae_remote'
describe Chake::ConfigManager::ItamaeRemote do
let(:node) do
Chake::Node.new('somehost').tap do |n|
n.silent = true
n.data['itamae-remote'] = ['foo.rb', 'bar.rb']
end
end
let(:cfg) { Chake::ConfigManager.get(node) }
it 'is detected correctly' do
expect(cfg).to be_a(Chake::ConfigManager::ItamaeRemote)
end
it 'requires uploading' do
expect(cfg.needs_upload?).to eq(true)
end
it 'calls itamae remotely to converge' do
expect(node).to receive(:run_as_root).with(
a_string_matching(%r{itamae.*#{node.path}/foo.rb.*#{node.path}/bar.rb})
)
cfg.converge
end
it 'calls itamae remotely to apply' do
expect(node).to receive(:run_as_root).with(
a_string_matching(%r{itamae.*#{node.path}/doit.rb})
)
cfg.apply('doit.rb')
end
it 'handles silent mode' do
node.silent = true
expect(node).to receive(:run_as_root).with(
a_string_matching(/--log-level\\=warn/)
)
cfg.converge
end
it 'has a name with dashes' do
expect(cfg.name).to eq('itamae-remote')
end
end
chake-0.92/spec/chake/config_manager/chef_spec.rb 0000644 0000041 0000041 00000002147 14756133274 021777 0 ustar www-data www-data require 'chake/node'
require 'chake/config_manager/chef'
describe Chake::ConfigManager::Chef do
let(:node) do
Chake::Node.new('foobar')
end
subject do
Chake::ConfigManager::Chef.new(node)
end
it 'provides a name' do
expect(subject.name).to eq('chef')
end
it 'calls chef-solo on converge' do
expect(subject).to receive(:logging).and_return('-l debug')
expect(node).to receive(:run_as_root).with(%r{chef-solo -c #{node.path}/config.rb -l debug -j #{node.path}/#{Chake.tmpdir}/foobar.json})
subject.converge
end
it 'calls chef-solo on apply' do
expect(subject).to receive(:logging).and_return('-l debug')
expect(node).to receive(:run_as_root).with(%r{chef-solo -c #{node.path}/config.rb -l debug -j #{node.path}/#{Chake.tmpdir}/foobar.json --override-runlist recipe\[myrecipe\]})
subject.apply('myrecipe')
end
context 'logging' do
it 'logs when requested' do
expect(subject.send(:logging)).to eq('')
end
it 'only show fatal errrrs when requested' do
node.silent = true
expect(subject.send(:logging)).to eq('-l fatal')
end
end
end
chake-0.92/spec/chake/config_manager/itamae_spec.rb 0000644 0000041 0000041 00000004437 14756133274 022336 0 ustar www-data www-data require 'spec_helper'
require 'chake/node'
require 'chake/config_manager/itamae'
describe Chake::ConfigManager::Itamae do
let(:hostname) { 'foobar' }
let(:node) do
Chake::Node.new(hostname).tap do |n|
n.silent = true
n.data['itamae'] = ['foo.rb', 'bar.rb']
end
end
let(:cfg) { Chake::ConfigManager::Itamae.new(node) }
let(:output) { StringIO.new("line1\nline2\n") }
it 'does not require uploading' do
expect(cfg.needs_upload?).to eq(false)
end
it 'calls itamae when converging' do
expect(IO).to receive(:popen).with(
array_including('itamae', 'foo.rb', 'bar.rb'),
'r',
err: %i[child out]
).and_return(output)
cfg.converge
end
it 'calls itamae when applying' do
expect(IO).to receive(:popen).with(
array_including('itamae', 'foobarbaz.rb'),
'r',
err: %i[child out]
).and_return(output)
cfg.apply('foobarbaz.rb')
end
context 'for ssh hosts' do
let(:hostname) { 'ssh://theusernanme@thehostname' }
it 'calls itamae ssh subcommand' do
expect(IO).to receive(:popen).with(
array_including('itamae', 'ssh', '--host=thehostname', '--user=theusernanme'),
anything,
err: anything
).and_return(output)
cfg.converge
end
end
context 'for local hosts' do
let(:hostname) { 'local://localhostname' }
it 'calls itamae with local subcommand' do
expect(IO).to receive(:popen).with(
array_including('itamae', 'local', /--node-json=.*/, 'foo.rb', 'bar.rb'),
anything,
err: anything
).and_return(output)
cfg.converge
end
end
it 'throws an error for unsupported connection' do
allow(node).to receive(:connection).and_return(Object.new)
expect { cfg.converge }.to raise_error(NotImplementedError)
end
it 'handles silent mode' do
expect(IO).to receive(:popen).with(
array_including('--log-level=warn'),
anything,
err: anything
).and_return(output)
cfg.converge
end
RSpec::Matchers.define_negated_matcher :array_excluding, :include
it 'handles non-silent mode' do
node.silent = false
expect(IO).to receive(:popen).with(
array_excluding('--log-level=warn'),
anything,
err: anything
).and_return(output)
silence($stdout) { cfg.converge }
end
end
chake-0.92/spec/chake/config_manager/shell_spec.rb 0000644 0000041 0000041 00000003253 14756133274 022200 0 ustar www-data www-data require 'chake/node'
require 'chake/config_manager'
require 'chake/config_manager/shell'
describe Chake::ConfigManager::Shell do |_c|
let(:node) do
Chake::Node.new('foobar').tap do |n|
allow(n).to receive(:path).and_return(nil)
end
end
it 'accepts node with explicit config_manager in data' do
node.data['config_manager'] = 'shell'
expect(Chake::ConfigManager.get(node)).to be_a(Chake::ConfigManager::Shell)
end
it 'accepts node with `shell` in data' do
node.data['shell'] = ['date']
expect(Chake::ConfigManager.get(node)).to be_a(Chake::ConfigManager::Shell)
end
let(:subject) { Chake::ConfigManager::Shell.new(node) }
it 'calls all shell commands on converge' do
node.data['shell'] = %w[date true]
expect(node).to receive(:run_as_root).with("sh -xec 'date && true'")
subject.converge
end
it 'changes to node path to run commands' do
node.data['shell'] = %w[true]
allow(node).to receive(:path).and_return('/foo')
expect(node).to receive(:run_as_root).with("sh -xec 'cd /foo && true'")
subject.converge
end
it 'calls given shell command on apply' do
node.data['shell'] = %w[date true]
expect(node).to receive(:run_as_root).with("sh -xec 'reboot'")
subject.apply('reboot')
end
it 'hides output on converge in silent mode' do
node.data['shell'] = ['date']
node.silent = true
expect(node).to receive(:run_as_root).with("sh -ec 'date' >/dev/null")
subject.converge
end
it 'hides output on apply in silent mode' do
node.data['shell'] = ['date']
node.silent = true
expect(node).to receive(:run_as_root).with("sh -ec 'reboot' >/dev/null")
subject.apply('reboot')
end
end
chake-0.92/spec/integration_tests_spec.rb 0000644 0000041 0000041 00000002067 14756133274 020626 0 ustar www-data www-data require 'fileutils'
require 'pathname'
require 'tmpdir'
describe 'Chake' do
include FileUtils
def sh(*args)
cmd = Shellwords.join(args)
lib = [Pathname.new(__FILE__).parent.parent / 'lib', ENV.fetch('RUBYLIB', nil)].compact.join(':')
path = [Pathname.new(__FILE__).parent.parent / 'bin', ENV.fetch('PATH', nil)].join(':')
env = {
'RUBYLIB' => lib,
'PATH' => path
}
unless system(env, *args, out: ['.out', 'w'], err: ['.err', 'w'])
out = File.read('.out')
err = File.read('.err')
raise "Command [#{cmd}] failed with exit status #{$CHILD_STATUS} (PATH = #{path}, RUBYLIB = #{lib}).\nstdout:\n#{out}\nstderr:\n#{err}"
end
rm_f '.log'
end
def chake(*args)
cmd = [Gem.ruby, '-S', 'chake'] + args
sh(*cmd)
end
def rake(*args)
cmd = [Gem.ruby, '-S', 'rake'] + args
sh(*cmd)
end
def project
Dir.mktmpdir do |dir|
Dir.chdir(dir) do
yield dir
end
end
end
it 'loads node information' do
project do
chake 'init'
rake 'nodes'
end
end
end
chake-0.92/Rakefile 0000644 0000041 0000041 00000005720 14756133274 014234 0 ustar www-data www-data namespace :bundler do
require 'bundler/gem_tasks'
end
task :test do
sh 'rspec', '--color'
end
pkg = Gem::Specification.load('chake.gemspec')
task 'bundler:build' => :manifest
task 'build:tarball' => 'bundler:build' do
chdir 'pkg' do
sh 'gem2tgz', "#{pkg.name}-#{pkg.version}.gem"
end
end
desc 'Create Debian source package'
task 'build:debsrc' => ['bundler:clobber', 'build:tarball'] do
dirname = "#{pkg.name}-#{pkg.version}"
v = `git describe`.strip.tr('-', '.').sub(/^v/, '')
chdir 'pkg' do
sh 'gem2deb', '--no-wnpp-check', '-s', '-p', pkg.name, "#{dirname}.tar.gz"
sh "rename s/#{pkg.version}/#{v}/ *.orig.tar.gz"
chdir dirname do
ln 'man/Rakefile', 'debian/dh_ruby.rake'
sh "dch --preserve -v #{v}-1 'Development snapshot'"
sh "sed -i -e 's/#{pkg.version}/#{v}/' lib/chake/version.rb"
sh 'dpkg-buildpackage', '--diff-ignore=version.rb', '-S', '-us', '-uc'
end
end
end
desc 'Builds and installs Debian package'
task 'deb:install' => 'build:debsrc' do
chdir "pkg/#{pkg.name}-#{pkg.version}" do
sh 'dpkg-buildpackage --diff-ignore=version.rb -us -uc'
sh 'sudo apt-get install -qy --reinstall $(debc --list-debs)'
end
end
desc 'Create source RPM package'
task 'build:rpmsrc' => ['build:tarball', 'pkg/chake.spec'] do
chdir 'pkg' do
sh 'rpmbuild --define "_topdir .rpmbuild" --define "_sourcedir $(pwd)" --define "_srcrpmdir $(pwd)" -bs chake.spec --nodeps'
end
end
file 'pkg/chake.spec' => ['chake.spec.erb', 'lib/chake/version.rb'] do |t|
require 'erb'
pkg = Gem::Specification.load('chake.gemspec')
template = ERB.new(File.read('chake.spec.erb'))
File.open(t.name, 'w') do |f|
f.puts(template.result(binding))
end
puts "Generated #{t.name}"
end
task 'build:all' => ['build:debsrc', 'build:rpmsrc']
desc 'lists changes since last release'
task :changelog do
last_tag = `git tag | sort -V`.split.last
sh 'git', 'shortlog', "#{last_tag}.."
end
task :check_tag do
last_tag = `git tag | sort -V`.split.last
if last_tag == "v#{pkg.version}"
raise "Version #{pkg.version} was already released!"
end
end
desc 'checks if the latest release is properly documented in ChangeLog.md'
task :check_changelog do
sh 'grep', "^#\\s*#{pkg.version}", 'ChangeLog.md'
rescue StandardError
puts "Version #{pkg.version} not documented in ChangeLog.md!"
raise
end
desc 'Updates manifest file'
task :manifest do
manifest = File.read('.manifest')
git = `git ls-files`
if manifest != git
File.write('.manifest', git)
sh 'git commit .manifest -m "Update manifest"'
end
end
desc 'Makes a release'
task release: [:check_tag, :check_changelog, :default, 'bundler:release']
desc 'Check coding style'
task :style do
sh 'rubocop'
end
desc 'Check spelling in the source code'
task :codespell do
sh 'codespell', '--skip=.git', '--skip=coverage', '--skip=*.asc', '--skip=*.swp', '--skip=tags', '--skip=*.1'
end
task default: [:test, :style, :codespell]
task clean: 'bundler:clobber'
load './man/Rakefile'
chake-0.92/ChangeLog.md 0000644 0000041 0000041 00000017757 14756133274 014755 0 ustar www-data www-data # 0.92
- Add support for connect:$HOST hooks
# 0.91
- itamae: handle empty recipe list
- Add support for configuring encrypted files explicitly
- itamae-remote: handle empty recipe list
- Rakefile: deb:install: install dependencies as well
- activate.sh: add script to use this source dir in a shell
- Make rsync invocations quiet by default
# 0.90.3
- `itamae_spec`: fix rspec warning about syntax for `expect { }.to raise`
- bootstrap: `00_set_hostname.sh`: don't set hostname if not needed
- Chake::Connection: add missing require for `$CHILD_STATUS`
# 0.90.2
- upload: make sure to reupload on config manager changes
- Apply suggestions by rubocop 1.39.0
- Chake::Connection: avoid setting constant inside of block
- rubocop: keep assignment to `test_files` in the gemspec
- gemspec: set `spec.metadata['rubygems_mfa_required']`
# 0.90.1
* Fix loading node data under ruby < 3.1
# 0.90
* itamae: use --sudo when root for local backend
* Chake::ConfigManager: fix typo
* chake/config: allow aliases in YAML data
* codespell: ignore tags file
* ChangeLog.md: fix typo found by codespell
* Implement new configuration manager: itamae-remote
# 0.82
* gemspec: drop bundler version constraint
* Chake::Wipe: improve wording in warning message
* chake/config: store the node definition file in the node data
# 0.81.1
* manpages: make sure all instances of \' are fixed
* rake nodes: format output by ourselves
# 0.81
* bootstrap/chef: exit if chef-solo is available
* Always bootstrap nodes
* Decrypt files in place when upload is not needed
* itamae: handle silent mode
* manpages: drop accute accent erroneously added by ronn
# 0.80
This release adds support for multiple configuration managers. Chef is now only
one of the options. There is also now support for configuration management with
itamae, and lightweight configuration management tool inspired by Chef, and via
shell commands. This should be mostly transparent to current Chef users, but
new repositories initiated by chake will use itamae by default.
Other notable changes:
* rake nodes: list configuration manager and format as table
* Chake::Connection: fix handling of stderr
* Rebootstrap nodes when changing config managers
* bootstrap, upload: skip when config manager does not need them
# 0.21.2
* Chake::Backend#run: don't strip leading whitespace
# 0.21.1
* Fix converge when the connection is not already made as root. This bug was
introduced by the change in the previous release.
# 0.21
* converge, apply: allow removing data from the node JSON attributes
# 0.20
* check: give some feedback by running `sudo echo OK` instead of `sudo true`
* Get rid of global variables
* bin/chake: make rake run one thread for each node
* Chake::Backend: run commands by opening a shell and writing to it
* Document Chake.nodes
# 0.19
* Protect node JSON files from other users
# 0.18
* add console task
* manpage: fix header transformation
* manpage: ignore intermediary .adoc file
# 0.17.1
* manpage: drop ad-hoc handling of `SOURCE_DATE_EPOCH` (let asciidoctor handle
it)
# 0.17
* make rsync exclude extra directories who are created as root by chef-solo at
the server side. This fixes the case where upload phase when the SSH user is
not root.
# 0.16
* make `run` also capture stderr, for now mixed together with stdout. In the
future that may be improved for example to print stderr output in red when
running on a TTY.
# 0.15
* improve text in the parallel execution docs
* add new hook: `connect_common`, which will run before any attempt to connect
to any node.
* make output of `check` target more explicit about what was tested
# 0.14
* Fix typo in README.md
* thanks to Luciano Prestes Cavalcanti
* Turn "all hosts" tasks (converge, upload, bootstrap, run, apply) into
multitasks. This will make them run in parallel.
# 0.13
* transmit decrypted files with mode 0400
* Use the Omnibus packages from Chef upstream on platforms where we don't have
proper Chef packages from the OS official repository.
# 0.12
* Switch manpage build from ronn to asciidoctor
* Add ability to override the Chef configuration file by setting
`$CHAKE_CHEF_CONFIG` (default: `config.rb`)
* bootstrap: ensure short hostname is in /etc/hosts
# 0.11
* bootstrap: make sure FQDN matches hostname
* Add `rake check` task to check SSH connectivity and sudo setup
* Add tasks to apply a single recipe to nodes: `rake apply[recipe]` and `rake
apply:$NODE[recipe]`. If `[recipe]` is not passed in the command line, the
user is prompted for the recipe name.
* run task changed to have the same interface and behavior as the new apply
task: `rake run[command]`, or `rake run:$NODE[command]`. If `[command]` is
not passed in the command line, the user is prompted for the command.
# 0.10.2
* Fix check for modified files at the upload phase. Now chake will properly
avoiding rsync calls when there is no changed files since the latest upload.
* Fix generated RPM spec file. Will now properly build, install, and work under
both CentOS 7 and Fedora 22+.
* Collect test coverage statistics when running tests.
* Added dependency on simplecov
# 0.10.1
* actually implement support for custom ports in Node URL's. Despite being
documented, that didn't actually work until now.
# 0.10
* Add hook functionality. See README/manpage for documentation.
* README.md: a few reviews
# 0.9.1
* fix manpage installation path
# 0.9
* fix build step for obs uploads
* add infrastructure to build and install a manpage
* Add support for a nodes.d/ directory; very useful when dealing with a larger
amount of nodes.
# 0.8
* gemspec: minor improvements in the long description
* LICENSE.txt: fixed license name
* run: print small message before prompting
* Add history support for the `run` tasks
* Abort `run` tasks if no command is provided
# 0.7
* gemspec: improve summary and description
* Also for encrypted files under $cookbook/files/, and not only under
$cookbook/files/\*/.
* Allow overriding tmpdir with `$CHAKE_TMPDIR`
* Stop cloud-init from resetting the hostname
# 0.6
* Support a ssh prefix command by setting `$CHAKE_SSH_PREFIX` in the
environment. For example, `CHAKE_SSH_PREFIX=tsocks` will make all ssh
invocations as `tocks ssh ...` instead of just `ssh ...`.
# 0.5
* Add a task login:$host that you can use to easily log in to any of your
hosts.
# 0.4.3
* When running remote commands as root, run `sudo COMMAND` directly instead of
`sudo sh -c "COMMAND"`. Under over-restrictive sudo setups (i.e. one in which
you cannot run a shell as root), `sudo sh -c "FOO"` will not be allowed.
# 0.4.2
* tmp/chake: create only when actually needed
* Control nodes files with `$CHAKE_NODES`
# 0.4.1
* Don't always assume the local username as the remote username for SSH
connections:
* `user@host`: connect with `user@host`
* `host`: connect with `host` (username will be obtained by SSH itself from
either its configuration files or the current username)
# 0.4.0
* Redesign build of RPM package
* Output of command run on nodes is now aligned
* Change storage of temporary files from .tmp to tmp/chake
* The JSON node attributes files generated in tmp/chake are not readable
* SSH config file can now be controlled with the `$CHAKE_SSH_CONFIG`
environment variable
* Extra options for rsync can now be passed in the `$CHAKE_RSYNC_OPTIONS`
environment variable
* Chake::VERSION is now available in Rakefiles
* update test suite to use new rspec syntax instead the old one which is
obsolete in rspec 3.
* Thanks to Athos Ribeiro.
# 0.3.3
* rsync: exclude cache/ to work with the version of rsync in OSX
# 0.3.2
* Now finally, hopefully, really fix RPM builds
* chake init: rename 'myhost' → 'basics'
* The official home is on gitlab
* Completed basic documentation
# 0.3.1
* Fix setting hostname when bootstrapping
* Rakefile: do not allow releases without a changelog entry
* Now *really* fix RPM builds, hopefully
# 0.3
* Fix RPM build
* bootstrap: set hostname
# 0.2.3
* No functional changes
* Small changes to make chake compatible with Debian 7, and most of the
RPM-based distributions
chake-0.92/chake.gemspec 0000644 0000041 0000041 00000002645 14756133274 015212 0 ustar www-data www-data lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'chake/version'
Gem::Specification.new do |spec|
spec.name = 'chake'
spec.version = Chake::VERSION
spec.authors = ['Antonio Terceiro']
spec.email = ['terceiro@softwarelivre.org']
spec.summary = 'serverless configuration management tool for chef'
spec.description = "chake allows one to manage a number of hosts via SSH by combining chef (solo) and rake. It doesn't require a chef server; all you need is a workstation from where you can SSH into all your hosts. chake automates copying the configuration management repository to the target host (including managing encrypted files), running chef on them, and running arbitrary commands on the hosts."
spec.homepage = 'https://gitlab.com/terceiro/chake'
spec.license = 'MIT'
spec.files = File.read('.manifest').split("\n") + ['.manifest']
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ['lib']
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'ronn-ng'
spec.add_development_dependency 'rspec'
spec.add_development_dependency 'rubocop'
spec.add_development_dependency 'simplecov'
spec.add_dependency 'rake'
spec.metadata['rubygems_mfa_required'] = 'true'
end
chake-0.92/.rubocop_todo.yml 0000644 0000041 0000041 00000002161 14756133274 016062 0 ustar www-data www-data # This configuration was generated by
# `rubocop --auto-gen-config`
# on 2020-03-25 17:43:43 -0300 using RuboCop version 0.52.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
Layout/HeredocIndentation:
Exclude:
- 'lib/chake.rb'
# Offense count: 3
Lint/AmbiguousOperator:
Exclude:
- 'lib/chake.rb'
# Offense count: 1
Lint/InterpolationCheck:
Exclude:
- 'lib/chake.rb'
# Offense count: 1
# Configuration parameters: Blacklist.
# Blacklist: END, (?-mix:EO[A-Z]{1})
Naming/HeredocDelimiterNaming:
Exclude:
- 'lib/chake.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
Exclude:
- 'bin/chake'
chake-0.92/Gemfile 0000644 0000041 0000041 00000000132 14756133274 014052 0 ustar www-data www-data source 'https://rubygems.org'
# Specify your gem's dependencies in chake.gemspec
gemspec
chake-0.92/man/ 0000755 0000041 0000041 00000000000 14756133274 013336 5 ustar www-data www-data chake-0.92/man/.gitignore 0000644 0000041 0000041 00000000024 14756133274 015322 0 ustar www-data www-data chake.1*
chake.adoc
chake-0.92/man/readme2man.sed 0000644 0000041 0000041 00000000225 14756133274 016045 0 ustar www-data www-data # Capitalize section titles
s/^\(##\+\)\(.*\)/\1 \U\2/
# Turn fenced code blocks into 4-space indented blocks
/^```/,/```/ s/^/ /
/^ ```.*/ d
chake-0.92/man/Rakefile 0000644 0000041 0000041 00000002136 14756133274 015005 0 ustar www-data www-data MAIN_MANPAGE = 'man/chake.1'.freeze
OTHER_MANPAGES = %w[
man/chake-chef.7
man/chake-itamae.7
man/chake-itamae-remote.7
man/chake-shell.7
].freeze
MANPAGES = [MAIN_MANPAGE] + OTHER_MANPAGES
task default: :man
task man: MANPAGES
MANPAGES.each do |man|
source = "README#{man.pathmap('%n').sub(/^chake/, '').sub('-', '.')}.md"
file man => [source, 'man/readme2man.sed'] do
sh "sed -f man/readme2man.sed #{source} > #{man}.ronn || (rm -f #{man}.ronn; false)"
sh "ronn --roff #{man}.ronn"
sh "rm -f #{man}.ronn"
sh 'sed', '-i', '-e', 's/\\\\\'/\'/g', man
end
end
task install: MANPAGES do
prefix = ENV['PREFIX'] || (File.exist?('debian/rules') && '/usr') || '/usr/local'
man1 = File.join(*[ENV.fetch('DESTDIR', nil), prefix, 'share/man/man1'].compact)
man7 = File.join(*[ENV.fetch('DESTDIR', nil), prefix, 'share/man/man7'].compact)
target = { '.1' => man1, '.7' => man7 }
sh 'install', '-d', '-m', '0755', man1
sh 'install', '-d', '-m', '0755', man7
MANPAGES.each do |m|
sh 'install', '-m', '0644', m, target[m.pathmap('%x')]
end
end
task :clean do
rm_f MANPAGES
end
chake-0.92/README.itamae.md 0000644 0000041 0000041 00000002624 14756133274 015305 0 ustar www-data www-data chake-itamae(7) -- configure chake nodes with itamae
====================================================
## Description
This configuration manager will run **itamae(1)** against your nodes.
## Configuration
The _itamae_ configuration manager requires one key called `itamae`, and the
value must be a list of strings representing the list of recipes to apply to
the node when converging.
```yaml
host1.mycompany.com:
itamae:
- cookbooks/basic/default.rb
- roles/server.rb
service1:
option1: "here we go"
```
Any extra configuration under `host1.mycompany.com` will be saved to a JSON file
and given to the itamae --node-json option in the command line. For example,
the above configuration will produce a JSON file that looks like this:
```json
{
"itamae": [
"cookbooks/basic.rb",
"roles/server.rb"
]
,
"service1": {
"option1": "here we go"
}
}
```
Inside itamae recipes, you can access those values by using the `node` object.
For example:
```ruby
template "/etc/service1.conf.d/option1.conf" do
variables option1: node["option1"]
end
```
## Bootstrapping
Very little bootstrapping is required for this configuration manager, as itamae
requires no setup on the node site since the Ruby code in the recipes is
interpreted locally and not on the nodes. During bootstrapping, only the node
hostname will be set according to your chake configuration.
## See also
* **chake(1)**
chake-0.92/chake.spec.erb 0000644 0000041 0000041 00000001504 14756133274 015261 0 ustar www-data www-data %define gem_name <%= pkg.name %>
Summary: <%= pkg.summary %>
Name: <%= pkg.name %>
Version: <%= pkg.version %>
Release: 1
Source0: %{name}-%{version}.tar.gz
License: <%= pkg.license %>
Group: Development/Tools
Prefix: %{_prefix}
Vendor: <%= pkg.authors.first %> <<%= pkg.email.first %>>
Url: <%= pkg.homepage %>
BuildArch: noarch
BuildRequires: ruby, rubygems-devel, rubygem-rake, rubygem-bundler
Requires: ruby, rubygem-rake
%description
<%= pkg.description %>
%prep
%setup -n %{name}-%{version}
%build
%{__rm} -rf %{buildroot}
sed -i -e 's#spec.files\s*=.*#spec.files = Dir.glob("**/*")#' %{name}.gemspec
rake bundler:build
%gem_install -n pkg/%{name}-%{version}.gem
%install
cp -a usr %{buildroot}/usr
%clean
rm -rf $RPM_BUILD_ROOT
%files
%{gem_instdir}/
%exclude %{gem_cache}
%{gem_spec}
%{_bindir}/chake
%doc %{gem_docdir}
chake-0.92/README.md 0000644 0000041 0000041 00000030443 14756133274 014046 0 ustar www-data www-data chake(1) -- serverless configuration management tool
========================================
## SYNOPSIS
`chake` init
`chake` [rake arguments]
## Description
chake is a tool that helps you manage multiple hosts without the need for a
central server. Configuration is managed in a local directory, which should
(but doesn't need to) be under version control with **git(1)** or any other
version control system.
Configuration is deployed to managed hosts remotely, either by invoking a
configuration management tool that will connect to them, or by first uploading
the necessary configuration and them remotely running a tool on the hosts.
## Supported configuration managers.
chake supports the following configuration management tools:
* **itamae**: configuration is applied by running the itamae command line tool
on the management host; no configuration needs to be uploaded to the managed
hosts. See chake-itamae(7) for details.
* **shell**: the local repository is copied to the host, and the shell commands
specified in the node configuration is executed from the directory where that
copy is. See chake-shell(7) for details.
* **chef**: the local repository is copied to the host, and **chef-solo** is
executed remotely on the managed host. See chake-chef(7) for details.
Beyond applying configuration management recipes on the hosts, chake also
provides useful tools to manage multiple hosts, such as listing nodes, running
commands against all of them simultaneously, logging in to interactive
shells, and others.
## creating the repository
$ chake init[:configmanager]
This will create an initial directory structure. Some of the files are specific
to your your chosen **configmanager**, which can be one of [SUPPORTED
CONFIGURATION MANAGERS]. The following files, though, will be common to any
usage of chake:
* `nodes.yaml`: where you will list the hosts you will be managing, and what
recipes to apply to each of them.
* `nodes.d`: a directory with multiple files in the same format as nodes.yaml.
All files matching `*.yaml` in it will be added to the list of nodes.
* `Rakefile`: Contains just the `require 'chake'` line. You can augment it with
other tasks specific to your intrastructure.
If you omit _configmanager_, `itamae` will be used by default.
After the repository is created, you can call either `chake` or `rake`, as they
are completely equivalent.
## Managing nodes
Just after you created your repository, the contents of `nodes.yaml` is the
following:
```yaml
host1.mycompany.com:
itamae:
- roles/basic.rb
```
The exact contents depends on the chosen configuration management tool.
You can list your hosts with `rake nodes`:
```
$ rake nodes
host1.mycompany.com ssh
```
To add more nodes, just append to `nodes.yaml`:
```yaml
host1.mycompany.com:
itamae:
- roles/basic.rb
host2.mycompany.com:
itamae:
- roles/basic.rb
```
And chake now knows about your new node:
```
$ rake nodes
host1.mycompany.com ssh
host2.mycompany.com ssh
```
## Preparings nodes to be managed
Nodes have very few initial requirements to be managed with `chake`:
- The node must be accessible via SSH.
- The user you connect to the node must either be `root`, or be allowed to run
`sudo` (in which case `sudo` must be installed).
**A note on password prompts:** every time chake calls ssh on a node, you may
be required to type in your password; every time chake calls sudo on the node,
you may be require to type in your password. For managing one or two nodes this
is probably fine, but for larger numbers of nodes it is not practical. To avoid
password prompts, you can:
- Configure SSH key-based authentication. This is more secure than using passwords.
While you are at it, you also probably want disable password authentication
completely, and only allow key-based authentication
- Configure passwordless `sudo` access for the user you use to connect to your
nodes.
## Checking connectivity and initial host setup
To check whether hosts are correctly configured, you can use the `check` task:
```
$ rake check
```
That will run the the `sudo true` command on each host. If that pass without
you having to type any passwords, it means that:
* you have SSH access to each host; and
* the user you are connecting as has password-less sudo correctly setup.
## Applying configuration
Note that by default all tasks that apply to all hosts will run in parallel,
using rake's support for multitasks. If for some reason you need to prevent
that, you can pass `-j1` (or --jobs=1`) in the rake invocation. Note that by
default rake will only run N+4 tasks in parallel, where N is the number of
cores on the machine you are running it. If you have more than N+4 hosts and
want all of them to be handled in parallel, you might want to pass `-j` (or
`--jobs`), without any number, as the last argument; with that rake will have
no limit on the number of tasks to perform in parallel.
To apply the configuration to all nodes, run
```
$ rake converge
```
To apply the configuration to a single node, run
```
$ rake converge:$NODE
```
To apply a single recipe on all nodes, run
```
$ rake apply[myrecipe]
```
What `recipe` is depends on the configuration manager.
To apply a single recipe on a specific node, run
```
$ rake apply:$NODE[myrecipe]
```
If you don't inform a recipe in the command line, you will be prompted for one.
To run a shell command on all nodes, run
```
$ rake run
```
The above will prompt you for a command, then execute it on all nodes.
To pass the command to run in the command line, use the following syntax:
```
$ rake run[command]
```
If the `command` you want to run contains spaces, or other characters that are
special do the shell, you have to quote them, for example:
```
$ rake run["cat /etc/hostname"]
```
To run a shell command on a specific node, run
```
$ rake run:$NODE[command]
```
As before, if you run just `rake run:$NODE`, you will be prompted for the
command.
To list all existing tasks, run:
```
$ rake -T
```
## Writing configuration management code
As chake supports different configuration management tools, the specifics of
configuration management code depends on the the tool you choose. See the
corresponding documentation.
## The node bootstrapping process
Some of the configuration management tools require some software to be
installed on the managed hosts. When that's the case, chake acts on a node for
the first time, it has to bootstrap it. The bootstrapping process includes
doing the following:
- installing and configuring the needed software
- setting up the hostname
## Node URLs
The keys in the hash that is represented in `nodes.yaml` is a node URL. All
components of the URL but the hostname are optional, so just listing hostnames
is the simplest form of specifying your nodes. Here are all the components of
the node URLs:
```
[connection://][username@]hostname[:port][/path]
```
* `connection`: what to use to connect to the host. `ssh` or `local` (default: `ssh`)
* `username`: user name to connect with (default: the username on your local workstation)
* `hostname`: the hostname to connect to (default: _none_)
* `port`: port number to connect to (default: 22)
* `/path`: where to store the cookbooks at the node (default: `/var/tmp/chef.$USERNAME`)
## Extra features
### Hooks
You can define rake tasks that will be executed before bootstrapping nodes,
before uploading configuration management content to nodes, and before
converging. To do this, you just need to enhance the corresponding tasks:
* `bootstrap_common`: executed before bootstrapping nodes (even if nodes have
already been bootstrapped)
* `upload_common`: executed before uploading content to the node
* `converge_common`: executed before converging (i.e. running chef)
* `connect_common`: executed before doing any action that connects to any of
the hosts. This can be used for example to generate a ssh configuration file
based on the contents of the nodes definition files.
* `connect:HOSTNAME`: executed before doing any action that connects to
`HOSTNAME`.
Example:
```ruby
task :bootstrap_common do
sh './scripts/pre-bootstrap-checks'
end
```
### Encrypted files
`chake` supports encrypted files matching either `\*.gpg` or `\*.asc`. There are
two ways of specicying per-host encrypted files:
1. listing them in the `encrypted` attribute in the node configuration file.
Example:
```yaml
host1.mycompany.com:
itamae:
- roles/basic.rb
encrypted:
- foo.txt.asc
```
2. (deprecated) any files matching
`\*\*/files/{default,host-#{node}}/\*.{asc,gpg}` and
`\*\*/files/\*.{asc,gpg}`, **if** `encrypted` is not defined in the node
configuration.
They will be decrypted with GnuPG before being sent to the node (for the
configuration management tools that required files to be sent), without the
`\*.asc` or `\*.gpg` extension. You can use them to store passwords and other
sensitive information (SSL keys, etc) in the repository together with the rest
of the configuration.
For configuration managers that don't require uploading files to the managed
node, this decryption will happen right before converging or applying single
recipes, and the decrypted files will be wiped right after that.
If you use this feature, make sure that you have the `wipe` program installed.
This way chake will be able to delete the decrypted files in a slightly more
secure way, after being done with them.
### repository-local SSH configuration
If you need special SSH configuration parameters, you can create a file called
`.ssh_config` (or whatever file name you have in the `$CHAKE_SSH_CONFIG`
environment variable, see below for details) in at the root of your repository,
and chake will use it when calling `ssh`.
### Logging in to a host
To easily login to one of your host, just run `rake login:$HOSTNAME`. This will
automatically use the repository-local SSH configuration as above so you don't
have to type `-F .ssh_config` all the time.
### Running all SSH invocations with some prefix command
Some times, you will also want or need to prefix your SSH invocations with some
prefix command in order to e.g. tunnel it through some central exit node. You
can do this by setting `$CHAKE_SSH_PREFIX` on your environment. Example:
```bash
CHAKE_SSH_PREFIX=tsocks rake converge
```
The above will make all SSH invocations to all hosts be called as `tsocks ssh
[...]`
### Converging local host
If you want to manage your local workstation with chake, you can declare a
local node using the "local" connection type, like this (in `nodes.yaml`):
```yaml
local://thunderbolt:
itamae:
- role/workstation.rb
```
To apply the configuration to the local host, you can use the conventional
`rake converge:thunderbolt`, or the special target `rake local`.
When converging all nodes, `chake` will skip nodes that are declared with the
`local://` connection and whose hostname does not match the hostname in the
declaration. For example:
```yaml
local://desktop:
itamae:
- role/workstation.rb
local://laptop:
itamae:
- role/workstation.rb
```
When you run `rake converge` on `desktop`, `laptop` will be skipped, and
vice-versa.
### Accessing node data from your own tasks
It's often useful to be able to run arbitrary commands against the data you
have about nodes. You can use the `Chake.nodes` for that. For example, if you
want to geolocate each of yours hosts:
```ruby
task :geolocate do
Chake.nodes.each do |node|
puts "#{node.hostname}: %s" % `geoiplookup #{node.hostname}`.strip
end
end
```
## Environment variables
* `$CHAKE_SSH_CONFIG`:
Local SSH configuration file. Defaults to `.ssh_config`.
* `$CHAKE_SSH_PREFIX`:
Command to prefix SSH (and rsync over SSH) calls with.
* `$CHAKE_RSYNC_OPTIONS`:
extra options to pass to `rsync`. Useful to e.g. exclude large files from
being upload to each server.
* `$CHAKE_NODES`:
File containing the list of servers to be managed. Default: `nodes.yaml`.
* `$CHAKE_NODES_D`:
Directory containing node definition files servers to be managed. Default: `nodes.d`.
* `$CHAKE_TMPDIR`:
Directory used to store temporary cache files. Default: `tmp/chake`.
* `$CHAKE_CHEF_CONFIG`:
Chef configuration file, relative to the root of the repository. Default: `config.rb`.
## See also
* **rake(1)**
* **chake-itamae(7)**, https://itamae.kitchen/
* **chake-shell(7)**
* **chake-chef(7)**, **chef-solo(1)**, https://docs.chef.io/
chake-0.92/examples/ 0000755 0000041 0000041 00000000000 14756133274 014401 5 ustar www-data www-data chake-0.92/examples/test/ 0000755 0000041 0000041 00000000000 14756133274 015360 5 ustar www-data www-data chake-0.92/examples/test/config.rb 0000644 0000041 0000041 00000000200 14756133274 017142 0 ustar www-data www-data root = __dir__
file_cache_path "#{root}/cache"
cookbook_path "#{root}/cookbooks"
role_path "#{root}/config/roles"
chake-0.92/examples/test/cookbooks/ 0000755 0000041 0000041 00000000000 14756133274 017351 5 ustar www-data www-data chake-0.92/examples/test/cookbooks/example/ 0000755 0000041 0000041 00000000000 14756133274 021004 5 ustar www-data www-data chake-0.92/examples/test/cookbooks/example/files/ 0000755 0000041 0000041 00000000000 14756133274 022106 5 ustar www-data www-data chake-0.92/examples/test/cookbooks/example/files/host-lemur/ 0000755 0000041 0000041 00000000000 14756133274 024205 5 ustar www-data www-data chake-0.92/examples/test/cookbooks/example/files/host-lemur/test.asc 0000644 0000041 0000041 00000001564 14756133274 025662 0 ustar www-data www-data -----BEGIN PGP MESSAGE-----
Version: GnuPG v1
hQIMA5A8ZkAWdYz7AQ//dgQhKXuGS0dY04TXa1cXEtOHYC64LLnoo+UZT/KgnkzI
/IAgLFbAV0Fd9DGLK857qv9fWf/FB5b6loYLPOVEys0mb5aQrqPPFeKwTTXxTJdk
Ts2NvSVfNZx95Igotm/vkKW6/dbGlDfQSOVQMzhvmKOMMpRP+ixqn+G/nwE/0wQG
QXc3UPAe9gBFlI9GWLTafhftwrxXiYeNF8N03W9BUk1OiQqJUmDRK9ZjVe/vbEiZ
iQ689MnF5l+/6gptU0j77QIqk5vEItkl7RISxOS8PDFI+926NV3fZUrRAlu2eDIy
HNMGkcKTjGoPNrj/UzzmqjP3uNQtKoK559cul7uY44QmsEINoFP3HoAOHeVxm1pG
6IG5EY6znwVEYTIVPK21NAPFpfk9yAB53sv6GrtOaYp8FFp+lLHJlPQcOOP51UV9
GqiAuec7Lgr3iy1yaXIBHFlLG0lmZ1OI41zwqh+Z8EF1NC0gFPhGuOJqBGmBbOxy
Wt1IFx1JUHi0f277us9pFbQlcUb8tgFZ0J69epBrod+xWaZQKFwLWsCTN66fKJfp
rqBzRBcNDJwsKOd54v/Cmrws8bwnfB8iNZYuEQdEt9u5TGIZFl4R9k+/pydAQouP
Z95g4vh2ST2ZEeblnbCc2TFY/7j2O+aXyBzX/4+/bM0kZbFjxCNuefU/v3ZnDwXS
QAH+NPQ31IiqMmoETUqHzo1UI+hV9em81Llt2bsbgWULp84LEmzczbjAcMi2EWNt
SzPyJzOLrqEvEYg2O/+bGho=
=Y2iZ
-----END PGP MESSAGE-----
chake-0.92/examples/test/cookbooks/example/files/default/ 0000755 0000041 0000041 00000000000 14756133274 023532 5 ustar www-data www-data chake-0.92/examples/test/cookbooks/example/files/default/test 0000644 0000041 0000041 00000000005 14756133274 024427 0 ustar www-data www-data test
chake-0.92/examples/test/cookbooks/example/recipes/ 0000755 0000041 0000041 00000000000 14756133274 022436 5 ustar www-data www-data chake-0.92/examples/test/cookbooks/example/recipes/default.rb 0000644 0000041 0000041 00000000403 14756133274 024404 0 ustar www-data www-data file '/tmp/chake.test' do
content "It works on #{node[:fqdn]}!\n"
mode '0644'
owner 'root'
group 'root'
end
cookbook_file '/tmp/chake.test.unencrypted' do
source 'test'
mode '0600'
owner 'root'
group 'root'
end
chake-0.92/examples/test/cookbooks/basics/ 0000755 0000041 0000041 00000000000 14756133274 020615 5 ustar www-data www-data chake-0.92/examples/test/cookbooks/basics/recipes/ 0000755 0000041 0000041 00000000000 14756133274 022247 5 ustar www-data www-data chake-0.92/examples/test/cookbooks/basics/recipes/default.rb 0000644 0000041 0000041 00000000031 14756133274 024212 0 ustar www-data www-data package 'openssh-server'
chake-0.92/examples/test/Rakefile 0000644 0000041 0000041 00000000663 14756133274 017032 0 ustar www-data www-data $LOAD_PATH.unshift '../../lib' # this shouldn't be needed when you have chake installed
require 'chake'
manifest = %w[
Rakefile
cookbooks
cookbooks/example
cookbooks/example/recipes
cookbooks/example/recipes/default.rb
cookbooks/example/files
cookbooks/example/files/host-homer
cookbooks/example/files/host-homer/test.asc
config.rb
]
desc 'removes everything'
task :clean do
rm_rf Dir.glob('**/*') - manifest
end
chake-0.92/examples/test/.ssh_config 0000644 0000041 0000041 00000000142 14756133274 017500 0 ustar www-data www-data Host test.local
IdentityFile .vagrant/machines/default/libvirt/private_key
# vim: ft=sshconfig
chake-0.92/examples/test/Vagrantfile 0000644 0000041 0000041 00000000165 14756133274 017547 0 ustar www-data www-data # -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure('2') do |config|
config.vm.box = 'debian/buster64'
end
chake-0.92/.rubocop.yml 0000644 0000041 0000041 00000001463 14756133274 015041 0 ustar www-data www-data inherit_from: .rubocop_todo.yml
AllCops:
NewCops: enable
Exclude:
- pkg/**/*
Layout/LineLength:
Enabled: false
Metrics/AbcSize:
Enabled: false
Metrics/BlockLength:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/PerceivedComplexity:
Enabled: false
Style/Documentation:
Enabled: false
Style/FormatString:
EnforcedStyle: percent
Style/FrozenStringLiteralComment:
Enabled: false
Style/GlobalVars:
Exclude:
- lib/chake.rb
Style/GuardClause:
Enabled: false
Style/HashEachMethods:
Enabled: false
Style/HashTransformKeys:
Enabled: false
Style/HashTransformValues:
Enabled: false
Style/IfUnlessModifier:
Enabled: false
Style/SymbolArray:
Enabled: false
Gemspec/RequiredRubyVersion:
Enabled: false
Gemspec/DeprecatedAttributeAssignment:
Enabled: false