github.com/crowdsecurity/crowdsec@v1.6.1/cmd/crowdsec-cli/config_restore.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "path/filepath" 8 9 log "github.com/sirupsen/logrus" 10 "github.com/spf13/cobra" 11 12 "github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/require" 13 "github.com/crowdsecurity/crowdsec/pkg/cwhub" 14 ) 15 16 func (cli *cliConfig) restoreHub(dirPath string) error { 17 cfg := cli.cfg() 18 19 hub, err := require.Hub(cfg, require.RemoteHub(cfg), nil) 20 if err != nil { 21 return err 22 } 23 24 for _, itype := range cwhub.ItemTypes { 25 itemDirectory := fmt.Sprintf("%s/%s/", dirPath, itype) 26 if _, err = os.Stat(itemDirectory); err != nil { 27 log.Infof("no %s in backup", itype) 28 continue 29 } 30 /*restore the upstream items*/ 31 upstreamListFN := fmt.Sprintf("%s/upstream-%s.json", itemDirectory, itype) 32 33 file, err := os.ReadFile(upstreamListFN) 34 if err != nil { 35 return fmt.Errorf("error while opening %s: %w", upstreamListFN, err) 36 } 37 38 var upstreamList []string 39 40 err = json.Unmarshal(file, &upstreamList) 41 if err != nil { 42 return fmt.Errorf("error unmarshaling %s: %w", upstreamListFN, err) 43 } 44 45 for _, toinstall := range upstreamList { 46 item := hub.GetItem(itype, toinstall) 47 if item == nil { 48 log.Errorf("Item %s/%s not found in hub", itype, toinstall) 49 continue 50 } 51 52 if err = item.Install(false, false); err != nil { 53 log.Errorf("Error while installing %s : %s", toinstall, err) 54 } 55 } 56 57 /*restore the local and tainted items*/ 58 files, err := os.ReadDir(itemDirectory) 59 if err != nil { 60 return fmt.Errorf("failed enumerating files of %s: %w", itemDirectory, err) 61 } 62 63 for _, file := range files { 64 // this was the upstream data 65 if file.Name() == fmt.Sprintf("upstream-%s.json", itype) { 66 continue 67 } 68 69 if itype == cwhub.PARSERS || itype == cwhub.POSTOVERFLOWS { 70 // we expect a stage here 71 if !file.IsDir() { 72 continue 73 } 74 75 stage := file.Name() 76 stagedir := fmt.Sprintf("%s/%s/%s/", cfg.ConfigPaths.ConfigDir, itype, stage) 77 log.Debugf("Found stage %s in %s, target directory : %s", stage, itype, stagedir) 78 79 if err = os.MkdirAll(stagedir, os.ModePerm); err != nil { 80 return fmt.Errorf("error while creating stage directory %s: %w", stagedir, err) 81 } 82 83 // find items 84 ifiles, err := os.ReadDir(itemDirectory + "/" + stage + "/") 85 if err != nil { 86 return fmt.Errorf("failed enumerating files of %s: %w", itemDirectory+"/"+stage, err) 87 } 88 89 // finally copy item 90 for _, tfile := range ifiles { 91 log.Infof("Going to restore local/tainted [%s]", tfile.Name()) 92 sourceFile := fmt.Sprintf("%s/%s/%s", itemDirectory, stage, tfile.Name()) 93 94 destinationFile := fmt.Sprintf("%s%s", stagedir, tfile.Name()) 95 if err = CopyFile(sourceFile, destinationFile); err != nil { 96 return fmt.Errorf("failed copy %s %s to %s: %w", itype, sourceFile, destinationFile, err) 97 } 98 99 log.Infof("restored %s to %s", sourceFile, destinationFile) 100 } 101 } else { 102 log.Infof("Going to restore local/tainted [%s]", file.Name()) 103 sourceFile := fmt.Sprintf("%s/%s", itemDirectory, file.Name()) 104 destinationFile := fmt.Sprintf("%s/%s/%s", cfg.ConfigPaths.ConfigDir, itype, file.Name()) 105 106 if err = CopyFile(sourceFile, destinationFile); err != nil { 107 return fmt.Errorf("failed copy %s %s to %s: %w", itype, sourceFile, destinationFile, err) 108 } 109 110 log.Infof("restored %s to %s", sourceFile, destinationFile) 111 } 112 } 113 } 114 115 return nil 116 } 117 118 /* 119 Restore crowdsec configurations to directory <dirPath>: 120 121 - Main config (config.yaml) 122 - Profiles config (profiles.yaml) 123 - Simulation config (simulation.yaml) 124 - Backup of API credentials (local API and online API) 125 - List of scenarios, parsers, postoverflows and collections that are up-to-date 126 - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections 127 - Acquisition files (acquis.yaml, acquis.d/*.yaml) 128 */ 129 func (cli *cliConfig) restore(dirPath string) error { 130 var err error 131 132 cfg := cli.cfg() 133 134 backupMain := fmt.Sprintf("%s/config.yaml", dirPath) 135 if _, err = os.Stat(backupMain); err == nil { 136 if cfg.ConfigPaths != nil && cfg.ConfigPaths.ConfigDir != "" { 137 if err = CopyFile(backupMain, fmt.Sprintf("%s/config.yaml", cfg.ConfigPaths.ConfigDir)); err != nil { 138 return fmt.Errorf("failed copy %s to %s: %w", backupMain, cfg.ConfigPaths.ConfigDir, err) 139 } 140 } 141 } 142 143 // Now we have config.yaml, we should regenerate config struct to have rights paths etc 144 ConfigFilePath = fmt.Sprintf("%s/config.yaml", cfg.ConfigPaths.ConfigDir) 145 146 log.Debug("Reloading configuration") 147 148 csConfig, _, err = loadConfigFor("config") 149 if err != nil { 150 return fmt.Errorf("failed to reload configuration: %w", err) 151 } 152 153 cfg = cli.cfg() 154 155 backupCAPICreds := fmt.Sprintf("%s/online_api_credentials.yaml", dirPath) 156 if _, err = os.Stat(backupCAPICreds); err == nil { 157 if err = CopyFile(backupCAPICreds, cfg.API.Server.OnlineClient.CredentialsFilePath); err != nil { 158 return fmt.Errorf("failed copy %s to %s: %w", backupCAPICreds, cfg.API.Server.OnlineClient.CredentialsFilePath, err) 159 } 160 } 161 162 backupLAPICreds := fmt.Sprintf("%s/local_api_credentials.yaml", dirPath) 163 if _, err = os.Stat(backupLAPICreds); err == nil { 164 if err = CopyFile(backupLAPICreds, cfg.API.Client.CredentialsFilePath); err != nil { 165 return fmt.Errorf("failed copy %s to %s: %w", backupLAPICreds, cfg.API.Client.CredentialsFilePath, err) 166 } 167 } 168 169 backupProfiles := fmt.Sprintf("%s/profiles.yaml", dirPath) 170 if _, err = os.Stat(backupProfiles); err == nil { 171 if err = CopyFile(backupProfiles, cfg.API.Server.ProfilesPath); err != nil { 172 return fmt.Errorf("failed copy %s to %s: %w", backupProfiles, cfg.API.Server.ProfilesPath, err) 173 } 174 } 175 176 backupSimulation := fmt.Sprintf("%s/simulation.yaml", dirPath) 177 if _, err = os.Stat(backupSimulation); err == nil { 178 if err = CopyFile(backupSimulation, cfg.ConfigPaths.SimulationFilePath); err != nil { 179 return fmt.Errorf("failed copy %s to %s: %w", backupSimulation, cfg.ConfigPaths.SimulationFilePath, err) 180 } 181 } 182 183 /*if there is a acquisition dir, restore its content*/ 184 if cfg.Crowdsec.AcquisitionDirPath != "" { 185 if err = os.MkdirAll(cfg.Crowdsec.AcquisitionDirPath, 0o700); err != nil { 186 return fmt.Errorf("error while creating %s: %w", cfg.Crowdsec.AcquisitionDirPath, err) 187 } 188 } 189 190 // if there was a single one 191 backupAcquisition := fmt.Sprintf("%s/acquis.yaml", dirPath) 192 if _, err = os.Stat(backupAcquisition); err == nil { 193 log.Debugf("restoring backup'ed %s", backupAcquisition) 194 195 if err = CopyFile(backupAcquisition, cfg.Crowdsec.AcquisitionFilePath); err != nil { 196 return fmt.Errorf("failed copy %s to %s: %w", backupAcquisition, cfg.Crowdsec.AcquisitionFilePath, err) 197 } 198 } 199 200 // if there are files in the acquis backup dir, restore them 201 acquisBackupDir := filepath.Join(dirPath, "acquis", "*.yaml") 202 if acquisFiles, err := filepath.Glob(acquisBackupDir); err == nil { 203 for _, acquisFile := range acquisFiles { 204 targetFname, err := filepath.Abs(cfg.Crowdsec.AcquisitionDirPath + "/" + filepath.Base(acquisFile)) 205 if err != nil { 206 return fmt.Errorf("while saving %s to %s: %w", acquisFile, targetFname, err) 207 } 208 209 log.Debugf("restoring %s to %s", acquisFile, targetFname) 210 211 if err = CopyFile(acquisFile, targetFname); err != nil { 212 return fmt.Errorf("failed copy %s to %s: %w", acquisFile, targetFname, err) 213 } 214 } 215 } 216 217 if cfg.Crowdsec != nil && len(cfg.Crowdsec.AcquisitionFiles) > 0 { 218 for _, acquisFile := range cfg.Crowdsec.AcquisitionFiles { 219 log.Infof("backup filepath from dir -> %s", acquisFile) 220 221 // if it was the default one, it has already been backed up 222 if cfg.Crowdsec.AcquisitionFilePath == acquisFile { 223 log.Infof("skip this one") 224 continue 225 } 226 227 targetFname, err := filepath.Abs(filepath.Join(acquisBackupDir, filepath.Base(acquisFile))) 228 if err != nil { 229 return fmt.Errorf("while saving %s to %s: %w", acquisFile, acquisBackupDir, err) 230 } 231 232 if err = CopyFile(acquisFile, targetFname); err != nil { 233 return fmt.Errorf("failed copy %s to %s: %w", acquisFile, targetFname, err) 234 } 235 236 log.Infof("Saved acquis %s to %s", acquisFile, targetFname) 237 } 238 } 239 240 if err = cli.restoreHub(dirPath); err != nil { 241 return fmt.Errorf("failed to restore hub config: %w", err) 242 } 243 244 return nil 245 } 246 247 func (cli *cliConfig) newRestoreCmd() *cobra.Command { 248 cmd := &cobra.Command{ 249 Use: `restore "directory"`, 250 Short: `Restore config in backup "directory"`, 251 Long: `Restore the crowdsec configuration from specified backup "directory" including: 252 253 - Main config (config.yaml) 254 - Simulation config (simulation.yaml) 255 - Profiles config (profiles.yaml) 256 - List of scenarios, parsers, postoverflows and collections that are up-to-date 257 - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections 258 - Backup of API credentials (local API and online API)`, 259 Args: cobra.ExactArgs(1), 260 DisableAutoGenTag: true, 261 RunE: func(_ *cobra.Command, args []string) error { 262 dirPath := args[0] 263 264 if err := cli.restore(dirPath); err != nil { 265 return fmt.Errorf("failed to restore config from %s: %w", dirPath, err) 266 } 267 268 return nil 269 }, 270 } 271 272 return cmd 273 }