machinery-tool 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS +11 -0
  3. data/helpers/changed_managed_files.sh +6 -1
  4. data/html/assets/angular-sanitize.min.js +16 -0
  5. data/html/assets/angular.min.js +251 -0
  6. data/html/assets/compare/machinery-compare.js +36 -0
  7. data/html/assets/compare/machinery.js +53 -0
  8. data/html/assets/machinery.css +30 -1
  9. data/html/assets/show/machinery-show.js +65 -0
  10. data/html/assets/{machinery.js → show/machinery.js} +10 -83
  11. data/html/comparison.html.haml +613 -0
  12. data/html/index.html.haml +353 -414
  13. data/lib/cli.rb +36 -2
  14. data/lib/compare_task.rb +29 -2
  15. data/lib/config.rb +5 -1
  16. data/lib/config_task.rb +4 -1
  17. data/lib/export_task.rb +6 -1
  18. data/{plugins/model → lib}/file_scope.rb +0 -0
  19. data/lib/filter.rb +1 -0
  20. data/lib/filter_option_parser.rb +4 -7
  21. data/lib/helper.rb +12 -0
  22. data/lib/html.rb +25 -2
  23. data/lib/inspect_task.rb +1 -1
  24. data/lib/inspector.rb +21 -1
  25. data/lib/json_validator.rb +7 -6
  26. data/lib/machinery.rb +2 -1
  27. data/lib/manifest.rb +1 -1
  28. data/lib/migration.rb +1 -1
  29. data/lib/remote_system.rb +29 -8
  30. data/lib/{scope_mixin.rb → scope.rb} +1 -1
  31. data/lib/show_task.rb +1 -0
  32. data/lib/system.rb +5 -4
  33. data/lib/system_description.rb +3 -3
  34. data/lib/version.rb +1 -1
  35. data/man/generated/machinery.1.gz +0 -0
  36. data/man/generated/machinery.1.html +38 -36
  37. data/plugins/{docs → changed_managed_files}/changed_managed_files.md +0 -0
  38. data/plugins/{inspect → changed_managed_files}/changed_managed_files_inspector.rb +2 -1
  39. data/plugins/{model → changed_managed_files}/changed_managed_files_model.rb +1 -3
  40. data/plugins/{show → changed_managed_files}/changed_managed_files_renderer.rb +0 -0
  41. data/plugins/{schema/v1/system-description-changed-managed-files.schema.json → changed_managed_files/schema/system-description-changed-managed-files.schema-v1.json} +0 -0
  42. data/plugins/{schema/v2/system-description-changed-managed-files.schema.json → changed_managed_files/schema/system-description-changed-managed-files.schema-v2.json} +0 -0
  43. data/plugins/{schema/v3/system-description-changed-managed-files.schema.json → changed_managed_files/schema/system-description-changed-managed-files.schema-v3.json} +0 -0
  44. data/plugins/{docs → config_files}/config_files.md +0 -0
  45. data/plugins/{inspect → config_files}/config_files_inspector.rb +5 -3
  46. data/plugins/{model → config_files}/config_files_model.rb +1 -3
  47. data/plugins/{show → config_files}/config_files_renderer.rb +0 -0
  48. data/plugins/{schema/v1/system-description-config-files.schema.json → config_files/schema/system-description-config-files.schema-v1.json} +0 -0
  49. data/plugins/{schema/v2/system-description-config-files.schema.json → config_files/schema/system-description-config-files.schema-v2.json} +0 -0
  50. data/plugins/{schema/v3/system-description-config-files.schema.json → config_files/schema/system-description-config-files.schema-v3.json} +0 -0
  51. data/plugins/{docs → groups}/groups.md +0 -0
  52. data/plugins/{inspect → groups}/groups_inspector.rb +2 -0
  53. data/plugins/{model → groups}/groups_model.rb +1 -1
  54. data/plugins/{show → groups}/groups_renderer.rb +0 -0
  55. data/plugins/{schema/v1/system-description-groups.schema.json → groups/schema/system-description-groups.schema-v1.json} +0 -0
  56. data/plugins/{schema/v2/system-description-groups.schema.json → groups/schema/system-description-groups.schema-v2.json} +0 -0
  57. data/plugins/{schema/v3/system-description-groups.schema.json → groups/schema/system-description-groups.schema-v3.json} +0 -0
  58. data/plugins/{docs → os}/os.md +0 -0
  59. data/plugins/{inspect → os}/os_inspector.rb +6 -0
  60. data/plugins/{model → os}/os_model.rb +15 -1
  61. data/plugins/{show → os}/os_renderer.rb +0 -0
  62. data/plugins/{schema/v1/system-description-os.schema.json → os/schema/system-description-os.schema-v1.json} +0 -0
  63. data/plugins/{schema/v2/system-description-os.schema.json → os/schema/system-description-os.schema-v2.json} +0 -0
  64. data/plugins/{schema/v3/system-description-os.schema.json → os/schema/system-description-os.schema-v3.json} +0 -0
  65. data/plugins/{docs → packages}/packages.md +0 -0
  66. data/plugins/{inspect → packages}/packages_inspector.rb +1 -0
  67. data/plugins/{model → packages}/packages_model.rb +1 -1
  68. data/plugins/{show → packages}/packages_renderer.rb +0 -0
  69. data/plugins/{schema/v1/system-description-packages.schema.json → packages/schema/system-description-packages.schema-v1.json} +0 -0
  70. data/plugins/{schema/v2/system-description-packages.schema.json → packages/schema/system-description-packages.schema-v2.json} +0 -0
  71. data/plugins/{schema/v3/system-description-packages.schema.json → packages/schema/system-description-packages.schema-v3.json} +0 -0
  72. data/plugins/{docs → patterns}/patterns.md +0 -0
  73. data/plugins/{inspect → patterns}/patterns_inspector.rb +1 -0
  74. data/plugins/{model → patterns}/patterns_model.rb +1 -1
  75. data/plugins/{show → patterns}/patterns_renderer.rb +0 -0
  76. data/plugins/{schema/v1/system-description-patterns.schema.json → patterns/schema/system-description-patterns.schema-v1.json} +0 -0
  77. data/plugins/{schema/v2/system-description-patterns.schema.json → patterns/schema/system-description-patterns.schema-v2.json} +0 -0
  78. data/plugins/{schema/v3/system-description-patterns.schema.json → patterns/schema/system-description-patterns.schema-v3.json} +0 -0
  79. data/plugins/{docs → repositories}/repositories.md +0 -0
  80. data/plugins/{inspect → repositories}/repositories_inspector.rb +1 -0
  81. data/plugins/{model → repositories}/repositories_model.rb +1 -1
  82. data/plugins/{show → repositories}/repositories_renderer.rb +0 -0
  83. data/plugins/{schema/v1/system-description-repositories.schema.json → repositories/schema/system-description-repositories.schema-v1.json} +0 -0
  84. data/plugins/{schema/v2/system-description-repositories.schema.json → repositories/schema/system-description-repositories.schema-v2.json} +0 -0
  85. data/plugins/{schema/v3/system-description-repositories.schema.json → repositories/schema/system-description-repositories.schema-v3.json} +0 -0
  86. data/plugins/{schema/v1/system-description-services.schema.json → services/schema/system-description-services.schema-v1.json} +0 -0
  87. data/plugins/{schema/v2/system-description-services.schema.json → services/schema/system-description-services.schema-v2.json} +0 -0
  88. data/plugins/{schema/v3/system-description-services.schema.json → services/schema/system-description-services.schema-v3.json} +0 -0
  89. data/plugins/{docs → services}/services.md +0 -0
  90. data/plugins/{inspect → services}/services_inspector.rb +13 -1
  91. data/plugins/{model → services}/services_model.rb +1 -1
  92. data/plugins/{show → services}/services_renderer.rb +0 -0
  93. data/plugins/{schema/v1/system-description-unmanaged-files.schema.json → unmanaged_files/schema/system-description-unmanaged-files.schema-v1.json} +0 -0
  94. data/plugins/{schema/v2/system-description-unmanaged-files.schema.json → unmanaged_files/schema/system-description-unmanaged-files.schema-v2.json} +0 -0
  95. data/plugins/{schema/v3/system-description-unmanaged-files.schema.json → unmanaged_files/schema/system-description-unmanaged-files.schema-v3.json} +6 -0
  96. data/plugins/{docs → unmanaged_files}/unmanaged_files.md +0 -0
  97. data/plugins/{inspect → unmanaged_files}/unmanaged_files_inspector.rb +19 -32
  98. data/plugins/{model → unmanaged_files}/unmanaged_files_model.rb +1 -3
  99. data/plugins/{show → unmanaged_files}/unmanaged_files_renderer.rb +0 -0
  100. data/plugins/{schema/v1/system-description-users.schema.json → users/schema/system-description-users.schema-v1.json} +0 -0
  101. data/plugins/{schema/v2/system-description-users.schema.json → users/schema/system-description-users.schema-v2.json} +0 -0
  102. data/plugins/{schema/v3/system-description-users.schema.json → users/schema/system-description-users.schema-v3.json} +0 -0
  103. data/plugins/{docs → users}/users.md +0 -0
  104. data/plugins/{inspect → users}/users_inspector.rb +2 -0
  105. data/plugins/{model → users}/users_model.rb +1 -1
  106. data/plugins/{show → users}/users_renderer.rb +0 -0
  107. data/schema/{v1/system-description-global.schema.json → system-description-global.schema-v1.json} +0 -0
  108. data/schema/{v2/system-description-global.schema.json → system-description-global.schema-v2.json} +0 -0
  109. data/schema/{v3/system-description-global.schema.json → system-description-global.schema-v3.json} +0 -0
  110. metadata +158 -153
  111. data/html/assets/hogan-3.0.2.min.mustache.js +0 -5
data/lib/cli.rb CHANGED
@@ -56,6 +56,16 @@ class Cli
56
56
 
57
57
  GLI::Commands::Help.skips_post = false
58
58
 
59
+ def self.buildable_distributions
60
+ distribution_string = ""
61
+ Os.supported_host_systems.each do |distribution|
62
+ distribution_string += "* #{distribution.canonical_name}\n\n"
63
+ distribution_string += distribution.buildable_systems.map(&:canonical_name).join(", ")
64
+ distribution_string += "\n\n"
65
+ end
66
+ distribution_string
67
+ end
68
+
59
69
  def self.handle_error(e)
60
70
  case e
61
71
  when GLI::UnknownCommandArgument, GLI::UnknownGlobalArgument,
@@ -116,6 +126,12 @@ class Cli
116
126
  Cli.handle_error(e)
117
127
  end
118
128
 
129
+ def self.show_filter_note(scopes, filter)
130
+ if scopes.any? { |scope| !filter.element_filters_for_scope(scope).empty? }
131
+ Machinery::Ui.puts "\nFilters are applied during inspection.\n\n"
132
+ end
133
+ end
134
+
119
135
  def self.shift_arg(args, name)
120
136
  if !res = args.shift
121
137
  raise GLI::BadCommandLine.new("You need to provide the required argument #{name}.")
@@ -187,7 +203,7 @@ class Cli
187
203
  )
188
204
  end
189
205
 
190
- scopes.uniq
206
+ Inspector.sort_scopes(scopes.uniq)
191
207
  end
192
208
 
193
209
  AVAILABLE_SCOPE_LIST = Machinery::Ui.internal_scope_list_to_string(
@@ -232,6 +248,10 @@ class Cli
232
248
  long_desc <<-LONGDESC
233
249
  Build image from a given system description and store it to the given
234
250
  location.
251
+
252
+ The following combinations of build hosts and targets are supported:
253
+
254
+ #{buildable_distributions}
235
255
  LONGDESC
236
256
  arg "NAME"
237
257
  command :build do |c|
@@ -274,6 +294,10 @@ class Cli
274
294
  desc: "Exclude specified scopes", arg_name: "SCOPE_LIST"
275
295
  c.switch "show-all", required: false, negatable: false,
276
296
  desc: "Show also common properties"
297
+ if @config.experimental_features
298
+ c.switch "html", required: false, negatable: false,
299
+ desc: "Open comparison in HTML format in your web browser."
300
+ end
277
301
  c.switch "pager", required: false, default_value: true,
278
302
  desc: "Pipe output into a pager"
279
303
 
@@ -289,6 +313,7 @@ class Cli
289
313
 
290
314
  task = CompareTask.new
291
315
  opts = {
316
+ show_html: options["html"],
292
317
  show_all: options["show-all"]
293
318
  }
294
319
  task.compare(description1, description2, scope_list, opts)
@@ -427,6 +452,9 @@ class Cli
427
452
  c.flag "skip-files", required: false, negatable: false,
428
453
  desc: "Do not consider given files or directories during inspection. " \
429
454
  "Either provide one file or directory name or a list of names separated by commas."
455
+ c.flag ["remote-user", :r], type: String, required: false, default_value: @config.remote_user,
456
+ desc: "Defines the user which is used to access the inspected system via SSH."\
457
+ "This user needs sudo access on the remote machine or be root.", arg_name: "USER"
430
458
  c.switch ["extract-files", :x], required: false, negatable: false,
431
459
  desc: "Extract changed configuration files and unmanaged files from inspected system"
432
460
  c.switch "extract-changed-config-files", required: false, negatable: false,
@@ -456,6 +484,9 @@ class Cli
456
484
  if options["show"]
457
485
  inspect_options[:show] = true
458
486
  end
487
+ if options["verbose"]
488
+ inspect_options[:verbose] = true
489
+ end
459
490
  if options["extract-files"] || options["extract-changed-config-files"]
460
491
  inspect_options[:extract_changed_config_files] = true
461
492
  end
@@ -465,12 +496,15 @@ class Cli
465
496
  if options["extract-files"] || options["extract-unmanaged-files"]
466
497
  inspect_options[:extract_unmanaged_files] = true
467
498
  end
499
+ inspect_options[:remote_user] = options["remote-user"]
468
500
 
469
501
  filter = FilterOptionParser.parse("inspect", options, global_options)
470
502
 
471
503
  if options["verbose"] && !filter.empty?
472
504
  Machinery::Ui.puts "\nThe following filters are applied during inspection:"
473
505
  Machinery::Ui.puts filter.to_array.join("\n") + "\n\n"
506
+ else
507
+ show_filter_note(scope_list, filter)
474
508
  end
475
509
 
476
510
  inspector_task.inspect_system(
@@ -573,7 +607,7 @@ class Cli
573
607
 
574
608
  inspected_filters = description.filter_definitions("inspect")
575
609
 
576
- if options["verbose"]
610
+ if options[:verbose]
577
611
  if !inspected_filters.empty?
578
612
  Machinery::Ui.puts "\nThe following filters were applied during inspection:"
579
613
  Machinery::Ui.puts inspected_filters.join("\n") + "\n\n"
data/lib/compare_task.rb CHANGED
@@ -17,9 +17,36 @@
17
17
 
18
18
  class CompareTask
19
19
  def compare(description1, description2, scopes, options = {})
20
- output = render_comparison(description1, description2, scopes, options)
20
+ if options[:show_html]
21
+ render_html_comparison(description1, description2, scopes, options)
22
+ else
23
+ output = render_comparison(description1, description2, scopes, options)
21
24
 
22
- Machinery::Ui.puts output
25
+ Machinery::Ui.puts output
26
+ end
27
+ end
28
+
29
+ def render_html_comparison(description1, description2, scopes, options)
30
+ diff = {
31
+ meta: {
32
+ description_a: description1.name,
33
+ description_b: description2.name,
34
+ }
35
+ }
36
+
37
+ scopes.each do |scope|
38
+ if description1[scope] && description2[scope]
39
+ comparison = description1[scope].compare_with(description2[scope])
40
+ diff[scope] = comparison.map { |scope| scope.as_json if scope }
41
+ end
42
+ end
43
+
44
+ target = "/tmp/machinery-html-comparison"
45
+ FileUtils.rm_r(target) if Dir.exists?(target)
46
+ FileUtils.mkdir_p(target)
47
+
48
+ Html.generate_comparison(diff, target)
49
+ LoggedCheetah.run("xdg-open", File.join(target, "index.html"))
23
50
  end
24
51
 
25
52
  def render_comparison(description1, description2, scopes, options = {})
data/lib/config.rb CHANGED
@@ -29,10 +29,14 @@ module Machinery
29
29
  description: "Show hints about usage of Machinery in the context of the commands ran by" \
30
30
  " the user"
31
31
  )
32
+ entry("remote-user",
33
+ default: "root",
34
+ description: "Defines the user which is used to access the inspected system via SSH"
35
+ )
32
36
  entry("experimental-features",
33
37
  default: false,
34
38
  description: "Enable experimental features. See " \
35
- "https://github.com/SUSE/machinery/wiki/Experimental-Features for more details."
39
+ "https://github.com/SUSE/machinery/wiki/Experimental-Features for more details"
36
40
  )
37
41
  end
38
42
  end
data/lib/config_task.rb CHANGED
@@ -45,7 +45,10 @@ class ConfigTask
45
45
  elsif value_string == "false" || value_string == "off"
46
46
  return false
47
47
  else
48
- raise Machinery::Errors::MachineryError.new("The value '#{value_string}' is not valid for key '#{key}'.")
48
+ raise Machinery::Errors::MachineryError.new(
49
+ "The value '#{value_string}' is not valid for key '#{key}'." \
50
+ " Please enter a valid variable of type boolean."
51
+ )
49
52
  end
50
53
  elsif current_value.kind_of?(Integer)
51
54
  return value_string.to_i
data/lib/export_task.rb CHANGED
@@ -36,7 +36,12 @@ class ExportTask
36
36
  end
37
37
  end
38
38
 
39
- FileUtils.mkdir_p(output_dir, mode: 0700) if !Dir.exists?(output_dir)
39
+ begin
40
+ FileUtils.mkdir_p(output_dir, mode: 0700) if !Dir.exists?(output_dir)
41
+ rescue Errno::EACCES
42
+ raise(Machinery::Errors::ExportFailed, \
43
+ "Permission denied. Directory '#{output_dir}' is not writable")
44
+ end
40
45
 
41
46
  if @exporter.system_description["unmanaged_files"]
42
47
  filters = File.read(
File without changes
data/lib/filter.rb CHANGED
@@ -54,6 +54,7 @@ class Filter
54
54
  Array(filter_definitions).each do |definition|
55
55
  path, operator, matcher_definition = definition.scan(/([a-zA-Z_\/]+)(.*=)(.*)/)[0]
56
56
 
57
+ raise Machinery::Errors::InvalidFilter.new("Invalid filter: '#{definition}'") if !operator
57
58
  element_filters[path] ||= ElementFilter.new(path)
58
59
  if matcher_definition.index(",")
59
60
  matchers = matcher_definition.split(/(?<!\\),/)
@@ -38,13 +38,10 @@ class FilterOptionParser
38
38
  def exclude_definitions(exclude)
39
39
  return [] if !exclude
40
40
 
41
- filters = exclude.scan(/(@[^,]+)|\"([^,]+?=[^\"]+)\"|([^,]+=[^=]+)$|([^,]+=[^,]+)/).
42
- map(&:compact).flat_map do |filter_definition|
43
- if filter_definition[0].start_with?("@")
44
- expand_filter_file(filter_definition[0])
45
- else
46
- filter_definition
47
- end
41
+ filters = if exclude.start_with?("@")
42
+ expand_filter_file(exclude)
43
+ else
44
+ [exclude]
48
45
  end
49
46
 
50
47
  filters.reject!(&:empty?) # Ignore empty filters
data/lib/helper.rb CHANGED
@@ -19,6 +19,18 @@ module Machinery
19
19
  def self.is_int?(string)
20
20
  (string =~ /^\d+$/) != nil
21
21
  end
22
+
23
+ # Implementation of String#scrub for Ruby < 2.1. Assumes the string is in
24
+ # UTF-8.
25
+ def self.scrub(s)
26
+ # We have a string in UTF-8 with possible invalid byte sequences. It turns
27
+ # out that String#encode can remove these sequences when given appropriate
28
+ # options, but just converting into UTF-8 would be a no-op. So let's convert
29
+ # into UTF-16 (which has the same character set as UTF-8) and back.
30
+ #
31
+ # See also: http://stackoverflow.com/a/21315619
32
+ s.dup.force_encoding("UTF-8").encode("UTF-16", invalid: :replace).encode("UTF-8")
33
+ end
22
34
  end
23
35
 
24
36
  def with_c_locale(&block)
data/lib/html.rb CHANGED
@@ -16,6 +16,10 @@
16
16
  # you may find current contact information at www.suse.com
17
17
 
18
18
  class Html
19
+ def self.escape_javascript(object)
20
+ object.gsub(/([\\'"])/, "\\\\\\1")
21
+ end
22
+
19
23
  def self.generate(description)
20
24
  template = Haml::Engine.new(
21
25
  File.read(File.join(Machinery::ROOT, "html", "index.html.haml"))
@@ -36,7 +40,7 @@ class Html
36
40
 
37
41
  # Generate JSON and escape the 's and "s in order to not break the JSON
38
42
  # string in javascript.
39
- json = description.to_hash.to_json.gsub("'", "\\\\'").gsub("\"", "\\\\\"")
43
+ json = escape_javascript(description.to_hash.to_json)
40
44
  File.write(File.join(target, "assets/description.js"),<<-EOT
41
45
  function getDescription() {
42
46
  return JSON.parse('#{json}'
@@ -47,14 +51,33 @@ class Html
47
51
  target
48
52
  end
49
53
 
54
+ def self.generate_comparison(diff, target)
55
+ FileUtils.mkdir_p(File.join(target, "assets"))
56
+ template = Haml::Engine.new(
57
+ File.read(File.join(Machinery::ROOT, "html", "comparison.html.haml"))
58
+ )
59
+
60
+ FileUtils.cp_r(File.join(Machinery::ROOT, "html", "assets"), target)
61
+ File.write(File.join(target, "index.html"), template.render(binding))
62
+ json = diff.to_json.gsub("'", "\\\\'").gsub("\"", "\\\\\"")
63
+ File.write(File.join(target, "assets/diff.js"),<<-EOT
64
+ function getDiff() {
65
+ return JSON.parse('#{json}'
66
+ )
67
+ }
68
+ EOT
69
+ )
70
+ end
71
+
50
72
  # Template helpers
51
73
 
52
74
  def self.scope_help(scope)
53
- text = File.read(File.join(Machinery::ROOT, "plugins", "docs", "#{scope}.md"))
75
+ text = File.read(File.join(Machinery::ROOT, "plugins", "#{scope}/#{scope}.md"))
54
76
  Kramdown::Document.new(text).to_html
55
77
  end
56
78
 
57
79
  def self.diff_to_object(diff)
80
+ diff = Machinery.scrub(diff)
58
81
  lines = diff.lines[2..-1]
59
82
  diff_object = {
60
83
  file: diff[/--- a(.*)/, 1],
data/lib/inspect_task.rb CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  class InspectTask
19
19
  def inspect_system(store, host, name, current_user, scopes, filter, options = {})
20
- system = System.for(host)
20
+ system = System.for(host, options[:remote_user])
21
21
  check_root(system, current_user)
22
22
 
23
23
  description, failed_inspections = build_description(store, name, system,
data/lib/inspector.rb CHANGED
@@ -38,6 +38,14 @@ class Inspector
38
38
  @inspectors = []
39
39
 
40
40
  class << self
41
+ def priority
42
+ @priority || 1000
43
+ end
44
+
45
+ def has_priority(value)
46
+ @priority = value
47
+ end
48
+
41
49
  def inherited(klass)
42
50
  @inspectors << klass
43
51
  end
@@ -53,7 +61,19 @@ class Inspector
53
61
  end
54
62
 
55
63
  def all_scopes
56
- all.map(&:scope)
64
+ sort_scopes(all.map(&:scope))
65
+ end
66
+
67
+ def sort_scopes(scope_list)
68
+ scope_priority = {}
69
+
70
+ scope_list.each do |scope|
71
+ scope_priority[self.for(scope).priority] = scope
72
+ end
73
+
74
+ scope_priority.sort.map do |key, value|
75
+ scope_priority[key] = value
76
+ end
57
77
  end
58
78
 
59
79
  def scope
@@ -61,22 +61,23 @@ class JsonValidator
61
61
  JSON.parse(File.read(File.join(
62
62
  Machinery::ROOT,
63
63
  "schema",
64
- "v#{format_version}",
65
- "system-description-global.schema.json"
64
+ "system-description-global.schema-v#{format_version}.json"
66
65
  )))
67
66
  end
68
67
 
69
68
  def scope_schemas(format_version = SystemDescription::CURRENT_FORMAT_VERSION)
70
- schema_dir = File.join(
69
+ schema_path = File.join(
71
70
  Machinery::ROOT,
72
71
  "plugins",
72
+ "**",
73
73
  "schema",
74
- "v#{format_version}",
74
+ "*.schema-v#{format_version}.json"
75
75
  )
76
76
 
77
77
  Hash[
78
- Dir["#{schema_dir}/*.schema.json"].map do |file|
79
- scope = file.match(/system-description-(.*)\.schema\.json$/)[1].tr("-", "_")
78
+ Dir[schema_path].map do |file|
79
+ scope = file.match(/system-description-(.*)\.schema-v#{format_version}\.json$/)[1].
80
+ tr("-", "_")
80
81
  schema = JSON.parse(File.read(file))
81
82
 
82
83
  [scope, schema]
data/lib/machinery.rb CHANGED
@@ -69,7 +69,7 @@ require_relative "helper"
69
69
  require_relative "deploy_task"
70
70
  require_relative "analyze_config_file_diffs_task"
71
71
  require_relative "copy_task"
72
- require_relative "scope_mixin"
72
+ require_relative "scope"
73
73
  require_relative "ui"
74
74
  require_relative "validate_task"
75
75
  require_relative "migration"
@@ -90,6 +90,7 @@ require_relative "file_validator"
90
90
  require_relative "element_filter"
91
91
  require_relative "filter"
92
92
  require_relative "filter_option_parser"
93
+ require_relative "file_scope"
93
94
 
94
95
  Dir[File.join(Machinery::ROOT, "plugins", "**", "*.rb")].each { |f| require(f) }
95
96
 
data/lib/manifest.rb CHANGED
@@ -46,7 +46,7 @@ class Manifest
46
46
  errors = JsonValidator.new(@hash).validate
47
47
  if !errors.empty?
48
48
  Machinery::Ui.warn("Warning: System Description validation errors:")
49
- Machinery::Ui.warn(errors)
49
+ Machinery::Ui.warn(errors.join("\n"))
50
50
  end
51
51
  end
52
52
 
data/lib/migration.rb CHANGED
@@ -73,7 +73,7 @@ class Migration
73
73
  if !errors.empty?
74
74
  if options[:force]
75
75
  Machinery::Ui.warn("Warning: System Description validation errors:")
76
- Machinery::Ui.warn(errors)
76
+ Machinery::Ui.warn(errors.join(", "))
77
77
  else
78
78
  raise Machinery::Errors::SystemDescriptionValidationFailed.new(errors)
79
79
  end
data/lib/remote_system.rb CHANGED
@@ -17,9 +17,11 @@
17
17
 
18
18
  class RemoteSystem < System
19
19
  attr_accessor :host
20
+ attr_accessor :remote_user
20
21
 
21
- def initialize(host)
22
+ def initialize(host, remote_user = "root")
22
23
  @host = host
24
+ @remote_user = remote_user
23
25
 
24
26
  connect
25
27
  end
@@ -70,19 +72,21 @@ class RemoteSystem < System
70
72
  cheetah_class = LoggedCheetah
71
73
  end
72
74
 
73
- cheetah_class.run("ssh", "root@#{host}", "LC_ALL=C", *piped_args, options)
75
+ sudo = "sudo" if options[:privileged] && remote_user != "root"
76
+ cmds = ["ssh", "#{remote_user}@#{host}", sudo, "LC_ALL=C", *piped_args, options].compact
77
+ cheetah_class.run(*cmds)
74
78
  end
75
79
 
76
80
  # Tries to connect to the remote system as root (without a password or passphrase)
77
81
  # and raises an Machinery::Errors::SshConnectionFailed exception when it's not successful.
78
82
  def connect
79
- LoggedCheetah.run "ssh", "-q", "-o", "BatchMode=yes", "root@#{host}"
83
+ LoggedCheetah.run "ssh", "-q", "-o", "BatchMode=yes", "#{remote_user}@#{host}"
80
84
  rescue Cheetah::ExecutionFailed
81
85
  raise Machinery::Errors::SshConnectionFailed.new(
82
86
  "Could not establish SSH connection to host '#{host}'. Please make sure that " \
83
- "you can connect non-interactively as root, e.g. using ssh-agent.\n\n" \
87
+ "you can connect non-interactively as #{remote_user}, e.g. using ssh-agent.\n\n" \
84
88
  "To copy your default ssh key to the machine run:\n" \
85
- "ssh-copy-id root@#{host}"
89
+ "ssh-copy-id #{remote_user}@#{host}"
86
90
  )
87
91
  end
88
92
 
@@ -91,9 +95,26 @@ class RemoteSystem < System
91
95
  # Machinery::Errors::RsyncFailed exception when it's not successful. Destination is
92
96
  # the directory where to put the files.
93
97
  def retrieve_files(filelist, destination)
94
- source="root@#{host}:/"
98
+ source = "#{remote_user}@#{host}:/"
99
+ if remote_user != "root"
100
+ rsync_path = "sudo rsync"
101
+ else
102
+ rsync_path = "rsync"
103
+ end
104
+
105
+ cmd = [
106
+ "rsync",
107
+ "-e", "ssh",
108
+ "--chmod=go-rwx",
109
+ "--files-from=-",
110
+ "--rsync-path=#{rsync_path}",
111
+ source,
112
+ destination,
113
+ stdout: :capture,
114
+ stdin: filelist.join("\n")
115
+ ]
95
116
  begin
96
- LoggedCheetah.run("rsync", "-e", "ssh", "--chmod=go-rwx", "--files-from=-", source, destination, :stdout => :capture, :stdin => filelist.join("\n") )
117
+ LoggedCheetah.run(*cmd)
97
118
  rescue Cheetah::ExecutionFailed => e
98
119
  raise Machinery::Errors::RsyncFailed.new(
99
120
  "Could not rsync files from host '#{host}'.\n" \
@@ -104,7 +125,7 @@ class RemoteSystem < System
104
125
 
105
126
  # Reads a file from the System. Returns nil if it does not exist.
106
127
  def read_file(file)
107
- run_command("cat", file, stdout: :capture)
128
+ run_command("cat", file, stdout: :capture, privileged: true)
108
129
  rescue Cheetah::ExecutionFailed => e
109
130
  if e.status.exitstatus == 1
110
131
  # File not found, return nil