knife-solo 0.0.14 → 0.0.15

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.
@@ -1,11 +1,8 @@
1
- require 'pathname'
2
-
3
1
  require 'chef/knife'
4
- require 'chef/config'
5
- require 'chef/cookbook/chefignore'
6
2
 
7
3
  require 'knife-solo/ssh_command'
8
4
  require 'knife-solo/kitchen_command'
5
+ require 'knife-solo/node_config_command'
9
6
  require 'knife-solo/tools'
10
7
 
11
8
  class Chef
@@ -14,13 +11,20 @@ class Chef
14
11
  # Copyright 2009, Trotter Cashion
15
12
  class Cook < Knife
16
13
  OMNIBUS_EMBEDDED_PATHS = ["/opt/chef/embedded/bin", "/opt/opscode/embedded/bin"]
14
+ OMNIBUS_EMBEDDED_GEM_PATHS = ["/opt/chef/embedded/lib/ruby/gems/1.9.1", "/opt/opscode/embedded/lib/ruby/gems/1.9.1"]
17
15
  CHEF_VERSION_CONSTRAINT = ">=0.10.4"
18
16
 
19
17
  include KnifeSolo::SshCommand
20
18
  include KnifeSolo::KitchenCommand
19
+ include KnifeSolo::NodeConfigCommand
21
20
  include KnifeSolo::Tools
22
21
 
23
- class WrongCookError < KnifeSolo::KnifeSoloError; end
22
+ deps do
23
+ require 'chef/cookbook/chefignore'
24
+ require 'pathname'
25
+ KnifeSolo::SshCommand.load_deps
26
+ KnifeSolo::NodeConfigCommand.load_deps
27
+ end
24
28
 
25
29
  banner "knife cook [user@]hostname [json] (options)"
26
30
 
@@ -34,53 +38,25 @@ class Chef
34
38
  :boolean => false,
35
39
  :description => "Only sync the cookbook - do not run Chef"
36
40
 
37
- option :skip_syntax_check,
38
- :long => '--skip-syntax-check',
39
- :boolean => true,
40
- :description => "Skip Ruby syntax checks"
41
+ option :why_run,
42
+ :short => '-W',
43
+ :long => '--why-run',
44
+ :boolean => true,
45
+ :description => "Enable whyrun mode"
41
46
 
42
- option :syntax_check_only,
43
- :long => '--syntax-check-only',
44
- :boolean => true,
45
- :description => "Only run syntax checks - do not run Chef"
46
-
47
47
  def run
48
48
  time('Run') do
49
49
  validate_params!
50
50
  super
51
- check_syntax unless config[:skip_syntax_check]
52
- return if config[:syntax_check_only]
53
51
  Chef::Config.from_file('solo.rb')
54
52
  check_chef_version unless config[:skip_chef_check]
53
+ generate_node_config
55
54
  rsync_kitchen
56
55
  add_patches
57
56
  cook unless config[:sync_only]
58
57
  end
59
58
  end
60
59
 
61
- def check_syntax
62
- ui.msg('Checking cookbook syntax...')
63
- chefignore.remove_ignores_from(Dir["**/*.rb"]).each do |recipe|
64
- ok = system "ruby -c #{recipe} >/dev/null 2>&1"
65
- raise "Syntax error in #{recipe}" if not ok
66
- end
67
-
68
- chefignore.remove_ignores_from(Dir["**/*.json"]).each do |json|
69
- begin
70
- require 'json'
71
- # parse without instantiating Chef classes
72
- JSON.parse File.read(json), :create_additions => false
73
- rescue => error
74
- raise "Syntax error in #{json}: #{error.message}"
75
- end
76
- end
77
- Chef::Log.info "cookbook and json syntax is ok"
78
- end
79
-
80
- def node_config
81
- @name_args[1] || super
82
- end
83
-
84
60
  def chef_path
85
61
  Chef::Config.file_cache_path
86
62
  end
@@ -103,26 +79,30 @@ class Chef
103
79
  (%w{revision-deploys tmp '.*'} + chefignore.ignores).uniq
104
80
  end
105
81
 
82
+ def debug?
83
+ config[:verbosity] and config[:verbosity] > 0
84
+ end
85
+
106
86
  # Time a command
107
87
  def time(msg)
108
- return yield if config[:verbosity] == 0
109
- puts "Starting #{msg}"
88
+ return yield unless debug?
89
+ ui.msg "Starting '#{msg}'"
110
90
  start = Time.now
111
91
  yield
112
- puts "#{msg} finished in #{Time.now - start} seconds"
92
+ ui.msg "#{msg} finished in #{Time.now - start} seconds"
113
93
  end
114
94
 
115
95
  def rsync_kitchen
116
96
  time('Rsync kitchen') do
117
97
  cmd = %Q{rsync -rl --rsh="ssh #{ssh_args}" --delete #{rsync_exclude.collect{ |ignore| "--exclude #{ignore} " }.join} ./ :#{adjust_rsync_path(chef_path)}}
118
- puts cmd unless config[:verbosity] == 0
98
+ ui.msg cmd if debug?
119
99
  system! cmd
120
100
  end
121
101
  end
122
102
 
123
103
  def add_patches
124
104
  run_portable_mkdir_p(patch_path)
125
- Dir[Pathname.new(__FILE__).dirname.join("patches", "*.rb")].each do |patch|
105
+ Dir[Pathname.new(__FILE__).dirname.join("patches", "*.rb").to_s].each do |patch|
126
106
  time(patch) do
127
107
  system! %Q{rsync -rl --rsh="ssh #{ssh_args}" #{patch} :#{adjust_rsync_path(patch_path)}}
128
108
  end
@@ -130,28 +110,28 @@ class Chef
130
110
  end
131
111
 
132
112
  def check_chef_version
133
- ui.msg('Checking Chef version')
113
+ ui.msg "Checking Chef version..."
134
114
  result = run_command <<-BASH
135
115
  export PATH="#{OMNIBUS_EMBEDDED_PATHS.join(":")}:$PATH"
116
+ export GEM_PATH="#{OMNIBUS_EMBEDDED_GEM_PATHS.join(":")}:$GEM_PATH"
136
117
  ruby -rubygems -e "gem 'chef', '#{CHEF_VERSION_CONSTRAINT}'"
137
118
  BASH
138
119
  raise "Couldn't find Chef #{CHEF_VERSION_CONSTRAINT} on #{host}. Please run `#{$0} prepare #{ssh_args}` to ensure Chef is installed and up to date." unless result.success?
139
120
  end
140
-
121
+
141
122
  def cook
142
- logging_arg = "-l debug" if config[:verbosity] > 0
123
+ cmd = "sudo chef-solo -c #{chef_path}/solo.rb -j #{chef_path}/#{node_config}"
124
+ cmd << " -l debug" if debug?
125
+ cmd << " -N #{config[:chef_node_name]}" if config[:chef_node_name]
126
+ cmd << " -W" if config[:why_run]
143
127
 
144
- stream_command <<-BASH
145
- sudo chef-solo -c #{chef_path}/solo.rb \
146
- -j #{chef_path}/#{node_config} \
147
- #{logging_arg}
148
- BASH
128
+ stream_command cmd
149
129
  end
150
130
 
151
131
  def validate_params!
152
- validate_first_cli_arg_is_a_hostname!(WrongCookError)
132
+ validate_first_cli_arg_is_a_hostname!
153
133
  end
154
-
134
+
155
135
  end
156
136
  end
157
137
  end
@@ -5,16 +5,41 @@ class Chef
5
5
  class Kitchen < Knife
6
6
  include FileUtils
7
7
 
8
+ deps do
9
+ require 'knife-solo/knife_solo_error'
10
+ end
11
+
8
12
  banner "knife kitchen NAME or initialize current directory with '.'"
9
13
 
10
14
  def run
11
- name = @name_args.first
12
- mkdir name if name != '.'
13
- %w(nodes roles data_bags site-cookbooks cookbooks).each do |dir|
14
- mkdir name + "/#{dir}"
15
- touch name + "/#{dir}/.gitkeep"
15
+ raise KnifeSolo::KnifeSoloError.new(banner) unless base = @name_args.first
16
+
17
+ create_kitchen base
18
+ create_cupboards base, %w(nodes roles data_bags site-cookbooks cookbooks)
19
+ create_solo_config base
20
+ end
21
+
22
+ private
23
+
24
+ def create_cupboards(base, dirs)
25
+ dirs.each do |dir|
26
+ cupboard_dir = File.join(base, dir)
27
+ unless File.exist?(cupboard_dir)
28
+ mkdir cupboard_dir
29
+ touch File.join(cupboard_dir, '.gitkeep')
30
+ end
16
31
  end
17
- File.open(name + "/solo.rb", 'w') do |f|
32
+ end
33
+
34
+ def create_kitchen(base)
35
+ mkdir base unless base == '.'
36
+ end
37
+
38
+ def create_solo_config(base)
39
+ solo_file = File.join(base, 'solo.rb')
40
+ return if File.exist? solo_file
41
+
42
+ File.open(solo_file, 'w') do |f|
18
43
  f << <<-RUBY.gsub(/^ {12}/, '')
19
44
  file_cache_path "/tmp/chef-solo"
20
45
  data_bag_path "/tmp/chef-solo/data_bags"
@@ -1,8 +1,7 @@
1
1
  require 'chef/knife'
2
2
  require 'knife-solo/ssh_command'
3
3
  require 'knife-solo/kitchen_command'
4
- require 'knife-solo/bootstraps'
5
- require 'knife-solo/knife_solo_error'
4
+ require 'knife-solo/node_config_command'
6
5
 
7
6
  class Chef
8
7
  class Knife
@@ -11,12 +10,15 @@ class Chef
11
10
  class Prepare < Knife
12
11
  include KnifeSolo::SshCommand
13
12
  include KnifeSolo::KitchenCommand
13
+ include KnifeSolo::NodeConfigCommand
14
14
 
15
- class WrongPrepareError < KnifeSolo::KnifeSoloError
16
- alias :message :to_s
15
+ deps do
16
+ require 'knife-solo/bootstraps'
17
+ KnifeSolo::SshCommand.load_deps
18
+ KnifeSolo::NodeConfigCommand.load_deps
17
19
  end
18
20
 
19
- banner "knife prepare [user@]hostname (options)"
21
+ banner "knife prepare [user@]hostname [json] (options)"
20
22
 
21
23
  option :omnibus_version,
22
24
  :long => "--omnibus-version VERSION",
@@ -38,23 +40,16 @@ class Chef
38
40
  end
39
41
 
40
42
  def bootstrap
43
+ ui.msg "Bootstrapping Chef..."
41
44
  KnifeSolo::Bootstraps.class_for_operating_system(operating_system()).new(self)
42
45
  end
43
46
 
44
- def generate_node_config
45
- File.open(node_config, 'w') do |f|
46
- f.print <<-JSON.gsub(/^\s+/, '')
47
- { "run_list": [] }
48
- JSON
49
- end unless node_config.exist?
50
- end
51
-
52
47
  def operating_system
53
48
  @operating_system ||= run_command('uname -s').stdout.strip
54
49
  end
55
50
 
56
51
  def validate_params!
57
- validate_first_cli_arg_is_a_hostname!(WrongPrepareError)
52
+ validate_first_cli_arg_is_a_hostname!
58
53
  end
59
54
  end
60
55
  end
@@ -11,6 +11,7 @@ class Chef
11
11
  banner "knife wash_up [user@]hostname"
12
12
 
13
13
  def run
14
+ validate_first_cli_arg_is_a_hostname!
14
15
  super
15
16
  Chef::Config.from_file('solo.rb')
16
17
  run_command "rm -rf #{Chef::Config.file_cache_path}"
@@ -66,7 +66,7 @@ module KnifeSolo
66
66
  end
67
67
 
68
68
  def omnibus_install
69
- url = prepare.config[:omnibus_url] || "http://opscode.com/chef/install.sh"
69
+ url = prepare.config[:omnibus_url] || "https://www.opscode.com/chef/install.sh"
70
70
  file = File.basename(url)
71
71
  http_client_get_url(url, file)
72
72
  # `release_version` within install.sh will be installed if
@@ -78,13 +78,20 @@ module KnifeSolo
78
78
  stream_command(install_command)
79
79
  end
80
80
 
81
- def ubuntu_omnibus_install
81
+ def yum_omnibus_install
82
+ omnibus_install
83
+ # Make sure we have rsync on builds that don't include it by default
84
+ # (for example Scientific Linux minimal)
85
+ run_command("sudo yum -y install rsync")
86
+ end
87
+
88
+ def debianoid_omnibus_install
82
89
  omnibus_install
83
90
  # Update to avoid out-of-date package caches
84
91
  run_command("sudo apt-get update")
85
92
  # Make sure we have rsync on builds that don't include it by default
86
- # (observed on linode's ubuntu 10.04 images)
87
- run_command("sudo apt-get install rsync")
93
+ # (for example linode's ubuntu 10.04 images)
94
+ run_command("sudo apt-get -y install rsync")
88
95
  end
89
96
 
90
97
  def gem_install
@@ -5,6 +5,11 @@ module KnifeSolo::Bootstraps
5
5
  prepare.run_command("cat /etc/issue").stdout.strip || perepare.run_command("lsb_release -d -s").stdout.strip
6
6
  end
7
7
 
8
+ def x86?
9
+ machine = run_command('uname -m').stdout.strip
10
+ %w{i686 x86 x86_64}.include?(machine)
11
+ end
12
+
8
13
  def package_list
9
14
  @packages.join(' ')
10
15
  end
@@ -68,14 +73,14 @@ module KnifeSolo::Bootstraps
68
73
  return @distro if @distro
69
74
  @distro = case issue
70
75
  when %r{Debian GNU/Linux 5}
71
- {:type => "omnibus", :version => "lenny"}
76
+ {:type => if x86? then "debianoid_omnibus" else "debian_gem" end, :version => "lenny"}
72
77
  when %r{Debian GNU/Linux 6}
73
- {:type => "omnibus", :version => "squeeze"}
78
+ {:type => if x86? then "debianoid_omnibus" else "debian_gem" end, :version => "squeeze"}
74
79
  when %r{Debian GNU/Linux wheezy}
75
80
  {:type => "debian_gem", :version => "wheezy"}
76
81
  when %r{Ubuntu}i
77
82
  version = run_command("lsb_release -cs").stdout.strip
78
- {:type => "ubuntu_omnibus", :version => version}
83
+ {:type => if x86? then "debianoid_omnibus" else "debian_gem" end, :version => version}
79
84
  when %r{Linaro}
80
85
  version = run_command("lsb_release -cs").stdout.strip
81
86
  {:type => "debian_gem", :version => version}
@@ -94,7 +99,7 @@ module KnifeSolo::Bootstraps
94
99
  when %r{Scientific Linux.*? 5}
95
100
  {:type => "omnibus", :version => "RHEL5"}
96
101
  when %r{Scientific Linux.*? 6}
97
- {:type => "omnibus", :version => "RHEL6"}
102
+ {:type => "yum_omnibus", :version => "RHEL6"}
98
103
  when %r{SUSE Linux Enterprise Server 11 SP1}
99
104
  {:type => "zypper_gem", :version => "SLES11"}
100
105
  when %r{openSUSE 11.4}
@@ -1,5 +1,5 @@
1
1
  module KnifeSolo
2
2
  def self.version
3
- '0.0.14'
3
+ '0.0.15'
4
4
  end
5
5
  end
@@ -25,19 +25,7 @@ module KnifeSolo
25
25
  end
26
26
 
27
27
  def warn_for_required_file(file)
28
- Chef::Log.warn "#{file} is a required file/directory"
28
+ ui.error "#{file} is a required file/directory"
29
29
  end
30
-
31
- def first_cli_arg_is_a_hostname?
32
- @name_args.first =~ /\A([^@]+(?>@)[^@]+|[^@]+?(?!@))\z/
33
- end
34
-
35
- def validate_first_cli_arg_is_a_hostname!(error_class)
36
- unless first_cli_arg_is_a_hostname?
37
- ui.msg opt_parser.help
38
- raise error_class.new "need to pass atleast a [user@]hostname as the first argument"
39
- end
40
- end
41
-
42
30
  end
43
31
  end
@@ -0,0 +1,40 @@
1
+ module KnifeSolo
2
+ module NodeConfigCommand
3
+
4
+ def self.load_deps
5
+ require 'pathname'
6
+ end
7
+
8
+ def self.included(other)
9
+ other.class_eval do
10
+ # Lazy load our dependencies if the including class did not call
11
+ # Knife#deps yet. See KnifeSolo::SshCommand for more information.
12
+ deps { KnifeSolo::NodeConfigCommand.load_deps } unless @dependency_loader
13
+
14
+ option :chef_node_name,
15
+ :short => "-N NAME",
16
+ :long => "--node-name NAME",
17
+ :description => "The Chef node name for your new node"
18
+ end
19
+ end
20
+
21
+ def node_config
22
+ # host method must be defined by the including class
23
+ Pathname.new(@name_args[1] || "nodes/#{config[:chef_node_name] || host}.json")
24
+ end
25
+
26
+ def generate_node_config
27
+ if node_config.exist?
28
+ Chef::Log.debug "Node config '#{node_config}' already exists"
29
+ else
30
+ ui.msg "Generating node config '#{node_config}'..."
31
+ File.open(node_config, 'w') do |f|
32
+ f.print <<-JSON.gsub(/^\s+/, '')
33
+ { "run_list": [] }
34
+ JSON
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -1,12 +1,26 @@
1
- require 'pathname'
2
-
3
1
  module KnifeSolo
4
2
  module SshCommand
3
+
4
+ def self.load_deps
5
+ require 'knife-solo/knife_solo_error'
6
+ require 'net/ssh'
7
+ end
8
+
5
9
  def self.included(other)
6
- other.instance_eval do
7
- deps do
8
- require 'net/ssh'
9
- end
10
+ other.class_eval do
11
+ # Lazy load our dependencies if the including class did not call
12
+ # Knife#deps yet. Later calls to #deps override previous ones, so if
13
+ # the outer class calls it, it should also call our #load_deps, i.e:
14
+ #
15
+ # Include KnifeSolo::SshCommand
16
+ #
17
+ # dep do
18
+ # require 'foo'
19
+ # require 'bar'
20
+ # KnifeSolo::SshCommand.load_deps
21
+ # end
22
+ #
23
+ deps { KnifeSolo::SshCommand.load_deps } unless @dependency_loader
10
24
 
11
25
  option :ssh_config,
12
26
  :short => "-F CONFIG_FILE",
@@ -35,8 +49,15 @@ module KnifeSolo
35
49
  end
36
50
  end
37
51
 
38
- def node_config
39
- Pathname.new("nodes/#{host}.json")
52
+ def first_cli_arg_is_a_hostname?
53
+ @name_args.first =~ /\A([^@]+(?>@)[^@]+|[^@]+?(?!@))\z/
54
+ end
55
+
56
+ def validate_first_cli_arg_is_a_hostname!
57
+ unless first_cli_arg_is_a_hostname?
58
+ ui.msg opt_parser.help
59
+ raise KnifeSoloError.new "need to pass atleast a [user@]hostname as the first argument"
60
+ end
40
61
  end
41
62
 
42
63
  def host_descriptor
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-solo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
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-09-22 00:00:00.000000000 Z
12
+ date: 2012-11-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -116,6 +116,7 @@ files:
116
116
  - lib/knife-solo/info.rb
117
117
  - lib/knife-solo/kitchen_command.rb
118
118
  - lib/knife-solo/knife_solo_error.rb
119
+ - lib/knife-solo/node_config_command.rb
119
120
  - lib/knife-solo/ssh_command.rb
120
121
  - lib/knife-solo/tools.rb
121
122
  - lib/knife-solo.rb
@@ -131,18 +132,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
131
132
  - - ! '>='
132
133
  - !ruby/object:Gem::Version
133
134
  version: '0'
134
- segments:
135
- - 0
136
- hash: 3414347062334937427
137
135
  required_rubygems_version: !ruby/object:Gem::Requirement
138
136
  none: false
139
137
  requirements:
140
138
  - - ! '>='
141
139
  - !ruby/object:Gem::Version
142
140
  version: '0'
143
- segments:
144
- - 0
145
- hash: 3414347062334937427
146
141
  requirements: []
147
142
  rubyforge_project: nowarning
148
143
  rubygems_version: 1.8.24