github.com/flanksource/konfigadm@v0.12.0/pkg/phases/packages.go (about) 1 package phases 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "strings" 7 8 log "github.com/sirupsen/logrus" 9 10 "github.com/flanksource/konfigadm/pkg/types" 11 "github.com/flanksource/konfigadm/pkg/utils" 12 ) 13 14 var Packages types.AllPhases = packages{} 15 16 type packages struct{} 17 18 func (p packages) ApplyPhase(sys *types.Config, ctx *types.SystemContext) ([]types.Command, types.Filesystem, error) { 19 commands := types.Commands{} 20 files := types.Filesystem{} 21 22 for _, repo := range *sys.PackageRepos { 23 var os OS 24 var err error 25 if os, err = GetOSForTag(repo.Flags...); err != nil { 26 return nil, nil, err 27 } 28 29 if repo.URL != "" || repo.ExtraArgs["mirrorlist"] != "" { 30 _commands := os.GetPackageManager(). 31 AddRepo(repo.URL, repo.Channel, repo.VersionCodeName, repo.Name, repo.GPGKey, repo.ExtraArgs) 32 commands.Append(_commands.WithTags(repo.Flags...)) 33 } 34 } 35 if len(sys.TarPackages) > 0 { 36 sys.AddPackage("tar", nil) 37 sys.AddPackage("wget", nil) 38 } 39 addPackageCommands(sys, &commands) 40 41 for _, tar := range sys.TarPackages { 42 filename := filepath.Base(tar.URL) 43 commands.Add(fmt.Sprintf("wget -O %s -nv %s", filename, tar.URL)) 44 if tar.Checksum != "" { 45 tar.ChecksumType = strings.TrimSuffix(tar.ChecksumType, "sum") 46 commands.Add(fmt.Sprintf("echo %s | %ssum --check", tar.Checksum, tar.ChecksumType)) 47 } 48 commands.Add(extractTo(filename, tar.Destination)). 49 Add(fmt.Sprintf("rm %s", filename)) 50 } 51 52 _commands := commands.Merge() 53 return _commands, files, nil 54 } 55 56 func extractTo(filename, destination string) string { 57 switch { 58 case strings.HasSuffix(filename, "tar.gz"), strings.HasSuffix(filename, "tgz"): 59 return fmt.Sprintf("tar -zxf %s -C %s", filename, destination) 60 } 61 return fmt.Sprintf("mv %s %s", filename, destination) 62 } 63 64 type packageOperations struct { 65 install []string 66 uninstall []string 67 mark []string 68 tags []types.Flag 69 } 70 71 func appendStrings(slice []string, s string) []string { 72 var newSlice []string 73 if slice != nil { 74 newSlice = slice 75 } 76 newSlice = append(newSlice, s) 77 return newSlice 78 } 79 80 func getKeyFromTags(tags ...types.Flag) string { 81 return fmt.Sprintf("%s", tags) 82 } 83 84 func addPackageCommands(sys *types.Config, commands *types.Commands) { 85 // package installation can have 2 scenarios: 86 // 1) tags specified and we know the package manager 87 // 2) tags not specified, so we need to add tagged commands for each base operating system 88 89 // track operations by tag group 90 // TODO merge compatible tags, e.g. ubuntu and debian-like tags can be included in the same command 91 var managers = make(map[string]packageOperations) 92 93 // handle case 1) tags not specified 94 for _, p := range *sys.Packages { 95 if len(p.Flags) == 0 { 96 continue 97 } 98 99 var ops packageOperations 100 var ok bool 101 if ops, ok = managers[getKeyFromTags(p.Flags...)]; !ok { 102 ops = packageOperations{tags: p.Flags} 103 } 104 if p.Uninstall { 105 ops.uninstall = appendStrings(ops.uninstall, p.Name) 106 } else { 107 ops.install = appendStrings(ops.install, p.VersionedName()) 108 } 109 if p.Mark { 110 ops.mark = appendStrings(ops.mark, p.Name) 111 } 112 113 managers[getKeyFromTags(p.Flags...)] = ops 114 } 115 116 // handle case 2) tags specified 117 for _, os := range BaseOperatingSystems { 118 for _, p := range *sys.Packages { 119 if len(p.Flags) > 0 { 120 continue 121 } 122 var ops packageOperations 123 var ok bool 124 if ops, ok = managers[os.GetName()]; !ok { 125 ops = packageOperations{tags: []types.Flag{*types.GetTag(os.GetName())}} 126 } 127 if p.Uninstall { 128 ops.uninstall = appendStrings(ops.uninstall, p.Name) 129 } else { 130 ops.install = appendStrings(ops.install, p.VersionedName()) 131 } 132 if p.Mark { 133 ops.mark = appendStrings(ops.mark, p.Name) 134 } 135 managers[os.GetName()] = ops 136 } 137 } 138 139 // iterate over all tag/op combinations and emit commands 140 for _, ops := range managers { 141 os, _ := GetOSForTag(ops.tags...) 142 commands.Append(os.GetPackageManager().Update().WithTags(ops.tags...)) 143 144 if ops.install != nil && len(ops.install) > 0 { 145 commands = commands.Append(os.GetPackageManager().Install(ops.install...).WithTags(ops.tags...)) 146 } 147 if ops.uninstall != nil && len(ops.uninstall) > 0 { 148 commands = commands.Append(os.GetPackageManager().Uninstall(ops.uninstall...).WithTags(ops.tags...)) 149 } 150 if ops.mark != nil && len(ops.mark) > 0 { 151 commands = commands.Append(os.GetPackageManager().Mark(ops.mark...).WithTags(ops.tags...)) 152 } 153 } 154 155 } 156 157 func (p packages) ProcessFlags(sys *types.Config, flags ...types.Flag) { 158 minified := []types.Package{} 159 for _, pkg := range *sys.Packages { 160 if types.MatchAll(flags, pkg.Flags) { 161 minified = append(minified, pkg) 162 } 163 } 164 sys.Packages = &minified 165 166 minifiedRepos := []types.PackageRepo{} 167 for _, repo := range *sys.PackageRepos { 168 if types.MatchesAny(flags, repo.Flags) { 169 minifiedRepos = append(minifiedRepos, repo) 170 } 171 } 172 sys.PackageRepos = &minifiedRepos 173 } 174 175 func (p packages) Verify(cfg *types.Config, results *types.VerifyResults, flags ...types.Flag) bool { 176 verify := true 177 var os OS 178 var err error 179 if os, err = GetOSForTag(flags...); err != nil { 180 results.Fail("Unable to find OS for tags %s", flags) 181 return false 182 } 183 184 for _, p := range *cfg.Packages { 185 if !types.MatchesAny(flags, p.Flags) { 186 continue 187 } 188 expandedVersion, _ := utils.SafeExec("echo %s", p.Version) 189 expandedVersion = strings.Replace(expandedVersion, "\n", "", -1) 190 log.Tracef("Verifying package: %s, version: %s => %s", p.Name, p.Version, expandedVersion) 191 installed := os.GetPackageManager().GetInstalledVersion(p.Name) 192 if p.Uninstall { 193 if installed == "" { 194 results.Pass("%s is not installed", p) 195 } else { 196 results.Fail("%s should not be installed", p) 197 verify = false 198 } 199 } else if p.Version == "" && installed != "" { 200 results.Pass("%s is installed with any version: %s", p, installed) 201 } else if p.Version == "" && installed == "" { 202 results.Fail("%s is not installed, any version required", p) 203 verify = false 204 } else if strings.HasPrefix(expandedVersion, installed) || strings.HasPrefix(installed, expandedVersion) { 205 results.Pass("%s is installed with expected version: %s", p, installed) 206 } else { 207 results.Fail("%s is installed, but expected %s, got %s", p.Name, expandedVersion, installed) 208 verify = false 209 } 210 } 211 212 return verify 213 }