boxgrinder-build 0.2.0 → 0.3.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.
- data/bin/boxgrinder-build +81 -0
- data/docs/examples/appliances/appliances.appl +5 -0
- data/docs/examples/appliances/minimal.appl +9 -0
- data/docs/examples/appliances/mix.appl +8 -0
- data/docs/examples/appliances/packages.appl +13 -0
- data/lib/boxgrinder-build/appliance.rb +85 -18
- data/lib/boxgrinder-build/helpers/appliance-customize-helper.rb +2 -2
- data/lib/boxgrinder-build/helpers/guestfs-helper.rb +18 -15
- data/lib/boxgrinder-build/helpers/package-helper.rb +65 -0
- data/lib/boxgrinder-build/helpers/plugin-helper.rb +89 -0
- data/lib/boxgrinder-build/{defaults.rb → managers/base-plugin-manager.rb} +41 -8
- data/lib/{boxgrinder-build.rb → boxgrinder-build/managers/delivery-plugin-manager.rb} +15 -18
- data/lib/boxgrinder-build/managers/operating-system-plugin-manager.rb +6 -0
- data/{bin/boxgrinder → lib/boxgrinder-build/managers/platform-plugin-manager.rb} +6 -3
- data/lib/boxgrinder-build/plugins/base-plugin.rb +98 -0
- data/lib/boxgrinder-build/plugins/delivery/base/base-delivery-plugin.rb +43 -0
- data/lib/boxgrinder-build/plugins/delivery/local/local-plugin.rb +57 -0
- data/lib/boxgrinder-build/{helpers → plugins/delivery/s3}/aws-helper.rb +0 -0
- data/lib/boxgrinder-build/plugins/delivery/s3/s3-plugin.rb +133 -0
- data/lib/boxgrinder-build/{helpers/ssh-helper.rb → plugins/delivery/sftp/sftp-plugin.rb} +61 -42
- data/lib/boxgrinder-build/{appliance-kickstart.rb → plugins/os/base/kickstart.rb} +45 -55
- data/lib/boxgrinder-build/{images/raw-image.rb → plugins/os/base/rpm-based-os-plugin.rb} +63 -60
- data/lib/boxgrinder-build/{erb → plugins/os/base/src}/appliance.ks.erb +2 -5
- data/{src → lib/boxgrinder-build/plugins/os/base/src}/base.repo +0 -0
- data/{src → lib/boxgrinder-build/plugins/os/base/src}/motd.init +0 -0
- data/lib/boxgrinder-build/{validators/appliance-dependency-validator.rb → plugins/os/base/validators/rpm-dependency-validator.rb} +1 -1
- data/lib/boxgrinder-build/{models/ssh-config.rb → plugins/os/base-operating-system-plugin.rb} +10 -17
- data/lib/boxgrinder-build/plugins/os/centos/centos-plugin.rb +72 -0
- data/lib/boxgrinder-build/plugins/os/fedora/fedora-plugin.rb +66 -0
- data/lib/boxgrinder-build/plugins/os/rhel/rhel-plugin.rb +38 -0
- data/lib/boxgrinder-build/plugins/platform/base-platform-plugin.rb +37 -0
- data/lib/boxgrinder-build/plugins/platform/ec2/ec2-plugin.rb +283 -0
- data/{src → lib/boxgrinder-build/plugins/platform/ec2/src}/f12/yum.conf +0 -0
- data/{src/ec2 → lib/boxgrinder-build/plugins/platform/ec2/src}/f12-i386-boxgrinder.repo +0 -0
- data/{src/ec2 → lib/boxgrinder-build/plugins/platform/ec2/src}/f12-x86_64-boxgrinder.repo +0 -0
- data/{src/ec2 → lib/boxgrinder-build/plugins/platform/ec2/src}/fstab_32bit +0 -0
- data/{src/ec2 → lib/boxgrinder-build/plugins/platform/ec2/src}/fstab_64bit +0 -0
- data/{src/ec2 → lib/boxgrinder-build/plugins/platform/ec2/src}/ifcfg-eth0 +0 -0
- data/{src/ec2 → lib/boxgrinder-build/plugins/platform/ec2/src}/rc_local +1 -4
- data/{src/README.vmware → lib/boxgrinder-build/plugins/platform/vmware/src/README} +10 -10
- data/{src → lib/boxgrinder-build/plugins/platform/vmware/src}/base.vmdk +1 -1
- data/{src → lib/boxgrinder-build/plugins/platform/vmware/src}/base.vmx +0 -0
- data/lib/boxgrinder-build/plugins/platform/vmware/vmware-plugin.rb +181 -0
- data/lib/boxgrinder-build/validators/config-validator.rb +0 -19
- metadata +73 -44
- data/docs/examples/appliances/appliances-appliance/appliances-appliance.appl +0 -6
- data/docs/examples/appliances/appliances-appliance/appliances-appliance.pp +0 -16
- data/docs/examples/appliances/minimal-appliance/minimal-appliance.appl +0 -2
- data/docs/examples/appliances/minimal-appliance/minimal-appliance.pp +0 -16
- data/docs/examples/appliances/mix-appliance/mix-appliance.appl +0 -9
- data/docs/examples/appliances/mix-appliance/mix-appliance.pp +0 -16
- data/docs/examples/appliances/packages-appliance/packages-appliance.appl +0 -6
- data/docs/examples/appliances/packages-appliance/packages-appliance.pp +0 -16
- data/extras/sign-rpms +0 -12
- data/lib/boxgrinder-build/boxgrinder.rb +0 -93
- data/lib/boxgrinder-build/helpers/release-helper.rb +0 -136
- data/lib/boxgrinder-build/images/ec2-image.rb +0 -317
- data/lib/boxgrinder-build/images/vmware-image.rb +0 -214
- data/lib/boxgrinder-build/validators/appliance-definition-validator.rb +0 -89
- data/lib/progressbar/progressbar.rb +0 -236
- data/src/oddthesis/RPM-GPG-KEY-oddthesis +0 -30
- data/src/oddthesis/oddthesis.repo +0 -23
@@ -1,317 +0,0 @@
|
|
1
|
-
# JBoss, Home of Professional Open Source
|
2
|
-
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
-
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
-
# full listing of individual contributors.
|
5
|
-
#
|
6
|
-
# This is free software; you can redistribute it and/or modify it
|
7
|
-
# under the terms of the GNU Lesser General Public License as
|
8
|
-
# published by the Free Software Foundation; either version 2.1 of
|
9
|
-
# the License, or (at your option) any later version.
|
10
|
-
#
|
11
|
-
# This software is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
-
# Lesser General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU Lesser General Public
|
17
|
-
# License along with this software; if not, write to the Free
|
18
|
-
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
-
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
-
|
21
|
-
require 'rake/tasklib'
|
22
|
-
require 'fileutils'
|
23
|
-
require 'boxgrinder-core/validators/errors'
|
24
|
-
require 'yaml'
|
25
|
-
require 'AWS'
|
26
|
-
require 'aws/s3'
|
27
|
-
require 'boxgrinder-build/helpers/aws-helper'
|
28
|
-
include AWS::S3
|
29
|
-
|
30
|
-
module BoxGrinder
|
31
|
-
class EC2Image < Rake::TaskLib
|
32
|
-
|
33
|
-
def initialize( config, appliance_config, options = {} )
|
34
|
-
@config = config
|
35
|
-
@appliance_config = appliance_config
|
36
|
-
|
37
|
-
@log = options[:log] || Logger.new(STDOUT)
|
38
|
-
@exec_helper = options[:exec_helper] || ExecHelper.new( :log => @log )
|
39
|
-
|
40
|
-
define_tasks
|
41
|
-
end
|
42
|
-
|
43
|
-
def define_tasks
|
44
|
-
directory @appliance_config.path.dir.ec2.build
|
45
|
-
directory @appliance_config.path.dir.ec2.bundle
|
46
|
-
|
47
|
-
# TODO we should depend on actual disk file, not xml I think
|
48
|
-
file @appliance_config.path.file.ec2.disk => [ @appliance_config.path.file.raw.xml, @appliance_config.path.dir.ec2.build ] do
|
49
|
-
convert_image_to_ec2_format
|
50
|
-
end
|
51
|
-
|
52
|
-
file @appliance_config.path.file.ec2.manifest => [ @appliance_config.path.file.ec2.disk, @appliance_config.path.dir.ec2.bundle ] do
|
53
|
-
@aws_helper = AWSHelper.new( @config, @appliance_config )
|
54
|
-
bundle_image
|
55
|
-
end
|
56
|
-
|
57
|
-
task "appliance:#{@appliance_config.name}:ec2:bundle" => [ @appliance_config.path.file.ec2.manifest ]
|
58
|
-
|
59
|
-
task "appliance:#{@appliance_config.name}:ec2:upload" => [ "appliance:#{@appliance_config.name}:ec2:bundle" ] do
|
60
|
-
@aws_helper = AWSHelper.new( @config, @appliance_config )
|
61
|
-
upload_image
|
62
|
-
end
|
63
|
-
|
64
|
-
task "appliance:#{@appliance_config.name}:ec2:register" => [ "appliance:#{@appliance_config.name}:ec2:upload" ] do
|
65
|
-
@aws_helper = AWSHelper.new( @config, @appliance_config )
|
66
|
-
register_image
|
67
|
-
end
|
68
|
-
|
69
|
-
desc "Build #{@appliance_config.simple_name} appliance for Amazon EC2"
|
70
|
-
task "appliance:#{@appliance_config.name}:ec2" => [ @appliance_config.path.file.ec2.disk ]
|
71
|
-
end
|
72
|
-
|
73
|
-
def bundle_image
|
74
|
-
@log.info "Bundling AMI..."
|
75
|
-
|
76
|
-
@exec_helper.execute( "ec2-bundle-image -i #{@appliance_config.path.file.ec2.disk} --kernel #{AWS_DEFAULTS[:kernel_id][@appliance_config.hardware.arch]} --ramdisk #{AWS_DEFAULTS[:ramdisk_id][@appliance_config.hardware.arch]} -c #{@aws_helper.aws_data['cert_file']} -k #{@aws_helper.aws_data['key_file']} -u #{@aws_helper.aws_data['account_number']} -r #{@appliance_config.hardware.arch} -d #{@appliance_config.path.dir.ec2.bundle}" )
|
77
|
-
|
78
|
-
@log.info "Bundling AMI finished."
|
79
|
-
end
|
80
|
-
|
81
|
-
def appliance_already_uploaded?
|
82
|
-
begin
|
83
|
-
bucket = Bucket.find( @aws_helper.aws_data['bucket_name'] )
|
84
|
-
rescue
|
85
|
-
return false
|
86
|
-
end
|
87
|
-
|
88
|
-
manifest_location = @aws_helper.bucket_manifest_key( @appliance_config.name )
|
89
|
-
manifest_location = manifest_location[ manifest_location.index( "/" ) + 1, manifest_location.length ]
|
90
|
-
|
91
|
-
for object in bucket.objects do
|
92
|
-
return true if object.key.eql?( manifest_location )
|
93
|
-
end
|
94
|
-
|
95
|
-
false
|
96
|
-
end
|
97
|
-
|
98
|
-
def upload_image
|
99
|
-
if appliance_already_uploaded?
|
100
|
-
@log.debug "Image for #{@appliance_config.simple_name} appliance is already uploaded, skipping..."
|
101
|
-
return
|
102
|
-
end
|
103
|
-
|
104
|
-
@log.info "Uploading #{@appliance_config.simple_name} AMI to bucket '#{@aws_helper.aws_data['bucket_name']}'..."
|
105
|
-
|
106
|
-
@exec_helper.execute( "ec2-upload-bundle -b #{@aws_helper.bucket_key( @appliance_config.name )} -m #{@appliance_config.path.file.ec2.manifest} -a #{@aws_helper.aws_data['access_key']} -s #{@aws_helper.aws_data['secret_access_key']} --retry" )
|
107
|
-
end
|
108
|
-
|
109
|
-
def register_image
|
110
|
-
ami_info = @aws_helper.ami_info( @appliance_config.name )
|
111
|
-
|
112
|
-
if ami_info
|
113
|
-
@log.info "Image is registered under id: #{ami_info.imageId}"
|
114
|
-
return
|
115
|
-
else
|
116
|
-
ami_info = @aws_helper.ec2.register_image( :image_location => @aws_helper.bucket_manifest_key( @appliance_config.name ) )
|
117
|
-
@log.info "Image successfully registered under id: #{ami_info.imageId}."
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def convert_image_to_ec2_format
|
122
|
-
@log.info "Converting #{@appliance_config.simple_name} appliance image to EC2 format..."
|
123
|
-
|
124
|
-
ec2_disk_mount_dir = "#{@config.dir.build}/#{@appliance_config.appliance_path}/tmp/ec2-#{rand(9999999999).to_s.center(10, rand(9).to_s)}"
|
125
|
-
raw_disk_mount_dir = "#{@config.dir.build}/#{@appliance_config.appliance_path}/tmp/raw-#{rand(9999999999).to_s.center(10, rand(9).to_s)}"
|
126
|
-
|
127
|
-
ec2_prepare_disk
|
128
|
-
ec2_create_filesystem
|
129
|
-
|
130
|
-
raw_disk_offset = calculate_disk_offset( @appliance_config.path.file.raw.disk )
|
131
|
-
|
132
|
-
ec2_loop_device = mount_image(@appliance_config.path.file.ec2.disk, ec2_disk_mount_dir )
|
133
|
-
raw_loop_device = mount_image(@appliance_config.path.file.raw.disk, raw_disk_mount_dir, raw_disk_offset )
|
134
|
-
|
135
|
-
sync_files( raw_disk_mount_dir, ec2_disk_mount_dir )
|
136
|
-
|
137
|
-
umount_image( @appliance_config.path.file.raw.disk, raw_disk_mount_dir, raw_loop_device )
|
138
|
-
umount_image( @appliance_config.path.file.ec2.disk, ec2_disk_mount_dir, ec2_loop_device )
|
139
|
-
|
140
|
-
guestfs_helper = GuestFSHelper.new( @appliance_config.path.file.ec2.disk, :log => @log )
|
141
|
-
guestfs = guestfs_helper.guestfs
|
142
|
-
|
143
|
-
create_devices( guestfs )
|
144
|
-
upload_fstab( guestfs )
|
145
|
-
|
146
|
-
guestfs.mkdir( "/data" ) if @appliance_config.is64bit?
|
147
|
-
|
148
|
-
enable_networking( guestfs )
|
149
|
-
upload_rc_local( guestfs )
|
150
|
-
|
151
|
-
guestfs_helper.rebuild_rpm_database
|
152
|
-
|
153
|
-
install_additional_packages( guestfs )
|
154
|
-
change_configuration( guestfs )
|
155
|
-
|
156
|
-
if @appliance_config.os.name.eql?("fedora") and @appliance_config.os.version.to_s.eql?("12")
|
157
|
-
@log.debug "Downgrading udev package to use in EC2 environment..."
|
158
|
-
|
159
|
-
repo_included = false
|
160
|
-
|
161
|
-
@appliance_config.repos.each do |repo|
|
162
|
-
repo_included = true if repo['baseurl'] == "http://repo.boxgrinder.org/boxgrinder/packages/fedora/12/RPMS/#{@appliance_config.hardware.arch}"
|
163
|
-
end
|
164
|
-
|
165
|
-
guestfs.upload( "#{@config.dir.base}/src/ec2/f12-#{@appliance_config.hardware.arch}-boxgrinder.repo", "/etc/yum.repos.d/f12-#{@appliance_config.hardware.arch}-boxgrinder.repo" ) unless repo_included
|
166
|
-
guestfs.sh( "yum -y downgrade udev-142" )
|
167
|
-
guestfs.upload( "#{@config.dir.base}/src/f12/yum.conf", "/etc/yum.conf" )
|
168
|
-
guestfs.rm_rf( "/etc/yum.repos.d/f12-#{@appliance_config.hardware.arch}-boxgrinder.repo" ) unless repo_included
|
169
|
-
|
170
|
-
@log.debug "Package udev downgraded."
|
171
|
-
|
172
|
-
# TODO EC2 fix, remove that after Fedora pushes kernels to Amazon
|
173
|
-
@log.debug "Disabling unnecessary services..."
|
174
|
-
guestfs.sh( "/sbin/chkconfig ksm off" ) if guestfs.exists( "/etc/init.d/ksm" ) != 0
|
175
|
-
guestfs.sh( "/sbin/chkconfig ksmtuned off" ) if guestfs.exists( "/etc/init.d/ksmtuned" ) != 0
|
176
|
-
@log.debug "Services disabled."
|
177
|
-
end
|
178
|
-
|
179
|
-
guestfs.close
|
180
|
-
|
181
|
-
@log.info "Image converted to EC2 format."
|
182
|
-
end
|
183
|
-
|
184
|
-
def ec2_prepare_disk
|
185
|
-
# TODO add progress bar?
|
186
|
-
@log.debug "Preparing disk for EC2 image..."
|
187
|
-
@exec_helper.execute "dd if=/dev/zero of=#{@appliance_config.path.file.ec2.disk} bs=1 count=0 seek=#{10 * 1024}M"
|
188
|
-
@log.debug "Disk for EC2 image prepared"
|
189
|
-
end
|
190
|
-
|
191
|
-
def ec2_create_filesystem
|
192
|
-
@log.debug "Creating filesystem..."
|
193
|
-
@exec_helper.execute "mkfs.ext3 -F #{@appliance_config.path.file.ec2.disk}"
|
194
|
-
@log.debug "Filesystem created"
|
195
|
-
end
|
196
|
-
|
197
|
-
def calculate_disk_offset( disk )
|
198
|
-
loop_device = get_loop_device
|
199
|
-
|
200
|
-
@exec_helper.execute( "sudo losetup #{loop_device} #{disk}" )
|
201
|
-
offset = @exec_helper.execute("sudo parted -m #{loop_device} 'unit B print' | grep '^1' | awk -F: '{ print $2 }'").strip.chop
|
202
|
-
@exec_helper.execute( "sudo losetup -d #{loop_device}" )
|
203
|
-
|
204
|
-
offset
|
205
|
-
end
|
206
|
-
|
207
|
-
def mount_image( disk, mount_dir, offset = 0 )
|
208
|
-
loop_device = get_loop_device
|
209
|
-
|
210
|
-
@log.debug "Mounting image #{File.basename( disk )} in #{mount_dir} using #{loop_device} with offset #{offset}"
|
211
|
-
FileUtils.mkdir_p( mount_dir )
|
212
|
-
@exec_helper.execute( "sudo losetup -o #{offset.to_s} #{loop_device} #{disk}" )
|
213
|
-
@exec_helper.execute( "sudo mount #{loop_device} -t ext3 #{ mount_dir}")
|
214
|
-
|
215
|
-
loop_device
|
216
|
-
end
|
217
|
-
|
218
|
-
def umount_image( disk, mount_dir, loop_device )
|
219
|
-
@log.debug "Unmounting image #{File.basename( disk )}"
|
220
|
-
@exec_helper.execute( "sudo umount -d #{loop_device}" )
|
221
|
-
FileUtils.rm_rf( mount_dir )
|
222
|
-
end
|
223
|
-
|
224
|
-
|
225
|
-
def sync_files( from_dir, to_dir )
|
226
|
-
@log.debug "Syncing files between #{from_dir} and #{to_dir}..."
|
227
|
-
@exec_helper.execute "sudo rsync -u -r -a #{from_dir}/* #{to_dir}"
|
228
|
-
@log.debug "Sync finished."
|
229
|
-
end
|
230
|
-
|
231
|
-
def cache_rpms( rpms )
|
232
|
-
for name in rpms.keys
|
233
|
-
cache_file = "#{@config.dir.src_cache}/#{name}"
|
234
|
-
|
235
|
-
if ( ! File.exist?( cache_file ) )
|
236
|
-
FileUtils.mkdir_p( @config.dir.src_cache )
|
237
|
-
@exec_helper.execute( "wget #{rpms[name]} -O #{cache_file}" )
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
def create_devices( guestfs )
|
243
|
-
@log.debug "Creating required devices..."
|
244
|
-
guestfs.sh( "/sbin/MAKEDEV -d /dev -x console" )
|
245
|
-
guestfs.sh( "/sbin/MAKEDEV -d /dev -x null" )
|
246
|
-
guestfs.sh( "/sbin/MAKEDEV -d /dev -x zero" )
|
247
|
-
@log.debug "Devices created."
|
248
|
-
end
|
249
|
-
|
250
|
-
def upload_fstab( guestfs )
|
251
|
-
@log.debug "Uploading '/etc/fstab' file..."
|
252
|
-
fstab_file = @appliance_config.is64bit? ? "#{@config.dir.base}/src/ec2/fstab_64bit" : "#{@config.dir.base}/src/ec2/fstab_32bit"
|
253
|
-
guestfs.upload( fstab_file, "/etc/fstab" )
|
254
|
-
@log.debug "'/etc/fstab' file uploaded."
|
255
|
-
end
|
256
|
-
|
257
|
-
# enable networking on default runlevels
|
258
|
-
def enable_networking( guestfs )
|
259
|
-
@log.debug "Enabling networking..."
|
260
|
-
guestfs.sh( "/sbin/chkconfig network on" )
|
261
|
-
guestfs.upload( "#{@config.dir.base}/src/ec2/ifcfg-eth0", "/etc/sysconfig/network-scripts/ifcfg-eth0" )
|
262
|
-
@log.debug "Networking enabled."
|
263
|
-
end
|
264
|
-
|
265
|
-
def upload_rc_local( guestfs )
|
266
|
-
@log.debug "Uploading '/etc/rc.local' file..."
|
267
|
-
rc_local = Tempfile.new('rc_local')
|
268
|
-
rc_local << guestfs.read_file( "/etc/rc.local" ) + File.read( "#{@config.dir.base}/src/ec2/rc_local" )
|
269
|
-
rc_local.flush
|
270
|
-
|
271
|
-
guestfs.upload( rc_local.path, "/etc/rc.local" )
|
272
|
-
|
273
|
-
rc_local.close
|
274
|
-
@log.debug "'/etc/rc.local' file uploaded."
|
275
|
-
end
|
276
|
-
|
277
|
-
def install_additional_packages( guestfs )
|
278
|
-
rpms = {
|
279
|
-
File.basename(AWS_DEFAULTS[:kernel_rpm][@appliance_config.hardware.arch]) => AWS_DEFAULTS[:kernel_rpm][@appliance_config.hardware.arch],
|
280
|
-
"ec2-ami-tools.noarch.rpm" => "http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm"
|
281
|
-
}
|
282
|
-
|
283
|
-
cache_rpms( rpms )
|
284
|
-
|
285
|
-
@log.debug "Installing additional packages (#{rpms.keys.join( ", " )})..."
|
286
|
-
guestfs.mkdir_p("/tmp/rpms")
|
287
|
-
|
288
|
-
for name in rpms.keys
|
289
|
-
cache_file = "#{@config.dir.src_cache}/#{name}"
|
290
|
-
guestfs.upload( cache_file, "/tmp/rpms/#{name}" )
|
291
|
-
end
|
292
|
-
|
293
|
-
guestfs.sh( "rpm -Uvh --nodeps /tmp/rpms/*.rpm" )
|
294
|
-
guestfs.rm_rf("/tmp/rpms")
|
295
|
-
@log.debug "Additional packages installed."
|
296
|
-
end
|
297
|
-
|
298
|
-
def change_configuration( guestfs )
|
299
|
-
@log.debug "Changing configuration files using augeas..."
|
300
|
-
guestfs.aug_init( "/", 0 )
|
301
|
-
# disable password authentication
|
302
|
-
guestfs.aug_set( "/files/etc/ssh/sshd_config/PasswordAuthentication", "no" )
|
303
|
-
guestfs.aug_save
|
304
|
-
@log.debug "Augeas changes saved."
|
305
|
-
end
|
306
|
-
|
307
|
-
def get_loop_device
|
308
|
-
begin
|
309
|
-
loop_device = @exec_helper.execute("sudo losetup -f 2>&1").strip
|
310
|
-
rescue
|
311
|
-
raise "No free loop devices available, please free at least one. See 'losetup -d' command."
|
312
|
-
end
|
313
|
-
|
314
|
-
loop_device
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
@@ -1,214 +0,0 @@
|
|
1
|
-
# JBoss, Home of Professional Open Source
|
2
|
-
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
-
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
-
# full listing of individual contributors.
|
5
|
-
#
|
6
|
-
# This is free software; you can redistribute it and/or modify it
|
7
|
-
# under the terms of the GNU Lesser General Public License as
|
8
|
-
# published by the Free Software Foundation; either version 2.1 of
|
9
|
-
# the License, or (at your option) any later version.
|
10
|
-
#
|
11
|
-
# This software is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
-
# Lesser General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU Lesser General Public
|
17
|
-
# License along with this software; if not, write to the Free
|
18
|
-
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
-
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
-
|
21
|
-
require 'rake/tasklib'
|
22
|
-
require 'rexml/document'
|
23
|
-
require 'boxgrinder-build/helpers/appliance-customize-helper'
|
24
|
-
|
25
|
-
module BoxGrinder
|
26
|
-
|
27
|
-
class VMwareImage < Rake::TaskLib
|
28
|
-
|
29
|
-
def initialize( config, appliance_config, options = {} )
|
30
|
-
@config = config
|
31
|
-
@appliance_config = appliance_config
|
32
|
-
|
33
|
-
@log = options[:log] || Logger.new(STDOUT)
|
34
|
-
@exec_helper = options[:exec_helper] || ExecHelper.new( { :log => @log } )
|
35
|
-
|
36
|
-
define_tasks
|
37
|
-
end
|
38
|
-
|
39
|
-
def define_tasks
|
40
|
-
directory @appliance_config.path.dir.vmware.build
|
41
|
-
directory @appliance_config.path.dir.vmware.personal
|
42
|
-
directory @appliance_config.path.dir.vmware.enterprise
|
43
|
-
|
44
|
-
task "appliance:#{@appliance_config.name}:vmware:personal" => [ @appliance_config.path.file.vmware.disk, @appliance_config.path.dir.vmware.personal ] do
|
45
|
-
build_vmware_personal
|
46
|
-
end
|
47
|
-
|
48
|
-
task "appliance:#{@appliance_config.name}:vmware:enterprise" => [ @appliance_config.path.file.vmware.disk, @appliance_config.path.dir.vmware.enterprise ] do
|
49
|
-
build_vmware_enterprise
|
50
|
-
end
|
51
|
-
|
52
|
-
desc "Build #{@appliance_config.name} appliance for VMware"
|
53
|
-
task "appliance:#{@appliance_config.name}:vmware" => [ "appliance:#{@appliance_config.name}:vmware:personal", "appliance:#{@appliance_config.name}:vmware:enterprise" ]
|
54
|
-
|
55
|
-
file @appliance_config.path.file.vmware.disk => [ @appliance_config.path.dir.vmware.build, @appliance_config.path.file.raw.xml ] do
|
56
|
-
convert_to_vmware
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# returns value of cylinders, heads and sector for selected disk size (in GB)
|
61
|
-
|
62
|
-
def generate_scsi_chs(disk_size)
|
63
|
-
disk_size = disk_size * 1024
|
64
|
-
|
65
|
-
gb_sectors = 2097152
|
66
|
-
|
67
|
-
if disk_size == 1024
|
68
|
-
h = 128
|
69
|
-
s = 32
|
70
|
-
else
|
71
|
-
h = 255
|
72
|
-
s = 63
|
73
|
-
end
|
74
|
-
|
75
|
-
c = disk_size / 1024 * gb_sectors / (h*s)
|
76
|
-
total_sectors = gb_sectors * disk_size / 1024
|
77
|
-
|
78
|
-
return [ c, h, s, total_sectors ]
|
79
|
-
end
|
80
|
-
|
81
|
-
def change_vmdk_values( type )
|
82
|
-
vmdk_data = File.open( @config.files.base_vmdk ).read
|
83
|
-
|
84
|
-
disk_size = 0
|
85
|
-
@appliance_config.hardware.partitions.values.each { |part| disk_size += part['size'] }
|
86
|
-
|
87
|
-
c, h, s, total_sectors = generate_scsi_chs( disk_size )
|
88
|
-
|
89
|
-
is_enterprise = type.eql?("vmfs")
|
90
|
-
|
91
|
-
vmdk_data.gsub!( /#NAME#/, @appliance_config.name )
|
92
|
-
vmdk_data.gsub!( /#TYPE#/, type )
|
93
|
-
vmdk_data.gsub!( /#EXTENT_TYPE#/, is_enterprise ? "VMFS" : "FLAT" )
|
94
|
-
vmdk_data.gsub!( /#NUMBER#/, is_enterprise ? "" : "0" )
|
95
|
-
vmdk_data.gsub!( /#HW_VERSION#/, is_enterprise ? "4" : "3" )
|
96
|
-
vmdk_data.gsub!( /#CYLINDERS#/, c.to_s )
|
97
|
-
vmdk_data.gsub!( /#HEADS#/, h.to_s )
|
98
|
-
vmdk_data.gsub!( /#SECTORS#/, s.to_s )
|
99
|
-
vmdk_data.gsub!( /#TOTAL_SECTORS#/, total_sectors.to_s )
|
100
|
-
|
101
|
-
vmdk_data
|
102
|
-
end
|
103
|
-
|
104
|
-
def change_common_vmx_values
|
105
|
-
vmx_data = File.open( @config.files.base_vmx ).read
|
106
|
-
|
107
|
-
# replace version with current appliance version
|
108
|
-
vmx_data.gsub!( /#VERSION#/, "#{@appliance_config.version}.#{@appliance_config.release}" )
|
109
|
-
# replace builder with current builder name and version
|
110
|
-
vmx_data.gsub!( /#BUILDER#/, "#{@config.name} #{@config.version_with_release}" )
|
111
|
-
# change name
|
112
|
-
vmx_data.gsub!( /#NAME#/, @appliance_config.name.to_s )
|
113
|
-
# and summary
|
114
|
-
vmx_data.gsub!( /#SUMMARY#/, @appliance_config.summary.to_s )
|
115
|
-
# replace guestOS informations to: linux or otherlinux-64, this seems to be the savests values
|
116
|
-
vmx_data.gsub!( /#GUESTOS#/, "#{@appliance_config.hardware.arch == "x86_64" ? "otherlinux-64" : "linux"}" )
|
117
|
-
# memory size
|
118
|
-
vmx_data.gsub!( /#MEM_SIZE#/, @appliance_config.hardware.memory.to_s )
|
119
|
-
# memory size
|
120
|
-
vmx_data.gsub!( /#VCPU#/, @appliance_config.hardware.cpus.to_s )
|
121
|
-
# network name
|
122
|
-
# vmx_data.gsub!( /#NETWORK_NAME#/, @appliance_config.network_name )
|
123
|
-
|
124
|
-
vmx_data
|
125
|
-
end
|
126
|
-
|
127
|
-
def create_hardlink_to_disk_image( vmware_raw_file )
|
128
|
-
# Hard link RAW disk to VMware destination folder
|
129
|
-
FileUtils.ln( @appliance_config.path.file.vmware.disk, vmware_raw_file ) if ( !File.exists?( vmware_raw_file ) || File.new( @appliance_config.path.file.raw.disk ).mtime > File.new( vmware_raw_file ).mtime )
|
130
|
-
end
|
131
|
-
|
132
|
-
def build_vmware_personal
|
133
|
-
@log.debug "Building VMware personal image."
|
134
|
-
|
135
|
-
# link disk image
|
136
|
-
create_hardlink_to_disk_image( @appliance_config.path.file.vmware.personal.disk )
|
137
|
-
|
138
|
-
# create .vmx file
|
139
|
-
File.open( @appliance_config.path.file.vmware.personal.vmx, "w" ) {|f| f.write( change_common_vmx_values ) }
|
140
|
-
|
141
|
-
# create disk descriptor file
|
142
|
-
File.open( @appliance_config.path.file.vmware.personal.vmdk, "w" ) {|f| f.write( change_vmdk_values( "monolithicFlat" ) ) }
|
143
|
-
|
144
|
-
@log.debug "VMware personal image was built."
|
145
|
-
end
|
146
|
-
|
147
|
-
def build_vmware_enterprise
|
148
|
-
@log.debug "Building VMware enterprise image."
|
149
|
-
|
150
|
-
# link disk image
|
151
|
-
create_hardlink_to_disk_image( @appliance_config.path.file.vmware.enterprise.disk )
|
152
|
-
|
153
|
-
# defaults for ESXi (maybe for others too)
|
154
|
-
@appliance_config.hardware.network = "VM Network" if @appliance_config.hardware.network.eql?( "NAT" )
|
155
|
-
|
156
|
-
# create .vmx file
|
157
|
-
vmx_data = change_common_vmx_values
|
158
|
-
vmx_data += "ethernet0.networkName = \"#{@appliance_config.hardware.network}\""
|
159
|
-
|
160
|
-
File.open( @appliance_config.path.file.vmware.enterprise.vmx, "w" ) {|f| f.write( vmx_data ) }
|
161
|
-
|
162
|
-
# create disk descriptor file
|
163
|
-
File.open( @appliance_config.path.file.vmware.enterprise.vmdk, "w" ) {|f| f.write( change_vmdk_values( "vmfs" ) ) }
|
164
|
-
|
165
|
-
@log.debug "VMware enterprise image was built."
|
166
|
-
end
|
167
|
-
|
168
|
-
def convert_to_vmware
|
169
|
-
@log.info "Converting image to VMware format..."
|
170
|
-
@log.debug "Copying VMware image file, this may take several minutes..."
|
171
|
-
|
172
|
-
@exec_helper.execute "cp #{@appliance_config.path.file.raw.disk} #{@appliance_config.path.file.vmware.disk}" if ( !File.exists?( @appliance_config.path.file.vmware.disk ) || File.new( @appliance_config.path.file.raw.disk ).mtime > File.new( @appliance_config.path.file.vmware.disk ).mtime )
|
173
|
-
|
174
|
-
@log.debug "VMware image copied."
|
175
|
-
|
176
|
-
customize
|
177
|
-
|
178
|
-
@log.info "Image converted to VMware format."
|
179
|
-
end
|
180
|
-
|
181
|
-
def customize
|
182
|
-
@log.debug "Customizing VMware image..."
|
183
|
-
ApplianceCustomizeHelper.new( @config, @appliance_config, @appliance_config.path.file.vmware.disk, :log => @log ).customize do |customizer, guestfs|
|
184
|
-
# install_vmware_tools( customizer )
|
185
|
-
execute_post_operations( guestfs )
|
186
|
-
end
|
187
|
-
@log.debug "Image customized."
|
188
|
-
end
|
189
|
-
|
190
|
-
def execute_post_operations( guestfs )
|
191
|
-
@log.debug "Executing post commands..."
|
192
|
-
for cmd in @appliance_config.post.vmware
|
193
|
-
@log.debug "Executing #{cmd}"
|
194
|
-
guestfs.sh( cmd )
|
195
|
-
end
|
196
|
-
@log.debug "Post commands executed."
|
197
|
-
end
|
198
|
-
|
199
|
-
def install_vmware_tools( customizer )
|
200
|
-
@log.debug "Installing VMware tools..."
|
201
|
-
|
202
|
-
if @appliance_config.is_os_version_stable?
|
203
|
-
rpmfusion_repo_rpm = [ "http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-rawhide.noarch.rpm", "http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-rawhide.noarch.rpm" ]
|
204
|
-
else
|
205
|
-
rpmfusion_repo_rpm = [ "http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm", "http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-stable.noarch.rpm" ]
|
206
|
-
end
|
207
|
-
|
208
|
-
#TODO this takes about 11 minutes, need to find a quicker way to install kmod-open-vm-tools package
|
209
|
-
customizer.install_packages( @appliance_config.path.file.vmware.disk, { :packages => { :yum => [ "kmod-open-vm-tools" ] }, :repos => rpmfusion_repo_rpm } )
|
210
|
-
|
211
|
-
@log.debug "VMware tools installed."
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
# JBoss, Home of Professional Open Source
|
2
|
-
# Copyright 2009, Red Hat Middleware LLC, and individual contributors
|
3
|
-
# by the @authors tag. See the copyright.txt in the distribution for a
|
4
|
-
# full listing of individual contributors.
|
5
|
-
#
|
6
|
-
# This is free software; you can redistribute it and/or modify it
|
7
|
-
# under the terms of the GNU Lesser General Public License as
|
8
|
-
# published by the Free Software Foundation; either version 2.1 of
|
9
|
-
# the License, or (at your option) any later version.
|
10
|
-
#
|
11
|
-
# This software is distributed in the hope that it will be useful,
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
-
# Lesser General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU Lesser General Public
|
17
|
-
# License along with this software; if not, write to the Free
|
18
|
-
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
19
|
-
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
20
|
-
|
21
|
-
require 'boxgrinder-core/validators/errors'
|
22
|
-
|
23
|
-
module BoxGrinder
|
24
|
-
class ApplianceDefinitionValidator
|
25
|
-
def initialize( appliance_definition )
|
26
|
-
@appliance_definition = appliance_definition
|
27
|
-
end
|
28
|
-
|
29
|
-
def validate
|
30
|
-
check_for_missing_field( 'name' )
|
31
|
-
|
32
|
-
validate_os
|
33
|
-
validate_hardware
|
34
|
-
validate_repos
|
35
|
-
end
|
36
|
-
|
37
|
-
protected
|
38
|
-
|
39
|
-
def check_for_missing_field( name )
|
40
|
-
raise ApplianceValidationError, "Missing field: appliance definition file should have field '#{name}'" if @appliance_definition[name].nil?
|
41
|
-
end
|
42
|
-
|
43
|
-
def validate_os
|
44
|
-
return if @appliance_definition['os'].nil?
|
45
|
-
|
46
|
-
raise ApplianceValidationError, "Unsupported OS: operating system '#{@appliance_definition['os']['name']}' is not supported. Supported OS types: #{SUPPORTED_OSES.keys.join(", ")}. Please correct your appliance definition file, thanks." if !@appliance_definition['os']['name'].nil? and !SUPPORTED_OSES.keys.include?( @appliance_definition['os']['name'] )
|
47
|
-
|
48
|
-
#unless @appliance_definition['os']['version'].nil?
|
49
|
-
#@appliance_definition['os']['version'] = @appliance_definition['os']['version'].to_s
|
50
|
-
#raise ApplianceValidationError, "Not valid OS version: operating system version '#{@appliance_definition['os']['version']}' is not supported for OS type '#{@appliance_definition['os']['name']}'. Supported OS versions for this OS type are: #{SUPPORTED_OSES[@appliance_definition['os']['name']].join(", ")}. Please correct your definition file '#{@appliance_definition_file}', thanks" if !SUPPORTED_OSES[@appliance_definition['os']['name'].nil? ? APPLIANCE_DEFAULTS[:os][:name] : @appliance_definition['os']['name']].include?( @appliance_definition['os']['version'] )
|
51
|
-
#end
|
52
|
-
end
|
53
|
-
|
54
|
-
def validate_hardware
|
55
|
-
return if @appliance_definition['hardware'].nil?
|
56
|
-
|
57
|
-
unless @appliance_definition['hardware']['cpus'].nil?
|
58
|
-
raise ApplianceValidationError, "Not valid CPU amount: '#{@appliance_definition['hardware']['cpus']}' is not allowed here. Please correct your appliance definition file, thanks." if @appliance_definition['hardware']['cpus'] =~ /\d/
|
59
|
-
raise ApplianceValidationError, "Not valid CPU amount: Too many or too less CPU's: '#{@appliance_definition['hardware']['cpus']}'. Please choose from 1-4. Please correct your appliance definition file, thanks." unless @appliance_definition['hardware']['cpus'] >= 1 and @appliance_definition['hardware']['cpus'] <= 4
|
60
|
-
end
|
61
|
-
|
62
|
-
unless @appliance_definition['hardware']['memory'].nil?
|
63
|
-
raise ApplianceValidationError, "Not valid memory amount: '#{@appliance_definition['hardware']['memory']}' is wrong value. Please correct your appliance definition file, thanks." if @appliance_definition['hardware']['memory'] =~ /\d/
|
64
|
-
raise ApplianceValidationError, "Not valid memory amount: '#{@appliance_definition['hardware']['memory']}' is not allowed here. Memory should be a multiplicity of 64. Please correct your appliance definition file, thanks." if (@appliance_definition['hardware']['memory'].to_i % 64 > 0)
|
65
|
-
end
|
66
|
-
|
67
|
-
unless @appliance_definition['hardware']['partitions'].nil?
|
68
|
-
raise ApplianceValidationError, "Not valid partitions format: Please correct your appliance definition file, thanks." unless @appliance_definition['hardware']['partitions'].class.eql?(Array)
|
69
|
-
|
70
|
-
for partition in @appliance_definition['hardware']['partitions']
|
71
|
-
raise ApplianceValidationError, "Not valid partition format: '#{partition}' is wrong value. Please correct your appliance definition file, thanks." unless partition.class.eql?(Hash)
|
72
|
-
raise ApplianceValidationError, "Not valid partition format: Keys 'root' and 'size' should be specified for every partition. Please correct your appliance definition file, thanks." if !partition.keys.include?("root") or !partition.keys.include?("size")
|
73
|
-
raise ApplianceValidationError, "Not valid partition size: '#{partition['size']}' is not a valid value. Please correct your appliance definition file, thanks." if partition['size'] =~ /\d/ or partition['size'].to_i < 1
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def validate_repos
|
79
|
-
return if @appliance_definition['repos'].nil?
|
80
|
-
raise ApplianceValidationError, "Not valid repos format: Please correct your appliance definition file, thanks." unless @appliance_definition['repos'].class.eql?(Array)
|
81
|
-
|
82
|
-
for repo in @appliance_definition['repos']
|
83
|
-
raise ApplianceValidationError, "Not valid repo format: '#{repo}' is wrong value. Please correct your appliance definition file, thanks." unless repo.class.eql?(Hash)
|
84
|
-
raise ApplianceValidationError, "Not valid repo format: Please specify name for repository. Please correct your appliance definition file, thanks." unless repo.keys.include?('name')
|
85
|
-
raise ApplianceValidationError, "Not valid repo format: There is no 'mirrorlist' or 'baseurl' specified for '#{repo['name']}' repository. Please correct your appliance definition file, thanks." unless repo.keys.include?('mirrorlist') or repo.keys.include?('baseurl')
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|