ec2_amitools 1.0.2

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 (102) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +54 -0
  3. data/bin/console +14 -0
  4. data/bin/ec2-ami-tools-version +6 -0
  5. data/bin/ec2-bundle-image +6 -0
  6. data/bin/ec2-bundle-vol +6 -0
  7. data/bin/ec2-delete-bundle +6 -0
  8. data/bin/ec2-download-bundle +6 -0
  9. data/bin/ec2-migrate-bundle +6 -0
  10. data/bin/ec2-migrate-manifest +6 -0
  11. data/bin/ec2-unbundle +6 -0
  12. data/bin/ec2-upload-bundle +6 -0
  13. data/bin/setup +8 -0
  14. data/etc/ec2/amitools/cert-ec2-cn-north-1.pem +28 -0
  15. data/etc/ec2/amitools/cert-ec2-gov.pem +17 -0
  16. data/etc/ec2/amitools/cert-ec2.pem +23 -0
  17. data/etc/ec2/amitools/mappings.csv +9 -0
  18. data/lib/ec2/amitools/bundle.rb +251 -0
  19. data/lib/ec2/amitools/bundle_base.rb +58 -0
  20. data/lib/ec2/amitools/bundleimage.rb +94 -0
  21. data/lib/ec2/amitools/bundleimageparameters.rb +42 -0
  22. data/lib/ec2/amitools/bundlemachineparameters.rb +60 -0
  23. data/lib/ec2/amitools/bundleparameters.rb +120 -0
  24. data/lib/ec2/amitools/bundlevol.rb +240 -0
  25. data/lib/ec2/amitools/bundlevolparameters.rb +164 -0
  26. data/lib/ec2/amitools/crypto.rb +379 -0
  27. data/lib/ec2/amitools/decryptmanifest.rb +20 -0
  28. data/lib/ec2/amitools/defaults.rb +12 -0
  29. data/lib/ec2/amitools/deletebundle.rb +212 -0
  30. data/lib/ec2/amitools/deletebundleparameters.rb +78 -0
  31. data/lib/ec2/amitools/downloadbundle.rb +161 -0
  32. data/lib/ec2/amitools/downloadbundleparameters.rb +84 -0
  33. data/lib/ec2/amitools/exception.rb +86 -0
  34. data/lib/ec2/amitools/fileutil.rb +219 -0
  35. data/lib/ec2/amitools/format.rb +127 -0
  36. data/lib/ec2/amitools/instance-data.rb +97 -0
  37. data/lib/ec2/amitools/manifest_wrapper.rb +132 -0
  38. data/lib/ec2/amitools/manifestv20070829.rb +361 -0
  39. data/lib/ec2/amitools/manifestv20071010.rb +403 -0
  40. data/lib/ec2/amitools/manifestv3.rb +331 -0
  41. data/lib/ec2/amitools/mapids.rb +148 -0
  42. data/lib/ec2/amitools/migratebundle.rb +222 -0
  43. data/lib/ec2/amitools/migratebundleparameters.rb +173 -0
  44. data/lib/ec2/amitools/migratemanifest.rb +225 -0
  45. data/lib/ec2/amitools/migratemanifestparameters.rb +118 -0
  46. data/lib/ec2/amitools/minimalec2.rb +116 -0
  47. data/lib/ec2/amitools/parameter_exceptions.rb +34 -0
  48. data/lib/ec2/amitools/parameters_base.rb +168 -0
  49. data/lib/ec2/amitools/region.rb +93 -0
  50. data/lib/ec2/amitools/s3toolparameters.rb +183 -0
  51. data/lib/ec2/amitools/showversion.rb +12 -0
  52. data/lib/ec2/amitools/syschecks.rb +27 -0
  53. data/lib/ec2/amitools/tool_base.rb +224 -0
  54. data/lib/ec2/amitools/unbundle.rb +107 -0
  55. data/lib/ec2/amitools/unbundleparameters.rb +65 -0
  56. data/lib/ec2/amitools/uploadbundle.rb +361 -0
  57. data/lib/ec2/amitools/uploadbundleparameters.rb +108 -0
  58. data/lib/ec2/amitools/util.rb +532 -0
  59. data/lib/ec2/amitools/version.rb +33 -0
  60. data/lib/ec2/amitools/xmlbuilder.rb +237 -0
  61. data/lib/ec2/amitools/xmlutil.rb +55 -0
  62. data/lib/ec2/common/constants.rb +16 -0
  63. data/lib/ec2/common/curl.rb +110 -0
  64. data/lib/ec2/common/headers.rb +95 -0
  65. data/lib/ec2/common/headersv4.rb +173 -0
  66. data/lib/ec2/common/http.rb +333 -0
  67. data/lib/ec2/common/s3support.rb +231 -0
  68. data/lib/ec2/common/signature.rb +68 -0
  69. data/lib/ec2/oem/LICENSE.txt +58 -0
  70. data/lib/ec2/oem/open4.rb +399 -0
  71. data/lib/ec2/platform/base/architecture.rb +26 -0
  72. data/lib/ec2/platform/base/constants.rb +54 -0
  73. data/lib/ec2/platform/base/pipeline.rb +181 -0
  74. data/lib/ec2/platform/base.rb +57 -0
  75. data/lib/ec2/platform/current.rb +55 -0
  76. data/lib/ec2/platform/linux/architecture.rb +35 -0
  77. data/lib/ec2/platform/linux/constants.rb +23 -0
  78. data/lib/ec2/platform/linux/fstab.rb +99 -0
  79. data/lib/ec2/platform/linux/identity.rb +16 -0
  80. data/lib/ec2/platform/linux/image.rb +811 -0
  81. data/lib/ec2/platform/linux/mtab.rb +74 -0
  82. data/lib/ec2/platform/linux/pipeline.rb +40 -0
  83. data/lib/ec2/platform/linux/rsync.rb +114 -0
  84. data/lib/ec2/platform/linux/tar.rb +124 -0
  85. data/lib/ec2/platform/linux/uname.rb +50 -0
  86. data/lib/ec2/platform/linux.rb +83 -0
  87. data/lib/ec2/platform/solaris/architecture.rb +28 -0
  88. data/lib/ec2/platform/solaris/constants.rb +30 -0
  89. data/lib/ec2/platform/solaris/fstab.rb +43 -0
  90. data/lib/ec2/platform/solaris/identity.rb +16 -0
  91. data/lib/ec2/platform/solaris/image.rb +327 -0
  92. data/lib/ec2/platform/solaris/mtab.rb +29 -0
  93. data/lib/ec2/platform/solaris/pipeline.rb +40 -0
  94. data/lib/ec2/platform/solaris/rsync.rb +24 -0
  95. data/lib/ec2/platform/solaris/tar.rb +36 -0
  96. data/lib/ec2/platform/solaris/uname.rb +21 -0
  97. data/lib/ec2/platform/solaris.rb +38 -0
  98. data/lib/ec2/platform.rb +69 -0
  99. data/lib/ec2/version.rb +8 -0
  100. data/lib/ec2_amitools +1 -0
  101. data/lib/ec2_amitools.rb +7 -0
  102. metadata +184 -0
@@ -0,0 +1,28 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ #-------------------------------------------------------------------------------
12
+ # Solaris machine architectures as seen in EC2
13
+ require 'ec2/platform/base/architecture'
14
+ require 'ec2/platform/solaris/uname'
15
+ module EC2
16
+ module Platform
17
+ module Solaris
18
+ class Architecture < EC2::Platform::Base::Architecture
19
+ def self.bundling
20
+ processor = Uname.processor
21
+ return Architecture::I386 if processor =~ /^i\d86$/
22
+ return Architecture::X86_64 if processor =~ /^x86_64$/
23
+ return Architecture::UNKNOWN
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ #------------------------------------------------------------------------
12
+ # Solaris overrides for constants go here
13
+ #------------------------------------------------------------------------
14
+ require 'ec2/platform/base/constants'
15
+ module EC2
16
+ module Platform
17
+ module Solaris
18
+ module Constants
19
+ module Bundling
20
+ include EC2::Platform::Base::Constants::Bundling
21
+ DESTINATION = '/mnt'
22
+ end
23
+ module Utility
24
+ OPENSSL = '/usr/sfw/bin/openssl'
25
+ TAR = '/usr/sfw/bin/gtar'
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,43 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ require 'ec2/platform/linux/fstab'
12
+
13
+ module EC2
14
+ module Platform
15
+ module Solaris
16
+ class Fstab < EC2::Platform::Linux::Fstab
17
+ LOCATION = '/etc/vfstab'
18
+ def initialize(filename = LOCATION)
19
+ super filename
20
+ end
21
+
22
+ DEFAULT = IO.read(File.join('/etc', 'vfstab')) rescue <<TEXT
23
+ # Default /etc/vfstab
24
+ # Supplied by: #{PKG_NAME}-#{PKG_VERSION}-#{PKG_RELEASE}
25
+ #device device mount FS fsck mount mount
26
+ #to mount to fsck point type pass at boot options
27
+ #
28
+ fd - /dev/fd fd - no -
29
+ /proc - /proc proc - no -
30
+ /dev/dsk/c0d0s1 - - swap - no -
31
+ /dev/dsk/c0d0s0 /dev/rdsk/c0d0s0 / ufs 1 no -
32
+ /dev/dsk/c0d1s0 /dev/rdsk/c0d1s0 /mnt ufs 2 no -
33
+ /devices - /devices devfs - no -
34
+ sharefs - /etc/dfs/sharetab sharefs - no -
35
+ ctfs - /system/contract ctfs - no -
36
+ objfs - /system/object objfs - no -
37
+ swap - /tmp tmpfs - yes -
38
+ TEXT
39
+ LEGACY = :legacy # here for compatibility reasons
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,16 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ module EC2
12
+ module Platform
13
+ module Solaris; end
14
+ EC2::Platform::PEER = EC2::Platform::Solaris unless defined? EC2::Platform::PEER
15
+ end
16
+ end
@@ -0,0 +1,327 @@
1
+ # Copyright 2008-2014 Amazon.com, Inc. or its affiliates. All Rights
2
+ # Reserved. Licensed under the Amazon Software License (the
3
+ # "License"). You may not use this file except in compliance with the
4
+ # License. A copy of the License is located at
5
+ # http://aws.amazon.com/asl or in the "license" file accompanying this
6
+ # file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
+ # the License for the specific language governing permissions and
9
+ # limitations under the License.
10
+
11
+ #---------------------------------------------------------------------#
12
+ # Create a Solaris EC2 Image as follows:
13
+ # - create a bootable file-system archive in the SUN flash format
14
+ # - create, format and mount a blank file-system image
15
+ # - replicate the archive section of the flash archive into the image
16
+ # - customize the image
17
+ #
18
+ # Fasten your seat-belts and grab a pillow; this is painfully slow.
19
+ # Initial tests show an average bundling time of a virgin OpenSolaris
20
+ # system using this algorithm to be about 85-90 minutes. Optimization
21
+ # involves rewriting flar to combine the "flar create" and "flar split"
22
+ # steps into a "flar replicate" step
23
+ #---------------------------------------------------------------------#
24
+
25
+ require 'fileutils'
26
+ require 'ec2/oem/open4'
27
+ require 'ec2/amitools/fileutil'
28
+ require 'ec2/amitools/syschecks'
29
+ require 'ec2/amitools/exception'
30
+ require 'ec2/platform/solaris/mtab'
31
+ require 'ec2/platform/solaris/fstab'
32
+ require 'ec2/platform/solaris/constants'
33
+
34
+ module EC2
35
+ module Platform
36
+ module Solaris
37
+
38
+ class ExecutionError < RuntimeError
39
+ end
40
+
41
+ # This class encapsulate functionality to create an file loopback image
42
+ # from a volume. The image is created using mkfile. Sub-directories of the
43
+ # volume, including mounts of local filesystems, are copied to the image.
44
+ # Symbolic links are preserved wherever possible.
45
+ class Image
46
+ EXCLUDES = [ '/mnt' ]
47
+ WORKSPACE = '/mnt/ec2-bundle-workspace'
48
+ MOUNT = File.join( WORKSPACE, 'mnt' )
49
+ ARCHIVE = File.join( WORKSPACE, 'archive' )
50
+ PROFILING = true
51
+ RETRIES = 5
52
+ DELAY = 10
53
+ #---------------------------------------------------------------------#
54
+ def initialize( volume, # path to volume to be bundled
55
+ filename, # name of image file to create
56
+ size, # size of image file in MB
57
+ exclude, # list of directories to exclude
58
+ includes, # This does absolutely nothing on solaris - warrenr
59
+ filter, # Same as above - warrenr
60
+ vfstab=nil, # file system table to use
61
+ part_type=nil, # Disk partition type: MBR/GPT etc
62
+ arch=nil, # Architecture of the bundled volume
63
+ script=nil, # Post-cloning customization script
64
+ debug = false )
65
+ @volume = volume
66
+ @filename = filename
67
+ @size = size
68
+ @exclude = exclude
69
+ @debug = debug
70
+ @arch = arch
71
+ @script = script
72
+ self.set_partition_type( part_type )
73
+ if vfstab.nil? or vfstab == :legacy
74
+ @vfstab = EC2::Platform::Solaris::Fstab::DEFAULT
75
+ elsif File.exists? vfstab
76
+ @vfstab = IO.read(vfstab)
77
+ else
78
+ @vfstab = vfstab
79
+ end
80
+
81
+ # Exclude the workspace if it is in the volume being bundled.
82
+ @exclude << WORKSPACE if( WORKSPACE.index(volume) == 0 )
83
+ end
84
+
85
+ #---------------------------------------------------------------------#
86
+ def set_partition_type( input )
87
+ input ||= EC2::Platform::PartitionType::NONE
88
+ if input == EC2::Platform::PartitionType::NONE
89
+ @part_type = EC2::Platform::PartitionType::NONE
90
+ else
91
+ raise NotImplementedError, "Disk images not supported for Solaris"
92
+ end
93
+ end
94
+
95
+ #---------------------------------------------------------------------#
96
+ # Clone a running volume into a bootable Amazon Machine Image.
97
+ def make
98
+ begin
99
+ announce( "Cloning #{@volume} into image file #{@filename}...", true)
100
+ announce( 'Excluding: ', true )
101
+ @exclude.each { |x| announce( "\t #{x}", true ) }
102
+ archive
103
+ prepare
104
+ replicate
105
+ ensure
106
+ cleanup
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+
113
+ #---------------------------------------------------------------------#
114
+ # Create, format and mount the blank machine image file.
115
+ # TODO: investigate parallelizing prepare() with archive()
116
+ def prepare
117
+ FileUtils.mkdir_p( MOUNT )
118
+ announce( 'Creating and formatting file-system image...', true )
119
+ evaluate( "/usr/sbin/mkfile #{@size*1024*1024} #{@filename}" )
120
+
121
+ announce( 'Formatting file-system image...' )
122
+ execute( 'sync && devfsadm -C' )
123
+ @device = evaluate('/usr/sbin/lofiadm -a ' + @filename).strip
124
+ number = @device.split(/\//).last rescue nil
125
+ raise FatalError.new('Failed to attach image to a device' ) unless number
126
+ execute( "echo y | newfs /dev/rlofi/#{number} < /dev/null > /dev/null 2>&1", true )
127
+
128
+ execute( 'sync' )
129
+ mount( @device, MOUNT )
130
+ end
131
+
132
+ #---------------------------------------------------------------------#
133
+ # Create a flash archive of the system at the desired volume root.
134
+ def archive
135
+ FileUtils.mkdir_p( WORKSPACE )
136
+ announce( 'Creating flash archive of file system...', true )
137
+ exempt = []
138
+ @exclude.each do |item|
139
+ item = File.expand_path(item)
140
+ # Since flarcreate does not allow you to exclude a mount-point from
141
+ # a flash archive, we work around this by listing the files in that
142
+ # directory and excluding them individually.
143
+ if mounted? item
144
+ exempt.concat( evaluate( 'ls -A ' + item).split(/\s/).map{|i| File.join( item, i ) } )
145
+ else
146
+ exempt << item
147
+ end
148
+ end
149
+ exempt = exempt.join( ' -x ')
150
+
151
+ invocation = ['flar create -n ec2.archive -S -R ' + @volume ]
152
+ invocation << ( '-x ' + exempt ) unless exempt.empty?
153
+ invocation << ARCHIVE
154
+ evaluate( invocation.join( ' ' ) )
155
+ raise FatalError.new( "Archive creation failed" ) unless File.exist?( ARCHIVE )
156
+
157
+ asize = FileUtil.size( ARCHIVE ) / ( 1024 * 1024 )
158
+ raise FatalError.new( "Archive too small" ) unless asize > 0
159
+ raise FatalError.new( 'Archive exceeds target size' ) if asize > @size
160
+ end
161
+
162
+ #---------------------------------------------------------------------#
163
+ # Extract the archive into the file-system image.
164
+ def replicate
165
+ announce( 'Replicating archive to image (this will take a while)...', true )
166
+ # Extract flash archive into mounted image. The flar utility places
167
+ # the output in a folder called 'archive'. Since we cannot override
168
+ # this, we need to extract the content, move it to the image root
169
+ # and delete remove the cruft
170
+ extract = File.join( MOUNT, 'archive')
171
+ execute( "flar split -S archive -d #{MOUNT} -f #{ARCHIVE}" )
172
+ execute( "ls -A #{extract} | xargs -i mv #{extract}/'{}' #{MOUNT}" )
173
+ FileUtils.rm_rf( File.join(MOUNT, 'archive') )
174
+ FileUtils.rm_rf( File.join(MOUNT, 'identification') )
175
+
176
+ announce 'Saving system configuration...'
177
+ ['/boot/solaris/bootenv.rc', '/etc/vfstab', '/etc/path_to_inst'].each do |path|
178
+ file = File.join( MOUNT, path )
179
+ FileUtils.cp( file, file + '.phys' )
180
+ end
181
+
182
+ announce 'Fine-tuning system configuration...'
183
+ execute( '/usr/sbin/sys-unconfig -R ' + MOUNT )
184
+ bootenv = File.join( MOUNT, '/boot/solaris/bootenv.rc' )
185
+ execute( "sed '/setprop bootpath/,/setprop console/d' < #{bootenv}.phys > #{bootenv}" )
186
+ execute( "sed '/dsk/d' < #{MOUNT}/etc/vfstab.phys > #{MOUNT}/etc/vfstab" )
187
+
188
+ FileUtils.rm_f( File.join(MOUNT, '/etc/rc2.d/S99dtlogin') )
189
+
190
+ announce 'Creating missing image directories...'
191
+ [ '/dev/dsk', '/dev/rdsk', '/dev/fd', '/etc/mnttab', ].each do |item|
192
+ FileUtils.mkdir_p( File.join( MOUNT, item ) )
193
+ end
194
+
195
+ FileUtils.ln_s( '../../devices/xpvd/xdf@0:a', File.join( MOUNT, '/dev/dsk/c0d0s0' ) )
196
+ FileUtils.ln_s( '../../devices/xpvd/xdf@0:a,raw', File.join( MOUNT, '/dev/rdsk/c0d0s0' ) )
197
+
198
+ FileUtils.touch( File.join( MOUNT, Mtab::LOCATION ) )
199
+ fstab = File.join( MOUNT, Fstab::LOCATION )
200
+ File.open(fstab, 'w+') {|io| io << @vfstab }
201
+ announce( "--->/etc/vfstab<---:\n" + @vfstab , true )
202
+
203
+ execute( "bootadm update-archive -R #{MOUNT} > /dev/null 2>&1", true )
204
+
205
+ announce( 'Disable xen services' )
206
+ file = File.join( MOUNT, '/var/svc/profile/upgrade' )
207
+ execute( 'echo "/usr/sbin/svcadm disable svc:/system/xctl/xend:default" >> ' + file )
208
+
209
+ announce 'Setting up DHCP boot'
210
+ FileUtils.touch( File.join( MOUNT, '/etc/hostname.xnf0' ) )
211
+ FileUtils.touch( File.join( MOUNT, '/etc/dhcp.xnf0' ) )
212
+
213
+ announce 'Setting keyboard layout'
214
+ kbd = File.join( MOUNT, '/etc/default/kbd' )
215
+ execute( "egrep '^LAYOUT' #{kbd} || echo 'LAYOUT=US-English' >> #{kbd}" )
216
+
217
+ customize
218
+ end
219
+
220
+ def customize
221
+ return unless @script and File.executable?(@script)
222
+ announce 'Customizing replicated volume mounted at %s with script %s' % [MOUNT, @script]
223
+ output = evaluate('%s "%s"' % [@script, MOUNT])
224
+ STDERR.puts output if @debug
225
+ end
226
+
227
+ #---------------------------------------------------------------------#
228
+ # Mount the specified device. The mount point is created if necessary.
229
+ # We let mount guess the appropriate file system type.
230
+ def mount(device, mpoint)
231
+ FileUtils.mkdir_p(mpoint) if not FileUtil::exists?(mpoint)
232
+ raise FatalError.new("image already mounted") if mounted?(mpoint)
233
+ execute( 'sync' )
234
+ execute( 'mount ' + device + ' ' + mpoint )
235
+ end
236
+
237
+ #---------------------------------------------------------------------#
238
+
239
+ def unmount(mpoint, force=false)
240
+ GC.start
241
+ execute( 'sync && sync && sync' )
242
+ if mounted?( mpoint ) then
243
+ execute( 'umount ' + (force ? '-f ' : '') + mpoint )
244
+ end
245
+ end
246
+
247
+ #---------------------------------------------------------------------#
248
+
249
+ def mounted?(mpoint)
250
+ EC2::Platform::Solaris::Mtab.load.entries.keys.include? mpoint
251
+ end
252
+
253
+ #---------------------------------------------------------------------#
254
+ # Cleanup after self:
255
+ # - unmount relevant mount points.
256
+ # - release any device and resources attached to the image and mount-point
257
+ # - delete any intermediate files and directories.
258
+ def cleanup
259
+ attempts = 0
260
+ begin
261
+ unmount( MOUNT )
262
+ rescue ExecutionError
263
+ announce "Unable to unmount image. Retrying after a short sleep."
264
+ attempts += 1
265
+ if attempts < RETRIES
266
+ sleep DELAY
267
+ retry
268
+ else
269
+ announce( "Unable to unmount image after #{RETRIES} attempts. Baling out...", true )
270
+ unmount( MOUNT, true )
271
+ if File.exist?( @filename )
272
+ announce( "Deleting image file #{@filename}..." )
273
+ FileUtils.rm_f( @filename )
274
+ end
275
+ end
276
+ end
277
+ unless @device.nil?
278
+ devices = evaluate( 'lofiadm' ).split( /\n/ )
279
+ devices.each do |item|
280
+ execute( 'lofiadm -d' + @device ) if item.index( @device ) == 0
281
+ end
282
+ end
283
+ execute( 'devfsadm -C' )
284
+ FileUtils.rm_rf( WORKSPACE ) if File.directory?( WORKSPACE )
285
+ end
286
+
287
+ #---------------------------------------------------------------------#
288
+ # Output a message if running in debug mode
289
+ def announce(something, force=false)
290
+ STDOUT.puts( something ) if @debug or force
291
+ end
292
+
293
+ #---------------------------------------------------------------------#
294
+ # Execute the command line passed in.
295
+ def execute( cmd, verbattim = false )
296
+ verbattim ||= @debug
297
+ invocation = [ cmd ]
298
+ invocation << ' 2>&1 > /dev/null' unless verbattim
299
+ announce( "Executing: '#{cmd}' " )
300
+ time = Time.now
301
+ raise ExecutionError.new( "Failed to execute '#{cmd}'.") unless system( invocation.join )
302
+ announce( "Time: #{Time.now - time}s", PROFILING )
303
+ end
304
+
305
+ #---------------------------------------------------------------------#
306
+ # Execute command line passed in and return STDOUT output if successful.
307
+ def evaluate( cmd, success = 0, verbattim = false )
308
+ verbattim ||= @debug
309
+ cmd << ' 2> /dev/null' unless verbattim
310
+ announce( "Evaluating: '#{cmd}' " )
311
+ time = Time.now
312
+ pid, stdin, stdout, stderr = Open4::popen4( cmd )
313
+ ignore stdin
314
+ pid, status = Process::waitpid2 pid
315
+ unless status.exitstatus == success
316
+ raise ExecutionError.new( "Failed to evaluate '#{cmd }'. Reason: #{stderr.read}." )
317
+ end
318
+ announce( "Time: #{Time.now - time}s", PROFILING )
319
+ stdout.read
320
+ end
321
+
322
+ def ignore(stuff) stuff end
323
+
324
+ end
325
+ end
326
+ end
327
+ end