boxgrinder-build 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/CHANGELOG +14 -0
  2. data/README.md +136 -0
  3. data/Rakefile +11 -6
  4. data/bin/boxgrinder-build +199 -0
  5. data/boxgrinder-build.gemspec +26 -14
  6. data/lib/boxgrinder-build/appliance.rb +6 -6
  7. data/lib/boxgrinder-build/helpers/guestfs-helper.rb +5 -3
  8. data/lib/boxgrinder-build/helpers/image-helper.rb +6 -0
  9. data/lib/boxgrinder-build/helpers/plugin-helper.rb +15 -4
  10. data/lib/boxgrinder-build/plugins/base-plugin.rb +1 -0
  11. data/lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb +280 -0
  12. data/lib/boxgrinder-build/plugins/delivery/local/local-plugin.rb +66 -0
  13. data/lib/boxgrinder-build/plugins/delivery/s3/s3-plugin.rb +242 -0
  14. data/lib/boxgrinder-build/plugins/delivery/s3/src/cert-ec2.pem +23 -0
  15. data/lib/boxgrinder-build/plugins/delivery/sftp/sftp-plugin.rb +152 -0
  16. data/lib/boxgrinder-build/plugins/delivery/usb/usb-plugin.rb +43 -0
  17. data/lib/boxgrinder-build/plugins/os/centos/centos-plugin.rb +46 -0
  18. data/lib/boxgrinder-build/plugins/os/fedora/fedora-plugin.rb +61 -0
  19. data/lib/boxgrinder-build/plugins/os/rhel/rhel-plugin.rb +67 -0
  20. data/lib/boxgrinder-build/plugins/os/rpm-based/kickstart.rb +118 -0
  21. data/lib/boxgrinder-build/plugins/os/rpm-based/rpm-based-os-plugin.rb +202 -0
  22. data/lib/boxgrinder-build/plugins/os/rpm-based/rpm-dependency-validator.rb +153 -0
  23. data/lib/boxgrinder-build/plugins/os/rpm-based/src/appliance.ks.erb +37 -0
  24. data/lib/boxgrinder-build/plugins/os/rpm-based/src/base.repo +4 -0
  25. data/lib/boxgrinder-build/plugins/os/rpm-based/src/motd.init +21 -0
  26. data/lib/boxgrinder-build/plugins/platform/ec2/ec2-plugin.rb +239 -0
  27. data/lib/boxgrinder-build/plugins/platform/ec2/src/fstab_32bit +7 -0
  28. data/lib/boxgrinder-build/plugins/platform/ec2/src/fstab_64bit +7 -0
  29. data/lib/boxgrinder-build/plugins/platform/ec2/src/ifcfg-eth0 +7 -0
  30. data/lib/boxgrinder-build/plugins/platform/ec2/src/menu.lst +6 -0
  31. data/lib/boxgrinder-build/plugins/platform/ec2/src/rc_local +19 -0
  32. data/lib/boxgrinder-build/plugins/platform/virtualbox/virtualbox-plugin.rb +62 -0
  33. data/lib/boxgrinder-build/plugins/platform/vmware/src/README-enterprise +18 -0
  34. data/lib/boxgrinder-build/plugins/platform/vmware/src/README-personal +16 -0
  35. data/lib/boxgrinder-build/plugins/platform/vmware/src/base.vmdk +20 -0
  36. data/lib/boxgrinder-build/plugins/platform/vmware/src/base.vmx +45 -0
  37. data/lib/boxgrinder-build/plugins/platform/vmware/vmware-plugin.rb +194 -0
  38. data/rubygem-boxgrinder-build.spec +73 -10
  39. data/spec/appliance-spec.rb +2 -2
  40. data/spec/helpers/guestfs-helper-spec.rb +4 -2
  41. data/spec/helpers/image-helper-spec.rb +4 -0
  42. data/spec/helpers/plugin-helper-spec.rb +0 -38
  43. data/spec/managers/plugin-manager-spec.rb +6 -6
  44. data/spec/plugins/delivery/ebs/ebs-plugin-spec.rb +230 -0
  45. data/spec/plugins/delivery/ebs/ebs.yaml +3 -0
  46. data/spec/plugins/delivery/local/local-plugin-spec.rb +133 -0
  47. data/spec/plugins/delivery/s3/s3-plugin-spec.rb +351 -0
  48. data/spec/plugins/delivery/sftp/sftp-plugin-spec.rb +26 -0
  49. data/spec/plugins/os/centos/centos-plugin-spec.rb +52 -0
  50. data/spec/plugins/os/fedora/fedora-plugin-spec.rb +73 -0
  51. data/spec/plugins/os/rhel/rhel-plugin-spec.rb +158 -0
  52. data/spec/plugins/os/rpm-based/kickstart-spec.rb +129 -0
  53. data/spec/plugins/os/rpm-based/rpm-based-os-plugin-spec.rb +162 -0
  54. data/spec/plugins/os/rpm-based/rpm-dependency-validator-spec.rb +50 -0
  55. data/spec/plugins/os/rpm-based/src/jeos-f13-plain.ks +20 -0
  56. data/spec/plugins/os/rpm-based/src/jeos-f13-without-version.ks +22 -0
  57. data/spec/plugins/os/rpm-based/src/jeos-f13.ks +23 -0
  58. data/spec/plugins/platform/ec2/ec2-plugin-spec.rb +339 -0
  59. data/spec/plugins/platform/virtualbox/virtualbox-plugin-spec.rb +118 -0
  60. data/spec/plugins/platform/vmware/vmware-plugin-spec.rb +299 -0
  61. metadata +149 -25
  62. data/README +0 -7
  63. data/bin/boxgrinder +0 -128
  64. data/lib/boxgrinder-build/helpers/thor-helper.rb +0 -85
@@ -0,0 +1,152 @@
1
+ #
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # This is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU Lesser General Public License as
6
+ # published by the Free Software Foundation; either version 3 of
7
+ # the License, or (at your option) any later version.
8
+ #
9
+ # This software is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this software; if not, write to the Free
16
+ # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
+ # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
+
19
+ require 'rubygems'
20
+ require 'net/ssh'
21
+ require 'net/sftp'
22
+ require 'progressbar'
23
+ require 'boxgrinder-build/plugins/base-plugin'
24
+ require 'boxgrinder-build/helpers/package-helper'
25
+
26
+ module BoxGrinder
27
+ class SFTPPlugin < BasePlugin
28
+ def after_init
29
+ set_default_config_value('overwrite', false)
30
+ set_default_config_value('default_permissions', 0644)
31
+
32
+ register_deliverable(:package => "#{@appliance_config.name}-#{@appliance_config.version}.#{@appliance_config.release}-#{@appliance_config.os.name}-#{@appliance_config.os.version}-#{@appliance_config.hardware.arch}-#{current_platform}.tgz")
33
+ end
34
+
35
+ def execute( type = :sftp )
36
+ validate_plugin_config(['path', 'username', 'host'], 'http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#SFTP_Delivery_Plugin')
37
+
38
+ PackageHelper.new(@config, @appliance_config, :log => @log, :exec_helper => @exec_helper).package( File.dirname(@previous_deliverables[:disk]), @deliverables[:package] )
39
+
40
+ @log.info "Uploading #{@appliance_config.name} appliance via SSH..."
41
+
42
+ begin
43
+ #TODO move to a block
44
+ connect
45
+ upload_files(@plugin_config['path'], File.basename(@deliverables[:package]) => @deliverables[:package])
46
+ disconnect
47
+
48
+ @log.info "Appliance #{@appliance_config.name} uploaded."
49
+ rescue => e
50
+ @log.error e
51
+ @log.error "An error occurred while uploading files."
52
+ end
53
+ end
54
+
55
+ def connect
56
+ @log.info "Connecting to #{@plugin_config['host']}..."
57
+ @ssh = Net::SSH.start(@plugin_config['host'], @plugin_config['username'], {:password => @plugin_config['password']})
58
+ end
59
+
60
+ def connected?
61
+ return true if !@ssh.nil? and !@ssh.closed?
62
+ false
63
+ end
64
+
65
+ def disconnect
66
+ @log.info "Disconnecting from #{@plugin_config['host']}..."
67
+ @ssh.close if connected?
68
+ @ssh = nil
69
+ end
70
+
71
+ def upload_files(path, files = {})
72
+ return if files.size == 0
73
+
74
+ raise "You're not connected to server" unless connected?
75
+
76
+ @log.debug "Files to upload:"
77
+
78
+ files.each do |remote, local|
79
+ @log.debug "#{File.basename(local)} => #{path}/#{remote}"
80
+ end
81
+
82
+ global_size = 0
83
+
84
+ files.each_value do |file|
85
+ global_size += File.size(file)
86
+ end
87
+
88
+ global_size_kb = global_size / 1024
89
+ global_size_mb = global_size_kb / 1024
90
+
91
+ @log.info "#{files.size} files to upload (#{global_size_mb > 0 ? global_size_mb.to_s + "MB" : global_size_kb > 0 ? global_size_kb.to_s + "kB" : global_size.to_s})"
92
+
93
+ @ssh.sftp.connect do |sftp|
94
+ begin
95
+ sftp.stat!(path)
96
+ rescue Net::SFTP::StatusException => e
97
+ raise unless e.code == 2
98
+ @ssh.exec!("mkdir -p #{path}")
99
+ end
100
+
101
+ nb = 0
102
+
103
+ files.each do |key, local|
104
+ name = File.basename(local)
105
+ remote = "#{path}/#{key}"
106
+ size_b = File.size(local)
107
+ size_kb = size_b / 1024
108
+ nb_of = "#{nb += 1}/#{files.size}"
109
+
110
+ begin
111
+ sftp.stat!(remote)
112
+
113
+ unless @plugin_config['overwrite']
114
+
115
+ local_md5_sum = `md5sum #{local} | awk '{ print $1 }'`.strip
116
+ remote_md5_sum = @ssh.exec!("md5sum #{remote} | awk '{ print $1 }'").strip
117
+
118
+ if (local_md5_sum.eql?(remote_md5_sum))
119
+ @log.info "#{nb_of} #{name}: files are identical (md5sum: #{local_md5_sum}), skipping..."
120
+ next
121
+ end
122
+ end
123
+
124
+ rescue Net::SFTP::StatusException => e
125
+ raise unless e.code == 2
126
+ end
127
+
128
+ @ssh.exec!("mkdir -p #{File.dirname(remote) }")
129
+
130
+ pbar = ProgressBar.new("#{nb_of} #{name}", size_b)
131
+ pbar.file_transfer_mode
132
+
133
+ sftp.upload!(local, remote) do |event, uploader, * args|
134
+ case event
135
+ when :open then
136
+ when :put then
137
+ pbar.set(args[1])
138
+ when :close then
139
+ when :mkdir then
140
+ when :finish then
141
+ pbar.finish
142
+ end
143
+ end
144
+
145
+ sftp.setstat(remote, :permissions => @plugin_config['default_permissions'])
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ plugin :class => BoxGrinder::SFTPPlugin, :type => :delivery, :name => :sftp, :full_name => "SSH File Transfer Protocol"
@@ -0,0 +1,43 @@
1
+ #
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # This is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU Lesser General Public License as
6
+ # published by the Free Software Foundation; either version 3 of
7
+ # the License, or (at your option) any later version.
8
+ #
9
+ # This software is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this software; if not, write to the Free
16
+ # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
+ # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
+
19
+ require 'boxgrinder-build/plugins/base-plugin'
20
+
21
+ module BoxGrinder
22
+ class USBPlugin < BasePlugin
23
+ def after_init
24
+ validate_plugin_config(['device' ])
25
+ end
26
+
27
+ def execute( type = :usb )
28
+ validate_device
29
+
30
+ @log.debug "Using '#{@plugin_config['device']}' as a target device..."
31
+ @exec_helper.execute( "dd if=#{@previous_deliverables.disk} of=#{@plugin_config['device']} bs=1M" )
32
+
33
+ end
34
+
35
+ def validate_device
36
+ # check if this is USB
37
+ # see if it contains required space
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ # plugin :class => BoxGrinder::USBPlugin, :type => :delivery, :name => :usb, :full_name => "USB"
@@ -0,0 +1,46 @@
1
+ #
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # This is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU Lesser General Public License as
6
+ # published by the Free Software Foundation; either version 3 of
7
+ # the License, or (at your option) any later version.
8
+ #
9
+ # This software is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this software; if not, write to the Free
16
+ # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
+ # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
+
19
+ require 'boxgrinder-build/plugins/os/rhel/rhel-plugin'
20
+
21
+ module BoxGrinder
22
+ class CentOSPlugin < RHELPlugin
23
+
24
+ CENTOS_REPOS = {
25
+ "5" => {
26
+ "base" => {
27
+ "mirrorlist" => "http://mirrorlist.centos.org/?release=#OS_VERSION#&arch=#BASE_ARCH#&repo=os"
28
+ },
29
+ "updates" => {
30
+ "mirrorlist" => "http://mirrorlist.centos.org/?release=#OS_VERSION#&arch=#BASE_ARCH#&repo=updates"
31
+ }
32
+ }
33
+ }
34
+
35
+ def after_init
36
+ super
37
+ register_supported_os('centos', ['5'])
38
+ end
39
+
40
+ def execute(appliance_definition_file)
41
+ build_rhel(appliance_definition_file, CENTOS_REPOS)
42
+ end
43
+ end
44
+ end
45
+
46
+ plugin :class => BoxGrinder::CentOSPlugin, :type => :os, :name => :centos, :full_name => "CentOS", :versions => ["5"]
@@ -0,0 +1,61 @@
1
+ #
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # This is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU Lesser General Public License as
6
+ # published by the Free Software Foundation; either version 3 of
7
+ # the License, or (at your option) any later version.
8
+ #
9
+ # This software is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this software; if not, write to the Free
16
+ # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
+ # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
+
19
+ require 'boxgrinder-build/plugins/os/rpm-based/rpm-based-os-plugin'
20
+
21
+ module BoxGrinder
22
+ class FedoraPlugin < RPMBasedOSPlugin
23
+ def after_init
24
+ super
25
+ register_supported_os('fedora', ["13", "14", "15", "rawhide"])
26
+ end
27
+
28
+ def execute(appliance_definition_file)
29
+ normalize_packages(@appliance_config.packages)
30
+
31
+ @repos = {}
32
+
33
+ @plugin_info[:versions].each do |version|
34
+ if version.match(/\d+/)
35
+ @repos[version] = {
36
+ "base" => {"mirrorlist" => "http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-#{version}&arch=#BASE_ARCH#"},
37
+ "updates" => {"mirrorlist" => "http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f#{version}&arch=#BASE_ARCH#"}
38
+ }
39
+ else
40
+ @repos[version] = {"base" => {"mirrorlist" => "http://mirrors.fedoraproject.org/mirrorlist?repo=#{version}&arch=#BASE_ARCH#"}}
41
+ end
42
+ end
43
+
44
+ build_with_appliance_creator(appliance_definition_file, @repos)
45
+ end
46
+
47
+ def normalize_packages(packages)
48
+ # https://issues.jboss.org/browse/BGBUILD-89
49
+ packages << '@core'
50
+ packages << "system-config-firewall-base"
51
+ packages << "dhclient"
52
+
53
+ # kernel_PAE for 32 bit, kernel for 64 bit
54
+ packages.delete('kernel')
55
+ packages.delete('kernel-PAE')
56
+ packages << (@appliance_config.is64bit? ? "kernel" : "kernel-PAE")
57
+ end
58
+ end
59
+ end
60
+
61
+ plugin :class => BoxGrinder::FedoraPlugin, :type => :os, :name => :fedora, :full_name => "Fedora", :versions => ["13", "14", "15", "rawhide"]
@@ -0,0 +1,67 @@
1
+ #
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # This is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU Lesser General Public License as
6
+ # published by the Free Software Foundation; either version 3 of
7
+ # the License, or (at your option) any later version.
8
+ #
9
+ # This software is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this software; if not, write to the Free
16
+ # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
+ # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
+
19
+ require 'boxgrinder-build/plugins/os/rpm-based/rpm-based-os-plugin'
20
+
21
+ module BoxGrinder
22
+ class RHELPlugin < RPMBasedOSPlugin
23
+ def after_init
24
+ super
25
+ register_supported_os('rhel', ['5', '6'])
26
+ end
27
+
28
+ def build_rhel(appliance_definition_file, repos = {})
29
+ adjust_partition_table
30
+
31
+ normalize_packages(@appliance_config.packages)
32
+
33
+ build_with_appliance_creator(appliance_definition_file, repos) do |guestfs, guestfs_helper|
34
+ # required for VMware and KVM
35
+ @linux_helper.recreate_kernel_image(guestfs, ['mptspi', 'virtio_pci', 'virtio_blk']) if @appliance_config.os.version == '5' and !@appliance_config.packages.include?('kernel-xen')
36
+ end
37
+ end
38
+
39
+ def normalize_packages(packages)
40
+ # https://issues.jboss.org/browse/BGBUILD-89
41
+ add_packages(packages, ['@core', 'curl'])
42
+
43
+ case @appliance_config.os.version
44
+ when '5'
45
+ packages << 'kernel' unless packages.include?('kernel-xen')
46
+ add_packages(packages, ['system-config-securitylevel-tui', 'util-linux', 'setarch', 'sudo'])
47
+ when '6'
48
+ add_packages(packages, ['kernel', 'system-config-firewall-base'])
49
+ end
50
+ end
51
+
52
+ def add_packages(packages, package_array)
53
+ package_array.each { |package| packages << package unless packages.include?(package) }
54
+ end
55
+
56
+ # https://bugzilla.redhat.com/show_bug.cgi?id=466275
57
+ def adjust_partition_table
58
+ @appliance_config.hardware.partitions['/boot'] = {'root' => '/boot', 'type' => 'ext3', 'size' => 0.1} if @appliance_config.hardware.partitions['/boot'].nil?
59
+ end
60
+
61
+ def execute(appliance_definition_file)
62
+ build_rhel(appliance_definition_file)
63
+ end
64
+ end
65
+ end
66
+
67
+ plugin :class => BoxGrinder::RHELPlugin, :type => :os, :name => :rhel, :full_name => "Red Hat Enterprise Linux", :versions => ['5', '6']
@@ -0,0 +1,118 @@
1
+ #
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # This is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU Lesser General Public License as
6
+ # published by the Free Software Foundation; either version 3 of
7
+ # the License, or (at your option) any later version.
8
+ #
9
+ # This software is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this software; if not, write to the Free
16
+ # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
+ # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
+
19
+ require 'fileutils'
20
+ require 'yaml'
21
+ require 'erb'
22
+
23
+ module BoxGrinder
24
+
25
+ class Kickstart
26
+ def initialize(config, appliance_config, repos, dir, options = {})
27
+ @config = config
28
+ @repos = repos
29
+ @appliance_config = appliance_config
30
+ @dir = dir
31
+ @log = options[:log] || Logger.new(STDOUT)
32
+
33
+ @kickstart_file = "#{@dir.tmp}/#{@appliance_config.name}.ks"
34
+ end
35
+
36
+ def create
37
+ template = "#{File.dirname(__FILE__)}/src/appliance.ks.erb"
38
+ kickstart = ERB.new(File.read(template)).result(build_definition.send(:binding))
39
+ File.open(@kickstart_file, 'w') { |f| f.write(kickstart) }
40
+
41
+ @kickstart_file
42
+ end
43
+
44
+ def build_definition
45
+ definition = {}
46
+
47
+ definition['appliance_config'] = @appliance_config
48
+ definition['repos'] = []
49
+ definition['graphical'] = (@appliance_config.packages.include?( '@base-x' ) or @appliance_config.packages.include?( '@X Window System' )) ? true : false
50
+
51
+ def definition.method_missing(sym, * args)
52
+ self[sym.to_s]
53
+ end
54
+
55
+ cost = 40
56
+
57
+ definition['partitions'] = @appliance_config.hardware.partitions
58
+
59
+ repos = []
60
+ repos += default_repos if @appliance_config.default_repos
61
+ repos += @appliance_config.repos
62
+
63
+ for repo in repos
64
+ if repo.keys.include?('mirrorlist')
65
+ urltype = 'mirrorlist'
66
+ else
67
+ urltype = 'baseurl'
68
+ end
69
+
70
+ substitutions = {
71
+ /#ARCH#/ => @appliance_config.hardware.arch,
72
+ /#BASE_ARCH#/ => @appliance_config.hardware.base_arch,
73
+ /#OS_VERSION#/ => @appliance_config.os.version,
74
+ /#OS_NAME#/ => @appliance_config.os.name
75
+ }
76
+
77
+ url = repo[urltype]
78
+ name = repo['name']
79
+
80
+ substitutions.each do |key, value|
81
+ url = url.gsub(key, value)
82
+ name = name.gsub(key, value)
83
+ end
84
+
85
+ definition['repos'] << "repo --name=#{name} --cost=#{cost} --#{urltype}=#{url}"
86
+
87
+ cost += 1
88
+ end
89
+
90
+ definition
91
+ end
92
+
93
+ def default_repos
94
+ os_repos = @repos[@appliance_config.os.version]
95
+
96
+ repos = Array.new
97
+
98
+ for type in ["base", "updates"]
99
+ unless os_repos.nil? or os_repos[type].nil?
100
+
101
+ mirrorlist = os_repos[type]['mirrorlist']
102
+ baseurl = os_repos[type]['baseurl']
103
+
104
+ name = "#{@appliance_config.os.name}-#{@appliance_config.os.version}-#{type}"
105
+
106
+ if mirrorlist.nil?
107
+ repos.push({"name" => name, "baseurl" => baseurl})
108
+ else
109
+ repos.push({"name" => name, "mirrorlist" => mirrorlist})
110
+ end
111
+ end
112
+ end
113
+
114
+ repos
115
+ end
116
+ end
117
+
118
+ end
@@ -0,0 +1,202 @@
1
+ #
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # This is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU Lesser General Public License as
6
+ # published by the Free Software Foundation; either version 3 of
7
+ # the License, or (at your option) any later version.
8
+ #
9
+ # This software is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this software; if not, write to the Free
16
+ # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
+ # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
+
19
+ require 'boxgrinder-core/models/appliance-config'
20
+ require 'boxgrinder-build/plugins/base-plugin'
21
+ require 'boxgrinder-build/plugins/os/rpm-based/kickstart'
22
+ require 'boxgrinder-build/plugins/os/rpm-based/rpm-dependency-validator'
23
+ require 'boxgrinder-build/helpers/linux-helper'
24
+
25
+ module BoxGrinder
26
+ class RPMBasedOSPlugin < BasePlugin
27
+ def after_init
28
+ set_default_config_value('format', 'raw')
29
+
30
+ register_deliverable(
31
+ :disk => "#{@appliance_config.name}-sda.#{@plugin_config['format']}",
32
+ :descriptor => "#{@appliance_config.name}.xml"
33
+ )
34
+
35
+ @linux_helper = LinuxHelper.new(:log => @log)
36
+ end
37
+
38
+ def read_file(file)
39
+ read_kickstart(file) if File.extname(file).eql?('.ks')
40
+ end
41
+
42
+ def read_kickstart(file)
43
+ appliance_config = ApplianceConfig.new
44
+
45
+ appliance_config.name = File.basename(file, '.ks')
46
+
47
+ name = nil
48
+ version = nil
49
+
50
+ File.read(file).each do |line|
51
+ n = line.scan(/^# bg_os_name: (.*)/).flatten.first
52
+ v = line.scan(/^# bg_os_version: (.*)/).flatten.first
53
+
54
+ name = n unless n.nil?
55
+ version = v unless v.nil?
56
+ end
57
+
58
+ raise "No operating system name specified, please add comment to you kickstrt file like this: # bg_os_name: fedora" if name.nil?
59
+ raise "No operating system version specified, please add comment to you kickstrt file like this: # bg_os_version: 14" if version.nil?
60
+
61
+ appliance_config.os.name = name
62
+ appliance_config.os.version = version
63
+
64
+ appliance_config
65
+ end
66
+
67
+ def build_with_appliance_creator(appliance_definition_file, repos = {})
68
+ if File.extname(appliance_definition_file).eql?('.ks')
69
+ kickstart_file = appliance_definition_file
70
+ else
71
+ kickstart_file = Kickstart.new(@config, @appliance_config, repos, @dir, :log => @log).create
72
+ end
73
+
74
+ RPMDependencyValidator.new(@config, @appliance_config, @dir, kickstart_file, @options).resolve_packages
75
+
76
+ @log.info "Building #{@appliance_config.name} appliance..."
77
+
78
+ @exec_helper.execute "appliance-creator -d -v -t '#{@dir.tmp}' --cache=#{@config.dir.cache}/rpms-cache/#{@appliance_config.path.main} --config '#{kickstart_file}' -o '#{@dir.tmp}' --name '#{@appliance_config.name}' --vmem #{@appliance_config.hardware.memory} --vcpu #{@appliance_config.hardware.cpus} --format #{@plugin_config['format']}"
79
+
80
+ FileUtils.mv(Dir.glob("#{@dir.tmp}/#{@appliance_config.name}/*"), @dir.tmp)
81
+ FileUtils.rm_rf("#{@dir.tmp}/#{@appliance_config.name}/")
82
+
83
+ @image_helper.customize(@deliverables.disk) do |guestfs, guestfs_helper|
84
+ # TODO is this really needed?
85
+ @log.debug "Uploading '/etc/resolv.conf'..."
86
+ guestfs.upload("/etc/resolv.conf", "/etc/resolv.conf")
87
+ @log.debug "'/etc/resolv.conf' uploaded."
88
+
89
+ change_configuration(guestfs_helper)
90
+ # TODO check if this is still required
91
+ apply_root_password(guestfs)
92
+ fix_partition_labels(guestfs)
93
+ use_labels_for_partitions(guestfs)
94
+ disable_firewall(guestfs)
95
+ set_motd(guestfs)
96
+ install_repos(guestfs)
97
+
98
+ guestfs.sh("chkconfig firstboot off") if guestfs.exists('/etc/init.d/firstboot') != 0
99
+
100
+ @log.info "Executing post operations after build..."
101
+
102
+ unless @appliance_config.post['base'].nil?
103
+ @appliance_config.post['base'].each do |cmd|
104
+ guestfs_helper.sh(cmd, :arch => @appliance_config.hardware.arch)
105
+ end
106
+ @log.debug "Post commands from appliance definition file executed."
107
+ else
108
+ @log.debug "No commands specified, skipping."
109
+ end
110
+
111
+ yield guestfs, guestfs_helper if block_given?
112
+
113
+ @log.info "Post operations executed."
114
+ end
115
+
116
+ @log.info "Base image for #{@appliance_config.name} appliance was built successfully."
117
+ end
118
+
119
+ # https://issues.jboss.org/browse/BGBUILD-177
120
+ def disable_firewall(guestfs)
121
+ @log.debug "Disabling firewall..."
122
+ guestfs.sh("lokkit -q --disabled")
123
+ @log.debug "Firewall disabled."
124
+ end
125
+
126
+ def fix_partition_labels(guestfs)
127
+ guestfs.list_partitions.each do |partition|
128
+ guestfs.sh("/sbin/e2label #{partition} #{read_label(guestfs, partition)}")
129
+ end
130
+ end
131
+
132
+ def use_labels_for_partitions(guestfs)
133
+ device = guestfs.list_devices.first
134
+
135
+ # /etc/fstab
136
+ if fstab = guestfs.read_file('/etc/fstab').gsub!(/^(\/dev\/sda.)/) { |path| "LABEL=#{read_label(guestfs, path.gsub('/dev/sda', device))}" }
137
+ guestfs.write_file('/etc/fstab', fstab, 0)
138
+ end
139
+
140
+ # /boot/grub/grub.conf
141
+ if grub = guestfs.read_file('/boot/grub/grub.conf').gsub!(/(\/dev\/sda.)/) { |path| "LABEL=#{read_label(guestfs, path.gsub('/dev/sda', device))}" }
142
+ guestfs.write_file('/boot/grub/grub.conf', grub, 0)
143
+ end
144
+ end
145
+
146
+ def read_label(guestfs, partition)
147
+ (guestfs.respond_to?(:vfs_label) ? guestfs.vfs_label(partition) : guestfs.sh("/sbin/e2label #{partition}").chomp.strip).gsub('_', '')
148
+ end
149
+
150
+ def apply_root_password(guestfs)
151
+ @log.debug "Applying root password..."
152
+ guestfs.sh("/usr/bin/passwd -d root")
153
+ guestfs.sh("/usr/sbin/usermod -p '#{@appliance_config.os.password.crypt((0...8).map { 65.+(rand(25)).chr }.join)}' root")
154
+ @log.debug "Password applied."
155
+ end
156
+
157
+ def change_configuration(guestfs_helper)
158
+ guestfs_helper.augeas do
159
+ set('/etc/ssh/sshd_config', 'UseDNS', 'no')
160
+ set('/etc/sysconfig/selinux', 'SELINUX', 'permissive')
161
+ end
162
+ end
163
+
164
+ def set_motd(guestfs)
165
+ @log.debug "Setting up '/etc/motd'..."
166
+ # set nice banner for SSH
167
+ motd_file = "/etc/init.d/motd"
168
+ guestfs.upload("#{File.dirname(__FILE__)}/src/motd.init", motd_file)
169
+ guestfs.sh("sed -i s/#VERSION#/'#{@appliance_config.version}.#{@appliance_config.release}'/ #{motd_file}")
170
+ guestfs.sh("sed -i s/#APPLIANCE#/'#{@appliance_config.name} appliance'/ #{motd_file}")
171
+
172
+ guestfs.sh("/bin/chmod +x #{motd_file}")
173
+ guestfs.sh("/sbin/chkconfig --add motd")
174
+ @log.debug "'/etc/motd' is nice now."
175
+ end
176
+
177
+ def recreate_kernel_image(guestfs, modules = [])
178
+ @linux_helper.recreate_kernel_image(guestfs, modules)
179
+ end
180
+
181
+ def install_repos(guestfs)
182
+ @log.debug "Installing repositories from appliance definition file..."
183
+ @appliance_config.repos.each do |repo|
184
+ if repo['ephemeral']
185
+ @log.debug "Repository '#{repo['name']}' is an ephemeral repo. It'll not be installed in the appliance."
186
+ next
187
+ end
188
+
189
+ @log.debug "Installing #{repo['name']} repo..."
190
+ repo_file = File.read("#{File.dirname(__FILE__)}/src/base.repo").gsub(/#NAME#/, repo['name'])
191
+
192
+ ['baseurl', 'mirrorlist'].each do |type|
193
+ repo_file << ("#{type}=#{repo[type]}\n") unless repo[type].nil?
194
+ end
195
+
196
+ guestfs.write_file("/etc/yum.repos.d/#{repo['name']}.repo", repo_file, 0)
197
+ end
198
+ @log.debug "Repositories installed."
199
+ end
200
+
201
+ end
202
+ end