machinery-tool 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +674 -0
  3. data/NEWS +143 -0
  4. data/bin/machinery +29 -0
  5. data/helpers/changed_managed_files.sh +32 -0
  6. data/helpers/filter-packages-for-build.yaml +6 -0
  7. data/html/assets/arrow_down.png +0 -0
  8. data/html/assets/arrow_up.png +0 -0
  9. data/html/assets/bootstrap-popover.js +113 -0
  10. data/html/assets/bootstrap-tooltip.js +457 -0
  11. data/html/assets/bootstrap.min.css +5 -0
  12. data/html/assets/collapse.js +174 -0
  13. data/html/assets/hogan-3.0.2.min.mustache.js +5 -0
  14. data/html/assets/jquery-2.1.1.min.js +4 -0
  15. data/html/assets/logo-changed-managed-files-small.png +0 -0
  16. data/html/assets/logo-changed-managed-files.png +0 -0
  17. data/html/assets/logo-config-files-small.png +0 -0
  18. data/html/assets/logo-config-files.png +0 -0
  19. data/html/assets/logo-groups-small.png +0 -0
  20. data/html/assets/logo-groups.png +0 -0
  21. data/html/assets/logo-os-small.png +0 -0
  22. data/html/assets/logo-os.png +0 -0
  23. data/html/assets/logo-packages-small.png +0 -0
  24. data/html/assets/logo-packages.png +0 -0
  25. data/html/assets/logo-patterns-small.png +0 -0
  26. data/html/assets/logo-patterns.png +0 -0
  27. data/html/assets/logo-repositories-small.png +0 -0
  28. data/html/assets/logo-repositories.png +0 -0
  29. data/html/assets/logo-services-small.png +0 -0
  30. data/html/assets/logo-services.png +0 -0
  31. data/html/assets/logo-unmanaged-files-small.png +0 -0
  32. data/html/assets/logo-unmanaged-files.png +0 -0
  33. data/html/assets/logo-users-small.png +0 -0
  34. data/html/assets/logo-users.png +0 -0
  35. data/html/assets/machinery-base.css +5767 -0
  36. data/html/assets/machinery.css +131 -0
  37. data/html/assets/machinery.js +148 -0
  38. data/html/assets/transition.js +59 -0
  39. data/html/assets/wheels_horizontal.png +0 -0
  40. data/html/index.html.haml +468 -0
  41. data/kiwi_helpers/kiwi_export_readme.md +22 -0
  42. data/kiwi_helpers/merge_users_and_groups.pl.erb +231 -0
  43. data/kiwi_helpers/unmanaged_files_build_excludes +5 -0
  44. data/lib/analyze_config_file_diffs_task.rb +130 -0
  45. data/lib/array.rb +98 -0
  46. data/lib/build_task.rb +124 -0
  47. data/lib/changed_rpm_files_helper.rb +96 -0
  48. data/lib/cli.rb +600 -0
  49. data/lib/compare_task.rb +68 -0
  50. data/lib/config.rb +33 -0
  51. data/lib/config_base.rb +117 -0
  52. data/lib/config_task.rb +56 -0
  53. data/lib/constants.rb +24 -0
  54. data/lib/copy_task.rb +22 -0
  55. data/lib/current_user.rb +23 -0
  56. data/lib/deploy_task.rb +89 -0
  57. data/lib/exceptions.rb +113 -0
  58. data/lib/generate_html_task.rb +22 -0
  59. data/lib/helper.rb +22 -0
  60. data/lib/hint.rb +39 -0
  61. data/lib/html.rb +103 -0
  62. data/lib/inspect_task.rb +93 -0
  63. data/lib/inspector.rb +65 -0
  64. data/lib/kiwi_config.rb +356 -0
  65. data/lib/kiwi_export_task.rb +36 -0
  66. data/lib/list_task.rb +64 -0
  67. data/lib/local_system.rb +127 -0
  68. data/lib/logged_cheetah.rb +25 -0
  69. data/lib/machinery.rb +85 -0
  70. data/lib/machinery_logger.rb +47 -0
  71. data/lib/migration.rb +128 -0
  72. data/lib/mountpoints.rb +72 -0
  73. data/lib/object.rb +138 -0
  74. data/lib/os.rb +78 -0
  75. data/lib/remote_system.rb +114 -0
  76. data/lib/remove_task.rb +43 -0
  77. data/lib/renderer.rb +243 -0
  78. data/lib/renderer_helper.rb +26 -0
  79. data/lib/rpm.rb +52 -0
  80. data/lib/scope_mixin.rb +38 -0
  81. data/lib/show_task.rb +65 -0
  82. data/lib/system.rb +81 -0
  83. data/lib/system_description.rb +228 -0
  84. data/lib/system_description_store.rb +167 -0
  85. data/lib/system_description_validator.rb +216 -0
  86. data/lib/tarball.rb +82 -0
  87. data/lib/ui.rb +74 -0
  88. data/lib/upgrade_format_task.rb +55 -0
  89. data/lib/validate_task.rb +23 -0
  90. data/lib/version.rb +22 -0
  91. data/lib/zypper.rb +70 -0
  92. data/man/generated/machinery.1.gz +0 -0
  93. data/man/generated/machinery.1.html +1056 -0
  94. data/plugins/docs/changed_managed_files.md +2 -0
  95. data/plugins/docs/config_files.md +5 -0
  96. data/plugins/docs/groups.md +2 -0
  97. data/plugins/docs/os.md +2 -0
  98. data/plugins/docs/packages.md +2 -0
  99. data/plugins/docs/patterns.md +5 -0
  100. data/plugins/docs/repositories.md +24 -0
  101. data/plugins/docs/services.md +6 -0
  102. data/plugins/docs/unmanaged_files.md +13 -0
  103. data/plugins/docs/users.md +3 -0
  104. data/plugins/inspect/changed_managed_files_inspector.rb +109 -0
  105. data/plugins/inspect/config_files_inspector.rb +117 -0
  106. data/plugins/inspect/groups_inspector.rb +46 -0
  107. data/plugins/inspect/os_inspector.rb +116 -0
  108. data/plugins/inspect/packages_inspector.rb +46 -0
  109. data/plugins/inspect/patterns_inspector.rb +67 -0
  110. data/plugins/inspect/repositories_inspector.rb +107 -0
  111. data/plugins/inspect/services_inspector.rb +88 -0
  112. data/plugins/inspect/unmanaged_files_inspector.rb +393 -0
  113. data/plugins/inspect/users_inspector.rb +87 -0
  114. data/plugins/model/changed_managed_files_model.rb +29 -0
  115. data/plugins/model/config_files_model.rb +29 -0
  116. data/plugins/model/groups_model.rb +26 -0
  117. data/plugins/model/os_model.rb +20 -0
  118. data/plugins/model/packages_model.rb +26 -0
  119. data/plugins/model/patterns_model.rb +26 -0
  120. data/plugins/model/repositories_model.rb +26 -0
  121. data/plugins/model/services_model.rb +48 -0
  122. data/plugins/model/unmanaged_files_model.rb +29 -0
  123. data/plugins/model/users_model.rb +26 -0
  124. data/plugins/schema/v1/system-description-changed-managed-files.schema.json +83 -0
  125. data/plugins/schema/v1/system-description-config-files.schema.json +83 -0
  126. data/plugins/schema/v1/system-description-groups.schema.json +30 -0
  127. data/plugins/schema/v1/system-description-os.schema.json +21 -0
  128. data/plugins/schema/v1/system-description-packages.schema.json +34 -0
  129. data/plugins/schema/v1/system-description-patterns.schema.json +24 -0
  130. data/plugins/schema/v1/system-description-repositories.schema.json +41 -0
  131. data/plugins/schema/v1/system-description-services.schema.json +30 -0
  132. data/plugins/schema/v1/system-description-unmanaged-files.schema.json +105 -0
  133. data/plugins/schema/v1/system-description-users.schema.json +61 -0
  134. data/plugins/schema/v2/system-description-changed-managed-files.schema.json +92 -0
  135. data/plugins/schema/v2/system-description-config-files.schema.json +92 -0
  136. data/plugins/schema/v2/system-description-groups.schema.json +30 -0
  137. data/plugins/schema/v2/system-description-os.schema.json +21 -0
  138. data/plugins/schema/v2/system-description-packages.schema.json +34 -0
  139. data/plugins/schema/v2/system-description-patterns.schema.json +24 -0
  140. data/plugins/schema/v2/system-description-repositories.schema.json +41 -0
  141. data/plugins/schema/v2/system-description-services.schema.json +30 -0
  142. data/plugins/schema/v2/system-description-unmanaged-files.schema.json +138 -0
  143. data/plugins/schema/v2/system-description-users.schema.json +61 -0
  144. data/plugins/show/changed_managed_files_renderer.rb +46 -0
  145. data/plugins/show/config_files_renderer.rb +62 -0
  146. data/plugins/show/groups_renderer.rb +36 -0
  147. data/plugins/show/os_renderer.rb +31 -0
  148. data/plugins/show/packages_renderer.rb +32 -0
  149. data/plugins/show/patterns_renderer.rb +32 -0
  150. data/plugins/show/repositories_renderer.rb +38 -0
  151. data/plugins/show/services_renderer.rb +32 -0
  152. data/plugins/show/unmanaged_files_renderer.rb +42 -0
  153. data/plugins/show/users_renderer.rb +35 -0
  154. data/schema/migrations/migrate1to2.rb +56 -0
  155. data/schema/v1/system-description-global.schema.json +31 -0
  156. data/schema/v2/system-description-global.schema.json +31 -0
  157. metadata +370 -0
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class KiwiExportTask
19
+ def export(description, kiwi_dir, options)
20
+ if File.exists?(kiwi_dir)
21
+ if options[:force]
22
+ FileUtils.rm_r(kiwi_dir)
23
+ else
24
+ raise Machinery::Errors::KiwiExportFailed.new(
25
+ "The output directory '#{kiwi_dir}' already exists." \
26
+ " You can force overwriting it with the '--force' option."
27
+ )
28
+ end
29
+ end
30
+
31
+ FileUtils.mkdir_p(kiwi_dir) unless Dir.exists?(kiwi_dir)
32
+
33
+ config = KiwiConfig.new(description)
34
+ config.write(kiwi_dir)
35
+ end
36
+ end
data/lib/list_task.rb ADDED
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class ListTask
19
+ def list(store, options = {})
20
+ descriptions = store.list.sort
21
+
22
+ descriptions.each do |name|
23
+ name = File.basename(name)
24
+ begin
25
+ description = store.load(name)
26
+ rescue Machinery::Errors::SystemDescriptionError
27
+ Machinery::Ui.puts " #{name}:\n"
28
+ Machinery::Ui.puts " This description has an incompatible data format or is broken.\n" \
29
+ " Use `#{$0} validate #{name}` to see the error message.\n\n"
30
+ next
31
+ end
32
+ scopes = []
33
+
34
+ description.scopes.each do |scope|
35
+ entry = Machinery::Ui.internal_scope_list_to_string(scope)
36
+ if SystemDescription::EXTRACTABLE_SCOPES.include?(scope)
37
+ if description.scope_extracted?(scope)
38
+ entry += " (extracted)"
39
+ else
40
+ entry += " (not extracted)"
41
+ end
42
+ end
43
+
44
+ if options["verbose"]
45
+ meta = description[scope].meta
46
+ if meta
47
+ time = Time.parse(meta.modified).getlocal
48
+ date = time.strftime "%Y-%m-%d %H:%M:%S"
49
+ hostname = meta.hostname
50
+ else
51
+ date = "unknown"
52
+ hostname = "Unknown hostname"
53
+ end
54
+ entry += "\n Host: [#{hostname}]"
55
+ entry += "\n Date: (#{date})"
56
+ end
57
+
58
+ scopes << entry
59
+ end
60
+
61
+ Machinery::Ui.puts " #{name}:\n * " + scopes .join("\n * ") + "\n\n"
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,127 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class LocalSystem < System
19
+ class <<self
20
+ def os_object
21
+ description = SystemDescription.new("localhost")
22
+ inspector = OsInspector.new
23
+ inspector.inspect(System.for("localhost"), description)
24
+ description.os_object
25
+ end
26
+
27
+ def validate_existence_of_package(package)
28
+ begin
29
+ Cheetah.run("rpm", "-q", package)
30
+ rescue
31
+ needed_module = os_object.module_required_by_package(package)
32
+ if needed_module
33
+ raise(Machinery::Errors::MissingRequirement.new("You need the package '#{package}' from module '#{needed_module}'. You can install it as follows:\n" \
34
+ "If you haven't selected the module '#{needed_module}' before, run `yast2 scc` and choose 'Select Extensions' and activate '#{needed_module}'.\nRun `zypper install #{package}` to install the package."))
35
+ else
36
+ raise(Machinery::Errors::MissingRequirement.new("You need the package '#{package}'. You can install it by running `zypper install #{package}`"))
37
+ end
38
+ end
39
+ end
40
+
41
+ def validate_machinery_compatibility
42
+ begin
43
+ os = os_object
44
+ rescue Machinery::Errors::SystemDescriptionError
45
+ os = nil
46
+ end
47
+
48
+ if !os || !os.can_run_machinery?
49
+ message = "Running Machinery is not supported on this system.\n" \
50
+ "Check the 'Installation' section in the README.md for more information " \
51
+ "about the requirements."
52
+
53
+ raise(Machinery::Errors::IncompatibleHost.new(message))
54
+ end
55
+ end
56
+
57
+ def validate_build_compatibility(system_description)
58
+ if !os_object.can_build?(system_description.os_object)
59
+ message = "Building '#{system_description.os_object.name}' images is " \
60
+ "not supported on this distribution.\n" \
61
+ "Check the 'BUILD SUPPORT MATRIX' section in our man page for " \
62
+ "further information which build targets are supported."
63
+
64
+ raise(Machinery::Errors::BuildFailed.new(message))
65
+ end
66
+ end
67
+ end
68
+
69
+ def requires_root?
70
+ true
71
+ end
72
+
73
+ def run_command(*args)
74
+ if args.last.is_a?(Hash) && args.last[:disable_logging]
75
+ cheetah_class = Cheetah
76
+ else
77
+ cheetah_class = LoggedCheetah
78
+ end
79
+ with_c_locale do
80
+ cheetah_class.run(*args)
81
+ end
82
+ end
83
+
84
+ # Retrieves files specified in filelist from the local system and raises an
85
+ # Machinery::Errors::RsyncFailed exception when it's not successful. Destination is
86
+ # the directory where to put the files.
87
+ def retrieve_files(filelist, destination)
88
+ begin
89
+ LoggedCheetah.run("rsync", "--chmod=go-rwx", "--files-from=-", "/", destination, :stdout => :capture, :stdin => filelist.join("\n") )
90
+ rescue Cheetah::ExecutionFailed => e
91
+ raise Machinery::Errors::RsyncFailed.new(
92
+ "Could not rsync files from localhost. \n" \
93
+ "Error: #{e}\n" \
94
+ "If you lack read permissions on some files you may want to retry as user root or specify\n" \
95
+ "the fully qualified host name instead of localhost in order to connect as root via ssh."
96
+ )
97
+ end
98
+ end
99
+
100
+ # Reads a file from the System. Returns nil if it does not exist.
101
+ def read_file(file)
102
+ File.read(file)
103
+ rescue Errno::ENOENT
104
+ # File not found, return nil
105
+ return
106
+ end
107
+
108
+ private
109
+
110
+ def with_c_locale(&block)
111
+ with_env "LC_ALL" => "C", &block
112
+ end
113
+
114
+ def with_env(env)
115
+ # ENV isn't a Hash, but a weird Hash-like object. Calling #to_hash on it
116
+ # will copy its items into a newly created Hash instance. This approach
117
+ # ensures that any modifications of ENV won't affect the stored value.
118
+ saved_env = ENV.to_hash
119
+ begin
120
+ ENV.replace(saved_env.merge(env))
121
+ yield
122
+ ensure
123
+ ENV.replace(saved_env)
124
+ end
125
+ end
126
+
127
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class LoggedCheetah
19
+ def self.run(*args)
20
+ command = args.select{|e| e.is_a?(String)}.join(" ")
21
+ Machinery.logger.info("Running '#{command}'")
22
+
23
+ Cheetah.run(*args)
24
+ end
25
+ end
data/lib/machinery.rb ADDED
@@ -0,0 +1,85 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ require 'ostruct'
19
+ require 'json'
20
+ require "abstract_method"
21
+ require "cheetah"
22
+ require "tmpdir"
23
+ require 'tempfile'
24
+ require "time"
25
+ require "logger"
26
+ require "erb"
27
+ require "yaml"
28
+ require "uri"
29
+ require "gli"
30
+ require "json-schema"
31
+ require "haml"
32
+ require "kramdown"
33
+
34
+ require_relative 'machinery_logger'
35
+ require_relative 'zypper'
36
+ require_relative 'rpm'
37
+ require_relative 'array'
38
+ require_relative 'object'
39
+ require_relative 'constants'
40
+ require_relative 'system_description'
41
+ require_relative 'system_description_validator'
42
+ require_relative 'version'
43
+ require_relative 'tarball'
44
+ require_relative 'exceptions'
45
+ require_relative 'inspector'
46
+ require_relative 'system'
47
+ require_relative 'local_system'
48
+ require_relative 'remote_system'
49
+ require_relative 'current_user'
50
+ require_relative 'inspect_task'
51
+ require_relative 'inspector'
52
+ require_relative 'build_task'
53
+ require_relative 'kiwi_config'
54
+ require_relative 'renderer'
55
+ require_relative 'show_task'
56
+ require_relative 'compare_task'
57
+ require_relative 'remove_task'
58
+ require_relative 'list_task'
59
+ require_relative 'system_description_store'
60
+ require_relative 'logged_cheetah'
61
+ require_relative 'renderer_helper'
62
+ require_relative 'changed_rpm_files_helper'
63
+ require_relative 'kiwi_export_task'
64
+ require_relative 'helper'
65
+ require_relative 'deploy_task'
66
+ require_relative 'analyze_config_file_diffs_task'
67
+ require_relative 'copy_task'
68
+ require_relative 'scope_mixin'
69
+ require_relative 'os'
70
+ require_relative 'ui'
71
+ require_relative 'validate_task'
72
+ require_relative 'migration'
73
+ require_relative 'upgrade_format_task'
74
+ require_relative 'html'
75
+ require_relative 'generate_html_task'
76
+ require_relative 'hint'
77
+ require_relative 'mountpoints'
78
+ require_relative 'config_base'
79
+ require_relative 'config'
80
+ require_relative 'config_task'
81
+
82
+ Dir[File.join(Machinery::ROOT, "plugins", "**", "*.rb")].each { |f| require(f) }
83
+
84
+ # this file needs be loaded last, because it immediately collects the loaded inspectors
85
+ require_relative 'cli'
@@ -0,0 +1,47 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ module Machinery
19
+ @@logger = nil
20
+
21
+ def self.initialize_logger(log_file)
22
+ # We rotate one old log file of 21 MB
23
+ if File.exists?(log_file) && File.size(log_file) > 21*1024*1024
24
+ rotated_file = log_file + ".0"
25
+ FileUtils.rm(rotated_file) if File.exists?(rotated_file)
26
+ FileUtils.mv(log_file, rotated_file)
27
+ end
28
+
29
+ if !File.exists?(log_file)
30
+ dirname = File.dirname(log_file)
31
+ if !Dir.exists?(dirname)
32
+ FileUtils.mkdir_p(dirname)
33
+ File.chmod(0700, dirname)
34
+ end
35
+ FileUtils.touch(log_file)
36
+ FileUtils.chmod(0600, log_file)
37
+ end
38
+
39
+ @@logger = Logger.new(log_file)
40
+ end
41
+
42
+ def self.logger
43
+ initialize_logger(DEFAULT_LOG_FILE) unless @@logger
44
+
45
+ @@logger
46
+ end
47
+ end
data/lib/migration.rb ADDED
@@ -0,0 +1,128 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ # = SystemDescription Migrations
19
+ #
20
+ # Migrations are used for migrating descriptions with an older format version to
21
+ # the current version. They are defined as subclasses of `Migration` in
22
+ # `schema/migrations`.
23
+ #
24
+ # == Naming schema
25
+ #
26
+ # Migrations need to follow a naming schema defining which format version they
27
+ # are working on. `Migrate1To2` defines a migration which converts a version 1
28
+ # description to a version 2 one, for example.
29
+ #
30
+ # == Defining migrations
31
+ #
32
+ # The migration classes need to define a `migrate` method which does the actual
33
+ # migration. The raw hash of the system description in question is made
34
+ # available as the `@hash` instance variable, the path to the description on
35
+ # disk is given ash the `@path` instance variable.
36
+ #
37
+ # Migrations also need to describe their purpose using the `desc` class method
38
+ # (see example below).
39
+ #
40
+ # *Note*: Migrations do not need to take care of updating the format version
41
+ # attribute in the system description. That is already handled by the base
42
+ # class.
43
+ #
44
+ # Simple example migration which adds a new attribute to the JSON:
45
+ #
46
+ # class Migrate1To2 < Migration
47
+ # desc <<-EOT
48
+ # Add 'foo' element to the system description root.
49
+ # EOT
50
+ #
51
+ # def migrate
52
+ # is_extracted = Dir.exists?(File.join(@path, "config-files"))
53
+ # @hash["config_files"]["extracted"] = is_extracted
54
+ # end
55
+ # end
56
+ class Migration
57
+ MIGRATIONS_DIR= File.join(Machinery::ROOT, "schema/migrations")
58
+
59
+ class <<self
60
+ attr_reader :migration_desc
61
+
62
+ def desc(s)
63
+ @migration_desc = s
64
+ end
65
+
66
+ def migrate_description(store, description_name)
67
+ load_migrations
68
+
69
+ hash = JSON.parse(store.load_json(description_name))
70
+ path = store.description_path(description_name)
71
+
72
+ current_version = hash["meta"]["format_version"]
73
+ if !current_version
74
+ raise Machinery::Errors::SystemDescriptionError.new(
75
+ "The system description '#{description_name}' was generated by an old " \
76
+ "version of machinery that is not supported by the upgrade mechanism."
77
+ )
78
+ end
79
+
80
+ if current_version == SystemDescription::CURRENT_FORMAT_VERSION
81
+ # Nothing to do here
82
+ return false
83
+ end
84
+
85
+ (current_version..SystemDescription::CURRENT_FORMAT_VERSION-1).each do |version|
86
+ next_version = version + 1
87
+ begin
88
+ klass = Object.const_get("Migrate#{version}To#{next_version}")
89
+ rescue NameError
90
+ return
91
+ end
92
+
93
+ # Make sure that the migration was documented
94
+ if klass.migration_desc.nil?
95
+ raise Machinery::Errors::MigrationError.new(
96
+ "Invalid migration '#{klass}'. It does not specify its purpose using" \
97
+ " the 'desc' class method."
98
+ )
99
+ end
100
+
101
+ klass.new(hash, path).migrate
102
+ hash["meta"]["format_version"] = next_version
103
+ end
104
+
105
+ File.write(store.manifest_path(description_name), JSON.pretty_generate(hash))
106
+
107
+ true
108
+ end
109
+
110
+ private
111
+
112
+ def load_migrations
113
+ Dir.glob(File.join(MIGRATIONS_DIR, "*")).each do |migration|
114
+ require migration
115
+ end
116
+ end
117
+ end
118
+
119
+ attr_accessor :hash
120
+ attr_accessor :path
121
+
122
+ abstract_method :migrate
123
+
124
+ def initialize(hash, path)
125
+ @hash = hash
126
+ @path = path
127
+ end
128
+ end