machinery-tool 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 551ee9539d7129929b744957a8dd0ac26c6ae192
4
- data.tar.gz: ee438023ee53265b39100377a44fd9a424af341a
3
+ metadata.gz: c161742e300133d4d5a6514ddfe3e4284fc29b52
4
+ data.tar.gz: 28c974344534d7ad4df48e43dce31b60125bb1b1
5
5
  SHA512:
6
- metadata.gz: 056cc96bb640691c3fdb20f95a2d1adf62b5f22354dfa13d108c7cabddba2880ae657b56d2d14ccdbc15847268e236473aa64ab09d1f12e653935f944f17669f
7
- data.tar.gz: 43900b48ef6ed9739efbfbd239fac78c4f9e7c1add2bd2f36349f716ed333a51771b8627574f59e3fb285aabfabeffa214fc31b417f073a6252bbc46ec2fac2f
6
+ metadata.gz: ddd663cea68dfa8a41b8cd8921c91436a5e70a049439ee5b628b4d628f427ef4375923f9b33e967e4d6604ba487950cad0ebed0e2b62291ba66fed49ebfa1087
7
+ data.tar.gz: 285ed630148abb78038681ed823dd2079501a18ecd64d0882e642300c8d6f648b62dfb7f672e8efd4dcdfc1fc3131401cf82e88f09c6d3cdb6c886423f69302f
data/NEWS CHANGED
@@ -1,6 +1,12 @@
1
1
  # Machinery Release Notes
2
2
 
3
3
 
4
+ ## Version 1.1.1 - Tue Dec 02 13:24:38 CET 2014 - thardeck@suse.de
5
+
6
+ * Skip Gnome Virtual File System mounts on inspection (issue #393)
7
+ * Skip special file systems like proc, devtmpfs and so on (issue #384)
8
+ * Show names of packages where changed config files come from (issue #392)
9
+
4
10
  ## Version 1.1.0 - Mon Nov 17 16:30:44 CET 2014 - thardeck@suse.de
5
11
 
6
12
  * File extraction status is now shown in the comparison output
data/lib/autoyast.rb ADDED
@@ -0,0 +1,149 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class Autoyast
19
+ def initialize(description)
20
+ @system_description = description
21
+ end
22
+
23
+ def write(output_dir)
24
+ File.write(File.join(output_dir, "autoinst.xml"), profile)
25
+ end
26
+
27
+ def profile
28
+ builder = Nokogiri::XML::Builder.new do |xml|
29
+ xml.doc.create_internal_subset("profile", nil, nil)
30
+ xml.profile(
31
+ "xmlns" => "http://www.suse.com/1.0/yast2ns",
32
+ "xmlns:config" => "http://www.suse.com/1.0/configns"
33
+ ) do
34
+ apply_repositories(xml)
35
+ xml.software do
36
+ apply_packages(xml)
37
+ apply_patterns(xml)
38
+ end
39
+ apply_users(xml)
40
+ apply_groups(xml)
41
+ apply_services(xml)
42
+ end
43
+ end
44
+
45
+ builder.to_xml
46
+ end
47
+
48
+ private
49
+
50
+ def apply_repositories(xml)
51
+ return if !@system_description.repositories
52
+
53
+ xml.send("add-on") do
54
+ xml.add_on_products("config:type" => "list") do
55
+ @system_description.repositories.each do |repository|
56
+ xml.listentry do
57
+ xml.media_url repository.url
58
+ xml.name repository.alias
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def apply_packages(xml)
66
+ return if !@system_description.packages
67
+
68
+ xml.packages("config:type" => "list") do
69
+ @system_description.packages.each do |package|
70
+ xml.package package.name
71
+ end
72
+ end
73
+ end
74
+
75
+ def apply_patterns(xml)
76
+ return if !@system_description.patterns
77
+
78
+ xml.patterns("config:type" => "list") do
79
+ @system_description.patterns.each do |pattern|
80
+ xml.pattern pattern.name
81
+ end
82
+ end
83
+ end
84
+
85
+ def apply_users(xml)
86
+ return if !@system_description.users
87
+
88
+ xml.users("config:type" => "list") do
89
+ @system_description.users.each do |user|
90
+ xml.user do
91
+ xml.username user.name
92
+ xml.user_password user.encrypted_password
93
+ xml.encrypted "true", "config:type" => "boolean"
94
+ xml.uid user.uid
95
+ xml.gid user.gid
96
+ xml.home user.home
97
+ xml.shell user.shell
98
+ xml.fullname user.comment
99
+ xml.password_settings do
100
+ xml.min user.min_days
101
+ xml.max user.max_days
102
+ xml.warn user.warn_days
103
+ xml.inact user.disable_days
104
+ xml.expire user.disabled_date
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def apply_groups(xml)
112
+ return if !@system_description.groups
113
+
114
+ xml.groups("config:type" => "list") do
115
+ @system_description.groups.each do |group|
116
+ xml.group do
117
+ xml.encrypted "true", "config:type" => "boolean"
118
+ xml.gid group.gid
119
+ xml.groupname group.name
120
+ xml.group_password group.password
121
+ xml.userlist group.users.join(",")
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ def apply_services(xml)
128
+ xml.send("services-manager") do
129
+ xml.services do
130
+ @system_description.services.services.each do |service|
131
+ # systemd service states like "masked" and "static" are
132
+ # not supported by Autoyast
133
+ if service.enabled?
134
+ xml.service do
135
+ xml.service_name service.name
136
+ xml.service_status "enable"
137
+ end
138
+ end
139
+ if service.disabled?
140
+ xml.service do
141
+ xml.service_name service.name
142
+ xml.service_status "disable"
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
data/lib/cli.rb CHANGED
@@ -359,9 +359,42 @@ class Cli
359
359
  name = shift_arg(args, "NAME")
360
360
  store = SystemDescriptionStore.new
361
361
  description = store.load(name)
362
+ exporter = KiwiConfig.new(description)
362
363
 
363
- task = KiwiExportTask.new
364
- task.export(description, File.expand_path(options["kiwi-dir"]), force: options[:force])
364
+ task = ExportTask.new(exporter)
365
+ task.export(
366
+ File.expand_path(options["kiwi-dir"]),
367
+ force: options[:force]
368
+ )
369
+ end
370
+ end
371
+
372
+
373
+
374
+ desc "Export system description as AutoYaST profile"
375
+ long_desc <<-LONGDESC
376
+ Export system description as AutoYaST profile
377
+
378
+ The profile will be placed in the location given by the 'autoyast-dir' option.
379
+ LONGDESC
380
+ arg "NAME"
381
+ command "export-autoyast" do |c|
382
+ c.flag ["autoyast-dir", :a], type: String, required: true,
383
+ desc: "Location where the autoyast profile will be stored", arg_name: "DIRECTORY"
384
+ c.switch :force, default_value: false, required: false, negatable: false,
385
+ desc: "Overwrite existing profile"
386
+
387
+ c.action do |_global_options, options, args|
388
+ name = shift_arg(args, "NAME")
389
+ store = SystemDescriptionStore.new
390
+ description = store.load(name)
391
+ exporter = Autoyast.new(description)
392
+
393
+ task = ExportTask.new(exporter)
394
+ task.export(
395
+ File.expand_path(options["autoyast-dir"]),
396
+ force: options[:force]
397
+ )
365
398
  end
366
399
  end
367
400
 
@@ -446,6 +479,8 @@ class Cli
446
479
  command :list do |c|
447
480
  c.switch :verbose, :required => false, :negatable => false,
448
481
  :desc => "Display additional information about origin of scopes"
482
+ c.switch :quick, :required => false, :negatable => false,
483
+ :desc => "Show quick list without details"
449
484
 
450
485
  c.action do |global_options,options,args|
451
486
  store = SystemDescriptionStore.new
data/lib/exceptions.rb CHANGED
@@ -103,7 +103,7 @@ module Machinery
103
103
  class BuildFailed < MachineryError; end
104
104
  class DeployFailed < MachineryError; end
105
105
  class InspectionFailed < MachineryError; end
106
- class KiwiExportFailed < MachineryError; end
106
+ class ExportFailed < MachineryError; end
107
107
 
108
108
  class SshConnectionFailed < MachineryError; end
109
109
  class RsyncFailed < MachineryError; end
@@ -15,22 +15,25 @@
15
15
  # To contact SUSE about this file by physical or electronic mail,
16
16
  # you may find current contact information at www.suse.com
17
17
 
18
- class KiwiExportTask
19
- def export(description, kiwi_dir, options)
20
- if File.exists?(kiwi_dir)
18
+ class ExportTask
19
+ def initialize(exporter)
20
+ @exporter = exporter
21
+ end
22
+
23
+ def export(output_dir, options)
24
+ if File.exists?(output_dir)
21
25
  if options[:force]
22
- FileUtils.rm_r(kiwi_dir)
26
+ FileUtils.rm_r(output_dir)
23
27
  else
24
- raise Machinery::Errors::KiwiExportFailed.new(
25
- "The output directory '#{kiwi_dir}' already exists." \
28
+ raise Machinery::Errors::ExportFailed.new(
29
+ "The output directory '#{output_dir}' already exists." \
26
30
  " You can force overwriting it with the '--force' option."
27
31
  )
28
32
  end
29
33
  end
30
34
 
31
- FileUtils.mkdir_p(kiwi_dir) unless Dir.exists?(kiwi_dir)
35
+ FileUtils.mkdir_p(output_dir) unless Dir.exists?(output_dir)
32
36
 
33
- config = KiwiConfig.new(description)
34
- config.write(kiwi_dir)
37
+ @exporter.write(output_dir)
35
38
  end
36
39
  end
data/lib/kiwi_config.rb CHANGED
@@ -140,7 +140,7 @@ suseSetupProduct
140
140
  suseImportBuildKey
141
141
  suseConfig
142
142
  EOF
143
- case @system_description.os_object
143
+ case @system_description.os
144
144
  when OsOpenSuse13_1
145
145
  boot = "vmxboot/suse-13.1"
146
146
  bootloader = "grub2"
@@ -151,9 +151,9 @@ EOF
151
151
  boot = "vmxboot/suse-SLES11"
152
152
  bootloader = "grub"
153
153
  else
154
- raise Machinery::Errors::KiwiExportFailed.new(
154
+ raise Machinery::Errors::ExportFailed.new(
155
155
  "Building is not possible because the operating system " \
156
- "'#{@system_description.os_object.name}' is not supported."
156
+ "'#{@system_description.os.canonical_name}' is not supported."
157
157
  )
158
158
  end
159
159
 
@@ -194,7 +194,7 @@ EOF
194
194
  build_filter = YAML.load_file(File.join(
195
195
  Machinery::ROOT, "helpers", "filter-packages-for-build.yaml")
196
196
  )
197
- filter = build_filter[@system_description.os_object.name] || []
197
+ filter = build_filter[@system_description.os.canonical_name] || []
198
198
 
199
199
  xml.packages(type: "bootstrap") do
200
200
  if @system_description.packages
@@ -298,7 +298,7 @@ EOF
298
298
  # Don't do anything because these states are not supposed
299
299
  # to be permanent.
300
300
  else
301
- raise Machinery::Errors::KiwiExportFailed.new(
301
+ raise Machinery::Errors::ExportFailed.new(
302
302
  "The systemd unit state #{service.state} is unknown."
303
303
  )
304
304
  end
@@ -311,7 +311,7 @@ EOF
311
311
  end
312
312
 
313
313
  def enable_dhcp(output_location)
314
- case @system_description.os_object
314
+ case @system_description.os
315
315
  when OsSles11
316
316
  write_dhcp_network_config(output_location, "eth0")
317
317
  when OsSles12
data/lib/list_task.rb CHANGED
@@ -19,46 +19,52 @@ class ListTask
19
19
  def list(store, options = {})
20
20
  descriptions = store.list.sort
21
21
 
22
- descriptions.each do |name|
23
- name = File.basename(name)
24
- begin
25
- description = store.load(name)
26
- rescue Machinery::Errors::SystemDescriptionError
27
- Machinery::Ui.puts " #{name}:\n"
28
- Machinery::Ui.puts " This description has an incompatible data format or is broken.\n" \
29
- " Use `#{$0} validate #{name}` to see the error message.\n\n"
30
- next
22
+ if options[:quick]
23
+ descriptions.each do |name|
24
+ Machinery::Ui.puts(" #{name}")
31
25
  end
32
- scopes = []
26
+ else
27
+ descriptions.each do |name|
28
+ name = File.basename(name)
29
+ begin
30
+ description = store.load(name)
31
+ rescue Machinery::Errors::SystemDescriptionError
32
+ Machinery::Ui.puts " #{name}:\n"
33
+ Machinery::Ui.puts " This description has an incompatible data format or is broken.\n" \
34
+ " Use `#{$0} validate #{name}` to see the error message.\n\n"
35
+ next
36
+ end
37
+ scopes = []
33
38
 
34
- description.scopes.each do |scope|
35
- entry = Machinery::Ui.internal_scope_list_to_string(scope)
36
- if SystemDescription::EXTRACTABLE_SCOPES.include?(scope)
37
- if description.scope_extracted?(scope)
38
- entry += " (extracted)"
39
- else
40
- entry += " (not extracted)"
39
+ description.scopes.each do |scope|
40
+ entry = Machinery::Ui.internal_scope_list_to_string(scope)
41
+ if SystemDescription::EXTRACTABLE_SCOPES.include?(scope)
42
+ if description.scope_extracted?(scope)
43
+ entry += " (extracted)"
44
+ else
45
+ entry += " (not extracted)"
46
+ end
41
47
  end
42
- end
43
48
 
44
- if options["verbose"]
45
- meta = description[scope].meta
46
- if meta
47
- time = Time.parse(meta.modified).getlocal
48
- date = time.strftime "%Y-%m-%d %H:%M:%S"
49
- hostname = meta.hostname
50
- else
51
- date = "unknown"
52
- hostname = "Unknown hostname"
49
+ if options["verbose"]
50
+ meta = description[scope].meta
51
+ if meta
52
+ time = Time.parse(meta.modified).getlocal
53
+ date = time.strftime "%Y-%m-%d %H:%M:%S"
54
+ hostname = meta.hostname
55
+ else
56
+ date = "unknown"
57
+ hostname = "Unknown hostname"
58
+ end
59
+ entry += "\n Host: [#{hostname}]"
60
+ entry += "\n Date: (#{date})"
53
61
  end
54
- entry += "\n Host: [#{hostname}]"
55
- entry += "\n Date: (#{date})"
62
+
63
+ scopes << entry
56
64
  end
57
65
 
58
- scopes << entry
66
+ Machinery::Ui.puts " #{name}:\n * " + scopes .join("\n * ") + "\n\n"
59
67
  end
60
-
61
- Machinery::Ui.puts " #{name}:\n * " + scopes .join("\n * ") + "\n\n"
62
68
  end
63
69
  end
64
70
  end
data/lib/local_system.rb CHANGED
@@ -17,18 +17,18 @@
17
17
 
18
18
  class LocalSystem < System
19
19
  class << self
20
- def os_object
20
+ def os
21
21
  description = SystemDescription.new("localhost")
22
22
  inspector = OsInspector.new
23
23
  inspector.inspect(System.for("localhost"), description)
24
- description.os_object
24
+ description.os
25
25
  end
26
26
 
27
27
  def validate_existence_of_package(package)
28
28
  begin
29
29
  Cheetah.run("rpm", "-q", package)
30
30
  rescue
31
- needed_module = os_object.module_required_by_package(package)
31
+ needed_module = os.module_required_by_package(package)
32
32
  if needed_module
33
33
  raise(Machinery::Errors::MissingRequirement.new("You need the package '#{package}' from module '#{needed_module}'. You can install it as follows:\n" \
34
34
  "If you haven't selected the module '#{needed_module}' before, run `yast2 scc` and choose 'Select Extensions' and activate '#{needed_module}'.\nRun `zypper install #{package}` to install the package."))
@@ -39,14 +39,8 @@ class LocalSystem < System
39
39
  end
40
40
 
41
41
  def validate_machinery_compatibility
42
- begin
43
- os = os_object
44
- rescue Machinery::Errors::SystemDescriptionError
45
- os = nil
46
- end
47
-
48
- if !os || !os.can_run_machinery?
49
- supported_oses = Os.supported_host_systems.map { |o| o.new.name }.
42
+ if !os.can_run_machinery?
43
+ supported_oses = Os.supported_host_systems.map { |o| o.canonical_name }.
50
44
  sort.join(", ")
51
45
  message = "Running Machinery is not supported on this system.\n" \
52
46
  "Supported operating systems are: #{supported_oses}"
@@ -56,8 +50,8 @@ class LocalSystem < System
56
50
  end
57
51
 
58
52
  def validate_build_compatibility(system_description)
59
- if !os_object.can_build?(system_description.os_object)
60
- message = "Building '#{system_description.os_object.name}' images is " \
53
+ if !os.can_build?(system_description.os)
54
+ message = "Building '#{system_description.os.canonical_name}' images is " \
61
55
  "not supported on this distribution.\n" \
62
56
  "Check the 'BUILD SUPPORT MATRIX' section in our man page for " \
63
57
  "further information which build targets are supported."
data/lib/machinery.rb CHANGED
@@ -15,12 +15,12 @@
15
15
  # To contact SUSE about this file by physical or electronic mail,
16
16
  # you may find current contact information at www.suse.com
17
17
 
18
- require 'ostruct'
19
- require 'json'
18
+ require "ostruct"
19
+ require "json"
20
20
  require "abstract_method"
21
21
  require "cheetah"
22
22
  require "tmpdir"
23
- require 'tempfile'
23
+ require "tempfile"
24
24
  require "time"
25
25
  require "logger"
26
26
  require "erb"
@@ -31,55 +31,55 @@ require "json-schema"
31
31
  require "haml"
32
32
  require "kramdown"
33
33
 
34
- require_relative 'machinery_logger'
35
- require_relative 'zypper'
36
- require_relative 'rpm'
37
- require_relative 'array'
38
- require_relative 'object'
39
- require_relative 'constants'
40
- require_relative 'system_description'
41
- require_relative 'system_description_validator'
42
- require_relative 'version'
43
- require_relative 'tarball'
44
- require_relative 'exceptions'
45
- require_relative 'inspector'
46
- require_relative 'system'
47
- require_relative 'local_system'
48
- require_relative 'remote_system'
49
- require_relative 'current_user'
50
- require_relative 'inspect_task'
51
- require_relative 'inspector'
52
- require_relative 'build_task'
53
- require_relative 'kiwi_config'
54
- require_relative 'renderer'
55
- require_relative 'show_task'
56
- require_relative 'compare_task'
57
- require_relative 'remove_task'
58
- require_relative 'list_task'
59
- require_relative 'system_description_store'
60
- require_relative 'logged_cheetah'
61
- require_relative 'renderer_helper'
62
- require_relative 'changed_rpm_files_helper'
63
- require_relative 'kiwi_export_task'
64
- require_relative 'helper'
65
- require_relative 'deploy_task'
66
- require_relative 'analyze_config_file_diffs_task'
67
- require_relative 'copy_task'
68
- require_relative 'scope_mixin'
69
- require_relative 'os'
70
- require_relative 'ui'
71
- require_relative 'validate_task'
72
- require_relative 'migration'
73
- require_relative 'upgrade_format_task'
74
- require_relative 'html'
75
- require_relative 'generate_html_task'
76
- require_relative 'hint'
77
- require_relative 'mountpoints'
78
- require_relative 'config_base'
79
- require_relative 'config'
80
- require_relative 'config_task'
34
+ require_relative "machinery_logger"
35
+ require_relative "zypper"
36
+ require_relative "rpm"
37
+ require_relative "array"
38
+ require_relative "object"
39
+ require_relative "constants"
40
+ require_relative "system_description"
41
+ require_relative "system_description_validator"
42
+ require_relative "version"
43
+ require_relative "tarball"
44
+ require_relative "exceptions"
45
+ require_relative "inspector"
46
+ require_relative "system"
47
+ require_relative "local_system"
48
+ require_relative "remote_system"
49
+ require_relative "current_user"
50
+ require_relative "inspect_task"
51
+ require_relative "inspector"
52
+ require_relative "build_task"
53
+ require_relative "kiwi_config"
54
+ require_relative "renderer"
55
+ require_relative "show_task"
56
+ require_relative "compare_task"
57
+ require_relative "remove_task"
58
+ require_relative "list_task"
59
+ require_relative "system_description_store"
60
+ require_relative "logged_cheetah"
61
+ require_relative "renderer_helper"
62
+ require_relative "changed_rpm_files_helper"
63
+ require_relative "export_task"
64
+ require_relative "helper"
65
+ require_relative "deploy_task"
66
+ require_relative "analyze_config_file_diffs_task"
67
+ require_relative "copy_task"
68
+ require_relative "scope_mixin"
69
+ require_relative "ui"
70
+ require_relative "validate_task"
71
+ require_relative "migration"
72
+ require_relative "upgrade_format_task"
73
+ require_relative "html"
74
+ require_relative "generate_html_task"
75
+ require_relative "hint"
76
+ require_relative "mountpoints"
77
+ require_relative "config_base"
78
+ require_relative "config"
79
+ require_relative "config_task"
80
+ require_relative "autoyast"
81
81
 
82
82
  Dir[File.join(Machinery::ROOT, "plugins", "**", "*.rb")].each { |f| require(f) }
83
83
 
84
84
  # this file needs be loaded last, because it immediately collects the loaded inspectors
85
- require_relative 'cli'
85
+ require_relative "cli"
data/lib/mountpoints.rb CHANGED
@@ -24,6 +24,9 @@
24
24
  # remote() returns an array containing the mount points of all mounted
25
25
  # file systems that are remote file systems (e.g. nfs, cifs)
26
26
  #
27
+ # special() returns an array containing the mount points of all mounted
28
+ # special file systems, e.g. /proc
29
+ #
27
30
  # local() returns an array containing the mount points of all mounted
28
31
  # local file systems with permanent data (e.g. ext3, btrfs, xfs)
29
32
 
@@ -31,17 +34,22 @@
31
34
  class MountPoints
32
35
  attr_reader :mounts
33
36
  REMOTE_FILE_SYSTEMS = ["autofs", "cifs", "nfs", "nfs4"]
37
+ SPECIAL_FILE_SYSTEMS = ["proc", "sysfs", "devtmpfs", "tmpfs", "fuse.gvfs-fuse-daemon"]
34
38
  LOCAL_FILE_SYSTEMS = ["ext2", "ext3", "ext4", "reiserfs", "btrfs", "vfat", "xfs", "jfs"]
35
39
  def initialize(system)
36
40
  @mounts = parse_mounts(system.read_file("/proc/mounts"))
37
41
  end
38
42
 
43
+ def special
44
+ @mounts.select { |_fs_file, fs_vfstype| special_fs?(fs_vfstype) }.keys
45
+ end
46
+
39
47
  def remote
40
- @mounts.select { |fs_file,fs_vfstype| remote_fs?(fs_vfstype) }.keys
48
+ @mounts.select { |_fs_file, fs_vfstype| remote_fs?(fs_vfstype) }.keys
41
49
  end
42
50
 
43
51
  def local
44
- @mounts.select { |fs_file,fs_vfstype| local_fs?(fs_vfstype) }.keys
52
+ @mounts.select { |_fs_file, fs_vfstype| local_fs?(fs_vfstype) }.keys
45
53
  end
46
54
 
47
55
  def all
@@ -56,12 +64,16 @@ class MountPoints
56
64
  # we store the latest entry only, because that's the relevant one
57
65
  mounts = Hash.new
58
66
  proc_mounts.each_line do |line|
59
- fs_spec, fs_file, fs_vfstype, fs_mntops, fs_freq, fs_passno = line.split(' ')
67
+ _fs_spec, fs_file, fs_vfstype, _fs_mntops, _fs_freq, _fs_passno = line.split(" ")
60
68
  mounts[fs_file] = fs_vfstype
61
69
  end
62
70
  mounts
63
71
  end
64
72
 
73
+ def special_fs?(fs)
74
+ SPECIAL_FILE_SYSTEMS.include?(fs)
75
+ end
76
+
65
77
  def remote_fs?(fs)
66
78
  REMOTE_FILE_SYSTEMS.include?(fs)
67
79
  end
data/lib/object.rb CHANGED
@@ -23,7 +23,7 @@ module Machinery
23
23
  @property_classes[name.to_sym] = options[:class]
24
24
  end
25
25
 
26
- def from_json(json)
26
+ def object_hash_from_json(json)
27
27
  return nil unless json
28
28
 
29
29
  entries = json.map do |key, value|
@@ -43,13 +43,21 @@ module Machinery
43
43
  [key, value_converted]
44
44
  end
45
45
 
46
- new(Hash[entries])
46
+ Hash[entries]
47
+ end
48
+
49
+ def from_json(json)
50
+ new(object_hash_from_json(json))
47
51
  end
48
52
  end
49
53
 
50
54
  attr_reader :attributes
51
55
 
52
56
  def initialize(attrs = {})
57
+ set_attributes(attrs)
58
+ end
59
+
60
+ def set_attributes(attrs)
53
61
  @attributes = attrs.inject({}) do |attributes, (key, value)|
54
62
  key = key.to_sym if key.respond_to?(:to_sym)
55
63
 
data/lib/scope_mixin.rb CHANGED
@@ -17,6 +17,24 @@
17
17
 
18
18
  module Machinery
19
19
  module ScopeMixin
20
+ def self.included(mod)
21
+ @scopes ||= []
22
+ @scopes.push(mod)
23
+ end
24
+
25
+ def self.all_scopes
26
+ @scopes
27
+ end
28
+
29
+ def self.class_for(scope_name)
30
+ all_scopes.each do |scope|
31
+ if scope.new.scope_name == scope_name
32
+ return scope
33
+ end
34
+ end
35
+ nil
36
+ end
37
+
20
38
  attr_accessor :meta
21
39
 
22
40
  def set_metadata(timestring, host)
@@ -62,7 +62,7 @@ class SystemDescription < Machinery::Object
62
62
  end
63
63
 
64
64
  begin
65
- description = self.new(name, self.create_attrs(json_hash), store)
65
+ description = self.new(name, create_scopes(json_hash), store)
66
66
  rescue NameError
67
67
  raise Machinery::Errors::SystemDescriptionIncompatible.new(name)
68
68
  end
@@ -73,22 +73,22 @@ class SystemDescription < Machinery::Object
73
73
  description
74
74
  end
75
75
 
76
- def create_attrs(hash)
77
- entries = hash.map do |key, value|
78
- next if key == "meta"
76
+ def create_scopes(hash)
77
+ scopes = hash.map do |scope_name, scope_json|
78
+ next if scope_name == "meta"
79
79
 
80
- class_name = "#{key.split("_").map(&:capitalize).join}Scope"
81
- value_converted = Object.const_get(class_name).from_json(value)
80
+ scope_class = Machinery::ScopeMixin.class_for(scope_name)
81
+ scope_object = scope_class.from_json(scope_json)
82
82
 
83
83
  # Set metadata
84
- if hash["meta"] && hash["meta"][key]
85
- value_converted.meta = Machinery::Object.from_json(hash["meta"][key])
84
+ if hash["meta"] && hash["meta"][scope_name]
85
+ scope_object.meta = Machinery::Object.from_json(hash["meta"][scope_name])
86
86
  end
87
87
 
88
- [key, value_converted]
88
+ [scope_name, scope_object]
89
89
  end.compact
90
90
 
91
- Hash[entries]
91
+ Hash[scopes]
92
92
  end
93
93
 
94
94
  private
@@ -172,16 +172,6 @@ class SystemDescription < Machinery::Object
172
172
  self[scope] && self[scope].is_extractable? && self[scope].extracted
173
173
  end
174
174
 
175
- def os_object
176
- assert_scopes("os")
177
-
178
- begin
179
- Os.for(self.os.name)
180
- rescue Machinery::Errors::UnknownOs => e
181
- raise Machinery::Errors::SystemDescriptionError.new(e)
182
- end
183
- end
184
-
185
175
  def missing_files(scope, file_list)
186
176
  file_list.map! { |file| File.join(file_store(scope), file) }
187
177
 
@@ -49,7 +49,11 @@ class UpgradeFormatTask
49
49
  Machinery::Ui.puts "No system descriptions were upgraded."
50
50
  end
51
51
  else
52
- Machinery::Ui.puts "System description \"#{name}\" successfully upgraded." if migrations_done > 1
52
+ if migrations_done > 0
53
+ Machinery::Ui.puts "System description \"#{name}\" successfully upgraded."
54
+ else
55
+ Machinery::Ui.puts "System description \"#{name}\" is up to date, no upgrade necessary."
56
+ end
53
57
  end
54
58
  end
55
59
  end
data/lib/version.rb CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  module Machinery
19
19
 
20
- VERSION = "1.1.0"
20
+ VERSION = "1.1.1"
21
21
 
22
22
  end
@@ -1,9 +1,10 @@
1
1
  Contains the names and contents of all files which are not part of any RPM
2
2
  package. The list of unmanaged files contains only plain files and
3
3
  directories. Special files like device nodes, named pipes and Unix domain
4
- sockets are ignored. The directories `/tmp`, `/var/tmp`, `/sys`, `/dev`,
5
- `/.snapshots/`, and `/var/run` are ignored, too. If a directory is in this
6
- list, no file or directory below it belongs to a RPM package.
4
+ sockets are ignored. The directories `/tmp`, `/var/tmp`, `/.snapshots/`,
5
+ `/var/run` and special mounts like procfs and sysfs are ignored, too.
6
+ If a directory is in this list, no file or directory below it belongs to a
7
+ RPM package.
7
8
 
8
9
  Meta data information of unmanaged files is only available if the files were
9
10
  extracted during inspection.
@@ -47,8 +47,7 @@ class OsInspector < Inspector
47
47
  os.version += get_additional_version(system)
48
48
  summary = "Found operating system '#{os.name}' version '#{os.version}'."
49
49
  else
50
- os = OsScope.new(name: nil, version: nil, architecture: nil)
51
- summary = "Could not determine the operating system."
50
+ raise Machinery::Errors::UnknownOs
52
51
  end
53
52
 
54
53
  description.os = os
@@ -84,10 +83,9 @@ class OsInspector < Inspector
84
83
  end
85
84
  # return pretty_name as name as it contains the actual full length
86
85
  # name instead of an abbreviation
87
- OsScope.new(
88
- name: result["pretty_name"],
89
- version: result["version"]
90
- )
86
+ os = Os.for(result["pretty_name"])
87
+ os.version = result["version"]
88
+ os
91
89
  end
92
90
 
93
91
  # checks for old suse standard: /etc/SuSE-release
@@ -111,6 +109,8 @@ class OsInspector < Inspector
111
109
  if result["version"] && !patch.nil?
112
110
  result["version"] = "#{result["version"]} SP#{patch}"
113
111
  end
114
- OsScope.new(result)
112
+ os = Os.for(result["name"])
113
+ os.version = result["version"]
114
+ os
115
115
  end
116
116
  end
@@ -154,14 +154,21 @@ class UnmanagedFilesInspector < Inspector
154
154
  # "REPLACEMENT CHARACTER" (U+FFFD). That way we have both the raw data
155
155
  # (which is needed in order to be able to access the files) and the cleaned
156
156
  # string which can be safely used.
157
- out = system.run_command(
158
- "/bin/bash",
159
- {
160
- :stdin => cmd,
161
- :stdout => :capture,
162
- :disable_logging => true
163
- }
164
- ).force_encoding("binary")
157
+ out = ""
158
+ begin
159
+ out = system.run_command(
160
+ "/bin/bash",
161
+ stdin: cmd,
162
+ stdout: :capture,
163
+ disable_logging: true
164
+ ).force_encoding("binary")
165
+ rescue Cheetah::ExecutionFailed => e
166
+ out = e.stdout
167
+ message = "Warning: The command find of the unmanaged-file inspector" \
168
+ " ran into an issue. The error output was:\n#{e.stderr}"
169
+ Machinery.logger.warn(message)
170
+ Machinery::Ui.warn(message)
171
+ end
165
172
 
166
173
 
167
174
  # find creates three field per path
@@ -216,7 +223,7 @@ class UnmanagedFilesInspector < Inspector
216
223
 
217
224
  tmp_file_store = "unmanaged_files.tmp"
218
225
  final_file_store = "unmanaged_files"
219
-
226
+ mount_points = MountPoints.new(system)
220
227
 
221
228
  ignore_list = [
222
229
  "tmp",
@@ -226,7 +233,8 @@ class UnmanagedFilesInspector < Inspector
226
233
  "var/lib/rpm",
227
234
  ".snapshots",
228
235
  description.store.base_path.sub(/^\//, ""),
229
- "proc"
236
+ "proc",
237
+ "boot"
230
238
  ]
231
239
 
232
240
  # Information about users and groups are extracted by the according inspector
@@ -253,29 +261,38 @@ class UnmanagedFilesInspector < Inspector
253
261
 
254
262
  rpm_files, rpm_dirs = extract_rpm_database(system)
255
263
 
256
- mount_points = MountPoints.new(system)
257
264
  mounts = mount_points.local
258
265
  unmanaged_files = []
259
266
  unmanaged_trees = []
260
267
  excluded_files = []
261
268
  unmanaged_links = {}
262
269
  remote_dirs = mount_points.remote
270
+ special_dirs = mount_points.special
263
271
  ignore_list.each do |ignore|
264
272
  remote_dirs.delete_if { |e| e.start_with?(File.join("/", ignore, "/")) }
265
273
  end
266
- dirs_todo = [ "/" ]
267
- start = start_depth
268
- max = max_depth
269
- find_count = 0
270
- sub_tree_containing_remote_fs = []
271
274
  excluded_files += remote_dirs
275
+ excluded_files += special_dirs
272
276
 
273
277
  if !remote_dirs.empty?
274
- warning = "The content of the following remote directories is ignored: #{remote_dirs.uniq.join(", ")}."
278
+ warning = "The content of the following remote directories is ignored:" \
279
+ "#{remote_dirs.uniq.join(", ")}."
280
+ Machinery.logger.warn(warning)
281
+ Machinery::Ui.warn(warning)
282
+ end
283
+ if !special_dirs.empty?
284
+ warning = "The content of the following special directories is ignored:" \
285
+ " #{special_dirs.uniq.join(", ")}."
275
286
  Machinery.logger.warn(warning)
276
287
  Machinery::Ui.warn(warning)
277
288
  end
278
289
 
290
+ dirs_todo = ["/"]
291
+ start = start_depth
292
+ max = max_depth
293
+ find_count = 0
294
+ sub_tree_containing_remote_fs = []
295
+
279
296
  while !dirs_todo.empty?
280
297
  find_dir = dirs_todo.first
281
298
 
@@ -305,6 +322,9 @@ class UnmanagedFilesInspector < Inspector
305
322
  while !unmanaged.empty?
306
323
  dir = unmanaged.shift
307
324
 
325
+ # Ignore special mounts, e.g. procfs mounts in a chroot
326
+ next if special_dirs.include?(find_dir + dir)
327
+
308
328
  # save into list of unmanaged trees
309
329
  if !remote_dirs.include?(find_dir + dir)
310
330
  unmanaged_trees << find_dir + dir
@@ -15,6 +15,117 @@
15
15
  # To contact SUSE about this file by physical or electronic mail,
16
16
  # you may find current contact information at www.suse.com
17
17
 
18
- class OsScope < Machinery::Object
18
+ class Os < Machinery::Object
19
19
  include Machinery::ScopeMixin
20
+
21
+ def self.descendants
22
+ ObjectSpace.each_object(::Class).select { |klass| klass < self }
23
+ end
24
+
25
+ def self.for(os_name)
26
+ descendants.each do |os_class|
27
+ if os_name == os_class.canonical_name
28
+ os = os_class.new
29
+ os.name = os_name
30
+ return os
31
+ end
32
+ end
33
+ OsUnknown.new
34
+ end
35
+
36
+ def self.from_json(json)
37
+ scope_object = self.for(json["name"])
38
+ scope_object.set_attributes(object_hash_from_json(json))
39
+ scope_object
40
+ end
41
+
42
+ def scope_name
43
+ "os"
44
+ end
45
+
46
+ def self.buildable_systems
47
+ []
48
+ end
49
+
50
+ def self.module_dependencies
51
+ {}
52
+ end
53
+
54
+ def self.can_run_machinery?
55
+ true
56
+ end
57
+
58
+ def self.supported_host_systems
59
+ descendants.select { |os| os.can_run_machinery? }
60
+ end
61
+
62
+ def can_run_machinery?
63
+ self.class.can_run_machinery?
64
+ end
65
+
66
+ def can_build?(os)
67
+ self.class.buildable_systems.include?(os.class)
68
+ end
69
+
70
+ def module_required_by_package(package)
71
+ self.class.module_dependencies[package]
72
+ end
73
+
74
+ def canonical_name
75
+ self.class.canonical_name
76
+ end
77
+ end
78
+
79
+ class OsUnknown < Os
80
+ def self.canonical_name
81
+ "Unknown OS"
82
+ end
83
+
84
+ def self.can_run_machinery?
85
+ false
86
+ end
87
+ end
88
+
89
+ class OsSles11 < Os
90
+ def self.canonical_name
91
+ "SUSE Linux Enterprise Server 11"
92
+ end
93
+
94
+ def self.can_run_machinery?
95
+ false
96
+ end
97
+ end
98
+
99
+ class OsSles12 < Os
100
+ def self.canonical_name
101
+ "SUSE Linux Enterprise Server 12"
102
+ end
103
+
104
+ def self.buildable_systems
105
+ [OsSles12]
106
+ end
107
+
108
+ def self.module_dependencies
109
+ { "python-glanceclient" => "Public Cloud Module" }
110
+ end
111
+ end
112
+
113
+ class OsOpenSuse13_1 < Os
114
+ def self.canonical_name
115
+ "openSUSE 13.1 (Bottle)"
116
+ end
117
+
118
+ def self.buildable_systems
119
+ [OsSles11, OsOpenSuse13_1]
120
+ end
121
+ end
122
+
123
+ class OsOpenSuse13_2 < Os
124
+ def self.canonical_name
125
+ "openSUSE 13.2 (Harlequin)"
126
+ end
127
+
128
+ def self.buildable_systems
129
+ [OsSles11, OsOpenSuse13_1, OsOpenSuse13_2]
130
+ end
20
131
  end
@@ -17,6 +17,15 @@
17
17
 
18
18
 
19
19
  class Service < Machinery::Object
20
+ def enabled?
21
+ # systemd vs sysvinit
22
+ state == "enabled" || state == "on"
23
+ end
24
+
25
+ def disabled?
26
+ # systemd vs sysvinit
27
+ state == "disabled" || state == "off"
28
+ end
20
29
  end
21
30
 
22
31
  class ServiceList < Machinery::Array
@@ -54,4 +54,13 @@ end
54
54
  class UnmanagedFilesScope < FileScope
55
55
  include Machinery::ScopeMixin
56
56
  has_property :files, class: UnmanagedFileList
57
+
58
+ def compare_with(other)
59
+ if extracted != other.extracted
60
+ Machinery::Ui.warn("Warning: Comparing extracted with unextracted" \
61
+ " unmanaged files. Only common attributes are considered.")
62
+ end
63
+
64
+ super
65
+ end
57
66
  end
@@ -39,12 +39,14 @@ class ConfigFilesRenderer < Renderer
39
39
  files = @system_description["config_files"].files
40
40
  if files
41
41
  files.each do |p|
42
+ item_content = "#{p.name} (#{p.package_name}-#{p.package_version}, " \
43
+ "#{p.changes.join(", ")})"
42
44
  if @options[:show_diffs] && p.changes.include?("md5")
43
- item "#{p.name} (#{p.changes.join(", ")})" do
45
+ item item_content do
44
46
  render_diff_file(diffs_dir, p.name)
45
47
  end
46
48
  else
47
- item ("#{p.name} (#{p.changes.join(", ")})")
49
+ item item_content
48
50
  end
49
51
  end
50
52
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: machinery-tool
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - SUSE
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-26 00:00:00.000000000 Z
11
+ date: 2014-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cheetah
@@ -202,7 +202,6 @@ files:
202
202
  - lib/logged_cheetah.rb
203
203
  - lib/renderer.rb
204
204
  - lib/remote_system.rb
205
- - lib/kiwi_export_task.rb
206
205
  - lib/kiwi_config.rb
207
206
  - lib/upgrade_format_task.rb
208
207
  - lib/tarball.rb
@@ -211,7 +210,6 @@ files:
211
210
  - lib/renderer_helper.rb
212
211
  - lib/analyze_config_file_diffs_task.rb
213
212
  - lib/config.rb
214
- - lib/os.rb
215
213
  - lib/version.rb
216
214
  - lib/system.rb
217
215
  - lib/object.rb
@@ -219,6 +217,7 @@ files:
219
217
  - lib/config_task.rb
220
218
  - lib/remove_task.rb
221
219
  - lib/system_description.rb
220
+ - lib/autoyast.rb
222
221
  - lib/zypper.rb
223
222
  - lib/constants.rb
224
223
  - lib/mountpoints.rb
@@ -226,6 +225,7 @@ files:
226
225
  - lib/rpm.rb
227
226
  - lib/array.rb
228
227
  - lib/changed_rpm_files_helper.rb
228
+ - lib/export_task.rb
229
229
  - lib/copy_task.rb
230
230
  - lib/build_task.rb
231
231
  - lib/local_system.rb
data/lib/os.rb DELETED
@@ -1,90 +0,0 @@
1
- # Copyright (c) 2013-2014 SUSE LLC
2
- #
3
- # This program is free software; you can redistribute it and/or
4
- # modify it under the terms of version 3 of the GNU General Public License as
5
- # published by the Free Software Foundation.
6
- #
7
- # This program is distributed in the hope that it will be useful,
8
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
- # GNU General Public License for more details.
11
- #
12
- # You should have received a copy of the GNU General Public License
13
- # along with this program; if not, contact SUSE LLC.
14
- #
15
- # To contact SUSE about this file by physical or electronic mail,
16
- # you may find current contact information at www.suse.com
17
-
18
- class Os
19
- attr_reader :can_build, :name
20
-
21
- def self.descendants
22
- ObjectSpace.each_object(::Class).select { |klass| klass < self }
23
- end
24
-
25
- def self.for(os_name)
26
- descendants.each do |os_class|
27
- os_object = os_class.new
28
- if os_name == os_object.name
29
- return os_object
30
- end
31
- end
32
- raise Machinery::Errors::UnknownOs.new("Unknown OS: '#{os_name}'")
33
- end
34
-
35
- def self.supported_host_systems
36
- descendants.select { |os| os.new.can_run_machinery? }
37
- end
38
-
39
- def can_build?(os)
40
- if os.is_a?(Class)
41
- return @can_build.include?(os)
42
- else
43
- return @can_build.include?(os.class)
44
- end
45
- end
46
-
47
- def module_required_by_package(package)
48
- if @module_required_by_package
49
- return @module_required_by_package[package]
50
- end
51
- end
52
-
53
- def can_run_machinery?
54
- @can_run_machinery
55
- end
56
- end
57
-
58
- class OsSles11 < Os
59
- def initialize
60
- @can_build = []
61
- @name = "SUSE Linux Enterprise Server 11"
62
- end
63
- end
64
-
65
- class OsSles12 < Os
66
- def initialize
67
- @can_build = [OsSles12]
68
- @name = "SUSE Linux Enterprise Server 12"
69
- @module_required_by_package = {
70
- "python-glanceclient" => "Public Cloud Module"
71
- }
72
- @can_run_machinery = true
73
- end
74
- end
75
-
76
- class OsOpenSuse13_1 < Os
77
- def initialize
78
- @can_build = [OsSles11, OsOpenSuse13_1]
79
- @name = "openSUSE 13.1 (Bottle)"
80
- @can_run_machinery = true
81
- end
82
- end
83
-
84
- class OsOpenSuse13_2 < Os
85
- def initialize
86
- @can_build = [OsSles11, OsOpenSuse13_1, OsOpenSuse13_2]
87
- @name = "openSUSE 13.2 (Harlequin)"
88
- @can_run_machinery = true
89
- end
90
- end