machinery-tool 1.22.1 → 1.22.2

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