From e43ce3d3c4f1f7bc62870a1657f8253f8a5bac00 Mon Sep 17 00:00:00 2001 From: guangyee Date: Tue, 2 Mar 2021 07:28:09 +0100 Subject: [PATCH] Add package mapping capability If a given package/pattern in the source machine had been renamed/splitted/removed in the target machine, we need a way to map those packages/patterns into the new packages/patterns. This functionality is expecially helpful for cross-OS migration (i.e. CentOS to openSUSE). --- export_helpers/salt_package_map.sample | 37 +++++++++ lib/salt_states.rb | 100 +++++++++++++++++-------- 2 files changed, 107 insertions(+), 30 deletions(-) create mode 100644 export_helpers/salt_package_map.sample diff --git a/export_helpers/salt_package_map.sample b/export_helpers/salt_package_map.sample new file mode 100644 index 000000000..d4e3add53 --- /dev/null +++ b/export_helpers/salt_package_map.sample @@ -0,0 +1,37 @@ +# One-to-one package map. Source package version match is optional. If +# specified, the version must match the source package version for the mapping +# to take effect. If source package version is absent, that means it will +# match any version. Likewise, target package version is optional. +# When specified, it will map to a specific target package version. Otherwise, +# it will map to the latest version. +: + version: + packages: + - name: + version: + +# Map a source pattern package. + + version: + pattern: yes + packages: + - name: + version: + pattern: yes + +# One-to-many map. A source package can map to multiple packages and/or +# patterns. +: + version: + packages: + - name: + version: + pattern: yes + - name: + version: + +# A package without mapping means there are no target packages to map there. +# Therefore, it will be excluded from migration. +: + version: + diff --git a/lib/salt_states.rb b/lib/salt_states.rb index dc920ef79..c9c13bb98 100644 --- a/lib/salt_states.rb +++ b/lib/salt_states.rb @@ -37,12 +37,14 @@ def initialize(system_description, options) @system_description = system_description @options = options @group_id_to_name_mapping = {} + @package_map = nil @system_description.assert_scopes( "packages", "os" ) check_existance_of_extracted_files + load_package_map end def write(output_location) @@ -95,6 +97,15 @@ def check_existance_of_extracted_files end end + def load_package_map + package_map_file = File.join( + Machinery::ROOT, "export_helpers/#{@name}_package_map" + ) + if File.file?(package_map_file) + @package_map = YAML.load_file(package_map_file) + end + end + def add_group(name, gid) @group_id_to_name_mapping[gid] = name salt_group = <<~SALT @@ -382,52 +393,81 @@ def managed_file_states(output_location) managed_files_sls end - def add_package(package) + def add_package(name, version, pattern) salt_package = <<~SALT - install-package-#{package.name}: + install-package-#{name}: pkg.installed: - - name: #{package.name} + - name: #{name} SALT - if @options["skip-package-version"] + if pattern + salt_package += " - includes: [pattern]\n" + end + + if @options["skip-package-version"] or version.nil? salt_package + "\n" else - salt_package + " - version: '#{package.version}'\n\n" + salt_package + " - version: '#{version}'\n\n" end end - def add_pattern(pattern) - <<~SALT - install-pattern-#{pattern.name}: - pkg.installed: - - name: pattern:#{pattern.name} - - version: '#{pattern.version}' - - includes: [pattern] + def package_pattern_match?(package_mapping, pattern) + pattern == package_mapping.fetch('pattern', false) + end - SALT + def package_version_match?(package_mapping, version) + !package_mapping.include?('version') or ( + package_mapping['version'] == version) + end + + def package_has_mapping?(name, version, pattern) + if @package_map and @package_map.include?(name) + if @package_map[name] and @package_map[name].is_a?(Hash) + return (package_pattern_match?(@package_map[name], pattern) and + package_version_match?(@package_map[name], version)) + else + return !pattern + end + else + return false + end + end + + def map_package(name, version, pattern) + if package_has_mapping?(name, version, pattern) + if @package_map[name].is_a?(Hash) and + @package_map[name].include?('packages') + packages = [] + @package_map[name]['packages'].each do |package| + packages.append([package['name'], package.fetch('version', nil), + package.fetch('pattern', false)]) + end + return packages + else + # package maps to nothing. This means the package will not be + # migrated. + return [] + end + else + [[name, version, pattern]] + end end def package_states - uniq_packages = [] - packages_sls = "" + packages = [] @system_description&.packages&.each do |package| - # FIXME(gyee): seem like a bug in inspection that it has duplicate - # entries for packages in manifest.json. - next if uniq_packages.include? package.name - - uniq_packages.push(package.name) - packages_sls += add_package(package) + packages += map_package(package.name, package.version, false) + end + @system_description&.patterns&.each do |package| + packages += map_package(package.name, package.version, true) end - uniq_patterns = [] - @system_description&.patterns&.each do |pattern| - # FIXME(gyee): seem like a bug in inspection that it has duplicate - # entries for packages in manifest.json. - next if uniq_patterns.include? pattern.name - - uniq_patterns.push(pattern.name) - packages_sls += add_pattern(pattern) + + packages = packages.uniq + salt_package_states = '' + packages.each do |package| + salt_package_states += add_package(package[0], package[1], package[2]) end - packages_sls + salt_package_states end def add_repo(repo)