tinychef 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
4
 
5
5
  require 'optparse'
6
6
  require 'tinychef'
7
+ require 'tinychef/commands'
7
8
 
8
9
  parser = OptionParser.new do |opts|
9
10
  opts.banner = "Usage: tinychef COMMAND [ARGS]"
@@ -23,6 +24,7 @@ parser = OptionParser.new do |opts|
23
24
  opts.separator " bag:create NAME Creates an empty databag"
24
25
  opts.separator " bag:encrypt NAME Encrypts a databag"
25
26
  opts.separator " bag:decrypt NAME Decrypts a databag"
27
+ opts.separator " key:generate Generate a new random key"
26
28
  opts.separator " key:lock Lock the key with a password"
27
29
  opts.separator " key:unlock Unlock the key for a work session"
28
30
  opts.separator " secure Remove all unsecure files from this folder"
@@ -34,35 +36,24 @@ end
34
36
 
35
37
  parser.parse!
36
38
 
39
+ include Tinychef::Commands
40
+
37
41
  begin
38
42
  case ARGV[0]
39
- when 'new'
40
- Tinychef::NewDirectory.new(ARGV[1]).write
41
- when 'boot'
42
- when 'bag:create'
43
- when 'bag:encrypt'
44
- when 'bag:decrypt'
45
- when 'key:lock'
46
- when 'key:unlock'
47
- when 'secure'
48
- when 'unsecure'
49
- when 'run'
50
- options = {}
51
-
52
- options[:node] = ARGV[1]
53
-
54
- if ARGV.size == 3 # assume the destination is not given
55
- options[:dest] = nil ; options[:run_list] = ARGV[2]
56
- else
57
- options[:dest] = ARGV[2] ; options[:run_list] = ARGV[3]
58
- end
59
-
60
- Tinychef::NodeRun.new(options).start
43
+ when 'new' then new_command
44
+ when 'boot' then boot_command
45
+ when 'bag:create' then bag_create_command
46
+ when 'bag:encrypt' then bag_encrypt_command
47
+ when 'bag:decrypt' then bag_decrypt_command
48
+ when 'key:generate' then key_generate_command
49
+ when 'key:lock' then key_lock_command
50
+ when 'key:unlock' then key_unlock_command
51
+ when 'secure' then secure_command
52
+ when 'unsecure' then unsecure_command
53
+ when 'run' then run_command
61
54
  else
62
55
  puts parser.help
63
56
  end
64
- rescue Tinychef::NodeRun::OptionsError => e
57
+ rescue Tinychef::OptionsError, RuntimeError => e
65
58
  abort e.message
66
-
67
-
68
59
  end
@@ -1,5 +1,14 @@
1
+ require 'rubygems'
2
+ require 'chef/encrypted_data_bag_item'
3
+ require 'pp'
4
+
1
5
  require "tinychef/version"
6
+ require 'tinychef/key'
7
+ require 'tinychef/data_bag'
8
+ require 'tinychef/boot_script'
9
+ require 'tinychef/node_run'
2
10
 
3
- module Tinychef; end
11
+ module Tinychef
12
+ class OptionsError < Exception; end
13
+ end
4
14
 
5
- require 'tinychef/node_run'
@@ -0,0 +1,58 @@
1
+ require 'pathname'
2
+ require 'tinychef/node'
3
+ require 'tinychef/destination'
4
+
5
+ module Tinychef
6
+ class BootScript
7
+
8
+ OPTIONS_ERROR = <<-EOH
9
+ Required arguments:
10
+
11
+ DEST: ssh username@host string to use to connect to host.
12
+ SCRIPT: optional path to the boot script (boot.sh by default).
13
+ You must craft your Chef Solo boot script by yourself,
14
+ something like this: https://gist.github.com/3153784
15
+
16
+ EOH
17
+
18
+ attr_reader :dest, :script
19
+
20
+ def initialize(dest, script)
21
+ script ||= 'boot.sh'
22
+
23
+ begin
24
+ @dest = Tinychef::Destination.new(dest)
25
+ @script = Pathname.new(script)
26
+ rescue => e
27
+ raise OptionsError.new BootScript::OPTIONS_ERROR
28
+ end
29
+
30
+ file_check
31
+ end
32
+
33
+ def run
34
+ push_to_remote
35
+ execute_remote
36
+ end
37
+
38
+ private
39
+
40
+ def file_check
41
+ unless script.exist?
42
+ raise RuntimeError.new "File #{script} not found. Craft your boot script, something like this: https://gist.github.com/3153784"
43
+ end
44
+ unless script.extname == '.sh'
45
+ raise RuntimeError.new "File must be a shell script (.sh extension please)"
46
+ end
47
+ end
48
+
49
+ def push_to_remote
50
+ system %Q{ scp #{script} #{dest}: }
51
+ end
52
+
53
+ def execute_remote
54
+ system %Q{ ssh -t #{dest} "sh #{script.basename}" }
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,61 @@
1
+ module Tinychef
2
+ module Commands
3
+
4
+ def new_command
5
+ dir_name = ARGV[1]
6
+ Tinychef::NewDirectory.new(dir_name).create
7
+ end
8
+
9
+ def boot_command
10
+ dest = ARGV[1] ; script = ARGV[2]
11
+ Tinychef::BootScript.new(dest, script).run
12
+ end
13
+
14
+ def bag_create_command
15
+ recipe = ARGV[1] ; name = ARGV[2]
16
+ Tinychef::DataBag.new(recipe, name).create
17
+ end
18
+
19
+ def bag_encrypt_command
20
+ recipe = ARGV[1] ; name = ARGV[2]
21
+ Tinychef::DataBag.new(recipe, name).encrypt
22
+ end
23
+
24
+ def bag_decrypt_command
25
+ recipe = ARGV[1] ; name = ARGV[2]
26
+ Tinychef::DataBag.new(recipe, name).decrypt
27
+ end
28
+
29
+ def key_lock_command
30
+ Tinychef::Key.new(ARGV[1]).password_protect
31
+ end
32
+
33
+ def key_unlock_command
34
+ Tinychef::Key.new(ARGV[1]).unlock_and_restore
35
+ end
36
+
37
+ def key_generate_command
38
+ Tinychef::Key.new(ARGV[1]).generate
39
+ end
40
+
41
+ def secure_command
42
+ end
43
+
44
+ def unsecure_command
45
+ end
46
+
47
+ def run_command
48
+ options = {}
49
+
50
+ options[:node] = ARGV[1]
51
+
52
+ if ARGV.size == 3 # assume the destination is not given
53
+ options[:dest] = nil ; options[:run_list] = ARGV[2]
54
+ else
55
+ options[:dest] = ARGV[2] ; options[:run_list] = ARGV[3]
56
+ end
57
+
58
+ Tinychef::NodeRun.new(options).start
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,80 @@
1
+ module Tinychef
2
+ class DataBag
3
+
4
+ OPTIONS_ERROR = <<-EOH
5
+ Required arguments:
6
+
7
+ RECIPE: Databags must be archived under the name of a recipe.
8
+ NAME: Name of this databag.
9
+
10
+ EOH
11
+
12
+ attr_reader :recipe, :name, :ruby_name, :ruby_path, :json_name, :json_path
13
+
14
+ def initialize(recipe, name)
15
+
16
+ if recipe.nil? || name.nil?
17
+ raise OptionsError.new OPTIONS_ERROR
18
+ end
19
+
20
+ @name = name
21
+ @ruby_name = "#{name}.rb"
22
+ @json_name = "#{name}.json"
23
+ @recipe = recipe
24
+
25
+ @dir = Pathname.new(File.join('data_bags', @recipe))
26
+
27
+ @ruby_path = @dir.join @ruby_name
28
+ @json_path = @dir.join @json_name
29
+ end
30
+
31
+ def create
32
+ prepare_dir
33
+ create_empty_file
34
+ end
35
+
36
+ def decrypt
37
+ data = JSON.parse File.read(json_path)
38
+ secret = Chef::EncryptedDataBagItem.load_secret( key.path )
39
+ encrypted_data = Chef::EncryptedDataBagItem.new(data, secret)
40
+ new_hash = {}
41
+ data.keys.each do |key|
42
+ new_hash[key] = encrypted_data[key]
43
+ end
44
+ file = File.open ruby_path, 'w'
45
+ file.write new_hash.inspect
46
+ file.close
47
+ end
48
+
49
+ def encrypt
50
+ data = eval File.read(ruby_path)
51
+ secret = Chef::EncryptedDataBagItem.load_secret( key.path )
52
+ encrypted_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(data, secret)
53
+ file = File.open json_path, 'w'
54
+ file.write encrypted_data.to_json
55
+ file.close
56
+ end
57
+
58
+ private
59
+
60
+ def key
61
+ Tinychef::Key.new
62
+ end
63
+
64
+ def prepare_dir
65
+ dir = Pathname.new(File.join 'data_bags', recipe)
66
+ dir.mkpath unless dir.exist?
67
+ end
68
+
69
+ def create_empty_file
70
+ if ruby_path.exist?
71
+ RuntimeError.new 'File #{ruby_path.to_s} already exists.'
72
+ else
73
+ file = File.new ruby_path, 'a'
74
+ file.write %Q^{ "id" => "#{name}" }^
75
+ file.close
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,39 @@
1
+ module Tinychef
2
+ class Key
3
+
4
+ OPTIONS_ERROR = <<-EOH
5
+ Required arguments:
6
+
7
+ NAME: the name of the secret file.
8
+
9
+ EOH
10
+
11
+ attr_reader :name, :path
12
+
13
+ def initialize(name='secret')
14
+ raise if name.nil?
15
+
16
+ @name = name
17
+ @path = Pathname.new "#{name}.key"
18
+ rescue
19
+ raise OptionsError.new OPTIONS_ERROR
20
+ end
21
+
22
+ def password_protect
23
+ system "openssl aes-256-cbc -salt -in #{path} -out #{path}.aes"
24
+ end
25
+
26
+ def unlock_and_restore
27
+ system "openssl aes-256-cbc -d -salt -in #{path}.aes -out #{path}"
28
+ end
29
+
30
+ def generate
31
+ if path.exist?
32
+ raise RuntimeError.new "File #{path} exists."
33
+ else
34
+ system "openssl rand -base64 512 | tr -d '\r\n' > #{path}"
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -1,6 +1,29 @@
1
+ require 'pathname'
2
+
1
3
  module Tinychef
2
4
  class NewDirectory
3
- def initialize
5
+
6
+ DIR_MAP = {
7
+ 'cookbooks' => nil,
8
+ 'data_bags' => nil,
9
+ 'imported_cookbooks' => nil,
10
+ 'nodes' => nil,
11
+ 'roles' => nil,
12
+ 'vendor' => nil,
13
+ }
14
+
15
+ attr_reader :path
16
+
17
+ def initialize(name)
18
+ @path = Pathname.new(name)
19
+ end
20
+
21
+ def create
22
+ path.mkpath unless path.exist?
23
+
24
+ DIR_MAP.each do |key, value|
25
+ path.join(key).mkpath
26
+ end
4
27
  end
5
28
  end
6
29
  end
@@ -1,13 +1,11 @@
1
1
  require 'tinychef/node'
2
2
  require 'tinychef/destination'
3
+ require 'tinychef/new_directory'
3
4
 
4
5
  module Tinychef
5
6
  class NodeRun
6
7
 
7
- class OptionsError < Exception
8
- def initialize
9
- super <<-EOH
10
-
8
+ OPTIONS_ERROR = <<-EOH
11
9
  Required arguments:
12
10
 
13
11
  NODE: node file to execute
@@ -15,11 +13,9 @@ Required arguments:
15
13
  If missing, this is guessed by the node file name.
16
14
  RUN_LIST: an optional RUN_LIST to be passed to chef-solo executable.
17
15
 
18
- EOH
19
- end
20
- end
16
+ EOH
21
17
 
22
- RECIPES_DIR="recipes"
18
+ RECIPES_DIR = "recipes"
23
19
 
24
20
  attr_reader :dest, :node, :run_list, :run_list_command
25
21
 
@@ -36,8 +32,7 @@ Required arguments:
36
32
  prepare_run_list_command
37
33
 
38
34
  rescue => e
39
- puts e.inspect
40
- raise OptionsError
35
+ raise OptionsError.new NodeRun::OPTIONS_ERROR
41
36
  end
42
37
 
43
38
  def start
@@ -1,3 +1,3 @@
1
1
  module Tinychef
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tinychef
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-29 00:00:00.000000000 Z
12
+ date: 2012-12-30 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Simple command line tool for Chef Solo recipes
15
15
  email:
@@ -26,7 +26,11 @@ files:
26
26
  - Rakefile
27
27
  - bin/tinychef
28
28
  - lib/tinychef.rb
29
+ - lib/tinychef/boot_script.rb
30
+ - lib/tinychef/commands.rb
31
+ - lib/tinychef/data_bag.rb
29
32
  - lib/tinychef/destination.rb
33
+ - lib/tinychef/key.rb
30
34
  - lib/tinychef/new_directory.rb
31
35
  - lib/tinychef/node.rb
32
36
  - lib/tinychef/node_run.rb