boxgrinder-core 0.3.0 → 0.3.1

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 (28) hide show
  1. data/CHANGELOG +10 -0
  2. data/Rakefile +13 -9
  3. data/boxgrinder-core.gemspec +11 -8
  4. data/lib/boxgrinder-core/appliance-parser.rb +84 -0
  5. data/{spec/validators/appliance-config-validator-spec.rb → lib/boxgrinder-core/appliance-validator.rb} +15 -2
  6. data/lib/boxgrinder-core/{validators/errors.rb → errors.rb} +16 -0
  7. data/lib/boxgrinder-core/helpers/appliance-config-helper.rb +10 -18
  8. data/lib/boxgrinder-core/helpers/appliance-definition-helper.rb +19 -59
  9. data/lib/boxgrinder-core/helpers/appliance-transformation-helper.rb +58 -0
  10. data/lib/boxgrinder-core/helpers/exec-helper.rb +48 -21
  11. data/lib/boxgrinder-core/models/appliance-config.rb +39 -23
  12. data/lib/boxgrinder-core/models/config.rb +4 -2
  13. data/lib/boxgrinder-core/schemas/appliance_schema_0.8.0.yaml +95 -0
  14. data/lib/boxgrinder-core/schemas/appliance_schema_0.9.0.yaml +92 -0
  15. data/rubygem-boxgrinder-core.spec +13 -1
  16. data/spec/appliance-parser-spec.rb +68 -0
  17. data/spec/appliance-validator-spec.rb +71 -0
  18. data/spec/helpers/appliance-config-helper-spec.rb +136 -1
  19. data/spec/helpers/appliance-definition-helper-spec.rb +51 -79
  20. data/spec/helpers/appliance-transformation-helper-spec.rb +51 -0
  21. data/spec/helpers/exec-helper-spec.rb +40 -12
  22. data/spec/helpers/log-helper-spec.rb +1 -0
  23. data/spec/models/config-spec.rb +2 -1
  24. data/spec/rspec/src/appliances/0.8.x.appl +38 -0
  25. data/spec/rspec/src/appliances/0.9.x-invalid.appl +40 -0
  26. data/spec/rspec/src/appliances/0.9.x.appl +36 -0
  27. metadata +48 -19
  28. data/lib/boxgrinder-core/validators/appliance-config-validator.rb +0 -65
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ v0.3.1
2
+
3
+ * [BGBUILD-164] Guestfs writes to /tmp/ by default, potentially filling the root filesystem
4
+ * [BGBUILD-97] some filesystems dont get unmounted on BG interruption
5
+ * [BGBUILD-155] Images built on Centos5.x (el5) for VirtualBox kernel panic (/dev/root missing)
6
+ * [BGBUILD-190] Allow to specify kernel variant (PAE or not) for Fedora OS
7
+ * [BGBUILD-192] Use IO.popen4 instead open4 gem on JRuby
8
+ * [BGBUILD-198] root password is not inherited
9
+ * [BGBUILD-156] Validate appliance definition files early and return meaningful error messages
10
+
1
11
  v0.3.0
2
12
 
3
13
  * [BGBUILD-178] Remove sensitive data from logs
data/Rakefile CHANGED
@@ -17,19 +17,24 @@
17
17
  # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
18
 
19
19
  require 'rubygems'
20
- require 'spec/rake/spectask'
20
+
21
+ begin
22
+ require 'rake/dsl'
23
+ rescue LoadError
24
+ end
25
+
21
26
  require 'echoe'
22
27
 
23
28
  Echoe.new("boxgrinder-core") do |p|
24
- p.project = "BoxGrinder"
25
- p.author = "Marek Goldmann"
26
- p.summary = "Core library for BoxGrinder"
27
- p.url = "http://www.jboss.org/boxgrinder"
28
- p.email = "info@boxgrinder.org"
29
- p.runtime_dependencies = ['open4 >=1.0.0', 'hashery >=1.3.0']
29
+ p.project = "BoxGrinder"
30
+ p.author = "Marek Goldmann"
31
+ p.summary = "Core library for BoxGrinder"
32
+ p.url = "http://boxgrinder.org"
33
+ p.email = "info@boxgrinder.org"
34
+ p.runtime_dependencies = ['hashery >=1.3.0', 'kwalify >=0.7.2']
35
+ p.runtime_dependencies << 'open4 >=1.0.0' unless RUBY_PLATFORM =~ /java/
30
36
  end
31
37
 
32
- desc "Run all tests"
33
38
  Spec::Rake::SpecTask.new('spec') do |t|
34
39
  t.rcov = false
35
40
  t.spec_files = FileList["spec/**/*-spec.rb"]
@@ -37,7 +42,6 @@ Spec::Rake::SpecTask.new('spec') do |t|
37
42
  t.verbose = true
38
43
  end
39
44
 
40
- desc "Run all tests and generate code coverage report"
41
45
  Spec::Rake::SpecTask.new('spec:coverage') do |t|
42
46
  t.spec_files = FileList["spec/**/*-spec.rb"]
43
47
  t.spec_opts = ['--colour', '--format', 'html:pkg/rspec_report.html', '-b']
@@ -2,16 +2,16 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{boxgrinder-core}
5
- s.version = "0.3.0"
5
+ s.version = "0.3.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Marek Goldmann"]
9
- s.date = %q{2011-03-09}
9
+ s.date = %q{2011-04-27}
10
10
  s.description = %q{Core library for BoxGrinder}
11
11
  s.email = %q{info@boxgrinder.org}
12
- s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "lib/boxgrinder-core.rb", "lib/boxgrinder-core/helpers/appliance-config-helper.rb", "lib/boxgrinder-core/helpers/appliance-definition-helper.rb", "lib/boxgrinder-core/helpers/exec-helper.rb", "lib/boxgrinder-core/helpers/log-helper.rb", "lib/boxgrinder-core/models/appliance-config.rb", "lib/boxgrinder-core/models/config.rb", "lib/boxgrinder-core/models/task.rb", "lib/boxgrinder-core/validators/appliance-config-validator.rb", "lib/boxgrinder-core/validators/errors.rb"]
13
- s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "boxgrinder-core.gemspec", "lib/boxgrinder-core.rb", "lib/boxgrinder-core/helpers/appliance-config-helper.rb", "lib/boxgrinder-core/helpers/appliance-definition-helper.rb", "lib/boxgrinder-core/helpers/exec-helper.rb", "lib/boxgrinder-core/helpers/log-helper.rb", "lib/boxgrinder-core/models/appliance-config.rb", "lib/boxgrinder-core/models/config.rb", "lib/boxgrinder-core/models/task.rb", "lib/boxgrinder-core/validators/appliance-config-validator.rb", "lib/boxgrinder-core/validators/errors.rb", "rubygem-boxgrinder-core.spec", "spec/helpers/appliance-config-helper-spec.rb", "spec/helpers/appliance-definition-helper-spec.rb", "spec/helpers/exec-helper-spec.rb", "spec/helpers/log-helper-spec.rb", "spec/models/config-spec.rb", "spec/rspec/ls/one", "spec/rspec/ls/two", "spec/rspec/src/appliances/ephemeral-repo.appl", "spec/rspec/src/appliances/full.appl", "spec/rspec/src/appliances/invalid-yaml.appl", "spec/rspec/src/appliances/legacy.appl", "spec/rspec/src/appliances/repo.appl", "spec/rspec/src/config/empty", "spec/rspec/src/config/valid", "spec/validators/appliance-config-validator-spec.rb"]
14
- s.homepage = %q{http://www.jboss.org/boxgrinder}
12
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "lib/boxgrinder-core.rb", "lib/boxgrinder-core/appliance-parser.rb", "lib/boxgrinder-core/appliance-validator.rb", "lib/boxgrinder-core/errors.rb", "lib/boxgrinder-core/helpers/appliance-config-helper.rb", "lib/boxgrinder-core/helpers/appliance-definition-helper.rb", "lib/boxgrinder-core/helpers/appliance-transformation-helper.rb", "lib/boxgrinder-core/helpers/exec-helper.rb", "lib/boxgrinder-core/helpers/log-helper.rb", "lib/boxgrinder-core/models/appliance-config.rb", "lib/boxgrinder-core/models/config.rb", "lib/boxgrinder-core/models/task.rb", "lib/boxgrinder-core/schemas/appliance_schema_0.8.0.yaml", "lib/boxgrinder-core/schemas/appliance_schema_0.9.0.yaml"]
13
+ s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "boxgrinder-core.gemspec", "lib/boxgrinder-core.rb", "lib/boxgrinder-core/appliance-parser.rb", "lib/boxgrinder-core/appliance-validator.rb", "lib/boxgrinder-core/errors.rb", "lib/boxgrinder-core/helpers/appliance-config-helper.rb", "lib/boxgrinder-core/helpers/appliance-definition-helper.rb", "lib/boxgrinder-core/helpers/appliance-transformation-helper.rb", "lib/boxgrinder-core/helpers/exec-helper.rb", "lib/boxgrinder-core/helpers/log-helper.rb", "lib/boxgrinder-core/models/appliance-config.rb", "lib/boxgrinder-core/models/config.rb", "lib/boxgrinder-core/models/task.rb", "lib/boxgrinder-core/schemas/appliance_schema_0.8.0.yaml", "lib/boxgrinder-core/schemas/appliance_schema_0.9.0.yaml", "rubygem-boxgrinder-core.spec", "spec/appliance-parser-spec.rb", "spec/appliance-validator-spec.rb", "spec/helpers/appliance-config-helper-spec.rb", "spec/helpers/appliance-definition-helper-spec.rb", "spec/helpers/appliance-transformation-helper-spec.rb", "spec/helpers/exec-helper-spec.rb", "spec/helpers/log-helper-spec.rb", "spec/models/config-spec.rb", "spec/rspec/ls/one", "spec/rspec/ls/two", "spec/rspec/src/appliances/0.8.x.appl", "spec/rspec/src/appliances/0.9.x-invalid.appl", "spec/rspec/src/appliances/0.9.x.appl", "spec/rspec/src/appliances/ephemeral-repo.appl", "spec/rspec/src/appliances/full.appl", "spec/rspec/src/appliances/invalid-yaml.appl", "spec/rspec/src/appliances/legacy.appl", "spec/rspec/src/appliances/repo.appl", "spec/rspec/src/config/empty", "spec/rspec/src/config/valid"]
14
+ s.homepage = %q{http://boxgrinder.org}
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Boxgrinder-core", "--main", "README"]
16
16
  s.require_paths = ["lib"]
17
17
  s.rubyforge_project = %q{BoxGrinder}
@@ -23,14 +23,17 @@ Gem::Specification.new do |s|
23
23
  s.specification_version = 3
24
24
 
25
25
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
- s.add_runtime_dependency(%q<open4>, [">= 1.0.0"])
27
26
  s.add_runtime_dependency(%q<hashery>, [">= 1.3.0"])
27
+ s.add_runtime_dependency(%q<kwalify>, [">= 0.7.2"])
28
+ s.add_runtime_dependency(%q<open4>, [">= 1.0.0"])
28
29
  else
29
- s.add_dependency(%q<open4>, [">= 1.0.0"])
30
30
  s.add_dependency(%q<hashery>, [">= 1.3.0"])
31
+ s.add_dependency(%q<kwalify>, [">= 0.7.2"])
32
+ s.add_dependency(%q<open4>, [">= 1.0.0"])
31
33
  end
32
34
  else
33
- s.add_dependency(%q<open4>, [">= 1.0.0"])
34
35
  s.add_dependency(%q<hashery>, [">= 1.3.0"])
36
+ s.add_dependency(%q<kwalify>, [">= 0.7.2"])
37
+ s.add_dependency(%q<open4>, [">= 1.0.0"])
35
38
  end
36
39
  end
@@ -0,0 +1,84 @@
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 'kwalify'
20
+ require 'boxgrinder-core/helpers/appliance-transformation-helper'
21
+ require 'boxgrinder-core/helpers/log-helper'
22
+ require 'boxgrinder-core/appliance-validator'
23
+ require 'boxgrinder-core/errors'
24
+
25
+ module BoxGrinder
26
+ class ApplianceParser
27
+ def initialize(options = {})
28
+ @log = options[:log] || LogHelper.new
29
+ @schemas = {}
30
+ end
31
+
32
+ def load_schemas
33
+ Dir.glob("#{File.dirname(__FILE__)}/schemas/{*.yaml,*.yml}").each do |f|
34
+ schema = Kwalify::Yaml.load_file(f)
35
+ @schemas[schema['version']] = schema
36
+ end
37
+ end
38
+
39
+ def parse_definition(appliance_definition, file = true)
40
+ if file
41
+ @log.info "Validating appliance definition from #{appliance_definition} file..."
42
+ appliance_definition = File.read(appliance_definition)
43
+ else
44
+ @log.info "Validating appliance definition from string..."
45
+ end
46
+
47
+ failures = {}
48
+ schema_versions = @schemas.keys.sort.reverse
49
+
50
+ schema_versions.each do |schema_version|
51
+ @schemas[schema_version].delete('version')
52
+ appliance_config, errors = parse(@schemas[schema_version], appliance_definition)
53
+
54
+ if errors.empty?
55
+ @log.info "Appliance definition is valid."
56
+ return ApplianceTransformationHelper.new(schema_versions.first, :log => @log).transform(appliance_config, schema_version)
57
+ end
58
+
59
+ failures[schema_version] = errors
60
+ end
61
+
62
+ # If all schemas fail then we assume they are using the latest schema..
63
+ failures[schema_versions.first].each do |error|
64
+ @log.error "Error: [line #{error.linenum}, col #{error.column}] [#{error.path}] #{error.message}"
65
+ end
66
+
67
+ raise ApplianceValidationError, "The appliance definition was invalid according to schema #{schema_versions.first}. See log for details."
68
+ end
69
+
70
+ def parse(schema_document, appliance_definition)
71
+ validator = ApplianceValidator.new(schema_document)
72
+ parser = Kwalify::Yaml::Parser.new(validator)
73
+
74
+ begin
75
+ parsed = parser.parse(appliance_definition)
76
+ rescue Kwalify::KwalifyError => e
77
+ raise ApplianceValidationError, "The appliance definition couldn't be parsed. [line #{e.linenum}, col #{e.column}] [#{e.path}] Most probably you try to specify partition mount point starting with backslash (/), please quote it like this: \"/foo\"." if e.message =~ /document end expected \(maybe invalid tab char found\)/
78
+ raise ApplianceValidationError, "The appliance definition couldn't be parsed. #{e}"
79
+ end
80
+
81
+ [parsed, parser.errors]
82
+ end
83
+ end
84
+ end
@@ -16,9 +16,22 @@
16
16
  # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
17
  # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
18
 
19
- require 'boxgrinder-core/validators/appliance-config-validator'
19
+ require 'kwalify'
20
+ require 'boxgrinder-core/helpers/log-helper'
20
21
 
21
22
  module BoxGrinder
22
- describe ApplianceConfigValidator do
23
+ class ApplianceValidator < Kwalify::Validator
24
+ def initialize(schema)
25
+ super(schema) # Super constructor
26
+ end
27
+
28
+ def validate_hook(value, rule, path, errors)
29
+ case rule.name
30
+ when 'Repository' # enforce baseurl xor mirrorlist
31
+ errors << Kwalify::ValidationError.new("Please specify either a baseurl or a mirrorlist.", path) unless value['baseurl'].nil? ^ value['mirrorlist'].nil?
32
+ when 'Hardware' # enforce multiple of 64
33
+ errors << Kwalify::ValidationError.new("Specified memory amount: #{value['memory']} is invalid. The value must be a multiple of 64.", path) unless value['memory'].nil? or value['memory']%64==0
34
+ end
35
+ end
23
36
  end
24
37
  end
@@ -24,6 +24,22 @@ module BoxGrinder
24
24
  class ApplianceValidationError < ValidationError
25
25
 
26
26
  end
27
+
28
+ class SchemaValidationError < ValidationError
29
+
30
+ end
31
+
32
+ class PluginValidationError < ValidationError
33
+
34
+ end
35
+
36
+ class UnknownFormatError < ValidationError
37
+
38
+ end
39
+
40
+ class PluginError < StandardError
41
+
42
+ end
27
43
  end
28
44
 
29
45
  class StandardError
@@ -16,7 +16,7 @@
16
16
  # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
17
  # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
18
 
19
- require 'boxgrinder-core/validators/errors'
19
+ require 'boxgrinder-core/errors'
20
20
  require 'set'
21
21
 
22
22
  module BoxGrinder
@@ -80,7 +80,7 @@ module BoxGrinder
80
80
  resolve_stack.index(k).nil?
81
81
  }
82
82
  refs.each do |ref|
83
- resolve(Arrays.new(resolve_stack).push(ref), resolved_set) unless resolved_set.include?(ref)
83
+ resolve(Array.new(resolve_stack).push(ref), resolved_set) unless resolved_set.include?(ref)
84
84
  while @appliance_config.variables[var].include? "##{ref}#" do
85
85
  @appliance_config.variables[var].gsub!("##{ref}#", @appliance_config.variables[ref])
86
86
  end
@@ -112,7 +112,7 @@ module BoxGrinder
112
112
  partitions[root].delete('options') if partitions[root]['type'] != partition['type']
113
113
  partitions[root]['type'] = partition['type']
114
114
  else
115
- partitions[root]['type'] = default_filesystem_type
115
+ partitions[root]['type'] = @appliance_config.default_filesystem_type
116
116
  end
117
117
  else
118
118
  partitions[root] = {}
@@ -121,7 +121,7 @@ module BoxGrinder
121
121
  unless partition['type'].nil?
122
122
  partitions[root]['type'] = partition['type']
123
123
  else
124
- partitions[root]['type'] = default_filesystem_type
124
+ partitions[root]['type'] = @appliance_config.default_filesystem_type
125
125
  end
126
126
  end
127
127
 
@@ -130,21 +130,10 @@ module BoxGrinder
130
130
  end
131
131
  end
132
132
 
133
- @appliance_config.hardware.partitions = partitions
134
- end
135
-
136
- def default_filesystem_type
137
- fs = 'ext4'
138
-
139
- case @appliance_config.os.name
140
- when 'rhel', 'centos'
141
- case @appliance_config.os.version
142
- when '5'
143
- fs = 'ext3'
144
- end
145
- end
133
+ # https://bugzilla.redhat.com/show_bug.cgi?id=466275
134
+ partitions['/boot'] = {'type' => 'ext3', 'size' => 0.1} if partitions['/boot'].nil? and (@appliance_config.os.name == 'centos' or @appliance_config.os.name == 'rhel') and @appliance_config.os.version == '5'
146
135
 
147
- fs
136
+ @appliance_config.hardware.partitions = partitions
148
137
  end
149
138
 
150
139
  def merge_memory
@@ -155,6 +144,9 @@ module BoxGrinder
155
144
  merge_field('os.name') { |name| @appliance_config.os.name = name.to_s }
156
145
  merge_field('os.version') { |version| @appliance_config.os.version = version.to_s }
157
146
  merge_field('os.password') { |password| @appliance_config.os.password = password.to_s }
147
+ merge_field('os.pae') { |pae| @appliance_config.os.pae = false unless pae }
148
+
149
+ @appliance_config.os.password = 'boxgrinder' if @appliance_config.os.password.nil?
158
150
  end
159
151
 
160
152
  def prepare_appliances
@@ -16,40 +16,38 @@
16
16
  # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
17
  # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18
18
 
19
+ require 'boxgrinder-core/helpers/log-helper'
19
20
  require 'boxgrinder-core/models/appliance-config'
20
- require 'yaml'
21
+ require 'boxgrinder-core/appliance-parser'
21
22
 
22
23
  module BoxGrinder
23
24
  class ApplianceDefinitionHelper
24
25
  def initialize(options = {})
25
- @log = options[:log] || Logger.new(STDOUT)
26
+ @log = options[:log] || LogHelper.new
26
27
  @appliance_configs = []
28
+ @appliance_parser = ApplianceParser.new(:log => @log)
27
29
  end
28
30
 
29
31
  attr_reader :appliance_configs
32
+ attr_reader :appliance_parser
30
33
 
31
34
  # Reads definition provided as string. This string can be a YAML document. In this case
32
35
  # definition is parsed and an ApplianceConfig object is returned. In other cases it tries to search
33
36
  # for a file with provided name.
34
37
  def read_definitions(definition, content_type = nil)
38
+ @appliance_parser.load_schemas
35
39
  if File.exists?(definition)
36
- @log.debug "Reading definition from '#{definition}' file..."
37
-
38
40
  definition_file_extension = File.extname(definition)
39
41
 
40
42
  appliance_config =
41
43
  case definition_file_extension
42
44
  when '.appl', '.yml', '.yaml'
43
- read_yaml_file(definition)
44
- when '.xml'
45
- read_xml_file(definition)
45
+ parse_yaml(@appliance_parser.parse_definition(definition))
46
46
  else
47
47
  unless content_type.nil?
48
48
  case content_type
49
49
  when 'application/x-yaml', 'text/yaml'
50
- read_yaml_file(definition)
51
- when 'application/xml', 'text/xml', 'application/x-xml'
52
- read_xml_file(definition)
50
+ parse_yaml(@appliance_parser.parse_definition(definition))
53
51
  end
54
52
  end
55
53
  end
@@ -65,35 +63,12 @@ module BoxGrinder
65
63
  read_definitions("#{File.dirname(definition)}/#{appliance_name}#{definition_file_extension}") unless appliances.include?(appliance_name)
66
64
  end unless appliance_config.appliances.nil? or !appliance_config.appliances.is_a?(Array)
67
65
  else
68
- @log.debug "Reading definition..."
69
-
70
- @appliance_configs << read_yaml(definition)
71
- end
72
- end
73
-
74
- def read_yaml(content)
75
- begin
76
- definition = YAML.load(content)
77
- raise "Not a valid YAML content." if definition.nil? or definition == false
78
- rescue
79
- raise "Provided definition could not be read."
80
- end
81
-
82
- parse_yaml(definition)
83
- end
84
-
85
- def read_yaml_file(file)
86
- begin
87
- definition = YAML.load_file(file)
88
- raise "Not a valid YAML file." if definition.nil? or definition == false
89
- rescue
90
- raise "File '#{file}' could not be read."
66
+ # Assuming that the definition is provided as string
67
+ @appliance_configs << parse_yaml(@appliance_parser.parse_definition(definition, false))
91
68
  end
92
-
93
- parse_yaml(definition)
94
69
  end
95
70
 
96
- # TODO this needs to be rewritten
71
+ # TODO this needs to be rewritten - using kwalify it could be possible to instantiate document structure as objects[, or opencascade hash?]
97
72
  def parse_yaml(definition)
98
73
  return definition if definition.is_a?(ApplianceConfig)
99
74
  raise "Provided definition is not a Hash." unless definition.is_a?(Hash)
@@ -107,27 +82,15 @@ module BoxGrinder
107
82
 
108
83
  @log.debug "Adding packages to appliance..."
109
84
 
110
- unless definition['packages'].nil?
111
- if definition['packages'].is_a?(Array)
112
- # new format
113
- appliance_config.packages = definition['packages']
114
- elsif definition['packages'].is_a?(Hash)
115
- # legacy format
116
- @log.warn "BoxGrinder Build packages section format has been changed. Support for legacy format will be removed in the future. See http://boxgrinder.org/tutorials/appliance-definition/ for more information about current format."
117
- appliance_config.packages = definition['packages']['includes'] if definition['packages']['includes'].is_a?(Array)
118
- @log.warn "BoxGrinder Build no longer supports package exclusion, the following packages will not be explicitly excluded: #{definition['packages']['excludes'].join(", ")}." if definition['packages']['excludes'].is_a?(Array)
119
- else
120
- @log.warn "Unsupported format for packages section."
121
- end
122
- end
85
+ appliance_config.packages = definition['packages'] unless definition['packages'].nil?
123
86
 
124
- @log.debug "#{appliance_config.packages.size} package(s) added to appliance."
87
+ @log.debug "#{appliance_config.packages.size} package(s) added to appliance." if appliance_config.packages
125
88
 
126
89
  appliance_config.appliances = definition['appliances'] unless definition['appliances'].nil?
127
90
  appliance_config.repos = definition['repos'] unless definition['repos'].nil?
128
91
 
129
- appliance_config.version = definition['version'].to_s unless definition['version'].nil?
130
- appliance_config.release = definition['release'].to_s unless definition['release'].nil?
92
+ appliance_config.version = definition['version'] unless definition['version'].nil?
93
+ appliance_config.release = definition['release'] unless definition['release'].nil?
131
94
 
132
95
  unless definition['default_repos'].nil?
133
96
  appliance_config.default_repos = definition['default_repos']
@@ -135,9 +98,10 @@ module BoxGrinder
135
98
  end
136
99
 
137
100
  unless definition['os'].nil?
138
- appliance_config.os.name = definition['os']['name'].to_s unless definition['os']['name'].nil?
139
- appliance_config.os.version = definition['os']['version'].to_s unless definition['os']['version'].nil?
140
- appliance_config.os.password = definition['os']['password'].to_s unless definition['os']['password'].nil?
101
+ appliance_config.os.name = definition['os']['name'] unless definition['os']['name'].nil?
102
+ appliance_config.os.version = definition['os']['version'] unless definition['os']['version'].nil?
103
+ appliance_config.os.password = definition['os']['password'] unless definition['os']['password'].nil?
104
+ appliance_config.os.pae = definition['os']['pae'] unless definition['os']['pae'].nil?
141
105
  end
142
106
 
143
107
  unless definition['hardware'].nil?
@@ -157,9 +121,5 @@ module BoxGrinder
157
121
 
158
122
  appliance_config
159
123
  end
160
-
161
- def read_xml_file(file)
162
- raise "Reading XML files is not supported right now. File '#{file}' could not be read."
163
- end
164
124
  end
165
125
  end
@@ -0,0 +1,58 @@
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/helpers/log-helper'
20
+
21
+ module BoxGrinder
22
+ class ApplianceTransformationHelper
23
+ def initialize(latest_schema_version, options = {})
24
+ @latest_schema_version = latest_schema_version
25
+ @log = options[:log] || LogHelper.new
26
+
27
+ @versions = ['0.9.0']
28
+ end
29
+
30
+ def transform(appliance_definition, version)
31
+ return appliance_definition if version == @latest_schema_version
32
+
33
+ @log.debug "Transforming appliance definition from schema version #{version} to #{@latest_schema_version}..."
34
+
35
+ transformations = [version]
36
+ definition = appliance_definition
37
+
38
+ @versions.each do |v|
39
+ if (transformations.last <=> v) < 0
40
+ @log.trace "Round #{transformations.size}: transforming from version #{transformations.last} to #{v}..."
41
+ definition = self.send("to_#{v.gsub(/[-\.]/, '_')}", definition)
42
+ transformations << v
43
+ end
44
+ end
45
+
46
+ @log.debug "Following transformation were applied: #{transformations.join(' => ')}." if transformations.size > 1
47
+
48
+ definition
49
+ end
50
+
51
+ def to_0_9_0(appliance_definition)
52
+ packages = appliance_definition['packages']['includes']
53
+ @log.warn "BoxGrinder no longer supports package exclusion, the following packages will be not be explicitly excluded: #{appliance_definition['packages']['excludes'].join(", ")}." unless appliance_definition['packages']['excludes'].nil?
54
+ appliance_definition['packages'] = packages
55
+ appliance_definition
56
+ end
57
+ end
58
+ end
@@ -18,15 +18,23 @@
18
18
 
19
19
  require 'logger'
20
20
  require 'rubygems'
21
- require 'open4'
21
+ require 'open4' unless RUBY_PLATFORM =~ /java/
22
22
 
23
23
  module BoxGrinder
24
+ class InterruptionError < Interrupt
25
+ attr_reader :pid
26
+
27
+ def initialize(pid)
28
+ @pid = pid
29
+ end
30
+ end
31
+
24
32
  class ExecHelper
25
- def initialize( options = {} )
33
+ def initialize(options = {})
26
34
  @log = options[:log] || Logger.new(STDOUT)
27
35
  end
28
36
 
29
- def execute( command, options = {} )
37
+ def execute(command, options = {})
30
38
  redacted = options[:redacted] || []
31
39
 
32
40
  redacted_command = command
@@ -41,38 +49,57 @@ module BoxGrinder
41
49
  STDERR.sync = true
42
50
 
43
51
  begin
44
- status = Open4::popen4( command ) do |pid, stdin, stdout, stderr|
45
- threads = []
52
+ pid, stdin, stdout, stderr = (RUBY_PLATFORM =~ /java/ ? IO : Open4).send(:popen4, command)
53
+ threads = []
46
54
 
47
- threads << Thread.new(stdout) do |input_str|
48
- input_str.each do |l|
49
- l.chomp!
50
- l.strip!
55
+ threads << Thread.new(stdout) do |out|
56
+ out.each do |l|
57
+ l.chomp!
58
+ l.strip!
51
59
 
52
- output << "\n#{l}"
53
- @log.debug l
54
- end
60
+ output << "\n#{l}"
61
+ @log.debug l
55
62
  end
63
+ end
56
64
 
57
- threads << Thread.new(stderr) do |input_str|
58
- input_str.each do |l|
59
- l.chomp!
60
- l.strip!
65
+ threads << Thread.new(stderr) do |err|
66
+ err.each do |l|
67
+ l.chomp!
68
+ l.strip!
61
69
 
62
- output << "\n#{l}"
63
- @log.debug l
64
- end
70
+ output << "\n#{l}"
71
+ @log.debug l
65
72
  end
66
- threads.each{|t|t.join}
67
73
  end
68
74
 
69
- raise "process exited with wrong exit status: #{status.exitstatus}" if status.exitstatus != 0
75
+ threads.each { |t| t.join }
76
+
77
+ # Assume the process exited cleanly, which can cause some bad behaviour, but I don't see better way
78
+ # to get reliable status for processes both on MRI and JRuby
79
+ #
80
+ # http://jira.codehaus.org/browse/JRUBY-5673
81
+ status = OpenCascade.new(:exitstatus => 0)
82
+
83
+ fakepid, status = Process.waitpid2(pid) if process_alive?(pid)
84
+
85
+ raise "process exited with wrong exit status: #{status.exitstatus}" if !(RUBY_PLATFORM =~ /java/) and status.exitstatus != 0
70
86
 
71
87
  return output.strip
88
+ rescue Interrupt
89
+ raise InterruptionError.new(pid), "Program was interrupted."
72
90
  rescue => e
73
91
  @log.error e.backtrace.join($/)
74
92
  raise "An error occurred while executing command: '#{redacted_command}', #{e.message}"
75
93
  end
76
94
  end
95
+
96
+ def process_alive?(pid)
97
+ begin
98
+ Process.getpgid(pid)
99
+ true
100
+ rescue Errno::ESRCH
101
+ false
102
+ end
103
+ end
77
104
  end
78
105
  end