boxgrinder-core 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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