machinery-tool 1.22.1 → 1.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/.git_revision +1 -1
  3. data/NEWS +10 -0
  4. data/bin/machinery +1 -1
  5. data/lib/analyze_changed_config_files_diffs_task.rb +6 -6
  6. data/lib/autoyast.rb +2 -2
  7. data/lib/build_task.rb +10 -7
  8. data/lib/cli.rb +1005 -801
  9. data/lib/compare_task.rb +11 -7
  10. data/lib/comparison.rb +2 -2
  11. data/lib/config_base.rb +1 -1
  12. data/lib/config_task.rb +1 -1
  13. data/lib/containerize_task.rb +3 -3
  14. data/lib/containerized_app.rb +1 -1
  15. data/lib/copy_task.rb +1 -1
  16. data/lib/current_user.rb +1 -1
  17. data/lib/deploy_task.rb +6 -4
  18. data/lib/diff_widget.rb +67 -63
  19. data/lib/docker_system.rb +12 -8
  20. data/lib/dpkg_database.rb +1 -1
  21. data/lib/element_filter.rb +7 -4
  22. data/lib/exceptions.rb +23 -5
  23. data/lib/export_task.rb +1 -1
  24. data/lib/exporter.rb +1 -1
  25. data/lib/file_diff.rb +1 -1
  26. data/lib/file_scope.rb +1 -1
  27. data/lib/file_validator.rb +7 -4
  28. data/lib/filter.rb +97 -93
  29. data/lib/filter_option_parser.rb +2 -2
  30. data/lib/hint.rb +64 -59
  31. data/lib/html.rb +1 -1
  32. data/lib/inspect_task.rb +12 -12
  33. data/lib/inspector.rb +3 -3
  34. data/lib/json_validation_error_cleaner.rb +1 -1
  35. data/lib/json_validator.rb +4 -4
  36. data/lib/kiwi_config.rb +8 -4
  37. data/lib/list_task.rb +10 -9
  38. data/lib/local_system.rb +11 -5
  39. data/lib/logged_cheetah.rb +1 -1
  40. data/lib/man_task.rb +10 -6
  41. data/lib/managed_files_database.rb +1 -1
  42. data/lib/manifest.rb +5 -5
  43. data/lib/migration.rb +16 -10
  44. data/lib/mountpoints.rb +1 -1
  45. data/lib/move_task.rb +1 -1
  46. data/lib/remote_system.rb +7 -7
  47. data/lib/remove_task.rb +1 -1
  48. data/lib/renderer.rb +177 -172
  49. data/lib/rpm.rb +4 -4
  50. data/lib/rpm_database.rb +1 -1
  51. data/lib/scope.rb +2 -2
  52. data/lib/scope_file_access_archive.rb +1 -1
  53. data/lib/scope_file_access_flat.rb +1 -1
  54. data/lib/scope_file_store.rb +1 -1
  55. data/lib/serve_html_task.rb +6 -2
  56. data/lib/server.rb +19 -12
  57. data/lib/show_task.rb +10 -6
  58. data/lib/static_html.rb +1 -1
  59. data/lib/system.rb +10 -10
  60. data/lib/system_description.rb +14 -13
  61. data/lib/system_description_memory_store.rb +1 -1
  62. data/lib/system_description_store.rb +9 -9
  63. data/lib/tarball.rb +8 -2
  64. data/lib/upgrade_format_task.rb +11 -6
  65. data/lib/validate_task.rb +2 -2
  66. data/lib/version.rb +1 -1
  67. data/lib/workload_mapper.rb +2 -2
  68. data/lib/workload_mapper_dsl.rb +1 -1
  69. data/lib/zypper.rb +40 -17
  70. data/machinery-helper/machinery_helper.go +35 -16
  71. data/machinery-helper/version.go +1 -1
  72. data/man/generated/machinery.1.gz +0 -0
  73. data/manual/site/sitemap.xml +24 -24
  74. data/plugins/changed_config_files/changed_config_files_inspector.rb +59 -56
  75. data/plugins/changed_config_files/changed_config_files_model.rb +23 -21
  76. data/plugins/changed_config_files/changed_config_files_renderer.rb +56 -52
  77. data/plugins/changed_managed_files/changed_managed_files_inspector.rb +52 -50
  78. data/plugins/changed_managed_files/changed_managed_files_model.rb +23 -21
  79. data/plugins/changed_managed_files/changed_managed_files_renderer.rb +43 -39
  80. data/plugins/environment/environment_inspector.rb +25 -23
  81. data/plugins/environment/environment_model.rb +5 -3
  82. data/plugins/groups/groups_inspector.rb +30 -28
  83. data/plugins/groups/groups_model.rb +18 -17
  84. data/plugins/groups/groups_renderer.rb +29 -25
  85. data/plugins/os/os_inspector.rb +120 -118
  86. data/plugins/os/os_model.rb +139 -134
  87. data/plugins/os/os_renderer.rb +13 -9
  88. data/plugins/packages/packages_inspector.rb +99 -86
  89. data/plugins/packages/packages_model.rb +35 -34
  90. data/plugins/packages/packages_renderer.rb +47 -39
  91. data/plugins/patterns/patterns_inspector.rb +70 -68
  92. data/plugins/patterns/patterns_model.rb +19 -18
  93. data/plugins/patterns/patterns_renderer.rb +36 -32
  94. data/plugins/repositories/repositories_inspector.rb +162 -156
  95. data/plugins/repositories/repositories_model.rb +50 -49
  96. data/plugins/repositories/repositories_renderer.rb +48 -44
  97. data/plugins/repositories/schema/system-description-repositories.schema-v10.json +0 -1
  98. data/plugins/services/services_inspector.rb +187 -176
  99. data/plugins/services/services_model.rb +37 -36
  100. data/plugins/services/services_renderer.rb +28 -24
  101. data/plugins/unmanaged_files/unmanaged_files_inspector.rb +102 -99
  102. data/plugins/unmanaged_files/unmanaged_files_model.rb +64 -56
  103. data/plugins/unmanaged_files/unmanaged_files_renderer.rb +44 -40
  104. data/plugins/users/users_inspector.rb +67 -65
  105. data/plugins/users/users_model.rb +37 -36
  106. data/plugins/users/users_renderer.rb +31 -27
  107. data/schema/migrations/migrate1to2.rb +1 -1
  108. data/schema/migrations/migrate2to3.rb +1 -1
  109. data/schema/migrations/migrate3to4.rb +1 -1
  110. data/schema/migrations/migrate4to5.rb +1 -1
  111. data/schema/migrations/migrate5to6.rb +1 -1
  112. data/schema/migrations/migrate6to7.rb +1 -1
  113. data/schema/migrations/migrate7to8.rb +1 -1
  114. data/schema/migrations/migrate8to9.rb +1 -1
  115. data/schema/migrations/migrate9to10.rb +1 -1
  116. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dacdd7ed294b3fa071ce5c205cff0c9bc4888c33
4
- data.tar.gz: e5679c290377bd246cbde4d82c3bab5ad64c2ef7
3
+ metadata.gz: da0041ff3a8d3c178063228340914aca550a308f
4
+ data.tar.gz: e333966071f57a102961d8de5eb57f47d0cea5a2
5
5
  SHA512:
6
- metadata.gz: b66684bde79b39bb03551a8249a600b1c9c1811df5582ae4d48559c240a4dfc46a975e6bbb8425747216a576599297cb43b2419385cb15be5d36c5dd94569572
7
- data.tar.gz: aba642cb4e81b629a4cf1aa6a0090c97507b2995ba36097387eaed96a0a7f7f107ce976f3af602655b042f4c557ba4d2425655557ce884614d29df4133d3e86b
6
+ metadata.gz: 99fa10a1ff34c692d35638a5aaef0b411456e3f183ee822b4d803a1366b65ad7cc52b1be636e6df78ce4914bfbca17201efa7954f09efe0ab1f13dfbcff1a846
7
+ data.tar.gz: f612d4f45396600d41b6b579077bd85bce57768386b109a2bf549f25c8818e9ec48c8d8138ac1dec35ecfd31027464e4179ac0319129d7e74c43e622c674680f
data/.git_revision CHANGED
@@ -1 +1 @@
1
- c9cc765d7146920c59d05dd9e483a82eb5f836df
1
+ 5544d3469a45c0bf15d3263bc1bbbd32afb7f274
data/NEWS CHANGED
@@ -1,6 +1,16 @@
1
1
  # Machinery Release Notes
2
2
 
3
3
 
4
+ ## Version 1.22.2 - Wed Nov 16 16:44:00 CET 2016 - thardeck@suse.de
5
+
6
+ * Prevent machinery-helper from crashing when files are inaccessible during
7
+ inspection (bnc#1009774)
8
+ * Fix analyze of changed-config-files when NFS or SMB repositories are
9
+ used (gh#SUSE/machinery#2132)
10
+ * Do not add repositories which require registration to built images (bnc#1004697)
11
+ * Fix package inspection on older Debian systems
12
+ * Fix extraction of information for Debian packages containing a dash in their name
13
+
4
14
  ## Version 1.22.1 - Fri Oct 14 16:13:50 CEST 2016 - thardeck@suse.de
5
15
 
6
16
  * Only use sudo for reading files when necessary (gh#SUSE/machinery#2077)
data/bin/machinery CHANGED
@@ -38,7 +38,7 @@ begin
38
38
  command_log = "Executing (Version #{Machinery::VERSION}) '#{$PROGRAM_NAME} #{ARGV.join(" ")}'"
39
39
  command_log += " (store: #{ENV["MACHINERY_DIR"]})" if ENV["MACHINERY_DIR"]
40
40
  Machinery.logger.info command_log
41
- Cli.run(ARGV)
41
+ Machinery::Cli.run(ARGV)
42
42
  rescue Machinery::Errors::IncompatibleHost => e
43
43
  puts e
44
44
  end
@@ -15,11 +15,11 @@
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 AnalyzeConfigFileDiffsTask
18
+ class Machinery::AnalyzeConfigFileDiffsTask
19
19
  def analyze(description)
20
20
  description.assert_scopes("os")
21
21
  check_os(description)
22
- LocalSystem.validate_existence_of_packages(["zypper"])
22
+ Machinery::LocalSystem.validate_existence_of_packages(["zypper"])
23
23
  description.validate_analysis_compatibility
24
24
  description.assert_scopes(
25
25
  "repositories",
@@ -55,7 +55,7 @@ class AnalyzeConfigFileDiffsTask
55
55
  end
56
56
 
57
57
  package.files.each do |file|
58
- diff = Rpm.new(path).diff(file, File.join(extracted_files_path, file))
58
+ diff = Machinery::Rpm.new(path).diff(file, File.join(extracted_files_path, file))
59
59
 
60
60
  if !diff || diff.empty?
61
61
  Machinery::Ui.warn "Warning: Could not generate diff for #{file}."
@@ -76,7 +76,7 @@ class AnalyzeConfigFileDiffsTask
76
76
  private
77
77
 
78
78
  def check_os(description)
79
- unless description.os.is_a?(OsSuse)
79
+ unless description.os.is_a?(Machinery::OsSuse)
80
80
  raise Machinery::Errors::AnalysisFailed.new(
81
81
  "Can not analyze the system description because its operating system" \
82
82
  " '#{description.os.display_name}' is not supported."
@@ -100,7 +100,7 @@ class AnalyzeConfigFileDiffsTask
100
100
 
101
101
  files.inject({}) do |result, file|
102
102
  key = "#{file.package_name}-#{file.package_version}"
103
- result[key] ||= Package.new(
103
+ result[key] ||= Machinery::Package.new(
104
104
  "name" => file["package_name"],
105
105
  "version" => file["package_version"],
106
106
  "files" => []
@@ -114,7 +114,7 @@ class AnalyzeConfigFileDiffsTask
114
114
  def with_repositories(description, &block)
115
115
  Machinery::Ui.puts "Setting up repository access..."
116
116
  arch = description.os.architecture
117
- Zypper.isolated(arch: arch) do |zypper|
117
+ Machinery::Zypper.isolated(arch: arch) do |zypper|
118
118
  begin
119
119
  remote_repos = description.repositories.reject do |repo|
120
120
  repo.url.start_with?("cd://") || repo.url.start_with?("dvd://")
data/lib/autoyast.rb CHANGED
@@ -15,7 +15,7 @@
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 Autoyast < Exporter
18
+ class Machinery::Autoyast < Machinery::Exporter
19
19
  attr_accessor :name
20
20
 
21
21
  def initialize(description)
@@ -110,7 +110,7 @@ class Autoyast < Exporter
110
110
  private
111
111
 
112
112
  def check_exported_os
113
- unless @system_description.os.is_a?(OsSuse)
113
+ unless @system_description.os.is_a?(Machinery::OsSuse)
114
114
  raise Machinery::Errors::ExportFailed.new(
115
115
  "Export is not possible because the operating system " \
116
116
  "'#{@system_description.os.display_name}' is not supported."
data/lib/build_task.rb CHANGED
@@ -15,23 +15,26 @@
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 BuildTask
18
+ class Machinery::BuildTask
19
19
  def build(system_description, output_path, options = {})
20
- LocalSystem.validate_architecture("x86_64")
21
- LocalSystem.validate_existence_of_packages(["kiwi", "kiwi-desc-vmxboot"])
20
+ Machinery::LocalSystem.validate_architecture("x86_64")
21
+ Machinery::LocalSystem.validate_existence_of_packages(["kiwi", "kiwi-desc-vmxboot"])
22
22
  system_description.validate_build_compatibility
23
23
 
24
24
  tmp_config_dir = Dir.mktmpdir("machinery-config", "/tmp")
25
25
  tmp_image_dir = Dir.mktmpdir("machinery-image", "/tmp")
26
26
  img_extension = "qcow2"
27
27
 
28
- config = KiwiConfig.new(system_description, options)
28
+ config = Machinery::KiwiConfig.new(system_description, options)
29
29
  config.write(tmp_config_dir)
30
30
 
31
31
  begin
32
32
  FileUtils.mkdir_p(output_path)
33
33
  rescue Errno::EACCES
34
- raise Machinery::Errors::BuildDirectoryCreateError.new(output_path, CurrentUser.new.username)
34
+ raise Machinery::Errors::BuildDirectoryCreateError.new(
35
+ output_path,
36
+ Machinery::CurrentUser.new.username
37
+ )
35
38
  end
36
39
 
37
40
  if tmp_image_dir.start_with?("/tmp/") && tmp_config_dir.start_with?("/tmp/")
@@ -40,7 +43,7 @@ class BuildTask
40
43
 
41
44
  begin
42
45
  with_c_locale do
43
- LoggedCheetah.run(
46
+ Machinery::LoggedCheetah.run(
44
47
  "sudo",
45
48
  tmp_script.path,
46
49
  stdout: $stdout,
@@ -68,7 +71,7 @@ class BuildTask
68
71
 
69
72
  Machinery::Ui.warn "Cleaning up temporary files..."
70
73
  [tmp_config_dir, tmp_image_dir].each do |path|
71
- LoggedCheetah.run("sudo", "rm", "-r", path) if Dir.exist?(path)
74
+ Machinery::LoggedCheetah.run("sudo", "rm", "-r", path) if Dir.exist?(path)
72
75
  end
73
76
  end
74
77
  raise
data/lib/cli.rb CHANGED
@@ -15,672 +15,756 @@
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 Cli
19
- extend GLI::App
18
+ module Machinery
19
+ class Cli
20
+ extend GLI::App
21
+
22
+ program_desc "A systems management toolkit for Linux"
23
+ preserve_argv(true)
24
+ @version = "#{Machinery::VERSION} (system description format version "\
25
+ "#{SystemDescription::CURRENT_FORMAT_VERSION})"
26
+ @config = Machinery::Config.new
27
+ switch :version, negatable: false, desc: "Show version"
28
+ switch :debug, negatable: false, desc: "Enable debug mode"
29
+ switch [:help, :h], negatable: false, desc: "Show help"
30
+
31
+ sort_help :manually
32
+ pre do |global_options, command, _options, args|
33
+ Machinery.logger.level = if global_options[:debug]
34
+ Logger::DEBUG
35
+ else
36
+ Logger::INFO
37
+ end
20
38
 
21
- program_desc 'A systems management toolkit for Linux'
22
- preserve_argv(true)
23
- @version = Machinery::VERSION + " (system description format version " +
24
- "#{SystemDescription::CURRENT_FORMAT_VERSION})"
25
- @config = Machinery::Config.new
26
- switch :version, negatable: false, desc: "Show version"
27
- switch :debug, negatable: false, desc: "Enable debug mode"
28
- switch [:help, :h], negatable: false, desc: "Show help"
39
+ validate_command_line(command.arguments, args)
29
40
 
30
- sort_help :manually
31
- pre do |global_options,command,options,args|
32
- if global_options[:debug]
33
- Machinery.logger.level = Logger::DEBUG
34
- else
35
- Machinery.logger.level = Logger::INFO
41
+ true
36
42
  end
37
43
 
38
- validate_command_line(command.arguments, args)
44
+ post do |global_options, command, _options, _args|
45
+ if (command.is_a?(GLI::Commands::Help) &&
46
+ !global_options[:version]) || ARGV == ["help"]
39
47
 
40
- true
41
- end
48
+ Machinery::Ui.puts "\nFor more detailed information, open the "\
49
+ "documentation by typing 'machinery man --html'.\nIf you are unable "\
50
+ "to find a solution within the man page visit our wiki page\nat "\
51
+ "https://github.com/SUSE/machinery/wiki"
42
52
 
43
- post do |global_options,command,options,args|
44
- if (command.is_a?(GLI::Commands::Help) && !global_options[:version]) || ARGV == ["help"]
45
-
46
- Machinery::Ui.puts "\nFor more detailed information, open the documentation by typing " \
47
- "'machinery man --html'.\nIf you are unable to find a solution within the man page " \
48
- "visit our wiki page\nat https://github.com/SUSE/machinery/wiki"
53
+ Machinery::Ui.puts "\nMachinery can show hints which guide through a "\
54
+ "typical workflow."
55
+ if @config.hints
56
+ Machinery::Ui.puts "These hints can be switched off by " \
57
+ "'#{Ui::Hint.program_name} config hints=off'."
58
+ else
59
+ Machinery::Ui.puts "These hints can be switched on by " \
60
+ "'#{Ui::Hint.program_name} config hints=on'."
61
+ end
49
62
 
50
- Machinery::Ui.puts "\nMachinery can show hints which guide through a typical workflow."
51
- if @config.hints
52
- Machinery::Ui.puts "These hints can be switched off by " \
53
- "'#{Hint.program_name} config hints=off'."
54
- else
55
- Machinery::Ui.puts "These hints can be switched on by " \
56
- "'#{Hint.program_name} config hints=on'."
63
+ Ui::Hint.print(:get_started)
57
64
  end
58
-
59
- Hint.print(:get_started)
60
- end
61
- Machinery::Ui.close_pager
62
- end
63
-
64
- GLI::Commands::Help.skips_post = false
65
-
66
- def self.validate_command_line(defined, parsed)
67
- if defined.any?(&:multiple?) && !defined.any?(&:optional?) && parsed.empty?
68
- message = "No arguments given. Nothing to do."
69
- raise GLI::BadCommandLine.new(message)
70
- elsif !defined.any?(&:multiple?) && parsed.size > defined.size
71
- parsed_arguments = "#{parsed.size} #{Machinery.pluralize(parsed.size, "argument")}"
72
- defined_arguments = defined.empty? ? "none" : "only: #{defined.map(&:name).join(", ")}"
73
- message = "Too many arguments: got #{parsed_arguments}, expected #{defined_arguments}"
74
- raise GLI::BadCommandLine.new(message)
65
+ Machinery::Ui.close_pager
75
66
  end
76
- end
77
67
 
78
- def self.handle_error(e)
79
- Machinery::Ui.kill_pager
80
-
81
- case e
82
- when GLI::MissingRequiredArgumentsException
83
- Machinery::Ui.error("Option --" + e.message)
84
- exit 1
85
- when GLI::UnknownCommandArgument, GLI::UnknownGlobalArgument,
86
- GLI::UnknownCommand, GLI::BadCommandLine,
87
- OptionParser::MissingArgument, OptionParser::AmbiguousOption
88
- Machinery::Ui.error e.to_s + "\n\n"
89
- command = ARGV & @commands.keys.map(&:to_s)
90
- Machinery::Ui.error "Run '#{Hint.program_name} #{command.first} --help' for more information."
91
- exit 1
92
- when Machinery::Errors::MachineryError
93
- Machinery.logger.error(e.message)
94
- Machinery::Ui.error e.message
95
- exit 1
96
- when SystemExit
97
- raise
98
- when SignalException
99
- Machinery.logger.info "Machinery was aborted with signal #{e.signo}."
100
- exit 1
101
- when Errno::ENOSPC
102
- Machinery::Ui.error("Error: " + e.message)
103
- exit 1
104
- else
105
- if LocalSystem.os.canonical_name.include? ("SUSE Linux Enterprise")
106
- Machinery::Ui.error "Machinery experienced an unexpected error.\n" \
107
- "If this impacts your business please file a service request at " \
108
- "https://www.suse.com/mysupport\n" \
109
- "so that we can assist you on this issue. An active support contract is required.\n"
110
- else
111
- Machinery::Ui.error "Machinery experienced an unexpected error. Please file a " \
112
- "bug report at: https://github.com/SUSE/machinery/issues/new\n"
113
- end
114
-
115
- if e.is_a?(Cheetah::ExecutionFailed)
116
- result = ""
117
- result << "#{e.message}\n"
118
- result << "\n"
119
-
120
- if e.stderr && !e.stderr.empty?
121
- result << "Error output:\n"
122
- result << "#{e.stderr}\n"
68
+ GLI::Commands::Help.skips_post = false
69
+
70
+ def self.validate_command_line(defined, parsed)
71
+ if defined.any?(&:multiple?) &&
72
+ !defined.any?(&:optional?) &&
73
+ parsed.empty?
74
+ message = "No arguments given. Nothing to do."
75
+ raise GLI::BadCommandLine.new(message)
76
+ elsif !defined.any?(&:multiple?) && parsed.size > defined.size
77
+ parsed_arguments = "#{parsed.size} "\
78
+ "#{Machinery.pluralize(parsed.size, "argument")}"
79
+ defined_arguments = if defined.empty?
80
+ "none"
81
+ else
82
+ "only: #{defined.map(&:name).join(", ")}"
123
83
  end
84
+ message = "Too many arguments: got #{parsed_arguments}, "\
85
+ "expected #{defined_arguments}"
86
+ raise GLI::BadCommandLine.new(message)
87
+ end
88
+ end
124
89
 
125
- if e.stdout && !e.stdout.empty?
126
- result << "Standard output:\n"
127
- result << "#{e.stdout}\n\n"
128
- end
90
+ def self.handle_error(e)
91
+ Machinery::Ui.kill_pager
129
92
 
130
- if e.backtrace && !e.backtrace.empty?
131
- result << "Backtrace:\n"
132
- result << "#{e.backtrace.join("\n")}\n\n"
133
- end
134
- Machinery.logger.error(result)
135
- Machinery::Ui.error result
93
+ case e
94
+ when GLI::MissingRequiredArgumentsException
95
+ Machinery::Ui.error("Option --" + e.message)
136
96
  exit 1
137
- else
138
- Machinery.logger.error("Machinery experienced an unexpected error:")
97
+ when GLI::UnknownCommandArgument, GLI::UnknownGlobalArgument,
98
+ GLI::UnknownCommand, GLI::BadCommandLine,
99
+ OptionParser::MissingArgument, OptionParser::AmbiguousOption
100
+ Machinery::Ui.error e.to_s + "\n\n"
101
+ command = ARGV & @commands.keys.map(&:to_s)
102
+ Machinery::Ui.error "Run '#{Ui::Hint.program_name} #{command.first} "\
103
+ "--help' for more information."
104
+ exit 1
105
+ when Machinery::Errors::MachineryError
139
106
  Machinery.logger.error(e.message)
140
- Machinery.logger.error(e.backtrace.join("\n"))
107
+ Machinery::Ui.error e.message
108
+ exit 1
109
+ when SystemExit
141
110
  raise
111
+ when SignalException
112
+ Machinery.logger.info "Machinery was aborted with signal #{e.signo}."
113
+ exit 1
114
+ when Errno::ENOSPC
115
+ Machinery::Ui.error("Error: " + e.message)
116
+ exit 1
117
+ else
118
+ if LocalSystem.os.canonical_name.include? "SUSE Linux Enterprise"
119
+ Machinery::Ui.error "Machinery experienced an unexpected error.\n" \
120
+ "If this impacts your business please file a service request at " \
121
+ "https://www.suse.com/mysupport\n" \
122
+ "so that we can assist you on this issue. An active support "\
123
+ "contract is required.\n"
124
+ else
125
+ Machinery::Ui.error "Machinery experienced an unexpected error. "\
126
+ "Please file a bug report at: "\
127
+ "https://github.com/SUSE/machinery/issues/new\n"
128
+ end
129
+
130
+ if e.is_a?(Cheetah::ExecutionFailed)
131
+ result = ""
132
+ result << "#{e.message}\n"
133
+ result << "\n"
134
+
135
+ if e.stderr && !e.stderr.empty?
136
+ result << "Error output:\n"
137
+ result << "#{e.stderr}\n"
138
+ end
139
+
140
+ if e.stdout && !e.stdout.empty?
141
+ result << "Standard output:\n"
142
+ result << "#{e.stdout}\n\n"
143
+ end
144
+
145
+ if e.backtrace && !e.backtrace.empty?
146
+ result << "Backtrace:\n"
147
+ result << "#{e.backtrace.join("\n")}\n\n"
148
+ end
149
+ Machinery.logger.error(result)
150
+ Machinery::Ui.error result
151
+ exit 1
152
+ else
153
+ Machinery.logger.error("Machinery experienced an unexpected error:")
154
+ Machinery.logger.error(e.message)
155
+ Machinery.logger.error(e.backtrace.join("\n"))
156
+ raise
157
+ end
142
158
  end
159
+ true
143
160
  end
144
- true
145
- end
146
161
 
147
- def self.check_container_name!(image, name)
148
- if image == name && !SystemDescription.valid_name?(name)
149
- raise Machinery::Errors::InvalidCommandLine.new(
150
- "Error: System description name '#{name}' is invalid. By default Machinery" \
151
- " uses the image name as description name if the parameter `--name` is not" \
152
- " provided.\nIf the image name contains a slash the `--name=NAME` parameter" \
153
- " is mandatory. Valid characters are 'a-zA-Z0-9_:.-'.\n\nFor example run:\n" \
154
- "#{Hint.program_name} #{ARGV.join(" ")} --name='#{image.tr("/", "_")}'"
155
- )
162
+ def self.check_container_name!(image, name)
163
+ if image == name && !SystemDescription.valid_name?(name)
164
+ raise Machinery::Errors::InvalidCommandLine,
165
+ "Error: System description name '#{name}' is invalid. By default "\
166
+ "Machinery uses the image name as description name if the "\
167
+ "parameter `--name` is not provided.\nIf the image name contains "\
168
+ "a slash the `--name=NAME` parameter is mandatory. "\
169
+ "Valid characters are 'a-zA-Z0-9_:.-'.\n\nFor example run:\n" \
170
+ "#{Ui::Hint.program_name} #{ARGV.join(" ")} "\
171
+ "--name='#{image.tr("/", "_")}'"
172
+ end
156
173
  end
157
- end
158
174
 
159
- on_error do |e|
160
- Cli.handle_error(e)
161
- end
175
+ on_error do |e|
176
+ Cli.handle_error(e)
177
+ end
162
178
 
163
- def self.show_filter_note(scopes, filter)
164
- if scopes.any? { |scope| !filter.element_filters_for_scope(scope).empty? }
165
- Machinery::Ui.puts "\nNote: There are filters being applied during inspection. " \
166
- "(Use `--verbose` option to show the filters)\n\n"
179
+ def self.show_filter_note(scopes, filter)
180
+ if scopes.any? { |scope| !filter.element_filters_for_scope(scope).empty? }
181
+ Machinery::Ui.puts "\nNote: There are filters being applied during "\
182
+ "inspection. (Use `--verbose` option to show the filters)\n\n"
183
+ end
167
184
  end
168
- end
169
185
 
170
- def self.shift_arg(args, name)
171
- unless res = args.shift
172
- raise GLI::BadCommandLine.new("You need to provide the required argument #{name}.")
186
+ def self.shift_arg(args, name)
187
+ unless res = args.shift
188
+ raise GLI::BadCommandLine,
189
+ "You need to provide the required argument #{name}."
190
+ end
191
+ res
173
192
  end
174
- res
175
- end
176
193
 
177
- def self.process_scope_option(scopes, exclude_scopes)
178
- if scopes
179
- if exclude_scopes
194
+ def self.process_scope_option(scopes, exclude_scopes)
195
+ if scopes && exclude_scopes
180
196
  # scope and ignore-scope
181
- raise Machinery::Errors::InvalidCommandLine.new("You cannot provide the --scope and " \
182
- "--ignore-scope option at the same time.")
183
- else
197
+ raise Machinery::Errors::InvalidCommandLine,
198
+ "You cannot provide the --scope and "\
199
+ "--ignore-scope option at the same time."
200
+ elsif scopes && !exclude_scopes
184
201
  # scope only
185
202
  scope_list = parse_scopes(scopes)
186
- end
187
- else
188
- if exclude_scopes
203
+ elsif !scopes && exclude_scopes
189
204
  # ignore-scope only
190
205
  scope_list = Inspector.all_scopes - parse_scopes(exclude_scopes)
191
- else
206
+ elsif !scopes && !exclude_scopes
192
207
  # neither scope nor ignore-scope
193
208
  scope_list = Inspector.all_scopes
194
209
  end
210
+ if scope_list.empty?
211
+ raise Machinery::Errors::InvalidCommandLine,
212
+ "No scopes to process. Nothing to do."
213
+ end
214
+ scope_list
195
215
  end
196
- if scope_list.empty?
197
- raise Machinery::Errors::InvalidCommandLine.new( "No scopes to process. Nothing to do.")
198
- end
199
- scope_list
200
- end
201
216
 
202
- def self.parse_scopes(scope_string)
203
- unknown_scopes = []
204
- invalid_scopes = []
205
- scopes = []
217
+ def self.parse_scopes(scope_string)
218
+ unknown_scopes = []
219
+ invalid_scopes = []
220
+ scopes = []
221
+
222
+ scope_string.split(",").each do |scope|
223
+ unless scope =~ /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/
224
+ invalid_scopes << scope
225
+ next
226
+ end
227
+
228
+ if scope == "config-files"
229
+ Machinery::Ui.warn(
230
+ "The scope name `config-files` is deprecated. "\
231
+ "The new name is `changed-config-files`."
232
+ )
233
+ scope = "changed-config-files"
234
+ end
235
+
236
+ # convert cli scope naming to internal one
237
+ scope.tr!("-", "_")
206
238
 
207
- scope_string.split(",").each do |scope|
208
- unless scope =~ /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/
209
- invalid_scopes << scope
210
- next
239
+ if Inspector.all_scopes.include?(scope) && Ui::Renderer.for(scope)
240
+ scopes << scope
241
+ else
242
+ unknown_scopes << scope
243
+ end
211
244
  end
212
245
 
213
- if scope == "config-files"
214
- Machinery::Ui.warn(
215
- "The scope name `config-files` is deprecated. The new name is `changed-config-files`."
246
+ unless invalid_scopes.empty?
247
+ form = invalid_scopes.length > 1 ? "scopes are" : "scope is"
248
+ raise Machinery::Errors::UnknownScope.new(
249
+ "The following #{form} not valid:" \
250
+ " '#{invalid_scopes.join("', '")}'." \
251
+ " Scope names must start with a letter and contain only lowercase" \
252
+ " letters and digits separated by dashes ('-')."
216
253
  )
217
- scope = "changed-config-files"
218
254
  end
219
255
 
220
- # convert cli scope naming to internal one
221
- scope.tr!("-", "_")
222
-
223
- if Inspector.all_scopes.include?(scope) && Renderer.for(scope)
224
- scopes << scope
225
- else
226
- unknown_scopes << scope
256
+ unless unknown_scopes.empty?
257
+ form = unknown_scopes.length > 1 ? "scopes are" : "scope is"
258
+ raise Machinery::Errors::UnknownScope.new(
259
+ "The following #{form} not supported: " \
260
+ "#{Machinery::Ui.internal_scope_list_to_string(unknown_scopes)}. " \
261
+ "Valid scopes are: #{AVAILABLE_SCOPE_LIST}."
262
+ )
227
263
  end
264
+
265
+ Inspector.sort_scopes(scopes.uniq)
228
266
  end
229
267
 
230
- if invalid_scopes.length > 0
231
- form = invalid_scopes.length > 1 ? "scopes are" : "scope is"
232
- raise Machinery::Errors::UnknownScope.new(
233
- "The following #{form} not valid:" \
234
- " '#{invalid_scopes.join("', '")}'." \
235
- " Scope names must start with a letter and contain only lowercase" \
236
- " letters and digits separated by dashes ('-')."
237
- )
268
+ def self.supports_filtering(command)
269
+ if @config.experimental_features
270
+ command.flag :exclude,
271
+ negatable: false,
272
+ desc: "Exclude elements matching the filter criteria"
273
+ end
238
274
  end
239
275
 
240
- if unknown_scopes.length > 0
241
- form = unknown_scopes.length > 1 ? "scopes are" : "scope is"
242
- raise Machinery::Errors::UnknownScope.new(
243
- "The following #{form} not supported: " \
244
- "#{Machinery::Ui.internal_scope_list_to_string(unknown_scopes)}. " \
245
- "Valid scopes are: #{AVAILABLE_SCOPE_LIST}."
246
- )
276
+ def self.check_port_validity(port)
277
+ if port < 2 || port > 65_535
278
+ raise Machinery::Errors::ServerPortError,
279
+ "The specified port '#{port}' is not valid. " \
280
+ "A valid port can be in a range between 2 and 65535."
281
+ elsif port >= 2 && port <= 1_023 && !CurrentUser.new.is_root?
282
+ raise Machinery::Errors::ServerPortError,
283
+ "The specified port '#{port}' needs root privileges. "\
284
+ "Otherwise, the server cannot be started. All ports " \
285
+ "in a range of 2-1023 need root privileges."
286
+ end
247
287
  end
248
288
 
249
- Inspector.sort_scopes(scopes.uniq)
250
- end
289
+ AVAILABLE_SCOPE_LIST = Machinery::Ui.internal_scope_list_to_string(
290
+ Inspector.all_scopes
291
+ )
251
292
 
252
- def self.supports_filtering(command)
253
- if @config.experimental_features
254
- command.flag :exclude, negatable: false, desc: "Exclude elements matching the filter criteria"
255
- end
256
- end
293
+ desc "Analyze system description"
294
+ long_desc <<-LONGDESC
295
+ Analyze stored system description.
257
296
 
258
- def self.check_port_validity(port)
259
- if port < 2 || port > 65535
260
- raise Machinery::Errors::ServerPortError.new("The specified port '#{port}' is not " \
261
- "valid. A valid port can be in a range between 2 and 65535.")
262
- else
263
- if port >= 2 && port <= 1023 && !CurrentUser.new.is_root?
264
- raise Machinery::Errors::ServerPortError.new("The specified port '#{port}' needs " \
265
- "root privileges. Otherwise, the server cannot be started. All ports in a range " \
266
- "of 2-1023 need root privileges.")
267
- end
268
- end
269
- end
297
+ The supported operations are:
270
298
 
271
- AVAILABLE_SCOPE_LIST = Machinery::Ui.internal_scope_list_to_string(
272
- Inspector.all_scopes
273
- )
274
-
275
- desc "Analyze system description"
276
- long_desc <<-LONGDESC
277
- Analyze stored system description.
278
-
279
- The supported operations are:
280
-
281
- - changed-config-files-diffs: Generate diffs against the original version from
282
- the package for the changed configuration files
283
- LONGDESC
284
- arg "NAME"
285
- command "analyze" do |c|
286
- c.flag [:operation, :o], type: String, required: false,
287
- desc: "The analyze operation to perform", arg_name: "OPERATION", default_value: "changed-config-files-diffs"
288
-
289
- c.action do |global_options,options,args|
290
- name = shift_arg(args, "NAME")
291
- description = SystemDescription.load(name, system_description_store)
292
-
293
- case options[:operation]
294
- when "changed-config-files-diffs"
295
- task = AnalyzeConfigFileDiffsTask.new
296
- task.analyze(description)
297
- Hint.print(:show_analyze_data, name: name)
298
- else
299
- raise Machinery::Errors::InvalidCommandLine.new(
300
- "The operation '#{options[:operation]}' is not supported. " \
301
- "Valid operations are: changed-config-files-diffs."
302
- )
299
+ - changed-config-files-diffs: Generate diffs against the original
300
+ version from the package for the changed configuration files
301
+ LONGDESC
302
+ arg "NAME"
303
+ command "analyze" do |c|
304
+ c.flag [:operation, :o],
305
+ type: String,
306
+ required: false,
307
+ desc: "The analyze operation to perform",
308
+ arg_name: "OPERATION",
309
+ default_value: "changed-config-files-diffs"
310
+
311
+ c.action do |_global_options, options, args|
312
+ name = shift_arg(args, "NAME")
313
+ description = SystemDescription.load(name, system_description_store)
314
+
315
+ case options[:operation]
316
+ when "changed-config-files-diffs"
317
+ task = AnalyzeConfigFileDiffsTask.new
318
+ task.analyze(description)
319
+ Ui::Hint.print(:show_analyze_data, name: name)
320
+ else
321
+ raise Machinery::Errors::InvalidCommandLine,
322
+ "The operation '#{options[:operation]}' is not supported. " \
323
+ "Valid operations are: changed-config-files-diffs."
324
+ end
303
325
  end
304
326
  end
305
- end
306
327
 
307
328
 
308
329
 
309
- desc "Build image from system description"
310
- long_desc <<-LONGDESC
311
- Build image from a given system description and store it to the given
312
- location.
313
- LONGDESC
314
- arg "NAME"
315
- command "build" do |c|
316
- c.flag ["image-dir", :i], type: String, required: true,
317
- desc: "Store the image under the specified path", arg_name: "DIRECTORY"
318
- c.switch ["enable-dhcp", :d], required: false, negatable: false,
319
- desc: "Enable DCHP client on first network card of built image"
320
- c.switch ["enable-ssh", :s], required: false, negatable: false,
321
- desc: "Enable SSH service in built image"
322
-
323
- c.action do |global_options,options,args|
324
- name = shift_arg(args, "NAME")
325
- description = SystemDescription.load(name, system_description_store)
326
-
327
- task = BuildTask.new
328
- task.build(
329
- description, File.expand_path(options["image-dir"]),
330
- enable_dhcp: options["enable-dhcp"], enable_ssh: options["enable-ssh"]
331
- )
332
- end
333
- end
330
+ desc "Build image from system description"
331
+ long_desc <<-LONGDESC
332
+ Build image from a given system description and store it to the given
333
+ location.
334
+ LONGDESC
335
+ arg "NAME"
336
+ command "build" do |c|
337
+ c.flag ["image-dir", :i],
338
+ type: String,
339
+ required: true,
340
+ desc: "Store the image under the specified path",
341
+ arg_name: "DIRECTORY"
342
+ c.switch ["enable-dhcp", :d],
343
+ required: false,
344
+ negatable: false,
345
+ desc: "Enable DCHP client on first network card of built image"
346
+ c.switch ["enable-ssh", :s],
347
+ required: false,
348
+ negatable: false,
349
+ desc: "Enable SSH service in built image"
334
350
 
351
+ c.action do |_global_options, options, args|
352
+ name = shift_arg(args, "NAME")
353
+ description = SystemDescription.load(name, system_description_store)
335
354
 
355
+ task = BuildTask.new
356
+ task.build(
357
+ description,
358
+ File.expand_path(options["image-dir"]),
359
+ enable_dhcp: options["enable-dhcp"],
360
+ enable_ssh: options["enable-ssh"]
361
+ )
362
+ end
363
+ end
336
364
 
337
- desc "Compare system descriptions"
338
- long_desc <<-LONGDESC
339
- Compare system descriptions stored under specified names.
340
365
 
341
- Multiple scopes can be passed as comma-separated list. If no specific scopes
342
- are given, all scopes are compared.
343
366
 
344
- Available scopes: #{AVAILABLE_SCOPE_LIST}
345
- LONGDESC
346
- arg "NAME1"
347
- arg "NAME2"
348
- command "compare" do |c|
349
- c.flag [:scope, :s], type: String, required: false,
350
- desc: "Compare specified scopes", arg_name: "SCOPE_LIST"
351
- c.flag ["ignore-scope", :e], type: String, required: false,
352
- desc: "Exclude specified scopes", arg_name: "SCOPE_LIST"
353
- c.switch "show-all", required: false, negatable: false,
354
- desc: "Show also common properties"
355
- c.switch "html", required: false, negatable: false,
356
- desc: "Open comparison in HTML format in your web browser."
357
- c.switch "pager", required: false, default_value: true,
358
- desc: "Pipe output into a pager"
367
+ desc "Compare system descriptions"
368
+ long_desc <<-LONGDESC
369
+ Compare system descriptions stored under specified names.
359
370
 
360
- c.action do |global_options,options,args|
361
- Machinery::Ui.use_pager = options[:pager]
371
+ Multiple scopes can be passed as comma-separated list. If no
372
+ specific scopes are given, all scopes are compared.
362
373
 
363
- name1 = shift_arg(args, "NAME1")
364
- name2 = shift_arg(args, "NAME2")
374
+ Available scopes: #{AVAILABLE_SCOPE_LIST}
375
+ LONGDESC
376
+ arg "NAME1"
377
+ arg "NAME2"
378
+ command "compare" do |c|
379
+ c.flag [:scope, :s],
380
+ type: String,
381
+ required: false,
382
+ desc: "Compare specified scopes",
383
+ arg_name: "SCOPE_LIST"
384
+ c.flag ["ignore-scope", :e],
385
+ type: String,
386
+ required: false,
387
+ desc: "Exclude specified scopes",
388
+ arg_name: "SCOPE_LIST"
389
+ c.switch "show-all",
390
+ required: false,
391
+ negatable: false,
392
+ desc: "Show also common properties"
393
+ c.switch "html",
394
+ required: false,
395
+ negatable: false,
396
+ desc: "Open comparison in HTML format in your web browser."
397
+ c.switch "pager",
398
+ required: false,
399
+ default_value: true,
400
+ desc: "Pipe output into a pager"
365
401
 
366
- if options[:html]
367
- begin
368
- check_port_validity(@config.http_server_port)
369
- rescue Machinery::Errors::ServerPortError => e
370
- raise Machinery::Errors::InvalidCommandLine.new(e.message + " The port can be " \
371
- "specified in the 'http_server_port' section of the configuration file.")
402
+ c.action do |_global_options, options, args|
403
+ Machinery::Ui.use_pager = options[:pager]
404
+
405
+ name1 = shift_arg(args, "NAME1")
406
+ name2 = shift_arg(args, "NAME2")
407
+
408
+ if options[:html]
409
+ begin
410
+ check_port_validity(@config.http_server_port)
411
+ rescue Machinery::Errors::ServerPortError => e
412
+ raise Machinery::Errors::InvalidCommandLine,
413
+ "#{e.message} The port can be specified in the " \
414
+ "'http_server_port' section of the configuration file."
415
+ end
372
416
  end
373
- end
374
417
 
375
- store = system_description_store
376
- description1 = SystemDescription.load(name1, store)
377
- description2 = SystemDescription.load(name2, store)
378
- scope_list = process_scope_option(options[:scope], options["ignore-scope"])
379
-
380
- task = CompareTask.new
381
- opts = {
382
- show_html: options["html"],
383
- show_all: options["show-all"],
384
- ip: "127.0.0.1",
385
- port: @config.http_server_port
386
- }
387
- task.compare(description1, description2, scope_list, opts)
418
+ store = system_description_store
419
+ description1 = SystemDescription.load(name1, store)
420
+ description2 = SystemDescription.load(name2, store)
421
+ scope_list =
422
+ process_scope_option(options[:scope], options["ignore-scope"])
423
+
424
+ task = CompareTask.new
425
+ opts = {
426
+ show_html: options["html"],
427
+ show_all: options["show-all"],
428
+ ip: "127.0.0.1",
429
+ port: @config.http_server_port
430
+ }
431
+ task.compare(description1, description2, scope_list, opts)
432
+ end
388
433
  end
389
- end
390
434
 
391
435
 
392
436
 
393
- desc "Copy system description"
394
- long_desc <<-LONGDESC
395
- Copy a system description.
437
+ desc "Copy system description"
438
+ long_desc <<-LONGDESC
439
+ Copy a system description.
396
440
 
397
- The system description is copied and stored under the provided name.
398
- LONGDESC
399
- arg "FROM_NAME"
400
- arg "TO_NAME"
401
- command "copy" do |c|
402
- c.action do |global_options,options,args|
403
- from = shift_arg(args, "FROM_NAME")
404
- to = shift_arg(args, "TO_NAME")
405
- task = CopyTask.new
406
- task.copy(system_description_store, from, to)
441
+ The system description is copied and stored under the provided name.
442
+ LONGDESC
443
+ arg "FROM_NAME"
444
+ arg "TO_NAME"
445
+ command "copy" do |c|
446
+ c.action do |_global_options, _options, args|
447
+ from = shift_arg(args, "FROM_NAME")
448
+ to = shift_arg(args, "TO_NAME")
449
+ task = CopyTask.new
450
+ task.copy(system_description_store, from, to)
451
+ end
407
452
  end
408
- end
409
453
 
410
- desc "Move system description"
411
- long_desc <<-LONGDESC
412
- Move a system description.
413
-
414
- The system description name is changed to the provided name.
415
- LONGDESC
416
- arg "FROM_NAME"
417
- arg "TO_NAME"
418
- command "move" do |c|
419
- c.action do |_global_options, _options, args|
420
- from = shift_arg(args, "FROM_NAME")
421
- to = shift_arg(args, "TO_NAME")
422
- task = MoveTask.new
423
- task.move(system_description_store, from, to)
454
+ desc "Move system description"
455
+ long_desc <<-LONGDESC
456
+ Move a system description.
457
+
458
+ The system description name is changed to the provided name.
459
+ LONGDESC
460
+ arg "FROM_NAME"
461
+ arg "TO_NAME"
462
+ command "move" do |c|
463
+ c.action do |_global_options, _options, args|
464
+ from = shift_arg(args, "FROM_NAME")
465
+ to = shift_arg(args, "TO_NAME")
466
+ task = MoveTask.new
467
+ task.move(system_description_store, from, to)
468
+ end
424
469
  end
425
- end
426
470
 
427
471
 
428
- desc "Deploy image to OpenStack cloud"
429
- long_desc <<-LONGDESC
430
- Deploy system description as image to OpenStack cloud.
431
-
432
- The image will be deployed to the OpenStack cloud. If no --image-dir is
433
- specified an image will be built from the description before deployment.
434
- LONGDESC
435
- arg "NAME"
436
- command "deploy" do |c|
437
- c.flag ["cloud-config", :c], type: String, required: true, arg_name: "FILE",
438
- desc: "Path to file where the cloud config (openrc.sh) is located"
439
- c.flag ["image-dir", :i], type: String, required: false,
440
- desc: "Directory where the image is located", arg_name: "DIRECTORY"
441
- c.switch [:insecure, :s], required: false, negatable: false,
442
- desc: "Explicitly allow glanceclient to perform 'insecure SSL' (https) requests."
443
- c.flag ["cloud-image-name", :n], type: String, required: false,
444
- desc: "Name of the image in the cloud", arg_name: "NAME"
445
-
446
- c.action do |global_options,options,args|
447
- name = shift_arg(args, "NAME")
448
- description = SystemDescription.load(name, system_description_store)
449
-
450
- task = DeployTask.new
451
- opts = {
472
+ desc "Deploy image to OpenStack cloud"
473
+ long_desc <<-LONGDESC
474
+ Deploy system description as image to OpenStack cloud.
475
+
476
+ The image will be deployed to the OpenStack cloud. If no --image-dir is
477
+ specified an image will be built from the description before deployment.
478
+ LONGDESC
479
+ arg "NAME"
480
+ command "deploy" do |c|
481
+ c.flag ["cloud-config", :c],
482
+ type: String,
483
+ required: true,
484
+ arg_name: "FILE",
485
+ desc: "Path to file where the cloud config (openrc.sh) is located"
486
+ c.flag ["image-dir", :i],
487
+ type: String,
488
+ required: false,
489
+ desc: "Directory where the image is located",
490
+ arg_name: "DIRECTORY"
491
+ c.switch [:insecure, :s],
492
+ required: false,
493
+ negatable: false,
494
+ desc: "Explicitly allow glanceclient to perform "\
495
+ "'insecure SSL' (https) requests."
496
+ c.flag ["cloud-image-name", :n],
497
+ type: String,
498
+ required: false,
499
+ desc: "Name of the image in the cloud",
500
+ arg_name: "NAME"
501
+
502
+ c.action do |_global_options, options, args|
503
+ name = shift_arg(args, "NAME")
504
+ description = SystemDescription.load(name, system_description_store)
505
+
506
+ task = DeployTask.new
507
+ opts = {
452
508
  image_name: options[:cloud_image_name],
453
- insecure: options[:insecure]
454
- }
455
- opts[:image_dir] = File.expand_path(options["image-dir"]) if options["image-dir"]
456
- task.deploy(description, File.expand_path(options["cloud-config"]), opts)
509
+ insecure: options[:insecure]
510
+ }
511
+ if options["image-dir"]
512
+ opts[:image_dir] = File.expand_path(options["image-dir"])
513
+ end
514
+ task.deploy(
515
+ description,
516
+ File.expand_path(options["cloud-config"]),
517
+ opts
518
+ )
519
+ end
457
520
  end
458
- end
459
521
 
460
522
 
461
523
 
462
- desc "Export system description as KIWI image description"
463
- long_desc <<-LONGDESC
464
- Export system description as KIWI image description.
524
+ desc "Export system description as KIWI image description"
525
+ long_desc <<-LONGDESC
526
+ Export system description as KIWI image description.
465
527
 
466
- The description will be placed in a subdirectory at the given location. The image format in
467
- the description is 'vmx'.
468
- LONGDESC
469
- arg "NAME"
470
- command "export-kiwi" do |c|
471
- c.flag ["kiwi-dir", :k], type: String, required: true,
472
- desc: "Location where the description will be stored", arg_name: "DIRECTORY"
473
- c.switch :force, default_value: false, required: false, negatable: false,
474
- desc: "Overwrite existing directory"
528
+ The description will be placed in a subdirectory at the given location.
529
+ The image format in the description is 'vmx'.
530
+ LONGDESC
531
+ arg "NAME"
532
+ command "export-kiwi" do |c|
533
+ c.flag ["kiwi-dir", :k],
534
+ type: String,
535
+ required: true,
536
+ desc: "Location where the description will be stored",
537
+ arg_name: "DIRECTORY"
538
+ c.switch :force,
539
+ default_value: false,
540
+ required: false,
541
+ negatable: false,
542
+ desc: "Overwrite existing directory"
475
543
 
476
- c.action do |global_options,options,args|
477
- name = shift_arg(args, "NAME")
478
- description = SystemDescription.load(name, system_description_store)
479
- exporter = KiwiConfig.new(description)
544
+ c.action do |_global_options, options, args|
545
+ name = shift_arg(args, "NAME")
546
+ description = SystemDescription.load(name, system_description_store)
547
+ exporter = KiwiConfig.new(description)
480
548
 
481
- task = ExportTask.new(exporter)
482
- task.export(
483
- File.expand_path(options["kiwi-dir"]),
484
- force: options[:force]
485
- )
549
+ task = ExportTask.new(exporter)
550
+ task.export(
551
+ File.expand_path(options["kiwi-dir"]),
552
+ force: options[:force]
553
+ )
554
+ end
486
555
  end
487
- end
488
556
 
489
- desc "Export system description as AutoYaST profile"
490
- long_desc <<-LONGDESC
491
- Export system description as AutoYaST profile
492
-
493
- The profile will be placed in a subdirectory at the given location by the 'autoyast-dir'
494
- option.
495
- LONGDESC
496
- arg "NAME"
497
- command "export-autoyast" do |c|
498
- c.flag ["autoyast-dir", :a], type: String, required: true,
499
- desc: "Location where the autoyast profile will be stored", arg_name: "DIRECTORY"
500
- c.switch :force, default_value: false, required: false, negatable: false,
501
- desc: "Overwrite existing directory"
502
-
503
- c.action do |_global_options, options, args|
504
- name = shift_arg(args, "NAME")
505
- description = SystemDescription.load(name, system_description_store)
506
- exporter = Autoyast.new(description)
507
-
508
- task = ExportTask.new(exporter)
509
- task.export(
510
- File.expand_path(options["autoyast-dir"]),
511
- force: options[:force]
512
- )
513
- end
514
- end
557
+ desc "Export system description as AutoYaST profile"
558
+ long_desc <<-LONGDESC
559
+ Export system description as AutoYaST profile
515
560
 
516
- desc "Export static HTML view of a system description"
517
- long_desc <<-LONGDESC
518
- Export system description as HTML
519
-
520
- The HTML view will be placed in a subdirectory at the given location by the 'html-dir'
521
- option.
522
- LONGDESC
523
- arg "NAME"
524
- command "export-html" do |c|
525
- c.flag ["html-dir", :d], type: String, required: true,
526
- desc: "Location where the HTML view will be stored", arg_name: "DIRECTORY"
527
- c.switch :force, default_value: false, required: false, negatable: false,
528
- desc: "Overwrite existing directory"
529
-
530
- c.action do |_global_options, options, args|
531
- name = shift_arg(args, "NAME")
532
- description = SystemDescription.load(name, system_description_store)
533
- exporter = StaticHtml.new(description, options["html-dir"])
534
- exporter.create_directory(options[:force])
535
- exporter.write
536
- end
537
- end
561
+ The profile will be placed in a subdirectory at the given location by
562
+ the 'autoyast-dir' option.
563
+ LONGDESC
564
+ arg "NAME"
565
+ command "export-autoyast" do |c|
566
+ c.flag ["autoyast-dir", :a],
567
+ type: String,
568
+ required: true,
569
+ desc: "Location where the autoyast profile will be stored",
570
+ arg_name: "DIRECTORY"
571
+ c.switch :force,
572
+ default_value: false,
573
+ required: false,
574
+ negatable: false,
575
+ desc: "Overwrite existing directory"
538
576
 
539
- def self.define_inspect_command_options(c)
540
- c.flag [:name, :n], type: String, required: false, arg_name: "NAME",
541
- desc: "Store system description under the specified name"
542
- c.flag [:scope, :s], type: String, required: false,
543
- desc: "Inspect specified scopes", arg_name: "SCOPE_LIST"
544
- c.flag ["ignore-scope", :e], type: String, required: false,
545
- desc: "Exclude specified scopes", arg_name: "SCOPE_LIST"
546
- c.flag "skip-files", required: false, negatable: false,
547
- desc: "Do not consider given files or directories during inspection. " \
548
- "Either provide one file or directory name or a list of names separated by commas."
549
- c.switch ["extract-files", :x], required: false, negatable: false,
550
- desc: "Extract changed configuration files and unmanaged files from inspected system"
551
- if @config.experimental_features
552
- c.switch ["extract-metadata", :m], required: false, negatable: false,
553
- desc: "Extract unmanaged files metadata without extracting the files."
554
- end
555
- c.switch "extract-changed-config-files", required: false, negatable: false,
556
- desc: "Extract changed configuration files from inspected system"
557
- c.switch "extract-unmanaged-files", required: false, negatable: false,
558
- desc: "Extract unmanaged files from inspected system"
559
- c.switch "extract-changed-managed-files", required: false, negatable: false,
560
- desc: "Extract changed managed files from inspected system"
561
- c.switch :show, required: false, negatable: false,
562
- desc: "Print inspection result"
563
- c.switch :verbose, required: false, negatable: false,
564
- desc: "Display the filters which are used during inspection"
565
- end
577
+ c.action do |_global_options, options, args|
578
+ name = shift_arg(args, "NAME")
579
+ description = SystemDescription.load(name, system_description_store)
580
+ exporter = Autoyast.new(description)
566
581
 
567
- def self.parse_inspect_command_options(host, options)
568
- scope_list = process_scope_option(options[:scope], options["ignore-scope"])
569
- name = options[:name] || host
582
+ task = ExportTask.new(exporter)
583
+ task.export(
584
+ File.expand_path(options["autoyast-dir"]),
585
+ force: options[:force]
586
+ )
587
+ end
588
+ end
570
589
 
590
+ desc "Export static HTML view of a system description"
591
+ long_desc <<-LONGDESC
592
+ Export system description as HTML
571
593
 
572
- unless scope_list.empty?
573
- inspected_scopes = " for #{Machinery::Ui.internal_scope_list_to_string(scope_list)}"
574
- end
575
- Machinery::Ui.puts "Inspecting #{host}#{inspected_scopes}..."
594
+ The HTML view will be placed in a subdirectory at the given location by
595
+ the 'html-dir' option.
596
+ LONGDESC
597
+ arg "NAME"
598
+ command "export-html" do |c|
599
+ c.flag ["html-dir", :d],
600
+ type: String,
601
+ required: true,
602
+ desc: "Location where the HTML view will be stored",
603
+ arg_name: "DIRECTORY"
604
+ c.switch :force,
605
+ default_value: false,
606
+ required: false,
607
+ negatable: false,
608
+ desc: "Overwrite existing directory"
576
609
 
577
- inspect_options = {}
578
- if options["show"]
579
- inspect_options[:show] = true
580
- end
581
- if options["verbose"]
582
- inspect_options[:verbose] = true
583
- end
584
- if options["extract-files"] || options["extract-changed-config-files"]
585
- inspect_options[:extract_changed_changed_config_files] = true
586
- end
587
- if options["extract-files"] || options["extract-changed-managed-files"]
588
- inspect_options[:extract_changed_managed_files] = true
589
- end
590
- if options["extract-files"] || options["extract-unmanaged-files"]
591
- inspect_options[:extract_unmanaged_files] = true
610
+ c.action do |_global_options, options, args|
611
+ name = shift_arg(args, "NAME")
612
+ description = SystemDescription.load(name, system_description_store)
613
+ exporter = StaticHtml.new(description, options["html-dir"])
614
+ exporter.create_directory(options[:force])
615
+ exporter.write
616
+ end
592
617
  end
593
- if options["extract-metadata"]
594
- inspect_options[:extract_metadata] = true
618
+
619
+ def self.define_inspect_command_options(c)
620
+ c.flag [:name, :n],
621
+ type: String,
622
+ required: false,
623
+ arg_name: "NAME",
624
+ desc: "Store system description under the specified name"
625
+ c.flag [:scope, :s],
626
+ type: String,
627
+ required: false,
628
+ desc: "Inspect specified scopes",
629
+ arg_name: "SCOPE_LIST"
630
+ c.flag ["ignore-scope", :e],
631
+ type: String,
632
+ required: false,
633
+ desc: "Exclude specified scopes",
634
+ arg_name: "SCOPE_LIST"
635
+ c.flag "skip-files",
636
+ required: false,
637
+ negatable: false,
638
+ desc: "Do not consider given files or directories during " \
639
+ "inspection. Either provide one file or directory name "\
640
+ "or a list of names separated by commas."
641
+ c.switch ["extract-files", :x],
642
+ required: false,
643
+ negatable: false,
644
+ desc: "Extract changed configuration files and unmanaged "\
645
+ "files from inspected system"
646
+ if @config.experimental_features
647
+ c.switch ["extract-metadata", :m],
648
+ required: false,
649
+ negatable: false,
650
+ desc: "Extract unmanaged files metadata without "\
651
+ "extracting the files."
652
+ end
653
+ c.switch "extract-changed-config-files",
654
+ required: false,
655
+ negatable: false,
656
+ desc: "Extract changed configuration files from inspected system"
657
+ c.switch "extract-unmanaged-files",
658
+ required: false,
659
+ negatable: false,
660
+ desc: "Extract unmanaged files from inspected system"
661
+ c.switch "extract-changed-managed-files",
662
+ required: false,
663
+ negatable: false,
664
+ desc: "Extract changed managed files from inspected system"
665
+ c.switch :show,
666
+ required: false,
667
+ negatable: false,
668
+ desc: "Print inspection result"
669
+ c.switch :verbose,
670
+ required: false,
671
+ negatable: false,
672
+ desc: "Display the filters which are used during inspection"
595
673
  end
596
674
 
597
- filter = FilterOptionParser.parse("inspect", options)
675
+ def self.parse_inspect_command_options(host, options)
676
+ scope_list = process_scope_option(
677
+ options[:scope],
678
+ options["ignore-scope"]
679
+ )
680
+ name = options[:name] || host
598
681
 
599
- if options["verbose"] && !filter.empty?
600
- Machinery::Ui.puts "\nThe following filters are applied during inspection:"
601
- Machinery::Ui.puts filter.to_array.join("\n") + "\n\n"
602
- else
603
- show_filter_note(scope_list, filter)
604
- end
605
682
 
606
- [name, scope_list, inspect_options, filter]
607
- end
683
+ unless scope_list.empty?
684
+ inspected_scopes =
685
+ " for #{Machinery::Ui.internal_scope_list_to_string(scope_list)}"
686
+ end
687
+ Machinery::Ui.puts "Inspecting #{host}#{inspected_scopes}..."
608
688
 
609
- desc "Inspect running system"
610
- long_desc <<-LONGDESC
611
- Inspect running system and generate system descripton from inspected data.
612
-
613
- Multiple scopes can be passed as comma-separated list. If no specific scopes
614
- are given, all scopes are inspected.
615
-
616
- Available scopes: #{AVAILABLE_SCOPE_LIST}
617
- LONGDESC
618
- arg "HOSTNAME"
619
- command "inspect" do |c|
620
- supports_filtering(c)
621
- define_inspect_command_options(c)
622
- c.flag ["remote-user", :r], type: String, required: false, default_value: @config.remote_user,
623
- desc: "Defines the user which is used to access the inspected system via SSH."\
624
- "This user needs sudo access on the remote machine or be root.", arg_name: "USER"
625
- c.flag ["ssh-port", :p], type: Integer, required: false,
626
- desc: "The SSH port of the remote server.",
627
- arg_name: "SSH-PORT"
628
- c.flag ["ssh-identity-file", :i], type: String, required: false,
629
- desc: "The private SSH key location what can be used to authenticate with the remote system.",
630
- arg_name: "SSH-KEY"
631
-
632
- c.action do |_global_options, options, args|
633
- host = shift_arg(args, "HOSTNAME")
634
- system = System.for(host, remote_user: options["remote-user"], ssh_port: options["ssh-port"],
635
- ssh_identity_file: options["ssh-identity-file"])
636
- inspector_task = InspectTask.new
637
-
638
- name, scope_list, inspect_options, filter = parse_inspect_command_options(host, options)
639
-
640
- inspector_task.inspect_system(
641
- system_description_store,
642
- system,
643
- name,
644
- CurrentUser.new,
645
- scope_list,
646
- filter,
647
- inspect_options
648
- )
689
+ inspect_options = {}
690
+ if options["show"]
691
+ inspect_options[:show] = true
692
+ end
693
+ if options["verbose"]
694
+ inspect_options[:verbose] = true
695
+ end
696
+ if options["extract-files"] || options["extract-changed-config-files"]
697
+ inspect_options[:extract_changed_changed_config_files] = true
698
+ end
699
+ if options["extract-files"] || options["extract-changed-managed-files"]
700
+ inspect_options[:extract_changed_managed_files] = true
701
+ end
702
+ if options["extract-files"] || options["extract-unmanaged-files"]
703
+ inspect_options[:extract_unmanaged_files] = true
704
+ end
705
+ if options["extract-metadata"]
706
+ inspect_options[:extract_metadata] = true
707
+ end
649
708
 
650
- Hint.print(:show_data, name: name) if options[:show] == false
709
+ filter = FilterOptionParser.parse("inspect", options)
651
710
 
652
- if !options["extract-files"] || Inspector.all_scopes.count != scope_list.count
653
- Hint.print(:do_complete_inspection, name: name, host: host)
711
+ if options["verbose"] && !filter.empty?
712
+ Machinery::Ui.puts "\nThe following filters are applied "\
713
+ "during inspection:"
714
+ Machinery::Ui.puts filter.to_array.join("\n") + "\n\n"
715
+ else
716
+ show_filter_note(scope_list, filter)
654
717
  end
655
- end
656
- end
657
718
 
658
- desc "Inspect container image"
659
- long_desc <<-LONGDESC
660
- Inspect container image and generate system descripton from inspected data.
661
- Right now we only support docker images.
719
+ [name, scope_list, inspect_options, filter]
720
+ end
662
721
 
663
- Multiple scopes can be passed as comma-separated list. If no specific scopes
664
- are given, all scopes are inspected.
722
+ desc "Inspect running system"
723
+ long_desc <<-LONGDESC
724
+ Inspect running system and generate system descripton from inspected data.
665
725
 
666
- Available scopes: #{AVAILABLE_SCOPE_LIST}
667
- LONGDESC
668
- arg "(IMAGENAME|IMAGEID)"
669
- command "inspect-container" do |c|
670
- supports_filtering(c)
671
- define_inspect_command_options(c)
726
+ Multiple scopes can be passed as comma-separated list. If no specific
727
+ scopes are given, all scopes are inspected.
672
728
 
673
- c.action do |_global_options, options, args|
674
- image = shift_arg(args, "(IMAGENAME|IMAGEID)")
675
- system = DockerSystem.new(image)
676
- inspector_task = InspectTask.new
729
+ Available scopes: #{AVAILABLE_SCOPE_LIST}
730
+ LONGDESC
731
+ arg "HOSTNAME"
732
+ command "inspect" do |c|
733
+ supports_filtering(c)
734
+ define_inspect_command_options(c)
735
+ c.flag ["remote-user", :r],
736
+ type: String,
737
+ required: false,
738
+ default_value: @config.remote_user,
739
+ desc: "Defines the user which is used to access the "\
740
+ "inspected system via SSH. This user needs sudo "\
741
+ "access on the remote machine or be root.",
742
+ arg_name: "USER"
743
+ c.flag ["ssh-port", :p],
744
+ type: Integer,
745
+ required: false,
746
+ desc: "The SSH port of the remote server.",
747
+ arg_name: "SSH-PORT"
748
+ c.flag ["ssh-identity-file", :i],
749
+ type: String,
750
+ required: false,
751
+ desc: "The private SSH key location what can be used to "\
752
+ "authenticate with the remote system.",
753
+ arg_name: "SSH-KEY"
677
754
 
678
- name, scope_list, inspect_options, filter = parse_inspect_command_options(image, options)
755
+ c.action do |_global_options, options, args|
756
+ host = shift_arg(args, "HOSTNAME")
757
+ system = System.for(
758
+ host,
759
+ remote_user: options["remote-user"],
760
+ ssh_port: options["ssh-port"],
761
+ ssh_identity_file: options["ssh-identity-file"]
762
+ )
763
+ inspector_task = InspectTask.new
679
764
 
680
- check_container_name!(image, name)
765
+ name, scope_list, inspect_options, filter =
766
+ parse_inspect_command_options(host, options)
681
767
 
682
- begin
683
- system.start
684
768
  inspector_task.inspect_system(
685
769
  system_description_store,
686
770
  system,
@@ -690,317 +774,437 @@ class Cli
690
774
  filter,
691
775
  inspect_options
692
776
  )
693
- ensure
694
- system.stop
695
- end
696
777
 
697
- Hint.print(:show_data, name: name) unless options[:show]
778
+ Ui::Hint.print(:show_data, name: name) if options[:show] == false
698
779
 
699
- if !options["extract-files"] || Inspector.all_scopes.count != scope_list.count
700
- Hint.print(:do_complete_inspection, name: name, docker_container: image)
780
+ if !options["extract-files"] ||
781
+ Inspector.all_scopes.count != scope_list.count
782
+ Ui::Hint.print(:do_complete_inspection, name: name, host: host)
783
+ end
701
784
  end
702
785
  end
703
- end
704
786
 
705
- desc "List system descriptions"
706
- long_desc <<-LONGDESC
707
- List all system descriptions and their stored scopes, when no NAME parameter is specified.
787
+ desc "Inspect container image"
788
+ long_desc <<-LONGDESC
789
+ Inspect container image and generate system descripton from inspected data.
790
+ Right now we only support docker images.
791
+
792
+ Multiple scopes can be passed as comma-separated list. If no specific scopes
793
+ are given, all scopes are inspected.
708
794
 
709
- List only the specified system descriptions and its stored scopes, when NAME parameter is given.
795
+ Available scopes: #{AVAILABLE_SCOPE_LIST}
796
+ LONGDESC
797
+ arg "(IMAGENAME|IMAGEID)"
798
+ command "inspect-container" do |c|
799
+ supports_filtering(c)
800
+ define_inspect_command_options(c)
801
+
802
+ c.action do |_global_options, options, args|
803
+ image = shift_arg(args, "(IMAGENAME|IMAGEID)")
804
+ system = DockerSystem.new(image)
805
+ inspector_task = InspectTask.new
710
806
 
711
- The date of modification for each scope can be shown with the verbose
712
- option.
713
- LONGDESC
714
- arg "NAME", [:multiple, :optional]
807
+ name, scope_list, inspect_options, filter =
808
+ parse_inspect_command_options(image, options)
715
809
 
716
- command "list" do |c|
717
- c.switch :verbose, required: false, negatable: false,
718
- desc: "Display additional information about origin of scopes"
719
- c.switch :short, required: false, negatable: false,
720
- desc: "List only description names"
721
- c.switch :html, required: false, negatable: false,
722
- desc: "Open overview of all system descriptions in HTML format in your web browser"
810
+ check_container_name!(image, name)
723
811
 
724
- c.action do |global_options,options,args|
725
- if options[:html]
726
812
  begin
727
- check_port_validity(@config.http_server_port)
728
- rescue Machinery::Errors::ServerPortError => e
729
- raise Machinery::Errors::InvalidCommandLine.new(e.message + " The port can be " \
730
- "specified in the 'http_server_port' section of the configuration file.")
813
+ system.start
814
+ inspector_task.inspect_system(
815
+ system_description_store,
816
+ system,
817
+ name,
818
+ CurrentUser.new,
819
+ scope_list,
820
+ filter,
821
+ inspect_options
822
+ )
823
+ ensure
824
+ system.stop
731
825
  end
732
- end
733
826
 
734
- opts = {
735
- ip: "127.0.0.1",
736
- port: @config.http_server_port
737
- }.merge(options)
827
+ Ui::Hint.print(:show_data, name: name) unless options[:show]
738
828
 
739
- task = ListTask.new
740
- task.list(system_description_store, args, opts)
829
+ if !options["extract-files"] ||
830
+ Inspector.all_scopes.count != scope_list.count
831
+ Ui::Hint.print(
832
+ :do_complete_inspection,
833
+ name: name,
834
+ docker_container: image
835
+ )
836
+ end
837
+ end
741
838
  end
742
- end
743
839
 
744
- desc "Shows man page"
745
- long_desc <<-LONGDESC
746
- Shows the man page of the machinery tool.
840
+ desc "List system descriptions"
841
+ long_desc <<-LONGDESC
842
+ List all system descriptions and their stored scopes, when no NAME
843
+ parameter is specified.
747
844
 
748
- LONGDESC
749
- command "man" do |c|
750
- c.switch "html", required: false, negatable: false,
751
- desc: "Open documentation in HTML format in your web browser."
845
+ List only the specified system descriptions and its stored scopes, when
846
+ NAME parameter is given.
752
847
 
753
- c.action do |_global_options, options, _args|
754
- options = {
755
- ip: "127.0.0.1",
756
- port: @config.http_server_port
757
- }.merge(options)
848
+ The date of modification for each scope can be shown with the verbose
849
+ option.
850
+ LONGDESC
851
+ arg "NAME", [:multiple, :optional]
852
+
853
+ command "list" do |c|
854
+ c.switch :verbose,
855
+ required: false,
856
+ negatable: false,
857
+ desc: "Display additional information about origin of scopes"
858
+ c.switch :short,
859
+ required: false,
860
+ negatable: false,
861
+ desc: "List only description names"
862
+ c.switch :html,
863
+ required: false,
864
+ negatable: false,
865
+ desc: "Open overview of all system descriptions in "\
866
+ "HTML format in your web browser"
758
867
 
759
- task = ManTask.new
760
- task.man(options)
761
- end
762
- end
868
+ c.action do |_global_options, options, args|
869
+ if options[:html]
870
+ begin
871
+ check_port_validity(@config.http_server_port)
872
+ rescue Machinery::Errors::ServerPortError => e
873
+ raise Machinery::Errors::InvalidCommandLine,
874
+ "#{e.message} The port can be specified in the "\
875
+ "'http_server_port' section of the configuration file."
876
+ end
877
+ end
763
878
 
879
+ opts = {
880
+ ip: "127.0.0.1",
881
+ port: @config.http_server_port
882
+ }.merge(options)
764
883
 
884
+ task = ListTask.new
885
+ task.list(system_description_store, args, opts)
886
+ end
887
+ end
765
888
 
766
- desc "Remove system descriptions"
767
- long_desc <<-LONGDESC
768
- Removes all specified descriptions stored under the specified names.
889
+ desc "Shows man page"
890
+ long_desc <<-LONGDESC
891
+ Shows the man page of the machinery tool.
769
892
 
770
- The success of a removal can be shown with the verbose option.
771
- LONGDESC
772
- arg "NAME", [:multiple, :optional]
893
+ LONGDESC
894
+ command "man" do |c|
895
+ c.switch "html",
896
+ required: false,
897
+ negatable: false,
898
+ desc: "Open documentation in HTML format in your web browser."
899
+
900
+ c.action do |_global_options, options, _args|
901
+ options = {
902
+ ip: "127.0.0.1",
903
+ port: @config.http_server_port
904
+ }.merge(options)
905
+
906
+ task = ManTask.new
907
+ task.man(options)
908
+ end
909
+ end
773
910
 
774
- command "remove" do |c|
775
- c.switch :all, negatable: false,
776
- desc: "Remove all system descriptions"
777
- c.switch :verbose, required: false, negatable: false,
778
- desc: "Explain what is being done"
779
911
 
780
- c.action do |global_options,options,args|
781
- if !options[:all] && args.empty?
782
- raise GLI::BadCommandLine.new, "You need to either specify `--all` or a list of system descriptions"
783
- end
784
912
 
785
- task = RemoveTask.new
786
- task.remove(system_description_store, args, verbose: options[:verbose], all: options[:all])
787
- end
788
- end
913
+ desc "Remove system descriptions"
914
+ long_desc <<-LONGDESC
915
+ Removes all specified descriptions stored under the specified names.
789
916
 
917
+ The success of a removal can be shown with the verbose option.
918
+ LONGDESC
919
+ arg "NAME", [:multiple, :optional]
790
920
 
921
+ command "remove" do |c|
922
+ c.switch :all,
923
+ negatable: false,
924
+ desc: "Remove all system descriptions"
925
+ c.switch :verbose,
926
+ required: false,
927
+ negatable: false,
928
+ desc: "Explain what is being done"
791
929
 
792
- desc "Show system description"
793
- long_desc <<-LONGDESC
794
- Show system description stored under the specified name.
795
-
796
- Multiple scopes can be passed as comma-separated list. If no specific scopes
797
- are given, all scopes are shown.
798
-
799
- Available scopes: #{AVAILABLE_SCOPE_LIST}
800
- LONGDESC
801
- arg "NAME"
802
- command "show" do |c|
803
- supports_filtering(c)
804
- c.flag [:scope, :s], type: String, required: false,
805
- desc: "Show specified scopes", arg_name: "SCOPE_LIST"
806
- c.flag ["ignore-scope", :e], type: String, required: false,
807
- desc: "Exclude specified scopes", arg_name: "SCOPE_LIST"
808
- c.switch "pager", required: false, default_value: true,
809
- desc: "Pipe output into a pager"
810
- c.switch "show-diffs", required: false, negatable: false,
811
- desc: "Show diffs of changed configuration files changes."
812
- c.switch "html", required: false, negatable: false,
813
- desc: "Open system description in HTML format in your web browser."
814
- c.switch "verbose", required: false, negatable: false,
815
- desc: "Show the filters that were applied before showing the description."
816
-
817
- c.action do |global_options,options,args|
818
- Machinery::Ui.use_pager = options["pager"]
819
-
820
- if options[:html]
821
- begin
822
- check_port_validity(@config.http_server_port)
823
- rescue Machinery::Errors::ServerPortError => e
824
- raise Machinery::Errors::InvalidCommandLine.new(e.message + " The port can be " \
825
- "specified in the 'http_server_port' section of the configuration file.")
930
+ c.action do |_global_options, options, args|
931
+ if !options[:all] && args.empty?
932
+ raise GLI::BadCommandLine,
933
+ "You need to either specify `--all` or a list of "\
934
+ "system descriptions"
826
935
  end
827
- end
828
936
 
829
- name = shift_arg(args, "NAME")
830
- if name == "localhost" && !CurrentUser.new.is_root?
831
- Machinery::Ui.puts "You need root rights to access the system description of your locally inspected system."
937
+ task = RemoveTask.new
938
+ task.remove(
939
+ system_description_store,
940
+ args,
941
+ verbose: options[:verbose],
942
+ all: options[:all]
943
+ )
832
944
  end
945
+ end
833
946
 
834
- description = SystemDescription.load(name, system_description_store)
835
- scope_list = process_scope_option(options[:scope], options["ignore-scope"])
836
947
 
837
- filter = FilterOptionParser.parse("show", options)
838
948
 
839
- inspected_filters = description.filter_definitions("inspect")
949
+ desc "Show system description"
950
+ long_desc <<-LONGDESC
951
+ Show system description stored under the specified name.
840
952
 
841
- if options[:verbose]
842
- details = ""
953
+ Multiple scopes can be passed as comma-separated list. If no specific
954
+ scopes are given, all scopes are shown.
843
955
 
844
- if description[:environment].system_type == "docker"
845
- details += "\n Type of inspected container: #{description[:environment].system_type}\n"
846
- end
956
+ Available scopes: #{AVAILABLE_SCOPE_LIST}
957
+ LONGDESC
958
+ arg "NAME"
959
+ command "show" do |c|
960
+ supports_filtering(c)
961
+ c.flag [:scope, :s],
962
+ type: String,
963
+ required: false,
964
+ desc: "Show specified scopes",
965
+ arg_name: "SCOPE_LIST"
966
+ c.flag ["ignore-scope", :e],
967
+ type: String,
968
+ required: false,
969
+ desc: "Exclude specified scopes",
970
+ arg_name: "SCOPE_LIST"
971
+ c.switch "pager",
972
+ required: false,
973
+ default_value: true,
974
+ desc: "Pipe output into a pager"
975
+ c.switch "show-diffs",
976
+ required: false,
977
+ negatable: false,
978
+ desc: "Show diffs of changed configuration files changes."
979
+ c.switch "html",
980
+ required: false,
981
+ negatable: false,
982
+ desc: "Open system description in HTML format in your web browser."
983
+ c.switch "verbose",
984
+ required: false,
985
+ negatable: false,
986
+ desc: "Show the filters that were applied before "\
987
+ "showing the description."
847
988
 
848
- unless inspected_filters.empty?
849
- details += "\n The following filters were applied during inspection:"
850
- details += "\n * " + inspected_filters.join("\n * ") + "\n\n"
989
+ c.action do |_global_options, options, args|
990
+ Machinery::Ui.use_pager = options["pager"]
991
+
992
+ if options[:html]
993
+ begin
994
+ check_port_validity(@config.http_server_port)
995
+ rescue Machinery::Errors::ServerPortError => e
996
+ raise Machinery::Errors::InvalidCommandLine,
997
+ "#{e.message} The port can be specified in the "\
998
+ "'http_server_port' section of the configuration file."
999
+ end
851
1000
  end
852
1001
 
853
- unless filter.empty?
854
- details += "\n The following filters were applied before showing the description:"
855
- details += "\n * " + filter.to_array.join("\n * ") + "\n\n"
1002
+ name = shift_arg(args, "NAME")
1003
+ if name == "localhost" && !CurrentUser.new.is_root?
1004
+ Machinery::Ui.puts "You need root rights to access the system "\
1005
+ "description of your locally inspected system."
856
1006
  end
857
1007
 
858
- Machinery::Ui.puts "# Inspection details\n" + details unless details.empty?
1008
+ description = SystemDescription.load(name, system_description_store)
1009
+ scope_list = process_scope_option(
1010
+ options[:scope],
1011
+ options["ignore-scope"]
1012
+ )
1013
+
1014
+ filter = FilterOptionParser.parse("show", options)
1015
+
1016
+ inspected_filters = description.filter_definitions("inspect")
1017
+
1018
+ if options[:verbose]
1019
+ details = ""
1020
+
1021
+ if description[:environment].system_type == "docker"
1022
+ details += "\n Type of inspected container: "\
1023
+ "#{description[:environment].system_type}\n"
1024
+ end
1025
+
1026
+ unless inspected_filters.empty?
1027
+ details += "\n The following filters were applied during "\
1028
+ "inspection:\n * #{inspected_filters.join("\n * ")}\n\n"
1029
+ end
1030
+
1031
+ unless filter.empty?
1032
+ details += "\n The following filters were applied before "\
1033
+ "showing the description:"
1034
+ details += "\n * " + filter.to_array.join("\n * ") + "\n\n"
1035
+ end
1036
+
1037
+ unless details.empty?
1038
+ Machinery::Ui.puts "# Inspection details\n#{details}"
1039
+ end
1040
+ end
1041
+ task = ShowTask.new
1042
+ opts = {
1043
+ show_diffs: options["show-diffs"],
1044
+ show_html: options["html"],
1045
+ ip: "127.0.0.1",
1046
+ port: @config.http_server_port
1047
+ }
1048
+ task.show(description, scope_list, filter, opts)
859
1049
  end
860
- task = ShowTask.new
861
- opts = {
862
- show_diffs: options["show-diffs"],
863
- show_html: options["html"],
864
- ip: "127.0.0.1",
865
- port: @config.http_server_port
866
- }
867
- task.show(description, scope_list, filter, opts)
868
1050
  end
869
- end
870
1051
 
871
1052
 
872
- desc "Validate system description"
873
- long_desc <<-LONGDESC
874
- Validate system description stored under the specified name.
875
- LONGDESC
876
- arg "NAME"
877
- command "validate" do |c|
878
- c.action do |global_options,options,args|
879
- name = shift_arg(args, "NAME")
880
- if name == "localhost" && !CurrentUser.new.is_root?
881
- Machinery::Ui.puts "You need root rights to access the system description of your locally inspected system."
882
- end
1053
+ desc "Validate system description"
1054
+ long_desc <<-LONGDESC
1055
+ Validate system description stored under the specified name.
1056
+ LONGDESC
1057
+ arg "NAME"
1058
+ command "validate" do |c|
1059
+ c.action do |_global_options, _options, args|
1060
+ name = shift_arg(args, "NAME")
1061
+ if name == "localhost" && !CurrentUser.new.is_root?
1062
+ Machinery::Ui.puts "You need root rights to access the system "\
1063
+ "description of your locally inspected system."
1064
+ end
883
1065
 
884
- task = ValidateTask.new
885
- task.validate(system_description_store, name)
1066
+ task = ValidateTask.new
1067
+ task.validate(system_description_store, name)
1068
+ end
886
1069
  end
887
- end
888
1070
 
889
- desc "Upgrade format of system description"
890
- long_desc <<-LONGDESC
891
- Upgrade the format of one or all system descriptions.
892
- LONGDESC
893
- arg "NAME"
894
- command "upgrade-format" do |c|
895
- c.switch :all, negatable: false,
896
- desc: "Upgrade all system descriptions"
897
- c.switch :force, default_value: false, required: false, negatable: false,
898
- desc: "Keep backup after migration and ingnore validation errors"
899
-
900
- c.action do |global_options,options,args|
901
- name = shift_arg(args, "NAME") unless options[:all]
902
-
903
- task = UpgradeFormatTask.new
904
- task.upgrade(
905
- system_description_store,
906
- name,
907
- all: options[:all],
908
- force: options[:force]
909
- )
1071
+ desc "Upgrade format of system description"
1072
+ long_desc <<-LONGDESC
1073
+ Upgrade the format of one or all system descriptions.
1074
+ LONGDESC
1075
+ arg "NAME"
1076
+ command "upgrade-format" do |c|
1077
+ c.switch :all,
1078
+ negatable: false,
1079
+ desc: "Upgrade all system descriptions"
1080
+ c.switch :force,
1081
+ default_value: false,
1082
+ required: false,
1083
+ negatable: false,
1084
+ desc: "Keep backup after migration and ignore "\
1085
+ "validation errors"
1086
+
1087
+ c.action do |_global_options, options, args|
1088
+ name = shift_arg(args, "NAME") unless options[:all]
1089
+
1090
+ task = UpgradeFormatTask.new
1091
+ task.upgrade(
1092
+ system_description_store,
1093
+ name,
1094
+ all: options[:all],
1095
+ force: options[:force]
1096
+ )
1097
+ end
910
1098
  end
911
- end
912
1099
 
913
- desc "Show or change machinery's configuration"
914
- long_desc <<-LONGDESC
915
- Show or change machinery's configuration.
1100
+ desc "Show or change machinery's configuration"
1101
+ long_desc <<-LONGDESC
1102
+ Show or change machinery's configuration.
916
1103
 
917
- The value of a key is shown when no value argument is passed.
918
- If neither the key argument nor the value argument are specified a list of all keys and their values are shown.
1104
+ The value of a key is shown when no value argument is passed.
1105
+ If neither the key argument nor the value argument are specified a list
1106
+ of all keys and their values are shown.
919
1107
 
920
- ALTERNATIVE SYNOPSIS:
1108
+ ALTERNATIVE SYNOPSIS:
921
1109
 
922
- machinery [global options] config [KEY][=VALUE]
923
- LONGDESC
924
- arg "KEY", :optional
925
- arg "VALUE", :optional
926
- command "config" do |c|
927
- c.action do |global_options,options,args|
928
- if args[0] && args[0].include?("=")
929
- if args[1]
930
- raise GLI::BadCommandLine, "Too many arguments: got 2 arguments, expected only: KEY=VALUE"
1110
+ machinery [global options] config [KEY][=VALUE]
1111
+ LONGDESC
1112
+ arg "KEY", :optional
1113
+ arg "VALUE", :optional
1114
+ command "config" do |c|
1115
+ c.action do |_global_options, _options, args|
1116
+ if args[0] && args[0].include?("=")
1117
+ if args[1]
1118
+ raise GLI::BadCommandLine,
1119
+ "Too many arguments: got 2 arguments, expected only: KEY=VALUE"
1120
+ else
1121
+ key, value = args[0].split("=")
1122
+ end
931
1123
  else
932
- key, value = args[0].split("=")
1124
+ key = args[0]
1125
+ value = args[1]
933
1126
  end
934
- else
935
- key = args[0]
936
- value = args[1]
937
- end
938
1127
 
939
- task = ConfigTask.new(@config)
940
- task.config(key, value)
1128
+ task = ConfigTask.new(@config)
1129
+ task.config(key, value)
941
1130
 
942
- if key == "hints" && (value == "false" || value == "off")
943
- Machinery::Ui.puts "Hints can be switched on again by " \
944
- "'#{Hint.program_name} config hints=on'."
1131
+ if key == "hints" && (value == "false" || value == "off")
1132
+ Machinery::Ui.puts "Hints can be switched on again by " \
1133
+ "'#{Ui::Hint.program_name} config hints=on'."
1134
+ end
945
1135
  end
946
1136
  end
947
- end
948
-
949
- desc "Start a web server for viewing system descriptions"
950
- long_desc <<-LONGDESC
951
- Starts a web server which serves an HTML view of all system descriptions and
952
- an overview page listing all descriptions.
953
- LONGDESC
954
- command "serve" do |c|
955
- c.flag [:port, :p], type: Integer, required: false,
956
- default_value: @config.http_server_port,
957
- desc: "Listen on port PORT. Ports can be selected in a range between 2-65535. Ports between
958
- 2 and 1023 can only be chosen when `machinery` will be executed as `root` user.",
959
- arg_name: "PORT"
960
- c.switch "public", required: false, negatable: false,
961
- desc: "Makes the server reachable from all IP addresses."
962
-
963
- c.action do |_global_options, options, args|
964
- begin
965
- check_port_validity(options[:port])
966
- rescue Machinery::Errors::ServerPortError => e
967
- raise Machinery::Errors::InvalidCommandLine.new(e.message + " The port can be " \
968
- "either specified in the 'http_server_port' section of the configuration file " \
969
- "or via the --port option.")
970
- end
971
-
972
- task = ServeHtmlTask.new
973
- task.serve(
974
- system_description_store, port: options[:port], public: options[:public]
975
- )
976
- end
977
- end
978
1137
 
979
- if @config.experimental_features
980
- desc "Containerize a system description"
1138
+ desc "Start a web server for viewing system descriptions"
981
1139
  long_desc <<-LONGDESC
982
- Detects workloads from a system description and creates a recommendation for a corresponding
983
- container setup
1140
+ Starts a web server which serves an HTML view of all system descriptions
1141
+ and an overview page listing all descriptions.
984
1142
  LONGDESC
985
- arg "NAME"
986
- command "containerize" do |c|
987
- c.flag ["output-dir", :o], type: String, required: true,
988
- desc: "Location where the container files will be stored", arg_name: "DIRECTORY"
1143
+ command "serve" do |c|
1144
+ c.flag [:port, :p],
1145
+ type: Integer,
1146
+ required: false,
1147
+ default_value: @config.http_server_port,
1148
+ desc: "Listen on port PORT. Ports can be selected in a range "\
1149
+ "between 2-65535. Ports between 2 and 1023 can only be "\
1150
+ "chosen when `machinery` will be executed as `root` "\
1151
+ "user.",
1152
+ arg_name: "PORT"
1153
+ c.switch "public",
1154
+ required: false,
1155
+ negatable: false,
1156
+ desc: "Makes the server reachable from all IP addresses."
989
1157
 
990
1158
  c.action do |_global_options, options, args|
991
- name = shift_arg(args, "NAME")
992
- description = SystemDescription.load(name, system_description_store)
993
- task = ContainerizeTask.new
994
- task.containerize(description, File.expand_path(options["output-dir"]))
1159
+ begin
1160
+ check_port_validity(options[:port])
1161
+ rescue Machinery::Errors::ServerPortError => e
1162
+ raise Machinery::Errors::InvalidCommandLine,
1163
+ "#{e.message} The port can be either specified in the "\
1164
+ "'http_server_port' section of the configuration file " \
1165
+ "or via the --port option."
1166
+ end
1167
+
1168
+ task = ServeHtmlTask.new
1169
+ task.serve(
1170
+ system_description_store,
1171
+ port: options[:port],
1172
+ public: options[:public]
1173
+ )
1174
+ end
1175
+ end
1176
+
1177
+ if @config.experimental_features
1178
+ desc "Containerize a system description"
1179
+ long_desc <<-LONGDESC
1180
+ Detects workloads from a system description and creates a recommendation
1181
+ for a corresponding container setup
1182
+ LONGDESC
1183
+ arg "NAME"
1184
+ command "containerize" do |c|
1185
+ c.flag ["output-dir", :o],
1186
+ type: String,
1187
+ required: true,
1188
+ desc: "Location where the container files will be stored",
1189
+ arg_name: "DIRECTORY"
1190
+
1191
+ c.action do |_global_options, options, args|
1192
+ name = shift_arg(args, "NAME")
1193
+ description = SystemDescription.load(name, system_description_store)
1194
+ task = ContainerizeTask.new
1195
+ task.containerize(
1196
+ description, File.expand_path(options["output-dir"])
1197
+ )
1198
+ end
995
1199
  end
996
1200
  end
997
- end
998
1201
 
999
- def self.system_description_store
1000
- if ENV.key?("MACHINERY_DIR")
1001
- SystemDescriptionStore.new(ENV["MACHINERY_DIR"])
1002
- else
1003
- SystemDescriptionStore.new
1202
+ def self.system_description_store
1203
+ if ENV.key?("MACHINERY_DIR")
1204
+ SystemDescriptionStore.new(ENV["MACHINERY_DIR"])
1205
+ else
1206
+ SystemDescriptionStore.new
1207
+ end
1004
1208
  end
1005
1209
  end
1006
1210
  end