tinychef 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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