chef-provisioning 2.0.0 → 2.0.1

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +899 -885
  3. data/Gemfile +17 -17
  4. data/LICENSE +201 -201
  5. data/README.md +312 -312
  6. data/Rakefile +55 -55
  7. data/chef-provisioning.gemspec +38 -38
  8. data/lib/chef/provider/load_balancer.rb +75 -75
  9. data/lib/chef/provider/machine.rb +219 -219
  10. data/lib/chef/provider/machine_batch.rb +224 -224
  11. data/lib/chef/provider/machine_execute.rb +36 -35
  12. data/lib/chef/provider/machine_file.rb +55 -55
  13. data/lib/chef/provider/machine_image.rb +105 -105
  14. data/lib/chef/provisioning.rb +110 -110
  15. data/lib/chef/provisioning/action_handler.rb +68 -68
  16. data/lib/chef/provisioning/add_prefix_action_handler.rb +35 -35
  17. data/lib/chef/provisioning/chef_managed_entry_store.rb +128 -128
  18. data/lib/chef/provisioning/chef_provider_action_handler.rb +74 -74
  19. data/lib/chef/provisioning/chef_run_data.rb +132 -132
  20. data/lib/chef/provisioning/convergence_strategy.rb +28 -28
  21. data/lib/chef/provisioning/convergence_strategy/ignore_convergence_failure.rb +54 -54
  22. data/lib/chef/provisioning/convergence_strategy/install_cached.rb +188 -188
  23. data/lib/chef/provisioning/convergence_strategy/install_msi.rb +71 -71
  24. data/lib/chef/provisioning/convergence_strategy/install_sh.rb +71 -71
  25. data/lib/chef/provisioning/convergence_strategy/no_converge.rb +35 -35
  26. data/lib/chef/provisioning/convergence_strategy/precreate_chef_objects.rb +255 -255
  27. data/lib/chef/provisioning/driver.rb +323 -323
  28. data/lib/chef/provisioning/load_balancer_spec.rb +14 -14
  29. data/lib/chef/provisioning/machine.rb +112 -112
  30. data/lib/chef/provisioning/machine/basic_machine.rb +84 -84
  31. data/lib/chef/provisioning/machine/unix_machine.rb +288 -288
  32. data/lib/chef/provisioning/machine/windows_machine.rb +108 -108
  33. data/lib/chef/provisioning/machine_image_spec.rb +34 -34
  34. data/lib/chef/provisioning/machine_spec.rb +58 -58
  35. data/lib/chef/provisioning/managed_entry.rb +121 -121
  36. data/lib/chef/provisioning/managed_entry_store.rb +136 -136
  37. data/lib/chef/provisioning/recipe_dsl.rb +99 -99
  38. data/lib/chef/provisioning/rspec.rb +27 -27
  39. data/lib/chef/provisioning/transport.rb +100 -100
  40. data/lib/chef/provisioning/transport/ssh.rb +403 -403
  41. data/lib/chef/provisioning/transport/winrm.rb +144 -156
  42. data/lib/chef/provisioning/version.rb +5 -5
  43. data/lib/chef/resource/chef_data_bag_resource.rb +146 -146
  44. data/lib/chef/resource/load_balancer.rb +57 -57
  45. data/lib/chef/resource/machine.rb +128 -128
  46. data/lib/chef/resource/machine_batch.rb +78 -78
  47. data/lib/chef/resource/machine_execute.rb +30 -29
  48. data/lib/chef/resource/machine_file.rb +34 -34
  49. data/lib/chef/resource/machine_image.rb +35 -35
  50. data/lib/chef_metal.rb +1 -1
  51. data/spec/chef/provisioning/convergence_strategy/ignore_convergence_failure_spec.rb +86 -86
  52. data/spec/spec_helper.rb +27 -27
  53. metadata +5 -5
@@ -1,14 +1,14 @@
1
- require 'chef/provisioning/managed_entry'
2
-
3
- class Chef
4
- module Provisioning
5
- #
6
- # Specification for a image. Sufficient information to find and contact it
7
- # after it has been set up.
8
- #
9
- class LoadBalancerSpec < ManagedEntry
10
- alias :location :reference
11
- alias :location= :reference=
12
- end
13
- end
14
- end
1
+ require 'chef/provisioning/managed_entry'
2
+
3
+ class Chef
4
+ module Provisioning
5
+ #
6
+ # Specification for a image. Sufficient information to find and contact it
7
+ # after it has been set up.
8
+ #
9
+ class LoadBalancerSpec < ManagedEntry
10
+ alias :location :reference
11
+ alias :location= :reference=
12
+ end
13
+ end
14
+ end
@@ -1,112 +1,112 @@
1
- class Chef
2
- module Provisioning
3
- class Machine
4
- def initialize(machine_spec)
5
- @machine_spec = machine_spec
6
- end
7
-
8
- attr_reader :machine_spec
9
-
10
- def name
11
- machine_spec.name
12
- end
13
-
14
- def node
15
- machine_spec.node
16
- end
17
-
18
- # Sets up everything necessary for convergence to happen on the machine.
19
- # The node MUST be saved as part of this procedure. Other than that,
20
- # nothing is guaranteed except that converge() will work when this is done.
21
- def setup_convergence(action_handler)
22
- raise "setup_convergence not overridden on #{self.class}"
23
- end
24
-
25
- def converge(action_handler)
26
- raise "converge not overridden on #{self.class}"
27
- end
28
-
29
- def cleanup_convergence(action_handler)
30
- raise "cleanup_convergence not overridden on #{self.class}"
31
- end
32
-
33
- def execute(action_handler, command, options = {})
34
- raise "execute not overridden on #{self.class}"
35
- end
36
-
37
- def execute_always(command, options = {})
38
- raise "execute_always not overridden on #{self.class}"
39
- end
40
-
41
- def read_file(path)
42
- raise "read_file not overridden on #{self.class}"
43
- end
44
-
45
- def download_file(action_handler, path, local_path)
46
- raise "read_file not overridden on #{self.class}"
47
- end
48
-
49
- def write_file(action_handler, path, content)
50
- raise "write_file not overridden on #{self.class}"
51
- end
52
-
53
- def upload_file(action_handler, local_path, path)
54
- raise "write_file not overridden on #{self.class}"
55
- end
56
-
57
- def create_dir(action_handler, path)
58
- raise "create_dir not overridden on #{self.class}"
59
- end
60
-
61
- # Delete file
62
- def delete_file(action_handler, path)
63
- raise "delete_file not overridden on #{self.class}"
64
- end
65
-
66
- # Return true if directory, false/nil if not
67
- def is_directory?(path)
68
- raise "is_directory? not overridden on #{self.class}"
69
- end
70
-
71
- # Return true or false depending on whether file exists
72
- def file_exists?(path)
73
- raise "file_exists? not overridden on #{self.class}"
74
- end
75
-
76
- # Return true or false depending on whether remote file differs from local path or content
77
- def files_different?(path, local_path, content=nil)
78
- raise "file_different? not overridden on #{self.class}"
79
- end
80
-
81
- # Set file attributes { mode, :owner, :group }
82
- def set_attributes(action_handler, path, attributes)
83
- raise "set_attributes not overridden on #{self.class}"
84
- end
85
-
86
- # Get file attributes { :mode, :owner, :group }
87
- def get_attributes(path)
88
- raise "get_attributes not overridden on #{self.class}"
89
- end
90
-
91
- # Ensure the given URL can be reached by the remote side (possibly by port forwarding)
92
- # Must return the URL that the remote side can use to reach the local_url
93
- def make_url_available_to_remote(local_url)
94
- raise "make_url_available_to_remote not overridden on #{self.class}"
95
- end
96
-
97
- def disconnect
98
- raise "disconnect not overridden on #{self.class}"
99
- end
100
-
101
- # TODO get rid of the action_handler attribute, that is ridiculous
102
- # Detect the OS on the machine (assumes the machine is up)
103
- # Returns a triplet:
104
- # platform, platform_version, machine_architecture = machine.detect_os(action_handler)
105
- # This triplet is suitable for passing to the Chef metadata API:
106
- # https://www.chef.io/chef/metadata?p=PLATFORM&pv=PLATFORM_VERSION&m=MACHINE_ARCHITECTURE
107
- def detect_os(action_handler)
108
- raise "detect_os not overridden on #{self.class}"
109
- end
110
- end
111
- end
112
- end
1
+ class Chef
2
+ module Provisioning
3
+ class Machine
4
+ def initialize(machine_spec)
5
+ @machine_spec = machine_spec
6
+ end
7
+
8
+ attr_reader :machine_spec
9
+
10
+ def name
11
+ machine_spec.name
12
+ end
13
+
14
+ def node
15
+ machine_spec.node
16
+ end
17
+
18
+ # Sets up everything necessary for convergence to happen on the machine.
19
+ # The node MUST be saved as part of this procedure. Other than that,
20
+ # nothing is guaranteed except that converge() will work when this is done.
21
+ def setup_convergence(action_handler)
22
+ raise "setup_convergence not overridden on #{self.class}"
23
+ end
24
+
25
+ def converge(action_handler)
26
+ raise "converge not overridden on #{self.class}"
27
+ end
28
+
29
+ def cleanup_convergence(action_handler)
30
+ raise "cleanup_convergence not overridden on #{self.class}"
31
+ end
32
+
33
+ def execute(action_handler, command, options = {})
34
+ raise "execute not overridden on #{self.class}"
35
+ end
36
+
37
+ def execute_always(command, options = {})
38
+ raise "execute_always not overridden on #{self.class}"
39
+ end
40
+
41
+ def read_file(path)
42
+ raise "read_file not overridden on #{self.class}"
43
+ end
44
+
45
+ def download_file(action_handler, path, local_path)
46
+ raise "read_file not overridden on #{self.class}"
47
+ end
48
+
49
+ def write_file(action_handler, path, content)
50
+ raise "write_file not overridden on #{self.class}"
51
+ end
52
+
53
+ def upload_file(action_handler, local_path, path)
54
+ raise "write_file not overridden on #{self.class}"
55
+ end
56
+
57
+ def create_dir(action_handler, path)
58
+ raise "create_dir not overridden on #{self.class}"
59
+ end
60
+
61
+ # Delete file
62
+ def delete_file(action_handler, path)
63
+ raise "delete_file not overridden on #{self.class}"
64
+ end
65
+
66
+ # Return true if directory, false/nil if not
67
+ def is_directory?(path)
68
+ raise "is_directory? not overridden on #{self.class}"
69
+ end
70
+
71
+ # Return true or false depending on whether file exists
72
+ def file_exists?(path)
73
+ raise "file_exists? not overridden on #{self.class}"
74
+ end
75
+
76
+ # Return true or false depending on whether remote file differs from local path or content
77
+ def files_different?(path, local_path, content=nil)
78
+ raise "file_different? not overridden on #{self.class}"
79
+ end
80
+
81
+ # Set file attributes { mode, :owner, :group }
82
+ def set_attributes(action_handler, path, attributes)
83
+ raise "set_attributes not overridden on #{self.class}"
84
+ end
85
+
86
+ # Get file attributes { :mode, :owner, :group }
87
+ def get_attributes(path)
88
+ raise "get_attributes not overridden on #{self.class}"
89
+ end
90
+
91
+ # Ensure the given URL can be reached by the remote side (possibly by port forwarding)
92
+ # Must return the URL that the remote side can use to reach the local_url
93
+ def make_url_available_to_remote(local_url)
94
+ raise "make_url_available_to_remote not overridden on #{self.class}"
95
+ end
96
+
97
+ def disconnect
98
+ raise "disconnect not overridden on #{self.class}"
99
+ end
100
+
101
+ # TODO get rid of the action_handler attribute, that is ridiculous
102
+ # Detect the OS on the machine (assumes the machine is up)
103
+ # Returns a triplet:
104
+ # platform, platform_version, machine_architecture = machine.detect_os(action_handler)
105
+ # This triplet is suitable for passing to the Chef metadata API:
106
+ # https://www.chef.io/chef/metadata?p=PLATFORM&pv=PLATFORM_VERSION&m=MACHINE_ARCHITECTURE
107
+ def detect_os(action_handler)
108
+ raise "detect_os not overridden on #{self.class}"
109
+ end
110
+ end
111
+ end
112
+ end
@@ -1,84 +1,84 @@
1
- require 'chef/provisioning/machine'
2
-
3
- class Chef
4
- module Provisioning
5
- class Machine
6
- class BasicMachine < Machine
7
- def initialize(machine_spec, transport, convergence_strategy)
8
- super(machine_spec)
9
- @transport = transport
10
- @convergence_strategy = convergence_strategy
11
- end
12
-
13
- attr_reader :transport
14
- attr_reader :convergence_strategy
15
-
16
- def setup_convergence(action_handler)
17
- convergence_strategy.setup_convergence(action_handler, self)
18
- end
19
-
20
- def converge(action_handler)
21
- convergence_strategy.converge(action_handler, self)
22
- end
23
-
24
- def cleanup_convergence(action_handler)
25
- convergence_strategy.cleanup_convergence(action_handler, machine_spec)
26
- end
27
-
28
- def execute(action_handler, command, options = {})
29
- action_handler.perform_action "run '#{command}' on #{machine_spec.name}" do
30
- result = transport.execute(command, options)
31
- result.error!
32
- result
33
- end
34
- end
35
-
36
- def execute_always(command, options = {})
37
- transport.execute(command, options)
38
- end
39
-
40
- def read_file(path)
41
- transport.read_file(path)
42
- end
43
-
44
- def download_file(action_handler, path, local_path)
45
- if files_different?(path, local_path)
46
- action_handler.perform_action "download file #{path} on #{machine_spec.name} to #{local_path}" do
47
- transport.download_file(path, local_path)
48
- end
49
- end
50
- end
51
-
52
- def write_file(action_handler, path, content, options = {})
53
- if files_different?(path, nil, content)
54
- if options[:ensure_dir]
55
- create_dir(action_handler, dirname_on_machine(path))
56
- end
57
- action_handler.perform_action "write file #{path} on #{machine_spec.name}" do
58
- transport.write_file(path, content)
59
- end
60
- end
61
- end
62
-
63
- def upload_file(action_handler, local_path, path, options = {})
64
- if files_different?(path, local_path)
65
- if options[:ensure_dir]
66
- create_dir(action_handler, dirname_on_machine(path))
67
- end
68
- action_handler.perform_action "upload file #{local_path} to #{path} on #{machine_spec.name}" do
69
- transport.upload_file(local_path, path)
70
- end
71
- end
72
- end
73
-
74
- def make_url_available_to_remote(local_url)
75
- transport.make_url_available_to_remote(local_url)
76
- end
77
-
78
- def disconnect
79
- transport.disconnect
80
- end
81
- end
82
- end
83
- end
84
- end
1
+ require 'chef/provisioning/machine'
2
+
3
+ class Chef
4
+ module Provisioning
5
+ class Machine
6
+ class BasicMachine < Machine
7
+ def initialize(machine_spec, transport, convergence_strategy)
8
+ super(machine_spec)
9
+ @transport = transport
10
+ @convergence_strategy = convergence_strategy
11
+ end
12
+
13
+ attr_reader :transport
14
+ attr_reader :convergence_strategy
15
+
16
+ def setup_convergence(action_handler)
17
+ convergence_strategy.setup_convergence(action_handler, self)
18
+ end
19
+
20
+ def converge(action_handler)
21
+ convergence_strategy.converge(action_handler, self)
22
+ end
23
+
24
+ def cleanup_convergence(action_handler)
25
+ convergence_strategy.cleanup_convergence(action_handler, machine_spec)
26
+ end
27
+
28
+ def execute(action_handler, command, options = {})
29
+ action_handler.perform_action "run '#{command}' on #{machine_spec.name}" do
30
+ result = transport.execute(command, options)
31
+ result.error!
32
+ result
33
+ end
34
+ end
35
+
36
+ def execute_always(command, options = {})
37
+ transport.execute(command, options)
38
+ end
39
+
40
+ def read_file(path)
41
+ transport.read_file(path)
42
+ end
43
+
44
+ def download_file(action_handler, path, local_path)
45
+ if files_different?(path, local_path)
46
+ action_handler.perform_action "download file #{path} on #{machine_spec.name} to #{local_path}" do
47
+ transport.download_file(path, local_path)
48
+ end
49
+ end
50
+ end
51
+
52
+ def write_file(action_handler, path, content, options = {})
53
+ if files_different?(path, nil, content)
54
+ if options[:ensure_dir]
55
+ create_dir(action_handler, dirname_on_machine(path))
56
+ end
57
+ action_handler.perform_action "write file #{path} on #{machine_spec.name}" do
58
+ transport.write_file(path, content)
59
+ end
60
+ end
61
+ end
62
+
63
+ def upload_file(action_handler, local_path, path, options = {})
64
+ if files_different?(path, local_path)
65
+ if options[:ensure_dir]
66
+ create_dir(action_handler, dirname_on_machine(path))
67
+ end
68
+ action_handler.perform_action "upload file #{local_path} to #{path} on #{machine_spec.name}" do
69
+ transport.upload_file(local_path, path)
70
+ end
71
+ end
72
+ end
73
+
74
+ def make_url_available_to_remote(local_url)
75
+ transport.make_url_available_to_remote(local_url)
76
+ end
77
+
78
+ def disconnect
79
+ transport.disconnect
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,288 +1,288 @@
1
- require 'chef/provisioning/machine/basic_machine'
2
- require 'digest'
3
-
4
- class Chef
5
- module Provisioning
6
- class Machine
7
- class UnixMachine < BasicMachine
8
- def initialize(machine_spec, transport, convergence_strategy)
9
- super
10
-
11
- @tmp_dir = '/tmp'
12
- end
13
-
14
- # Options include:
15
- #
16
- # command_prefix - prefix to put in front of any command, e.g. sudo
17
- attr_reader :options
18
-
19
- # Delete file
20
- def delete_file(action_handler, path)
21
- if file_exists?(path)
22
- action_handler.perform_action "delete file #{path} on #{machine_spec.name}" do
23
- transport.execute("rm -f #{path}").error!
24
- end
25
- end
26
- end
27
-
28
- def is_directory?(path)
29
- result = transport.execute("stat -c '%F' #{path}", :read_only => true)
30
- return nil if result.exitstatus != 0
31
- result.stdout.chomp == 'directory'
32
- end
33
-
34
- # Return true or false depending on whether file exists
35
- def file_exists?(path)
36
- result = transport.execute("ls -d #{path}", :read_only => true)
37
- result.exitstatus == 0 && result.stdout != ''
38
- end
39
-
40
- def files_different?(path, local_path, content=nil)
41
- if !file_exists?(path) || (local_path && !File.exists?(local_path))
42
- return true
43
- end
44
-
45
- # Get remote checksum of file
46
- result = transport.execute("md5sum -b #{path}", :read_only => true)
47
- unless result.exitstatus == 0
48
- result = transport.execute("md5 -r #{path}", :read_only => true)
49
- end
50
- result.error!
51
- remote_sum = result.stdout.split(' ')[0]
52
-
53
- digest = Digest::MD5.new
54
- if content
55
- digest.update(content)
56
- else
57
- File.open(local_path, 'rb') do |io|
58
- while (buf = io.read(4096)) && buf.length > 0
59
- digest.update(buf)
60
- end
61
- end
62
- end
63
- remote_sum != digest.hexdigest
64
- end
65
-
66
- def create_dir(action_handler, path)
67
- if !file_exists?(path)
68
- action_handler.perform_action "create directory #{path} on #{machine_spec.name}" do
69
- transport.execute("mkdir -p #{path}").error!
70
- end
71
- end
72
- end
73
-
74
- # Set file attributes { mode, :owner, :group }
75
- def set_attributes(action_handler, path, attributes)
76
- if attributes[:mode] || attributes[:owner] || attributes[:group]
77
- current_attributes = get_attributes(path)
78
- if attributes[:mode] && current_attributes[:mode].to_i != attributes[:mode].to_i
79
- action_handler.perform_action "change mode of #{path} on #{machine_spec.name} from #{current_attributes[:mode].to_i} to #{attributes[:mode].to_i}" do
80
- transport.execute("chmod #{attributes[:mode].to_i} #{path}").error!
81
- end
82
- end
83
- if attributes[:owner] && current_attributes[:owner] != attributes[:owner]
84
- action_handler.perform_action "change group of #{path} on #{machine_spec.name} from #{current_attributes[:owner]} to #{attributes[:owner]}" do
85
- transport.execute("chown #{attributes[:owner]} #{path}").error!
86
- end
87
- end
88
- if attributes[:group] && current_attributes[:group] != attributes[:group]
89
- action_handler.perform_action "change group of #{path} on #{machine_spec.name} from #{current_attributes[:group]} to #{attributes[:group]}" do
90
- transport.execute("chgrp #{attributes[:group]} #{path}").error!
91
- end
92
- end
93
- end
94
- end
95
-
96
- # Get file attributes { :mode, :owner, :group }
97
- def get_attributes(path)
98
- result = transport.execute("stat -c '%a %U %G %n' #{path}", :read_only => true)
99
- return nil if result.exitstatus != 0
100
- file_info = result.stdout.split(/\s+/)
101
- if file_info.size <= 1
102
- raise "#{path} does not exist in set_attributes()"
103
- end
104
- result = {
105
- :mode => file_info[0],
106
- :owner => file_info[1],
107
- :group => file_info[2]
108
- }
109
- end
110
-
111
- def dirname_on_machine(path)
112
- path.split('/')[0..-2].join('/')
113
- end
114
- end
115
-
116
- def detect_os(action_handler)
117
- #
118
- # Use detect.sh to detect the operating system of the remote machine
119
- #
120
- # TODO do this in terms of commands rather than writing a shell script
121
- self.write_file(action_handler, "#{@tmp_dir}/detect.sh", detect_sh)
122
- detected = self.execute_always("sh #{@tmp_dir}/detect.sh")
123
- if detected.exitstatus != 0
124
- raise "detect.sh exited with nonzero exit status: #{detected.exitstatus}"
125
- end
126
- platform = nil
127
- platform_version = nil
128
- machine_architecture = nil
129
- detected.stdout.each_line do |line|
130
- if line =~ /^PLATFORM: (.+)/
131
- platform = $1
132
- elsif line =~ /^PLATFORM_VERSION: (.+)/
133
- platform_version = $1
134
- elsif line =~ /^MACHINE: (.+)/
135
- machine_architecture = $1
136
- end
137
- end
138
- [ platform, platform_version, machine_architecture ]
139
- end
140
-
141
- private
142
-
143
- def detect_sh
144
- result = <<EOM
145
- prerelease="false"
146
-
147
- project="chef"
148
-
149
- report_bug() {
150
- echo "Please file a bug report at https://github.com/chef/chef-provisioning/issues"
151
- echo "Project: Chef"
152
- echo "Component: Packages"
153
- echo "Label: Omnibus"
154
- echo "Version: $version"
155
- echo " "
156
- echo "Please detail your operating system type, version and any other relevant details"
157
- }
158
-
159
-
160
- machine=`uname -m`
161
- os=`uname -s`
162
-
163
- # Retrieve Platform and Platform Version
164
- if test -f "/etc/lsb-release" && grep -q DISTRIB_ID /etc/lsb-release; then
165
- platform=`grep DISTRIB_ID /etc/lsb-release | cut -d "=" -f 2 | tr '[A-Z]' '[a-z]'`
166
- platform_version=`grep DISTRIB_RELEASE /etc/lsb-release | cut -d "=" -f 2`
167
- elif test -f "/etc/debian_version"; then
168
- platform="debian"
169
- platform_version=`cat /etc/debian_version`
170
- elif test -f "/etc/redhat-release"; then
171
- platform=`sed 's/^\\(.\\+\\) release.*/\\1/' /etc/redhat-release | tr '[A-Z]' '[a-z]'`
172
- platform_version=`sed 's/^.\\+ release \\([.0-9]\\+\\).*/\\1/' /etc/redhat-release`
173
-
174
- # If /etc/redhat-release exists, we act like RHEL by default
175
- if test "$platform" = "fedora"; then
176
- # Change platform version for use below.
177
- platform_version="6.0"
178
- fi
179
- platform="el"
180
- elif test -f "/etc/system-release"; then
181
- platform=`sed 's/^\\(.\\+\\) release.\\+/\\1/' /etc/system-release | tr '[A-Z]' '[a-z]'`
182
- platform_version=`sed 's/^.\\+ release \\([.0-9]\\+\\).*/\\1/' /etc/system-release | tr '[A-Z]' '[a-z]'`
183
- # amazon is built off of fedora, so act like RHEL
184
- if test "$platform" = "amazon linux ami"; then
185
- platform="el"
186
- platform_version="6.0"
187
- fi
188
- # Apple OS X
189
- elif test -f "/usr/bin/sw_vers"; then
190
- platform="mac_os_x"
191
- # Matching the tab-space with sed is error-prone
192
- platform_version=`sw_vers | awk '/^ProductVersion:/ { print $2 }'`
193
-
194
- major_version=`echo $platform_version | cut -d. -f1,2`
195
- case $major_version in
196
- "10.6") platform_version="10.6" ;;
197
- "10.7"|"10.8"|"10.9") platform_version="10.7" ;;
198
- *) echo "No builds for platform: $major_version"
199
- report_bug
200
- exit 1
201
- ;;
202
- esac
203
-
204
- # x86_64 Apple hardware often runs 32-bit kernels (see OHAI-63)
205
- x86_64=`sysctl -n hw.optional.x86_64`
206
- if test $x86_64 -eq 1; then
207
- machine="x86_64"
208
- fi
209
- elif test -f "/etc/release"; then
210
- platform="solaris2"
211
- machine=`/usr/bin/uname -p`
212
- platform_version=`/usr/bin/uname -r`
213
- elif test -f "/etc/SuSE-release"; then
214
- if grep -q 'Enterprise' /etc/SuSE-release;
215
- then
216
- platform="sles"
217
- platform_version=`awk '/^VERSION/ {V = $3}; /^PATCHLEVEL/ {P = $3}; END {print V "." P}' /etc/SuSE-release`
218
- else
219
- platform="suse"
220
- platform_version=`awk '/^VERSION =/ { print $3 }' /etc/SuSE-release`
221
- fi
222
- elif test "x$os" = "xFreeBSD"; then
223
- platform="freebsd"
224
- platform_version=`uname -r | sed 's/-.*//'`
225
- elif test "x$os" = "xAIX"; then
226
- platform="aix"
227
- platform_version=`uname -v`
228
- machine="ppc"
229
- elif test -f "/etc/os-release"; then
230
- . /etc/os-release
231
- if test "x$ID_LIKE" = "xwrlinux" || test "x$ID_LIKE" = "xcisco-wrlinux"; then
232
- platform="wrlinux"
233
- # 3.4.43-WR5.0.1.13_standard --> 5
234
- platform_version=`uname -r | sed 's/.*-WR\([0-9]\+\).*/\1/'`
235
- fi
236
- fi
237
-
238
- if test "x$platform" = "x"; then
239
- echo "Unable to determine platform version!"
240
- report_bug
241
- exit 1
242
- fi
243
-
244
- # Mangle $platform_version to pull the correct build
245
- # for various platforms
246
- major_version=`echo $platform_version | cut -d. -f1`
247
- case $platform in
248
- "el")
249
- platform_version=$major_version
250
- ;;
251
- "debian")
252
- case $major_version in
253
- "5") platform_version="6";;
254
- "6") platform_version="6";;
255
- "7") platform_version="6";;
256
- esac
257
- ;;
258
- "freebsd")
259
- platform_version=$major_version
260
- ;;
261
- "sles")
262
- platform_version=$major_version
263
- ;;
264
- "suse")
265
- platform_version=$major_version
266
- ;;
267
- esac
268
-
269
- if test "x$platform_version" = "x"; then
270
- echo "Unable to determine platform version!"
271
- report_bug
272
- exit 1
273
- fi
274
-
275
- if test "x$platform" = "xsolaris2"; then
276
- # hack up the path on Solaris to find wget
277
- PATH=/usr/sfw/bin:$PATH
278
- export PATH
279
- fi
280
-
281
- echo "PLATFORM: $platform"
282
- echo "PLATFORM_VERSION: $platform_version"
283
- echo "MACHINE: $machine"
284
- EOM
285
- end
286
- end
287
- end
288
- end
1
+ require 'chef/provisioning/machine/basic_machine'
2
+ require 'digest'
3
+
4
+ class Chef
5
+ module Provisioning
6
+ class Machine
7
+ class UnixMachine < BasicMachine
8
+ def initialize(machine_spec, transport, convergence_strategy)
9
+ super
10
+
11
+ @tmp_dir = '/tmp'
12
+ end
13
+
14
+ # Options include:
15
+ #
16
+ # command_prefix - prefix to put in front of any command, e.g. sudo
17
+ attr_reader :options
18
+
19
+ # Delete file
20
+ def delete_file(action_handler, path)
21
+ if file_exists?(path)
22
+ action_handler.perform_action "delete file #{path} on #{machine_spec.name}" do
23
+ transport.execute("rm -f #{path}").error!
24
+ end
25
+ end
26
+ end
27
+
28
+ def is_directory?(path)
29
+ result = transport.execute("stat -c '%F' #{path}", :read_only => true)
30
+ return nil if result.exitstatus != 0
31
+ result.stdout.chomp == 'directory'
32
+ end
33
+
34
+ # Return true or false depending on whether file exists
35
+ def file_exists?(path)
36
+ result = transport.execute("ls -d #{path}", :read_only => true)
37
+ result.exitstatus == 0 && result.stdout != ''
38
+ end
39
+
40
+ def files_different?(path, local_path, content=nil)
41
+ if !file_exists?(path) || (local_path && !File.exists?(local_path))
42
+ return true
43
+ end
44
+
45
+ # Get remote checksum of file
46
+ result = transport.execute("md5sum -b #{path}", :read_only => true)
47
+ unless result.exitstatus == 0
48
+ result = transport.execute("md5 -r #{path}", :read_only => true)
49
+ end
50
+ result.error!
51
+ remote_sum = result.stdout.split(' ')[0]
52
+
53
+ digest = Digest::MD5.new
54
+ if content
55
+ digest.update(content)
56
+ else
57
+ File.open(local_path, 'rb') do |io|
58
+ while (buf = io.read(4096)) && buf.length > 0
59
+ digest.update(buf)
60
+ end
61
+ end
62
+ end
63
+ remote_sum != digest.hexdigest
64
+ end
65
+
66
+ def create_dir(action_handler, path)
67
+ if !file_exists?(path)
68
+ action_handler.perform_action "create directory #{path} on #{machine_spec.name}" do
69
+ transport.execute("mkdir -p #{path}").error!
70
+ end
71
+ end
72
+ end
73
+
74
+ # Set file attributes { mode, :owner, :group }
75
+ def set_attributes(action_handler, path, attributes)
76
+ if attributes[:mode] || attributes[:owner] || attributes[:group]
77
+ current_attributes = get_attributes(path)
78
+ if attributes[:mode] && current_attributes[:mode].to_i != attributes[:mode].to_i
79
+ action_handler.perform_action "change mode of #{path} on #{machine_spec.name} from #{current_attributes[:mode].to_i} to #{attributes[:mode].to_i}" do
80
+ transport.execute("chmod #{attributes[:mode].to_i} #{path}").error!
81
+ end
82
+ end
83
+ if attributes[:owner] && current_attributes[:owner] != attributes[:owner]
84
+ action_handler.perform_action "change group of #{path} on #{machine_spec.name} from #{current_attributes[:owner]} to #{attributes[:owner]}" do
85
+ transport.execute("chown #{attributes[:owner]} #{path}").error!
86
+ end
87
+ end
88
+ if attributes[:group] && current_attributes[:group] != attributes[:group]
89
+ action_handler.perform_action "change group of #{path} on #{machine_spec.name} from #{current_attributes[:group]} to #{attributes[:group]}" do
90
+ transport.execute("chgrp #{attributes[:group]} #{path}").error!
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ # Get file attributes { :mode, :owner, :group }
97
+ def get_attributes(path)
98
+ result = transport.execute("stat -c '%a %U %G %n' #{path}", :read_only => true)
99
+ return nil if result.exitstatus != 0
100
+ file_info = result.stdout.split(/\s+/)
101
+ if file_info.size <= 1
102
+ raise "#{path} does not exist in set_attributes()"
103
+ end
104
+ result = {
105
+ :mode => file_info[0],
106
+ :owner => file_info[1],
107
+ :group => file_info[2]
108
+ }
109
+ end
110
+
111
+ def dirname_on_machine(path)
112
+ path.split('/')[0..-2].join('/')
113
+ end
114
+ end
115
+
116
+ def detect_os(action_handler)
117
+ #
118
+ # Use detect.sh to detect the operating system of the remote machine
119
+ #
120
+ # TODO do this in terms of commands rather than writing a shell script
121
+ self.write_file(action_handler, "#{@tmp_dir}/detect.sh", detect_sh)
122
+ detected = self.execute_always("sh #{@tmp_dir}/detect.sh")
123
+ if detected.exitstatus != 0
124
+ raise "detect.sh exited with nonzero exit status: #{detected.exitstatus}"
125
+ end
126
+ platform = nil
127
+ platform_version = nil
128
+ machine_architecture = nil
129
+ detected.stdout.each_line do |line|
130
+ if line =~ /^PLATFORM: (.+)/
131
+ platform = $1
132
+ elsif line =~ /^PLATFORM_VERSION: (.+)/
133
+ platform_version = $1
134
+ elsif line =~ /^MACHINE: (.+)/
135
+ machine_architecture = $1
136
+ end
137
+ end
138
+ [ platform, platform_version, machine_architecture ]
139
+ end
140
+
141
+ private
142
+
143
+ def detect_sh
144
+ result = <<EOM
145
+ prerelease="false"
146
+
147
+ project="chef"
148
+
149
+ report_bug() {
150
+ echo "Please file a bug report at https://github.com/chef/chef-provisioning/issues"
151
+ echo "Project: Chef"
152
+ echo "Component: Packages"
153
+ echo "Label: Omnibus"
154
+ echo "Version: $version"
155
+ echo " "
156
+ echo "Please detail your operating system type, version and any other relevant details"
157
+ }
158
+
159
+
160
+ machine=`uname -m`
161
+ os=`uname -s`
162
+
163
+ # Retrieve Platform and Platform Version
164
+ if test -f "/etc/lsb-release" && grep -q DISTRIB_ID /etc/lsb-release; then
165
+ platform=`grep DISTRIB_ID /etc/lsb-release | cut -d "=" -f 2 | tr '[A-Z]' '[a-z]'`
166
+ platform_version=`grep DISTRIB_RELEASE /etc/lsb-release | cut -d "=" -f 2`
167
+ elif test -f "/etc/debian_version"; then
168
+ platform="debian"
169
+ platform_version=`cat /etc/debian_version`
170
+ elif test -f "/etc/redhat-release"; then
171
+ platform=`sed 's/^\\(.\\+\\) release.*/\\1/' /etc/redhat-release | tr '[A-Z]' '[a-z]'`
172
+ platform_version=`sed 's/^.\\+ release \\([.0-9]\\+\\).*/\\1/' /etc/redhat-release`
173
+
174
+ # If /etc/redhat-release exists, we act like RHEL by default
175
+ if test "$platform" = "fedora"; then
176
+ # Change platform version for use below.
177
+ platform_version="6.0"
178
+ fi
179
+ platform="el"
180
+ elif test -f "/etc/system-release"; then
181
+ platform=`sed 's/^\\(.\\+\\) release.\\+/\\1/' /etc/system-release | tr '[A-Z]' '[a-z]'`
182
+ platform_version=`sed 's/^.\\+ release \\([.0-9]\\+\\).*/\\1/' /etc/system-release | tr '[A-Z]' '[a-z]'`
183
+ # amazon is built off of fedora, so act like RHEL
184
+ if test "$platform" = "amazon linux ami"; then
185
+ platform="el"
186
+ platform_version="6.0"
187
+ fi
188
+ # Apple OS X
189
+ elif test -f "/usr/bin/sw_vers"; then
190
+ platform="mac_os_x"
191
+ # Matching the tab-space with sed is error-prone
192
+ platform_version=`sw_vers | awk '/^ProductVersion:/ { print $2 }'`
193
+
194
+ major_version=`echo $platform_version | cut -d. -f1,2`
195
+ case $major_version in
196
+ "10.6") platform_version="10.6" ;;
197
+ "10.7"|"10.8"|"10.9") platform_version="10.7" ;;
198
+ *) echo "No builds for platform: $major_version"
199
+ report_bug
200
+ exit 1
201
+ ;;
202
+ esac
203
+
204
+ # x86_64 Apple hardware often runs 32-bit kernels (see OHAI-63)
205
+ x86_64=`sysctl -n hw.optional.x86_64`
206
+ if test $x86_64 -eq 1; then
207
+ machine="x86_64"
208
+ fi
209
+ elif test -f "/etc/release"; then
210
+ platform="solaris2"
211
+ machine=`/usr/bin/uname -p`
212
+ platform_version=`/usr/bin/uname -r`
213
+ elif test -f "/etc/SuSE-release"; then
214
+ if grep -q 'Enterprise' /etc/SuSE-release;
215
+ then
216
+ platform="sles"
217
+ platform_version=`awk '/^VERSION/ {V = $3}; /^PATCHLEVEL/ {P = $3}; END {print V "." P}' /etc/SuSE-release`
218
+ else
219
+ platform="suse"
220
+ platform_version=`awk '/^VERSION =/ { print $3 }' /etc/SuSE-release`
221
+ fi
222
+ elif test "x$os" = "xFreeBSD"; then
223
+ platform="freebsd"
224
+ platform_version=`uname -r | sed 's/-.*//'`
225
+ elif test "x$os" = "xAIX"; then
226
+ platform="aix"
227
+ platform_version=`uname -v`
228
+ machine="ppc"
229
+ elif test -f "/etc/os-release"; then
230
+ . /etc/os-release
231
+ if test "x$ID_LIKE" = "xwrlinux" || test "x$ID_LIKE" = "xcisco-wrlinux"; then
232
+ platform="wrlinux"
233
+ # 3.4.43-WR5.0.1.13_standard --> 5
234
+ platform_version=`uname -r | sed 's/.*-WR\([0-9]\+\).*/\1/'`
235
+ fi
236
+ fi
237
+
238
+ if test "x$platform" = "x"; then
239
+ echo "Unable to determine platform version!"
240
+ report_bug
241
+ exit 1
242
+ fi
243
+
244
+ # Mangle $platform_version to pull the correct build
245
+ # for various platforms
246
+ major_version=`echo $platform_version | cut -d. -f1`
247
+ case $platform in
248
+ "el")
249
+ platform_version=$major_version
250
+ ;;
251
+ "debian")
252
+ case $major_version in
253
+ "5") platform_version="6";;
254
+ "6") platform_version="6";;
255
+ "7") platform_version="6";;
256
+ esac
257
+ ;;
258
+ "freebsd")
259
+ platform_version=$major_version
260
+ ;;
261
+ "sles")
262
+ platform_version=$major_version
263
+ ;;
264
+ "suse")
265
+ platform_version=$major_version
266
+ ;;
267
+ esac
268
+
269
+ if test "x$platform_version" = "x"; then
270
+ echo "Unable to determine platform version!"
271
+ report_bug
272
+ exit 1
273
+ fi
274
+
275
+ if test "x$platform" = "xsolaris2"; then
276
+ # hack up the path on Solaris to find wget
277
+ PATH=/usr/sfw/bin:$PATH
278
+ export PATH
279
+ fi
280
+
281
+ echo "PLATFORM: $platform"
282
+ echo "PLATFORM_VERSION: $platform_version"
283
+ echo "MACHINE: $machine"
284
+ EOM
285
+ end
286
+ end
287
+ end
288
+ end