machinery-tool 1.13.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.git_revision +1 -0
  3. data/NEWS +10 -0
  4. data/bin/machinery +7 -1
  5. data/{helpers → filters}/default_filters.json +0 -0
  6. data/{helpers → filters}/filter-packages-for-build.yaml +0 -0
  7. data/{helpers → inspect_helpers}/changed_files.sh +0 -0
  8. data/{helpers → inspect_helpers}/yum_repositories.py +0 -0
  9. data/lib/cli.rb +136 -52
  10. data/lib/compare_task.rb +1 -1
  11. data/lib/constants.rb +1 -1
  12. data/lib/docker_system.rb +135 -0
  13. data/lib/exceptions.rb +3 -2
  14. data/lib/filter.rb +1 -1
  15. data/lib/hint.rb +8 -2
  16. data/lib/inspect_task.rb +3 -3
  17. data/lib/kiwi_config.rb +2 -2
  18. data/lib/list_task.rb +14 -7
  19. data/lib/local_system.rb +20 -2
  20. data/lib/machinery.rb +2 -0
  21. data/lib/machinery_helper.rb +17 -14
  22. data/lib/move_task.rb +22 -0
  23. data/lib/remote_system.rb +4 -0
  24. data/lib/scope_file_access_archive.rb +10 -0
  25. data/lib/scope_file_access_flat.rb +4 -0
  26. data/lib/show_task.rb +1 -1
  27. data/lib/system.rb +16 -2
  28. data/lib/system_description.rb +19 -9
  29. data/lib/system_description_store.rb +10 -0
  30. data/lib/version.rb +1 -1
  31. data/lib/workload_mapper.rb +2 -1
  32. data/machinery-helper/README.md +13 -0
  33. data/machinery-helper/Rakefile +124 -0
  34. data/machinery-helper/machinery_helper.go +228 -0
  35. data/machinery-helper/machinery_helper_test.go +192 -0
  36. data/machinery-helper/mountpoints.go +81 -0
  37. data/machinery-helper/mountpoints_test.go +74 -0
  38. data/machinery-helper/tar.go +142 -0
  39. data/machinery-helper/version.go +5 -0
  40. data/man/generated/machinery.1.gz +0 -0
  41. data/man/generated/machinery.1.html +43 -6
  42. data/plugins/changed_managed_files/changed_managed_files_inspector.rb +1 -1
  43. data/plugins/config_files/config_files_inspector.rb +1 -1
  44. data/plugins/config_files/config_files_renderer.rb +1 -1
  45. data/plugins/environment/environment_inspector.rb +2 -2
  46. data/plugins/environment/schema/system-description-environment.schema-v5.json +4 -0
  47. data/plugins/os/os_inspector.rb +23 -11
  48. data/plugins/repositories/repositories_inspector.rb +1 -1
  49. data/plugins/services/services_inspector.rb +6 -1
  50. data/plugins/unmanaged_files/unmanaged_files_inspector.rb +35 -30
  51. data/plugins/unmanaged_files/unmanaged_files_model.rb +12 -6
  52. data/workload_mapper/docker-registry/clue.rb +0 -2
  53. data/workload_mapper/docker-registry/compose-template.yml +2 -1
  54. data/workload_mapper/docker-registry/container/Dockerfile +1 -1
  55. data/workload_mapper/mariadb/clue.rb +1 -0
  56. data/workload_mapper/mariadb/compose-template.yml +2 -2
  57. data/workload_mapper/rails/compose-template.yml +0 -1
  58. data/workload_mapper/rails/container/Dockerfile +3 -4
  59. data/workload_mapper/wordpress/clue.rb +13 -0
  60. data/workload_mapper/wordpress/compose-template.yml +5 -0
  61. data/workload_mapper/wordpress/config/wp-config.php +38 -0
  62. data/workload_mapper/wordpress/container/Dockerfile +25 -0
  63. data/workload_mapper/wordpress/container/apache2/listen.conf +1 -0
  64. data/workload_mapper/wordpress/container/apache2/wordpress_vhost.conf +21 -0
  65. data/workload_mapper/wordpress/setup/setup.rb.erb +67 -0
  66. metadata +26 -8
  67. data/helpers/inspector_files.rb +0 -52
data/lib/machinery.rb CHANGED
@@ -107,6 +107,8 @@ require_relative "workload_mapper"
107
107
  require_relative "containerize_task"
108
108
  require_relative "workload_mapper_dsl"
109
109
  require_relative "containerized_app"
110
+ require_relative "move_task"
111
+ require_relative "docker_system"
110
112
 
111
113
  Dir[File.join(Machinery::ROOT, "plugins", "**", "*.rb")].each { |f| require(f) }
112
114
 
@@ -22,45 +22,48 @@
22
22
  # The inspection checks, if a binary helper is available on the machine where
23
23
  # the inspection is started. It looks at the location
24
24
  #
25
- # /usr/share/machinery/helpers/<arch>/machinery-helper
26
- #
27
- # where <arch> is the hardware architecture of the target system. Valid values
28
- # are x86_64, i586, s390x, and ppcle.
25
+ # <machinery-installation-path>/machinery-helper/machinery-helper
29
26
 
30
27
  class MachineryHelper
31
28
  attr_accessor :local_helpers_path
29
+ attr_accessor :remote_helper_path
32
30
 
33
31
  def initialize(s)
34
32
  @system = s
35
33
  @arch = @system.arch
36
34
 
37
- @local_helpers_path = "/usr/share/machinery/helpers"
35
+ @local_helpers_path = File.join(Machinery::ROOT, "machinery-helper")
36
+ @remote_helper_path = File.join(Machinery::HELPER_REMOTE_PATH, "machinery-helper")
38
37
  end
39
38
 
40
39
  def local_helper_path
41
- File.join(@local_helpers_path, @arch, "machinery-helper")
40
+ File.join(local_helpers_path, "machinery-helper")
42
41
  end
43
42
 
44
43
  # Returns true, if there is a helper binary matching the architecture of the
45
44
  # inspected system. Return false, if not.
46
45
  def can_help?
47
- File.exist?(local_helper_path)
46
+ File.exist?(local_helper_path) && LocalSystem.matches_architecture?(@arch)
48
47
  end
49
48
 
50
49
  def inject_helper
51
- @system.inject_file(local_helper_path, Machinery::REMOTE_HELPERS_PATH)
50
+ @system.inject_file(local_helper_path, Machinery::HELPER_REMOTE_PATH)
52
51
  end
53
52
 
54
53
  def run_helper(scope)
55
- json = @system.run_command(
56
- File.join(
57
- Machinery::REMOTE_HELPERS_PATH, "machinery-helper"
58
- ), stdout: :capture, stderr: STDERR
59
- )
54
+ json = @system.run_command(remote_helper_path, stdout: :capture, stderr: STDERR)
60
55
  scope.set_attributes(JSON.parse(json))
61
56
  end
62
57
 
63
58
  def remove_helper
64
- @system.remove_file(File.join(Machinery::REMOTE_HELPERS_PATH, "machinery-helper"))
59
+ @system.remove_file(remote_helper_path)
60
+ end
61
+
62
+ def has_compatible_version?
63
+ output = @system.run_command(remote_helper_path, "--version", stdout: :capture).chomp
64
+
65
+ version = output[/^Version: ([a-f0-9]{40})$/, 1]
66
+
67
+ version == File.read(File.join(Machinery::ROOT, ".git_revision"))
65
68
  end
66
69
  end
data/lib/move_task.rb ADDED
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2013-2015 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 MoveTask
19
+ def move(store, from, to)
20
+ store.move(from, to)
21
+ end
22
+ end
data/lib/remote_system.rb CHANGED
@@ -19,6 +19,10 @@ class RemoteSystem < System
19
19
  attr_accessor :host
20
20
  attr_accessor :remote_user
21
21
 
22
+ def type
23
+ "remote"
24
+ end
25
+
22
26
  def initialize(host, remote_user = "root")
23
27
  @host = host
24
28
  @remote_user = remote_user
@@ -32,6 +32,16 @@ module ScopeFileAccessArchive
32
32
  end
33
33
  end
34
34
 
35
+ def has_file?(name)
36
+ return true if files.any? { |file| file.name == name }
37
+ if files.any? { |file| file.name == File.join(File.dirname(name), "") }
38
+ tgz_file = File.join(scope_file_store.path, "trees", "#{File.dirname(name)}.tgz")
39
+ return Cheetah.run("tar", "ztf", tgz_file, stdout: :capture).split(/\n/).
40
+ any? { |f| "/#{f}" == name }
41
+ end
42
+ false
43
+ end
44
+
35
45
  def tarball_path(system_file)
36
46
  if system_file.directory?
37
47
  File.join(
@@ -33,4 +33,8 @@ module ScopeFileAccessFlat
33
33
  output = Cheetah.run("file", path, stdout: :capture)
34
34
  !output.include?("ASCII")
35
35
  end
36
+
37
+ def has_file?(name)
38
+ return true if files.any? { |file| file.name == name }
39
+ end
36
40
  end
data/lib/show_task.rb CHANGED
@@ -30,7 +30,7 @@ class ShowTask
30
30
 
31
31
  def show_html(description, options)
32
32
  begin
33
- LocalSystem.validate_existence_of_package("xdg-utils")
33
+ LocalSystem.validate_existence_of_command("xdg-open", "xdg-utils")
34
34
 
35
35
  url = "http://#{options[:ip]}:#{options[:port]}/#{CGI.escape(description.name)}"
36
36
 
data/lib/system.rb CHANGED
@@ -29,6 +29,7 @@ class System
29
29
  abstract_method :read_file
30
30
  abstract_method :inject_file
31
31
  abstract_method :remove_file
32
+ abstract_method :type
32
33
 
33
34
  attr_writer :locale
34
35
 
@@ -55,10 +56,22 @@ class System
55
56
  )
56
57
  end
57
58
 
59
+ def check_retrieve_files_dependencies
60
+ check_requirement("rsync", "--version")
61
+ end
62
+
63
+ def check_create_archive_dependencies
64
+ check_requirement("tar", "--version")
65
+ check_requirement("gzip", "--version")
66
+ end
67
+
58
68
  # Retrieves files specified in filelist from the remote system and create an archive.
59
69
  # To be able to deal with arbitrary filenames we use zero-terminated
60
70
  # filelist and the --null option of tar
61
71
  def create_archive(file_list, archive, exclude = [])
72
+ Machinery.logger.info(
73
+ "The following files are packaged in #{archive}: " + Array(file_list).join(", ")
74
+ )
62
75
  created = !File.exists?(archive)
63
76
  out = File.open(archive, "w")
64
77
  begin
@@ -67,7 +80,8 @@ class System
67
80
  *exclude.flat_map { |f| ["--exclude", f]},
68
81
  stdout: out,
69
82
  stdin: Array(file_list).join("\0"),
70
- privileged: true
83
+ privileged: true,
84
+ disable_logging: true
71
85
  )
72
86
  rescue Cheetah::ExecutionFailed => e
73
87
  if e.status.exitstatus == 1
@@ -83,7 +97,7 @@ class System
83
97
  end
84
98
 
85
99
  def run_script(*args)
86
- script = File.read(File.join(Machinery::ROOT, "helpers", args.shift))
100
+ script = File.read(File.join(Machinery::ROOT, "inspect_helpers", args.shift))
87
101
 
88
102
  run_command("bash", "-c", script, *args)
89
103
  end
@@ -276,19 +276,29 @@ class SystemDescription < Machinery::Object
276
276
  end
277
277
 
278
278
  def has_file?(name)
279
- self["config_files"].files.any? { |file| file.name == name } ||
280
- self["unmanaged_files"].files.any? { |file| file.name == name }
279
+ EXTRACTABLE_SCOPES.each do |scope|
280
+ if scope_extracted?(scope)
281
+ return true if self[scope] && self[scope].has_file?(name)
282
+ end
283
+ end
284
+ false
281
285
  end
282
286
 
283
287
  def read_config(path, key)
284
- if scope_extracted?("config_files")
285
- file = self["config_files"].files.find { |f| f.name == path }
286
- return parse_variable_assignment(file.content, key) if file
287
- end
288
- if scope_extracted?("unmanaged_files")
289
- file = self["unmanaged_files"].files.find { |f| f.name == path }
290
- return parse_variable_assignment(file.content, key) if file
288
+ EXTRACTABLE_SCOPES.each do |scope|
289
+ if scope_extracted?(scope)
290
+ file = self[scope].files.find { |f| f.name == path }
291
+ return parse_variable_assignment(file.content, key) if file
292
+ end
291
293
  end
294
+ # if scope_extracted?("config_files")
295
+ # file = self["config_files"].files.find { |f| f.name == path }
296
+ # return parse_variable_assignment(file.content, key) if file
297
+ # end
298
+ # if scope_extracted?("unmanaged_files")
299
+ # file = self["unmanaged_files"].files.find { |f| f.name == path }
300
+ # return parse_variable_assignment(file.content, key) if file
301
+ # end
292
302
  end
293
303
 
294
304
  private
@@ -74,6 +74,16 @@ class SystemDescriptionStore
74
74
  FileUtils.cp_r(description_path(from), description_path(to))
75
75
  end
76
76
 
77
+ def move(from, to)
78
+ SystemDescription.validate_name(from)
79
+ SystemDescription.validate_name(to)
80
+
81
+ validate_existence_of_description(from)
82
+ validate_nonexistence_of_description(to)
83
+
84
+ FileUtils.mv(description_path(from), description_path(to))
85
+ end
86
+
77
87
  def backup(description_name)
78
88
  SystemDescription.validate_name(description_name)
79
89
  validate_existence_of_description(description_name)
data/lib/version.rb CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  module Machinery
19
19
 
20
- VERSION = "1.13.0"
20
+ VERSION = "1.14.0"
21
21
 
22
22
  end
@@ -104,7 +104,8 @@ class WorkloadMapper
104
104
  tgz_file = File.join(dir, "trees", "#{origin.chop}.tgz")
105
105
  output_path = File.join(path, workload, destination)
106
106
  FileUtils.mkdir_p(output_path)
107
- Cheetah.run("tar", "zxf", tgz_file, "-C", output_path, "--strip=1")
107
+ strip_number = origin.split("/").size - 1
108
+ Cheetah.run("tar", "zxf", tgz_file, "-C", output_path, "--strip=#{strip_number}")
108
109
  copy_workload_config_files(workload, output_path)
109
110
  end
110
111
  if file && file.file?
@@ -0,0 +1,13 @@
1
+ # machinery-helper
2
+
3
+ A helper binary used by Machinery - http://machinery-project.org
4
+
5
+ It inspects a system for unmanaged-files (files not tracked by rpm)
6
+ and outputs the result in the
7
+ [Machinery json format](https://github.com/SUSE/machinery/blob/master/docs/System-Description-Format.md).
8
+
9
+ ## Build
10
+
11
+ Make sure that the official Go Development environment is installed.
12
+
13
+ To build the helper binary just run `go build`.
@@ -0,0 +1,124 @@
1
+ # Copyright (c) 2013-2015 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
+ task :default => "try_build"
19
+
20
+ HELPER_DIR = File.expand_path(File.dirname(__FILE__))
21
+ GIT_REVISION_FILE = File.join(HELPER_DIR, "..", ".git_revision")
22
+
23
+ def write_go_version_file
24
+ file = <<-EOF
25
+ // This is a generated file and shouldn't be changed
26
+
27
+ package main
28
+
29
+ const VERSION = "#{git_revision}"
30
+ EOF
31
+ File.write(File.join(HELPER_DIR, "version.go"), file)
32
+ end
33
+
34
+ def build_machinery_helper
35
+ FileUtils.rm_f(File.join(HELPER_DIR, "machinery-helper"))
36
+ Dir.chdir(HELPER_DIR) do
37
+ puts("Building machinery-helper binary.")
38
+ if !system("go build")
39
+ STDERR.puts("Warning: Building of the machinery-helper failed!")
40
+ false
41
+ else
42
+ true
43
+ end
44
+ end
45
+ end
46
+
47
+ def go_available?
48
+ if !system("which go > /dev/null 2>&1")
49
+ STDERR.puts(
50
+ "Warning: The Go compiler is not available on this system. Skipping building the" \
51
+ " machinery-helper.\nThe machinery-helper increases the inspection speed significantly."
52
+ )
53
+ false
54
+ else
55
+ true
56
+ end
57
+ end
58
+
59
+ def arch_supported?
60
+ arch = `uname -p`.chomp
61
+ if !["x86_64"].include?(arch)
62
+ STDERR.puts(
63
+ "Warning: The hardware architecture #{arch} is not yet supported by the machinery-helper."
64
+ )
65
+ false
66
+ else
67
+ true
68
+ end
69
+ end
70
+
71
+ def runs_in_git?
72
+ Dir.exist?(File.join(HELPER_DIR, "..", ".git")) && system("which git > /dev/null 2>&1")
73
+ end
74
+
75
+ def git_revision
76
+ `git rev-parse HEAD`.chomp
77
+ end
78
+
79
+ def write_git_revision_file
80
+ File.write(GIT_REVISION_FILE, git_revision)
81
+ end
82
+
83
+ def changed_revision?
84
+ if File.exist?(GIT_REVISION_FILE)
85
+ old_revision = File.read(GIT_REVISION_FILE)
86
+ else
87
+ old_revision = "unknown"
88
+ end
89
+ git_revision != old_revision
90
+ end
91
+
92
+ def run_build
93
+ # An unsupported architecture is no error
94
+ return true if !arch_supported?
95
+ return false if !go_available?
96
+
97
+ # handle changed branches (where go files are older than the helper)
98
+ if runs_in_git? && changed_revision?
99
+ write_go_version_file
100
+ if build_machinery_helper
101
+ write_git_revision_file
102
+ return true
103
+ else
104
+ return false
105
+ end
106
+ end
107
+
108
+ if !FileUtils.uptodate?(
109
+ File.join(HELPER_DIR, "machinery-helper"), Dir.glob(File.join(HELPER_DIR, "*.go"))
110
+ )
111
+ return build_machinery_helper
112
+ end
113
+ true
114
+ end
115
+
116
+ desc "Build the helper if needed"
117
+ task :build do
118
+ raise "Error: Build of Machinery helper failed" if !run_build
119
+ end
120
+
121
+ desc "Don't fail on build errors"
122
+ task :try_build do
123
+ run_build
124
+ end
@@ -0,0 +1,228 @@
1
+ // Copyright (c) 2015 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
+ package main
19
+
20
+ import (
21
+ "os/exec"
22
+ "bytes"
23
+ "log"
24
+ "strings"
25
+ "io/ioutil"
26
+ "encoding/json"
27
+ "os"
28
+ "sort"
29
+ "fmt"
30
+ "path/filepath"
31
+ "unicode/utf8"
32
+ "flag"
33
+ )
34
+
35
+ func getRpms() []string {
36
+ cmd := exec.Command("rpm", "-qlav")
37
+ var out bytes.Buffer
38
+ cmd.Stdout = &out
39
+ err := cmd.Run()
40
+ if err != nil {
41
+ log.Fatal(err)
42
+ }
43
+
44
+ f := func(c rune) bool {
45
+ return c == '\n'
46
+ }
47
+ packages := strings.FieldsFunc(out.String(), f)
48
+ return packages
49
+ }
50
+
51
+ func parseRpmLine(line string) (fileType string, fileName string, linkTarget string) {
52
+ fileType = line[0:1]
53
+
54
+ index := strings.Index(line, "/")
55
+ if index < 0 {
56
+ panic(line)
57
+ }
58
+ file := line[index:]
59
+ fields := strings.Split(file, " -> ")
60
+ if len(fields) == 2 {
61
+ fileName = fields[0]
62
+ linkTarget = fields[1]
63
+ } else {
64
+ fileName = file
65
+ }
66
+ return
67
+ }
68
+
69
+ func addImplicitlyManagedDirs(dirs map[string]bool, files map[string]string) {
70
+ for file, target := range files {
71
+ for i:= 1; i < len(file); i++ {
72
+ if file[i] == '/' {
73
+ topdir := file[:i]
74
+ if _, ok := dirs[topdir]; !ok {
75
+ dirs[topdir] = false
76
+ }
77
+ }
78
+ }
79
+
80
+ if target != "" {
81
+ if _, ok := dirs[target]; ok {
82
+ dirs[file] = false
83
+ }
84
+ }
85
+ }
86
+ return
87
+ }
88
+
89
+ func getManagedFiles() (map[string]string, map[string]bool) {
90
+ files := make(map[string]string)
91
+ dirs := make(map[string]bool)
92
+
93
+ for _, pkg := range getRpms() {
94
+ if pkg != "(contains no files)" {
95
+ fileType, fileName, linkTarget := parseRpmLine(pkg)
96
+ switch fileType {
97
+ case "-":
98
+ files[fileName] = ""
99
+ case "d":
100
+ dirs[fileName] = true
101
+ case "l":
102
+ files[fileName] = linkTarget
103
+ }
104
+ }
105
+ }
106
+
107
+ addImplicitlyManagedDirs(dirs, files)
108
+
109
+ return files, dirs
110
+ }
111
+
112
+ func assembleJSON(unmanagedFilesMap interface{}) string {
113
+ jsonMap := map[string]interface{}{ "extracted": false, "files": unmanagedFilesMap }
114
+ json, _ := json.MarshalIndent(jsonMap, " ", " ")
115
+ return string(json)
116
+ }
117
+
118
+ var readDir = func(dir string) ([]os.FileInfo, error) {
119
+ return ioutil.ReadDir(dir)
120
+ }
121
+
122
+ func hasManagedDirs(dir string, rpmDirs map[string]bool) bool {
123
+ for rpmDir := range rpmDirs {
124
+ if strings.HasPrefix(rpmDir, dir + "/") {
125
+ return true
126
+ }
127
+ }
128
+ return false
129
+ }
130
+
131
+ func findUnmanagedFiles(dir string, rpmFiles map[string]string, rpmDirs map[string]bool,
132
+ unmanagedFiles map[string]string, ignoreList map[string]bool) {
133
+ files, _ := readDir(dir)
134
+ for _, f := range files {
135
+ fileName := dir + f.Name()
136
+ if !utf8.ValidString(fileName) {
137
+ fmt.Fprintln(os.Stderr, fileName, "contains invalid UTF-8 characters. Skipping.")
138
+ } else {
139
+ if _, ok := ignoreList[fileName]; !ok {
140
+ if f.IsDir() {
141
+ if _, ok := rpmDirs[fileName]; ok {
142
+ findUnmanagedFiles(fileName + "/", rpmFiles, rpmDirs, unmanagedFiles, ignoreList)
143
+ } else {
144
+ if !hasManagedDirs(fileName, rpmDirs) {
145
+ unmanagedFiles[fileName + "/"] = "dir"
146
+ }
147
+ }
148
+ } else {
149
+ if _, ok := rpmFiles[fileName]; !ok {
150
+ if f.Mode() &
151
+ (os.ModeSocket | os.ModeNamedPipe | os.ModeDevice | os.ModeCharDevice) != 0 {
152
+ // Ignore sockets, named pipes and devices
153
+ } else if f.Mode() & os.ModeSymlink == os.ModeSymlink {
154
+ unmanagedFiles[fileName] = "link"
155
+ } else {
156
+ unmanagedFiles[fileName] = "file"
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+
165
+ func printVersion() {
166
+ fmt.Println("Version:", VERSION)
167
+ os.Exit(0)
168
+ }
169
+
170
+ func main() {
171
+ // check for tar extraction
172
+ if len(os.Args) >= 2 {
173
+ switch os.Args[1] {
174
+ case "tar":
175
+ Tar(os.Args[2:])
176
+ os.Exit(0)
177
+ }
178
+ }
179
+
180
+ // parse CLI arguments
181
+ var versionFlag = flag.Bool("version", false, "shows the version number")
182
+ flag.Parse()
183
+
184
+ // show version
185
+ if (*versionFlag == true) {
186
+ printVersion()
187
+ }
188
+
189
+ // fetch unmanaged files
190
+ unmanagedFiles := make(map[string]string)
191
+ thisBinary, _ := filepath.Abs(os.Args[0])
192
+
193
+ ignoreList := map[string]bool{
194
+ thisBinary: true,
195
+ }
196
+ for _, mount := range RemoteMounts() {
197
+ ignoreList[mount] = true
198
+ }
199
+ for _, mount := range SpecialMounts() {
200
+ ignoreList[mount] = true
201
+ }
202
+
203
+ for _, mount := range RemoteMounts() {
204
+ unmanagedFiles[mount + "/"] = "remote_dir"
205
+ }
206
+
207
+ rpmFiles, rpmDirs := getManagedFiles()
208
+ findUnmanagedFiles("/", rpmFiles, rpmDirs, unmanagedFiles, ignoreList)
209
+
210
+ files := make([]string, len(unmanagedFiles))
211
+ i := 0
212
+ for k := range unmanagedFiles {
213
+ files[i] = k
214
+ i++
215
+ }
216
+ sort.Strings(files)
217
+
218
+ unmanagedFilesMap := make([]map[string]string, len(unmanagedFiles))
219
+ for j := range files {
220
+ entry := make(map[string]string)
221
+ entry["name"] = files[j]
222
+ entry["type"] = unmanagedFiles[files[j]]
223
+ unmanagedFilesMap[j] = entry
224
+ }
225
+
226
+ json := assembleJSON(unmanagedFilesMap)
227
+ fmt.Println(json)
228
+ }