knife-solo 0.0.14 → 0.0.15

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