dust-deploy 0.16.4 → 0.16.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ require 'dust/server/ssh'
2
+ require 'dust/server/osdetect'
3
+ require 'dust/server/package'
4
+
5
+ module Dust
6
+ class Server
7
+ # collect additional system facts using puppets facter
8
+ def collect_facts(options={})
9
+ options = default_options.merge(options)
10
+
11
+ # if facts already have been collected, just return
12
+ return true if @node['operatingsystem']
13
+
14
+ # check if lsb-release (on apt systems) and facter are installed
15
+ # and install them if not
16
+ if uses_apt? and not package_installed?('lsb-release', :quiet => true)
17
+ install_package('lsb-release', :quiet => false)
18
+ end
19
+
20
+ unless package_installed?('facter', :quiet => true)
21
+ return false unless install_package('facter', :quiet => false)
22
+ end
23
+
24
+ msg = messages.add("collecting additional system facts (using facter)", options)
25
+
26
+ # run facter with -y for yaml output, and merge results into @node
27
+ ret = exec('facter -y')
28
+ @node = YAML.load(ret[:stdout]).merge(@node)
29
+
30
+ msg.parse_result(ret[:exit_code])
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,152 @@
1
+ require 'erb'
2
+ require 'tempfile'
3
+ require 'dust/server/ssh'
4
+ require 'dust/server/selinux'
5
+
6
+ module Dust
7
+ class Server
8
+ def write(destination, content, options={})
9
+ options = default_options.merge(options)
10
+
11
+ msg = messages.add("deploying #{File.basename destination}", options)
12
+
13
+ f = Tempfile.new('dust-write')
14
+ f.print(content)
15
+ f.close
16
+
17
+ ret = msg.parse_result(scp(f.path, destination, :quiet => true))
18
+ f.unlink
19
+
20
+ ret
21
+ end
22
+
23
+ def append(destination, newcontent, options={})
24
+ options = default_options.merge(options)
25
+
26
+ msg = messages.add("appending to #{File.basename destination}", options)
27
+
28
+ content = exec("cat #{destination}")[:stdout]
29
+ content.concat(newcontent)
30
+
31
+ msg.parse_result(write(destination, content, :quiet => true))
32
+ end
33
+
34
+ # if file is a regular file, copy it using scp
35
+ # if it's an file.erb exists, render template and push to server
36
+ def deploy_file(file, destination, options={})
37
+ options = default_options(:binding => binding).merge(options)
38
+
39
+ if File.exists?(file)
40
+ scp(file, destination, options)
41
+
42
+ elsif File.exists?("#{file}.erb")
43
+ template = ERB.new( File.read("#{file}.erb"), nil, '%<>')
44
+ write(destination, template.result(options[:binding]), options)
45
+
46
+ else
47
+ messages.add("'#{file}' was not found.", options).failed
48
+ end
49
+ end
50
+
51
+ # create a temporary file
52
+ def mktemp(options={:type => 'file'})
53
+ if options[:type] == 'file'
54
+ ret = exec('mktemp --tmpdir dust.XXXXXXXXXX')
55
+ elsif options[:type] == 'directory'
56
+ ret = exec('mktemp -d --tmpdir dust.XXXXXXXXXX')
57
+ else
58
+ return messages.add("mktemp: unknown type '#{options[:type]}'").failed
59
+ end
60
+
61
+ return false if ret[:exit_code] != 0
62
+ ret[:stdout].chomp
63
+ end
64
+
65
+ def symlink(source, destination, options={})
66
+ options = default_options.merge(options)
67
+
68
+ msg = messages.add("symlinking #{File.basename source} to '#{destination}'", options)
69
+ ret = msg.parse_result(exec("ln -s #{source} #{destination}")[:exit_code])
70
+ restorecon(destination, options) # restore SELinux labels
71
+ ret
72
+ end
73
+
74
+ def chmod(mode, file, options={})
75
+ options = default_options.merge(options)
76
+
77
+ msg = messages.add("setting mode of #{File.basename file} to #{mode}", options)
78
+ msg.parse_result(exec("chmod -R #{mode} #{file}")[:exit_code])
79
+ end
80
+
81
+ def chown(user, file, options={})
82
+ options = default_options.merge(options)
83
+
84
+ msg = messages.add("setting owner of #{File.basename file} to #{user}", options)
85
+ msg.parse_result(exec("chown -R #{user} #{file}")[:exit_code])
86
+ end
87
+
88
+
89
+ def rm(file, options={})
90
+ options = default_options.merge(options)
91
+
92
+ msg = messages.add("deleting #{file}", options)
93
+ msg.parse_result(exec("rm -rf #{file}")[:exit_code])
94
+ end
95
+
96
+ def cp(source, destination, options={})
97
+ options = default_options.merge(options)
98
+
99
+ # get rid of overly careful aliases
100
+ exec 'unalias -a'
101
+
102
+ msg = messages.add("copying #{source} to #{destination}", options)
103
+ msg.parse_result(exec("cp -a #{source} #{destination}")[:exit_code])
104
+ end
105
+
106
+ def mv(source, destination, options={})
107
+ options = default_options.merge(options)
108
+
109
+ # get rid of overly careful aliases
110
+ exec 'unalias -a'
111
+
112
+ msg = messages.add("moving #{source} to #{destination}", options)
113
+ msg.parse_result(exec("mv #{source} #{destination}")[:exit_code])
114
+ end
115
+
116
+ def mkdir(dir, options={})
117
+ options = default_options.merge(options)
118
+
119
+ return true if dir_exists?(dir, :quiet => true)
120
+
121
+ msg = messages.add("creating directory #{dir}", options)
122
+ ret = msg.parse_result(exec("mkdir -p #{dir}")[:exit_code])
123
+ restorecon(dir, options) # restore SELinux labels
124
+ ret
125
+ end
126
+
127
+ def is_executable?(file, options={})
128
+ options = default_options.merge(options)
129
+
130
+ msg = messages.add("checking if file #{file} exists and is executeable", options)
131
+ msg.parse_result(exec("test -x $(which #{file})")[:exit_code])
132
+ end
133
+
134
+ def file_exists?(file, options={})
135
+ options = default_options.merge(options)
136
+
137
+ msg = messages.add("checking if file #{file} exists", options)
138
+
139
+ # don't treat directories as files
140
+ return msg.failed if dir_exists?(file, :quiet => true)
141
+
142
+ msg.parse_result(exec("test -e #{file}")[:exit_code])
143
+ end
144
+
145
+ def dir_exists?(dir, options={})
146
+ options = default_options.merge(options)
147
+
148
+ msg = messages.add("checking if directory #{dir} exists", options)
149
+ msg.parse_result(exec("test -d #{dir}")[:exit_code])
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,112 @@
1
+ require 'dust/server/ssh'
2
+
3
+ module Dust
4
+ class Server
5
+ # determining the system packet manager has to be done without facter
6
+ # because it's used to find out whether facter is installed / install facter
7
+ def uses_apt?(options={})
8
+ options = default_options(:quiet => true).merge(options)
9
+
10
+ return @uses_apt if defined?(@uses_apt)
11
+ msg = messages.add('determining whether node uses apt', options)
12
+ @uses_apt = msg.parse_result(exec('test -e /etc/debian_version')[:exit_code])
13
+ end
14
+
15
+ def uses_rpm?(options={})
16
+ options = default_options(:quiet => true).merge(options)
17
+
18
+ return @uses_rpm if defined?(@uses_rpm)
19
+ msg = messages.add('determining whether node uses rpm', options)
20
+ @uses_rpm = msg.parse_result(exec('test -e /etc/redhat-release')[:exit_code])
21
+ end
22
+
23
+ def uses_emerge?(options={})
24
+ options = default_options(:quiet => true).merge(options)
25
+
26
+ return @uses_emerge if defined?(@uses_emerge)
27
+ msg = messages.add('determining whether node uses emerge', options)
28
+ @uses_emerge = msg.parse_result(exec('test -e /etc/gentoo-release')[:exit_code])
29
+ end
30
+
31
+ def uses_pacman?(options={})
32
+ options = default_options(:quiet => true).merge(options)
33
+
34
+ return @uses_pacman if defined?(@uses_pacman)
35
+ msg = messages.add('determining whether node uses pacman', options)
36
+ @uses_pacman = msg.parse_result(exec('test -e /etc/arch-release')[:exit_code])
37
+ end
38
+
39
+ def uses_opkg?(options={})
40
+ options = default_options(:quiet => true).merge(options)
41
+
42
+ return @uses_opkg if defined?(@uses_opkg)
43
+ msg = messages.add('determining whether node uses opkg', options)
44
+ @uses_opkg = msg.parse_result(exec('test -e /etc/opkg.conf')[:exit_code])
45
+ end
46
+
47
+ def is_os?(os_list, options={})
48
+ options = default_options(:quiet => true).merge(options)
49
+
50
+ msg = messages.add("checking if this machine runs #{os_list.join(' or ')}", options)
51
+ return msg.failed unless collect_facts options
52
+
53
+ os_list.each do |os|
54
+ if @node['operatingsystem'].downcase == os.downcase
55
+ return msg.ok
56
+ end
57
+ end
58
+
59
+ msg.failed
60
+ false
61
+ end
62
+
63
+ def is_debian?(options={})
64
+ options = default_options(:quiet => true).merge(options)
65
+
66
+ return false unless uses_apt?
67
+ is_os?(['debian'], options)
68
+ end
69
+
70
+ def is_ubuntu?(options={})
71
+ options = default_options(:quiet => true).merge(options)
72
+
73
+ return false unless uses_apt?
74
+ is_os?(['ubuntu'], options)
75
+ end
76
+
77
+ def is_gentoo?(options={})
78
+ options = default_options(:quiet => true).merge(options)
79
+
80
+ return false unless uses_emerge?
81
+ is_os?(['gentoo'], options)
82
+ end
83
+
84
+ def is_centos?(options={})
85
+ options = default_options(:quiet => true).merge(options)
86
+
87
+ return false unless uses_rpm?
88
+ is_os?(['centos'], options)
89
+ end
90
+
91
+ def is_scientific?(options={})
92
+ options = default_options(:quiet => true).merge(options)
93
+
94
+ return false unless uses_rpm?
95
+ is_os?(['scientific'], options)
96
+ end
97
+
98
+ def is_fedora?(options={})
99
+ options = default_options(:quiet => true).merge(options)
100
+
101
+ return false unless uses_rpm?
102
+ is_os?(['fedora'], options)
103
+ end
104
+
105
+ def is_arch?(options={})
106
+ options = default_options(:quiet => true).merge(options)
107
+
108
+ return false unless uses_pacman?
109
+ is_os?(['archlinux'], options)
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,215 @@
1
+ require 'dust/server/ssh'
2
+ require 'dust/server/osdetect'
3
+
4
+ module Dust
5
+ class Server
6
+ # checks if one of the packages is installed
7
+ def package_installed?(packages, options={})
8
+ options = default_options.merge(options)
9
+
10
+ packages = [ packages ] if packages.is_a?(String)
11
+
12
+ msg = messages.add("checking if #{packages.join(' or ')} is installed", options)
13
+
14
+ packages.each do |package|
15
+ if uses_apt?
16
+ return msg.ok if exec("dpkg -l #{package} |grep '^ii'")[:exit_code] == 0
17
+ elsif uses_emerge?
18
+ return msg.ok unless exec("qlist -I #{package}")[:stdout].empty?
19
+ elsif uses_rpm?
20
+ return msg.ok if exec("rpm -q #{package}")[:exit_code] == 0
21
+ elsif uses_pacman?
22
+ return msg.ok if exec("pacman -Q #{package}")[:exit_code] == 0
23
+ elsif uses_opkg?
24
+ return msg.ok unless exec("opkg status #{package}")[:stdout].empty?
25
+ end
26
+ end
27
+
28
+ msg.failed
29
+ end
30
+
31
+ def install_package(package, options={})
32
+ options = default_options.merge(options)
33
+ options[:env] ||= ''
34
+
35
+ if package_installed?(package, :quiet => true)
36
+ return messages.add("package #{package} already installed", options).ok
37
+ end
38
+
39
+ # if package is an url, download and install the package file
40
+ if package =~ /^(http:\/\/|https:\/\/|ftp:\/\/)/
41
+ if uses_apt?
42
+ messages.add("installing #{package}\n", options)
43
+ return false unless install_package('wget')
44
+
45
+ msg = messages.add('downloading package', options.merge(:indent => options[:indent] + 1))
46
+
47
+ # creating temporary file
48
+ tmpfile = mktemp
49
+ return msg.failed('could not create temporary file') unless tmpfile
50
+
51
+ msg.parse_result(exec("wget #{package} -O #{tmpfile}")[:exit_code])
52
+
53
+ msg = messages.add('installing package', options.merge(:indent => options[:indent] + 1))
54
+ ret = msg.parse_result(exec("dpkg -i #{tmpfile}")[:exit_code])
55
+
56
+ msg = messages.add('deleting downloaded file', options.merge(:indent => options[:indent] + 1))
57
+ msg.parse_result(rm(tmpfile, :quiet => true))
58
+
59
+ return ret
60
+
61
+ elsif uses_rpm?
62
+ msg = messages.add("installing #{package}", options)
63
+ return msg.parse_result(exec("rpm -U #{package}")[:exit_code])
64
+
65
+ else
66
+ return msg.failed("\ninstalling packages from url not yet supported " +
67
+ "for your distribution. feel free to contribute!").failed
68
+ end
69
+
70
+ # package is not an url, use package manager
71
+ else
72
+ msg = messages.add("installing #{package}", options)
73
+
74
+ if uses_apt?
75
+ exec "DEBIAN_FRONTEND=noninteractive apt-get install -y #{package}"
76
+ elsif uses_emerge?
77
+ exec "#{options[:env]} emerge #{package}"
78
+ elsif uses_rpm?
79
+ exec "yum install -y #{package}"
80
+ elsif uses_pacman?
81
+ exec "echo y |pacman -S #{package}"
82
+ elsif uses_opkg?
83
+ exec "opkg install #{package}"
84
+ else
85
+ return msg.failed("\ninstall_package only supports apt, emerge and yum systems at the moment")
86
+ end
87
+
88
+ # check if package actually was installed
89
+ return msg.parse_result(package_installed?(package, :quiet => true))
90
+ end
91
+ end
92
+
93
+ # check if installed package is at least version min_version
94
+ def package_min_version?(package, min_version, options={})
95
+ msg = messages.add("checking if #{package} is at least version #{min_version}", options)
96
+ return msg.failed unless package_installed?(package, :quiet => true)
97
+
98
+ if uses_apt?
99
+ v = exec("dpkg --list |grep #{package}")[:stdout].chomp
100
+ elsif uses_rpm?
101
+ v = exec("rpm -q #{package}")[:stdout].chomp
102
+ elsif uses_pacman?
103
+ v = exec("pacman -Q #{package}")[:stdout].chomp
104
+ else
105
+ return msg.failed('os not supported')
106
+ end
107
+
108
+ # convert version numbers to arrays
109
+ current_version = v.to_s.split(/[-. ]/ ).select {|j| j =~ /^[0-9]+$/ }
110
+ min_version = min_version.to_s.split(/[-. ]/ ).select {|j| j =~ /^[0-9]+$/ }
111
+
112
+ # compare
113
+ min_version.each_with_index do |i, pos|
114
+ break unless current_version[pos]
115
+ return msg.failed if i.to_i < current_version[pos].to_i
116
+ end
117
+
118
+ msg.ok
119
+ end
120
+
121
+ def remove_package(package, options={})
122
+ options = default_options.merge(options)
123
+
124
+ unless package_installed?(package, :quiet => true)
125
+ return messages.add("package #{package} not installed", options).ok
126
+ end
127
+
128
+ msg = messages.add("removing #{package}", options)
129
+ if uses_apt?
130
+ msg.parse_result(exec("DEBIAN_FRONTEND=noninteractive apt-get purge -y #{package}")[:exit_code])
131
+ elsif uses_emerge?
132
+ msg.parse_result(exec("emerge --unmerge #{package}")[:exit_code])
133
+ elsif uses_rpm?
134
+ msg.parse_result(exec("yum erase -y #{package}")[:exit_code])
135
+ elsif uses_pacman?
136
+ msg.parse_result(exec("echo y |pacman -R #{package}")[:exit_code])
137
+ elsif uses_opkg?
138
+ msg.parse_result(exec("opkg remove #{package}")[:exit_code])
139
+ else
140
+ msg.failed
141
+ end
142
+ end
143
+
144
+ def update_repos(options={})
145
+ options = default_options.merge(options)
146
+
147
+ msg = messages.add('updating system repositories', options)
148
+
149
+ if uses_apt?
150
+ ret = exec('apt-get update', options)
151
+ elsif uses_emerge?
152
+ ret = exec('emerge --sync', options)
153
+ elsif uses_rpm?
154
+ ret = exec('yum check-update', options)
155
+
156
+ # yum returns != 0 if packages that need to be updated are found
157
+ # we don't want that this is producing an error
158
+ ret[:exit_code] = 0 if ret[:exit_code] == 100
159
+ elsif uses_pacman?
160
+ ret = exec('pacman -Sy', options)
161
+ elsif uses_opkg?
162
+ ret = exec('opkg update', options)
163
+ else
164
+ return msg.failed
165
+ end
166
+
167
+ unless options[:live]
168
+ msg.parse_result(ret[:exit_code])
169
+ end
170
+
171
+ ret[:exit_code]
172
+ end
173
+
174
+ def system_update(options={})
175
+ options = default_options.merge(:live => true).merge(options)
176
+
177
+ update_repos
178
+
179
+ msg = messages.add('installing system updates', options)
180
+
181
+ if uses_apt?
182
+ ret = exec 'DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y', options
183
+ if is_ubuntu?
184
+ if install_package('update-manager-core')
185
+ ret = exec 'do-release-upgrade -d -f DistUpgradeViewNonInteractive', options
186
+ else
187
+ msg.failed('could not install the update-manager package')
188
+ return false
189
+ end
190
+ else
191
+ ret = exec 'DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y', options
192
+ end
193
+ elsif uses_emerge?
194
+ ret = exec('emerge -uND @world', options)
195
+ elsif uses_rpm?
196
+ ret = exec('yum upgrade -y', options)
197
+ elsif uses_pacman?
198
+ # pacman has no --yes option that i know of, so echoing y
199
+ ret = exec('echo y |pacman -Su', options)
200
+ elsif uses_opkg?
201
+ # upgrading openwrt is very experimental, and should not used normally
202
+ ret = exec('opkg upgrade $(echo $(opkg list-upgradable |cut -d' ' -f1 |grep -v Multiple))', options)
203
+ else
204
+ msg.failed('system not (yet) supported')
205
+ return false
206
+ end
207
+
208
+ unless options[:live]
209
+ msg.parse_result(ret[:exit_code])
210
+ end
211
+
212
+ ret[:exit_code]
213
+ end
214
+ end
215
+ end