chef-provisioning 2.0.0 → 2.0.1

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