machinery-tool 1.1.0 → 1.1.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.
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