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.
- checksums.yaml +4 -4
- data/.git_revision +1 -1
- data/NEWS +10 -0
- data/bin/machinery +1 -1
- data/lib/analyze_changed_config_files_diffs_task.rb +6 -6
- data/lib/autoyast.rb +2 -2
- data/lib/build_task.rb +10 -7
- data/lib/cli.rb +1005 -801
- data/lib/compare_task.rb +11 -7
- data/lib/comparison.rb +2 -2
- data/lib/config_base.rb +1 -1
- data/lib/config_task.rb +1 -1
- data/lib/containerize_task.rb +3 -3
- data/lib/containerized_app.rb +1 -1
- data/lib/copy_task.rb +1 -1
- data/lib/current_user.rb +1 -1
- data/lib/deploy_task.rb +6 -4
- data/lib/diff_widget.rb +67 -63
- data/lib/docker_system.rb +12 -8
- data/lib/dpkg_database.rb +1 -1
- data/lib/element_filter.rb +7 -4
- data/lib/exceptions.rb +23 -5
- data/lib/export_task.rb +1 -1
- data/lib/exporter.rb +1 -1
- data/lib/file_diff.rb +1 -1
- data/lib/file_scope.rb +1 -1
- data/lib/file_validator.rb +7 -4
- data/lib/filter.rb +97 -93
- data/lib/filter_option_parser.rb +2 -2
- data/lib/hint.rb +64 -59
- data/lib/html.rb +1 -1
- data/lib/inspect_task.rb +12 -12
- data/lib/inspector.rb +3 -3
- data/lib/json_validation_error_cleaner.rb +1 -1
- data/lib/json_validator.rb +4 -4
- data/lib/kiwi_config.rb +8 -4
- data/lib/list_task.rb +10 -9
- data/lib/local_system.rb +11 -5
- data/lib/logged_cheetah.rb +1 -1
- data/lib/man_task.rb +10 -6
- data/lib/managed_files_database.rb +1 -1
- data/lib/manifest.rb +5 -5
- data/lib/migration.rb +16 -10
- data/lib/mountpoints.rb +1 -1
- data/lib/move_task.rb +1 -1
- data/lib/remote_system.rb +7 -7
- data/lib/remove_task.rb +1 -1
- data/lib/renderer.rb +177 -172
- data/lib/rpm.rb +4 -4
- data/lib/rpm_database.rb +1 -1
- data/lib/scope.rb +2 -2
- data/lib/scope_file_access_archive.rb +1 -1
- data/lib/scope_file_access_flat.rb +1 -1
- data/lib/scope_file_store.rb +1 -1
- data/lib/serve_html_task.rb +6 -2
- data/lib/server.rb +19 -12
- data/lib/show_task.rb +10 -6
- data/lib/static_html.rb +1 -1
- data/lib/system.rb +10 -10
- data/lib/system_description.rb +14 -13
- data/lib/system_description_memory_store.rb +1 -1
- data/lib/system_description_store.rb +9 -9
- data/lib/tarball.rb +8 -2
- data/lib/upgrade_format_task.rb +11 -6
- data/lib/validate_task.rb +2 -2
- data/lib/version.rb +1 -1
- data/lib/workload_mapper.rb +2 -2
- data/lib/workload_mapper_dsl.rb +1 -1
- data/lib/zypper.rb +40 -17
- data/machinery-helper/machinery_helper.go +35 -16
- data/machinery-helper/version.go +1 -1
- data/man/generated/machinery.1.gz +0 -0
- data/manual/site/sitemap.xml +24 -24
- data/plugins/changed_config_files/changed_config_files_inspector.rb +59 -56
- data/plugins/changed_config_files/changed_config_files_model.rb +23 -21
- data/plugins/changed_config_files/changed_config_files_renderer.rb +56 -52
- data/plugins/changed_managed_files/changed_managed_files_inspector.rb +52 -50
- data/plugins/changed_managed_files/changed_managed_files_model.rb +23 -21
- data/plugins/changed_managed_files/changed_managed_files_renderer.rb +43 -39
- data/plugins/environment/environment_inspector.rb +25 -23
- data/plugins/environment/environment_model.rb +5 -3
- data/plugins/groups/groups_inspector.rb +30 -28
- data/plugins/groups/groups_model.rb +18 -17
- data/plugins/groups/groups_renderer.rb +29 -25
- data/plugins/os/os_inspector.rb +120 -118
- data/plugins/os/os_model.rb +139 -134
- data/plugins/os/os_renderer.rb +13 -9
- data/plugins/packages/packages_inspector.rb +99 -86
- data/plugins/packages/packages_model.rb +35 -34
- data/plugins/packages/packages_renderer.rb +47 -39
- data/plugins/patterns/patterns_inspector.rb +70 -68
- data/plugins/patterns/patterns_model.rb +19 -18
- data/plugins/patterns/patterns_renderer.rb +36 -32
- data/plugins/repositories/repositories_inspector.rb +162 -156
- data/plugins/repositories/repositories_model.rb +50 -49
- data/plugins/repositories/repositories_renderer.rb +48 -44
- data/plugins/repositories/schema/system-description-repositories.schema-v10.json +0 -1
- data/plugins/services/services_inspector.rb +187 -176
- data/plugins/services/services_model.rb +37 -36
- data/plugins/services/services_renderer.rb +28 -24
- data/plugins/unmanaged_files/unmanaged_files_inspector.rb +102 -99
- data/plugins/unmanaged_files/unmanaged_files_model.rb +64 -56
- data/plugins/unmanaged_files/unmanaged_files_renderer.rb +44 -40
- data/plugins/users/users_inspector.rb +67 -65
- data/plugins/users/users_model.rb +37 -36
- data/plugins/users/users_renderer.rb +31 -27
- data/schema/migrations/migrate1to2.rb +1 -1
- data/schema/migrations/migrate2to3.rb +1 -1
- data/schema/migrations/migrate3to4.rb +1 -1
- data/schema/migrations/migrate4to5.rb +1 -1
- data/schema/migrations/migrate5to6.rb +1 -1
- data/schema/migrations/migrate6to7.rb +1 -1
- data/schema/migrations/migrate7to8.rb +1 -1
- data/schema/migrations/migrate8to9.rb +1 -1
- data/schema/migrations/migrate9to10.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: da0041ff3a8d3c178063228340914aca550a308f
|
|
4
|
+
data.tar.gz: e333966071f57a102961d8de5eb57f47d0cea5a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 99fa10a1ff34c692d35638a5aaef0b411456e3f183ee822b4d803a1366b65ad7cc52b1be636e6df78ce4914bfbca17201efa7954f09efe0ab1f13dfbcff1a846
|
|
7
|
+
data.tar.gz: f612d4f45396600d41b6b579077bd85bce57768386b109a2bf549f25c8818e9ec48c8d8138ac1dec35ecfd31027464e4179ac0319129d7e74c43e622c674680f
|
data/.git_revision
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
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(
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
result << "#{e.stdout}\n\n"
|
|
128
|
-
end
|
|
90
|
+
def self.handle_error(e)
|
|
91
|
+
Machinery::Ui.kill_pager
|
|
129
92
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
138
|
-
|
|
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.
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
" uses the image name as description name if the
|
|
152
|
-
" provided.\nIf the image name contains
|
|
153
|
-
"
|
|
154
|
-
"
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
175
|
+
on_error do |e|
|
|
176
|
+
Cli.handle_error(e)
|
|
177
|
+
end
|
|
162
178
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
178
|
-
|
|
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
|
|
182
|
-
"
|
|
183
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
"
|
|
235
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
"
|
|
245
|
-
|
|
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
|
-
|
|
250
|
-
|
|
289
|
+
AVAILABLE_SCOPE_LIST = Machinery::Ui.internal_scope_list_to_string(
|
|
290
|
+
Inspector.all_scopes
|
|
291
|
+
)
|
|
251
292
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
end
|
|
256
|
-
end
|
|
293
|
+
desc "Analyze system description"
|
|
294
|
+
long_desc <<-LONGDESC
|
|
295
|
+
Analyze stored system description.
|
|
257
296
|
|
|
258
|
-
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
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
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
-
|
|
361
|
-
|
|
371
|
+
Multiple scopes can be passed as comma-separated list. If no
|
|
372
|
+
specific scopes are given, all scopes are compared.
|
|
362
373
|
|
|
363
|
-
|
|
364
|
-
|
|
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
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|
-
|
|
394
|
-
|
|
395
|
-
|
|
437
|
+
desc "Copy system description"
|
|
438
|
+
long_desc <<-LONGDESC
|
|
439
|
+
Copy a system description.
|
|
396
440
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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:
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
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
|
-
|
|
463
|
-
|
|
464
|
-
|
|
524
|
+
desc "Export system description as KIWI image description"
|
|
525
|
+
long_desc <<-LONGDESC
|
|
526
|
+
Export system description as KIWI image description.
|
|
465
527
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
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
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
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
|
-
|
|
568
|
-
|
|
569
|
-
|
|
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
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
594
|
-
|
|
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
|
-
|
|
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
|
-
|
|
607
|
-
|
|
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
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
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
|
-
|
|
709
|
+
filter = FilterOptionParser.parse("inspect", options)
|
|
651
710
|
|
|
652
|
-
if
|
|
653
|
-
|
|
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
|
-
|
|
659
|
-
|
|
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
|
-
|
|
664
|
-
|
|
722
|
+
desc "Inspect running system"
|
|
723
|
+
long_desc <<-LONGDESC
|
|
724
|
+
Inspect running system and generate system descripton from inspected data.
|
|
665
725
|
|
|
666
|
-
|
|
667
|
-
|
|
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
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
778
|
+
Ui::Hint.print(:show_data, name: name) if options[:show] == false
|
|
698
779
|
|
|
699
|
-
|
|
700
|
-
|
|
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
|
-
|
|
706
|
-
|
|
707
|
-
|
|
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
|
-
|
|
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
|
-
|
|
712
|
-
|
|
713
|
-
LONGDESC
|
|
714
|
-
arg "NAME", [:multiple, :optional]
|
|
807
|
+
name, scope_list, inspect_options, filter =
|
|
808
|
+
parse_inspect_command_options(image, options)
|
|
715
809
|
|
|
716
|
-
|
|
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
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
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
|
-
|
|
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
|
-
|
|
740
|
-
|
|
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
|
-
|
|
745
|
-
|
|
746
|
-
|
|
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
|
-
|
|
749
|
-
|
|
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
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
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
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
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
|
-
|
|
767
|
-
|
|
768
|
-
|
|
889
|
+
desc "Shows man page"
|
|
890
|
+
long_desc <<-LONGDESC
|
|
891
|
+
Shows the man page of the machinery tool.
|
|
769
892
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
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
|
-
|
|
786
|
-
|
|
787
|
-
|
|
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
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
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
|
-
|
|
830
|
-
|
|
831
|
-
|
|
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
|
-
|
|
949
|
+
desc "Show system description"
|
|
950
|
+
long_desc <<-LONGDESC
|
|
951
|
+
Show system description stored under the specified name.
|
|
840
952
|
|
|
841
|
-
|
|
842
|
-
|
|
953
|
+
Multiple scopes can be passed as comma-separated list. If no specific
|
|
954
|
+
scopes are given, all scopes are shown.
|
|
843
955
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
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
|
-
|
|
849
|
-
|
|
850
|
-
|
|
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
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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
|
-
|
|
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
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
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
|
-
|
|
885
|
-
|
|
1066
|
+
task = ValidateTask.new
|
|
1067
|
+
task.validate(system_description_store, name)
|
|
1068
|
+
end
|
|
886
1069
|
end
|
|
887
|
-
end
|
|
888
1070
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
name,
|
|
907
|
-
|
|
908
|
-
|
|
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
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1100
|
+
desc "Show or change machinery's configuration"
|
|
1101
|
+
long_desc <<-LONGDESC
|
|
1102
|
+
Show or change machinery's configuration.
|
|
916
1103
|
|
|
917
|
-
|
|
918
|
-
|
|
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
|
-
|
|
1108
|
+
ALTERNATIVE SYNOPSIS:
|
|
921
1109
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
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
|
|
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
|
-
|
|
940
|
-
|
|
1128
|
+
task = ConfigTask.new(@config)
|
|
1129
|
+
task.config(key, value)
|
|
941
1130
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
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
|
-
|
|
980
|
-
desc "Containerize a system description"
|
|
1138
|
+
desc "Start a web server for viewing system descriptions"
|
|
981
1139
|
long_desc <<-LONGDESC
|
|
982
|
-
|
|
983
|
-
|
|
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
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
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
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
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
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
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
|