config.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "path/filepath"
  8. "github.com/antonmedv/expr"
  9. "github.com/pkg/errors"
  10. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  11. "github.com/crowdsecurity/crowdsec/pkg/cwhub"
  12. "github.com/crowdsecurity/crowdsec/pkg/types"
  13. log "github.com/sirupsen/logrus"
  14. "github.com/spf13/cobra"
  15. "gopkg.in/yaml.v2"
  16. )
  17. type OldAPICfg struct {
  18. MachineID string `json:"machine_id"`
  19. Password string `json:"password"`
  20. }
  21. /* Backup crowdsec configurations to directory <dirPath> :
  22. - Main config (config.yaml)
  23. - Profiles config (profiles.yaml)
  24. - Simulation config (simulation.yaml)
  25. - Backup of API credentials (local API and online API)
  26. - List of scenarios, parsers, postoverflows and collections that are up-to-date
  27. - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections
  28. */
  29. func backupConfigToDirectory(dirPath string) error {
  30. var err error
  31. if dirPath == "" {
  32. return fmt.Errorf("directory path can't be empty")
  33. }
  34. log.Infof("Starting configuration backup")
  35. /*if parent directory doesn't exist, bail out. create final dir with Mkdir*/
  36. parentDir := filepath.Dir(dirPath)
  37. if _, err := os.Stat(parentDir); err != nil {
  38. return errors.Wrapf(err, "while checking parent directory %s existence", parentDir)
  39. }
  40. if err = os.Mkdir(dirPath, 0700); err != nil {
  41. return errors.Wrapf(err, "while creating %s", dirPath)
  42. }
  43. if csConfig.ConfigPaths.SimulationFilePath != "" {
  44. backupSimulation := filepath.Join(dirPath, "simulation.yaml")
  45. if err = types.CopyFile(csConfig.ConfigPaths.SimulationFilePath, backupSimulation); err != nil {
  46. return errors.Wrapf(err, "failed copy %s to %s", csConfig.ConfigPaths.SimulationFilePath, backupSimulation)
  47. }
  48. log.Infof("Saved simulation to %s", backupSimulation)
  49. }
  50. /*
  51. - backup AcquisitionFilePath
  52. - backup the other files of acquisition directory
  53. */
  54. if csConfig.Crowdsec != nil && csConfig.Crowdsec.AcquisitionFilePath != "" {
  55. backupAcquisition := filepath.Join(dirPath, "acquis.yaml")
  56. if err = types.CopyFile(csConfig.Crowdsec.AcquisitionFilePath, backupAcquisition); err != nil {
  57. return fmt.Errorf("failed copy %s to %s : %s", csConfig.Crowdsec.AcquisitionFilePath, backupAcquisition, err)
  58. }
  59. }
  60. acquisBackupDir := filepath.Join(dirPath, "acquis")
  61. if err = os.Mkdir(acquisBackupDir, 0700); err != nil {
  62. return fmt.Errorf("error while creating %s : %s", acquisBackupDir, err)
  63. }
  64. if csConfig.Crowdsec != nil && len(csConfig.Crowdsec.AcquisitionFiles) > 0 {
  65. for _, acquisFile := range csConfig.Crowdsec.AcquisitionFiles {
  66. /*if it was the default one, it was already backup'ed*/
  67. if csConfig.Crowdsec.AcquisitionFilePath == acquisFile {
  68. continue
  69. }
  70. targetFname, err := filepath.Abs(filepath.Join(acquisBackupDir, filepath.Base(acquisFile)))
  71. if err != nil {
  72. return errors.Wrapf(err, "while saving %s to %s", acquisFile, acquisBackupDir)
  73. }
  74. if err = types.CopyFile(acquisFile, targetFname); err != nil {
  75. return fmt.Errorf("failed copy %s to %s : %s", acquisFile, targetFname, err)
  76. }
  77. log.Infof("Saved acquis %s to %s", acquisFile, targetFname)
  78. }
  79. }
  80. if ConfigFilePath != "" {
  81. backupMain := fmt.Sprintf("%s/config.yaml", dirPath)
  82. if err = types.CopyFile(ConfigFilePath, backupMain); err != nil {
  83. return fmt.Errorf("failed copy %s to %s : %s", ConfigFilePath, backupMain, err)
  84. }
  85. log.Infof("Saved default yaml to %s", backupMain)
  86. }
  87. if csConfig.API != nil && csConfig.API.Server != nil && csConfig.API.Server.OnlineClient != nil && csConfig.API.Server.OnlineClient.CredentialsFilePath != "" {
  88. backupCAPICreds := fmt.Sprintf("%s/online_api_credentials.yaml", dirPath)
  89. if err = types.CopyFile(csConfig.API.Server.OnlineClient.CredentialsFilePath, backupCAPICreds); err != nil {
  90. return fmt.Errorf("failed copy %s to %s : %s", csConfig.API.Server.OnlineClient.CredentialsFilePath, backupCAPICreds, err)
  91. }
  92. log.Infof("Saved online API credentials to %s", backupCAPICreds)
  93. }
  94. if csConfig.API != nil && csConfig.API.Client != nil && csConfig.API.Client.CredentialsFilePath != "" {
  95. backupLAPICreds := fmt.Sprintf("%s/local_api_credentials.yaml", dirPath)
  96. if err = types.CopyFile(csConfig.API.Client.CredentialsFilePath, backupLAPICreds); err != nil {
  97. return fmt.Errorf("failed copy %s to %s : %s", csConfig.API.Client.CredentialsFilePath, backupLAPICreds, err)
  98. }
  99. log.Infof("Saved local API credentials to %s", backupLAPICreds)
  100. }
  101. if csConfig.API != nil && csConfig.API.Server != nil && csConfig.API.Server.ProfilesPath != "" {
  102. backupProfiles := fmt.Sprintf("%s/profiles.yaml", dirPath)
  103. if err = types.CopyFile(csConfig.API.Server.ProfilesPath, backupProfiles); err != nil {
  104. return fmt.Errorf("failed copy %s to %s : %s", csConfig.API.Server.ProfilesPath, backupProfiles, err)
  105. }
  106. log.Infof("Saved profiles to %s", backupProfiles)
  107. }
  108. if err = BackupHub(dirPath); err != nil {
  109. return fmt.Errorf("failed to backup hub config : %s", err)
  110. }
  111. return nil
  112. }
  113. /* Restore crowdsec configurations to directory <dirPath> :
  114. - Main config (config.yaml)
  115. - Profiles config (profiles.yaml)
  116. - Simulation config (simulation.yaml)
  117. - Backup of API credentials (local API and online API)
  118. - List of scenarios, parsers, postoverflows and collections that are up-to-date
  119. - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections
  120. */
  121. func restoreConfigFromDirectory(dirPath string) error {
  122. var err error
  123. if !restoreOldBackup {
  124. backupMain := fmt.Sprintf("%s/config.yaml", dirPath)
  125. if _, err = os.Stat(backupMain); err == nil {
  126. if csConfig.ConfigPaths != nil && csConfig.ConfigPaths.ConfigDir != "" {
  127. if err = types.CopyFile(backupMain, fmt.Sprintf("%s/config.yaml", csConfig.ConfigPaths.ConfigDir)); err != nil {
  128. return fmt.Errorf("failed copy %s to %s : %s", backupMain, csConfig.ConfigPaths.ConfigDir, err)
  129. }
  130. }
  131. }
  132. // Now we have config.yaml, we should regenerate config struct to have rights paths etc
  133. ConfigFilePath = fmt.Sprintf("%s/config.yaml", csConfig.ConfigPaths.ConfigDir)
  134. initConfig()
  135. backupCAPICreds := fmt.Sprintf("%s/online_api_credentials.yaml", dirPath)
  136. if _, err = os.Stat(backupCAPICreds); err == nil {
  137. if err = types.CopyFile(backupCAPICreds, csConfig.API.Server.OnlineClient.CredentialsFilePath); err != nil {
  138. return fmt.Errorf("failed copy %s to %s : %s", backupCAPICreds, csConfig.API.Server.OnlineClient.CredentialsFilePath, err)
  139. }
  140. }
  141. backupLAPICreds := fmt.Sprintf("%s/local_api_credentials.yaml", dirPath)
  142. if _, err = os.Stat(backupLAPICreds); err == nil {
  143. if err = types.CopyFile(backupLAPICreds, csConfig.API.Client.CredentialsFilePath); err != nil {
  144. return fmt.Errorf("failed copy %s to %s : %s", backupLAPICreds, csConfig.API.Client.CredentialsFilePath, err)
  145. }
  146. }
  147. backupProfiles := fmt.Sprintf("%s/profiles.yaml", dirPath)
  148. if _, err = os.Stat(backupProfiles); err == nil {
  149. if err = types.CopyFile(backupProfiles, csConfig.API.Server.ProfilesPath); err != nil {
  150. return fmt.Errorf("failed copy %s to %s : %s", backupProfiles, csConfig.API.Server.ProfilesPath, err)
  151. }
  152. }
  153. } else {
  154. var oldAPICfg OldAPICfg
  155. backupOldAPICfg := fmt.Sprintf("%s/api_creds.json", dirPath)
  156. jsonFile, err := os.Open(backupOldAPICfg)
  157. if err != nil {
  158. log.Warningf("failed to open %s : %s", backupOldAPICfg, err)
  159. } else {
  160. byteValue, _ := ioutil.ReadAll(jsonFile)
  161. err = json.Unmarshal(byteValue, &oldAPICfg)
  162. if err != nil {
  163. return fmt.Errorf("failed to load json file %s : %s", backupOldAPICfg, err)
  164. }
  165. apiCfg := csconfig.ApiCredentialsCfg{
  166. Login: oldAPICfg.MachineID,
  167. Password: oldAPICfg.Password,
  168. URL: CAPIBaseURL,
  169. }
  170. apiConfigDump, err := yaml.Marshal(apiCfg)
  171. if err != nil {
  172. return fmt.Errorf("unable to dump api credentials: %s", err)
  173. }
  174. apiConfigDumpFile := fmt.Sprintf("%s/online_api_credentials.yaml", csConfig.ConfigPaths.ConfigDir)
  175. if csConfig.API.Server.OnlineClient != nil && csConfig.API.Server.OnlineClient.CredentialsFilePath != "" {
  176. apiConfigDumpFile = csConfig.API.Server.OnlineClient.CredentialsFilePath
  177. }
  178. err = ioutil.WriteFile(apiConfigDumpFile, apiConfigDump, 0644)
  179. if err != nil {
  180. return fmt.Errorf("write api credentials in '%s' failed: %s", apiConfigDumpFile, err)
  181. }
  182. log.Infof("Saved API credentials to %s", apiConfigDumpFile)
  183. }
  184. }
  185. backupSimulation := fmt.Sprintf("%s/simulation.yaml", dirPath)
  186. if _, err = os.Stat(backupSimulation); err == nil {
  187. if err = types.CopyFile(backupSimulation, csConfig.ConfigPaths.SimulationFilePath); err != nil {
  188. return fmt.Errorf("failed copy %s to %s : %s", backupSimulation, csConfig.ConfigPaths.SimulationFilePath, err)
  189. }
  190. }
  191. /*if there is a acquisition dir, restore its content*/
  192. if csConfig.Crowdsec.AcquisitionDirPath != "" {
  193. if err = os.Mkdir(csConfig.Crowdsec.AcquisitionDirPath, 0700); err != nil {
  194. return fmt.Errorf("error while creating %s : %s", csConfig.Crowdsec.AcquisitionDirPath, err)
  195. }
  196. }
  197. //if there was a single one
  198. backupAcquisition := fmt.Sprintf("%s/acquis.yaml", dirPath)
  199. if _, err = os.Stat(backupAcquisition); err == nil {
  200. log.Debugf("restoring backup'ed %s", backupAcquisition)
  201. if err = types.CopyFile(backupAcquisition, csConfig.Crowdsec.AcquisitionFilePath); err != nil {
  202. return fmt.Errorf("failed copy %s to %s : %s", backupAcquisition, csConfig.Crowdsec.AcquisitionFilePath, err)
  203. }
  204. }
  205. //if there is files in the acquis backup dir, restore them
  206. acquisBackupDir := filepath.Join(dirPath, "acquis", "*.yaml")
  207. if acquisFiles, err := filepath.Glob(acquisBackupDir); err == nil {
  208. for _, acquisFile := range acquisFiles {
  209. targetFname, err := filepath.Abs(csConfig.Crowdsec.AcquisitionDirPath + "/" + filepath.Base(acquisFile))
  210. if err != nil {
  211. return errors.Wrapf(err, "while saving %s to %s", acquisFile, targetFname)
  212. }
  213. log.Debugf("restoring %s to %s", acquisFile, targetFname)
  214. if err = types.CopyFile(acquisFile, targetFname); err != nil {
  215. return fmt.Errorf("failed copy %s to %s : %s", acquisFile, targetFname, err)
  216. }
  217. }
  218. }
  219. if csConfig.Crowdsec != nil && len(csConfig.Crowdsec.AcquisitionFiles) > 0 {
  220. for _, acquisFile := range csConfig.Crowdsec.AcquisitionFiles {
  221. log.Infof("backup filepath from dir -> %s", acquisFile)
  222. /*if it was the default one, it was already backup'ed*/
  223. if csConfig.Crowdsec.AcquisitionFilePath == acquisFile {
  224. log.Infof("skip this one")
  225. continue
  226. }
  227. targetFname, err := filepath.Abs(filepath.Join(acquisBackupDir, filepath.Base(acquisFile)))
  228. if err != nil {
  229. return errors.Wrapf(err, "while saving %s to %s", acquisFile, acquisBackupDir)
  230. }
  231. if err = types.CopyFile(acquisFile, targetFname); err != nil {
  232. return fmt.Errorf("failed copy %s to %s : %s", acquisFile, targetFname, err)
  233. }
  234. log.Infof("Saved acquis %s to %s", acquisFile, targetFname)
  235. }
  236. }
  237. if err = RestoreHub(dirPath); err != nil {
  238. return fmt.Errorf("failed to restore hub config : %s", err)
  239. }
  240. return nil
  241. }
  242. func NewConfigCmd() *cobra.Command {
  243. var cmdConfig = &cobra.Command{
  244. Use: "config [command]",
  245. Short: "Allows to view current config",
  246. Args: cobra.ExactArgs(0),
  247. DisableAutoGenTag: true,
  248. }
  249. var key string
  250. type Env struct {
  251. Config *csconfig.Config
  252. }
  253. var cmdConfigShow = &cobra.Command{
  254. Use: "show",
  255. Short: "Displays current config",
  256. Long: `Displays the current cli configuration.`,
  257. Args: cobra.ExactArgs(0),
  258. DisableAutoGenTag: true,
  259. Run: func(cmd *cobra.Command, args []string) {
  260. if key != "" {
  261. program, err := expr.Compile(key, expr.Env(Env{}))
  262. if err != nil {
  263. log.Fatal(err)
  264. }
  265. output, err := expr.Run(program, Env{Config: csConfig})
  266. if err != nil {
  267. log.Fatal(err)
  268. }
  269. switch csConfig.Cscli.Output {
  270. case "human", "raw":
  271. switch output.(type) {
  272. case string:
  273. fmt.Printf("%s\n", output)
  274. case int:
  275. fmt.Printf("%d\n", output)
  276. default:
  277. fmt.Printf("%v\n", output)
  278. }
  279. case "json":
  280. data, err := json.MarshalIndent(output, "", " ")
  281. if err != nil {
  282. log.Fatalf("failed to marshal configuration: %s", err)
  283. }
  284. fmt.Printf("%s\n", string(data))
  285. }
  286. return
  287. }
  288. switch csConfig.Cscli.Output {
  289. case "human":
  290. fmt.Printf("Global:\n")
  291. if csConfig.ConfigPaths != nil {
  292. fmt.Printf(" - Configuration Folder : %s\n", csConfig.ConfigPaths.ConfigDir)
  293. fmt.Printf(" - Data Folder : %s\n", csConfig.ConfigPaths.DataDir)
  294. fmt.Printf(" - Hub Folder : %s\n", csConfig.ConfigPaths.HubDir)
  295. fmt.Printf(" - Simulation File : %s\n", csConfig.ConfigPaths.SimulationFilePath)
  296. }
  297. if csConfig.Common != nil {
  298. fmt.Printf(" - Log Folder : %s\n", csConfig.Common.LogDir)
  299. fmt.Printf(" - Log level : %s\n", csConfig.Common.LogLevel)
  300. fmt.Printf(" - Log Media : %s\n", csConfig.Common.LogMedia)
  301. }
  302. if csConfig.Crowdsec != nil {
  303. fmt.Printf("Crowdsec:\n")
  304. fmt.Printf(" - Acquisition File : %s\n", csConfig.Crowdsec.AcquisitionFilePath)
  305. fmt.Printf(" - Parsers routines : %d\n", csConfig.Crowdsec.ParserRoutinesCount)
  306. if csConfig.Crowdsec.AcquisitionDirPath != "" {
  307. fmt.Printf(" - Acquisition Folder : %s\n", csConfig.Crowdsec.AcquisitionDirPath)
  308. }
  309. }
  310. if csConfig.Cscli != nil {
  311. fmt.Printf("cscli:\n")
  312. fmt.Printf(" - Output : %s\n", csConfig.Cscli.Output)
  313. fmt.Printf(" - Hub Branch : %s\n", csConfig.Cscli.HubBranch)
  314. fmt.Printf(" - Hub Folder : %s\n", csConfig.Cscli.HubDir)
  315. }
  316. if csConfig.API != nil {
  317. if csConfig.API.Client != nil && csConfig.API.Client.Credentials != nil {
  318. fmt.Printf("API Client:\n")
  319. fmt.Printf(" - URL : %s\n", csConfig.API.Client.Credentials.URL)
  320. fmt.Printf(" - Login : %s\n", csConfig.API.Client.Credentials.Login)
  321. fmt.Printf(" - Credentials File : %s\n", csConfig.API.Client.CredentialsFilePath)
  322. }
  323. if csConfig.API.Server != nil {
  324. fmt.Printf("Local API Server:\n")
  325. fmt.Printf(" - Listen URL : %s\n", csConfig.API.Server.ListenURI)
  326. fmt.Printf(" - Profile File : %s\n", csConfig.API.Server.ProfilesPath)
  327. if csConfig.API.Server.TLS != nil {
  328. if csConfig.API.Server.TLS.CertFilePath != "" {
  329. fmt.Printf(" - Cert File : %s\n", csConfig.API.Server.TLS.CertFilePath)
  330. }
  331. if csConfig.API.Server.TLS.KeyFilePath != "" {
  332. fmt.Printf(" - Key File : %s\n", csConfig.API.Server.TLS.KeyFilePath)
  333. }
  334. }
  335. fmt.Printf(" - Trusted IPs: \n")
  336. for _, ip := range csConfig.API.Server.TrustedIPs {
  337. fmt.Printf(" - %s\n", ip)
  338. }
  339. if csConfig.API.Server.OnlineClient != nil && csConfig.API.Server.OnlineClient.Credentials != nil {
  340. fmt.Printf("Central API:\n")
  341. fmt.Printf(" - URL : %s\n", csConfig.API.Server.OnlineClient.Credentials.URL)
  342. fmt.Printf(" - Login : %s\n", csConfig.API.Server.OnlineClient.Credentials.Login)
  343. fmt.Printf(" - Credentials File : %s\n", csConfig.API.Server.OnlineClient.CredentialsFilePath)
  344. }
  345. }
  346. }
  347. if csConfig.DbConfig != nil {
  348. fmt.Printf(" - Database:\n")
  349. fmt.Printf(" - Type : %s\n", csConfig.DbConfig.Type)
  350. switch csConfig.DbConfig.Type {
  351. case "sqlite":
  352. fmt.Printf(" - Path : %s\n", csConfig.DbConfig.DbPath)
  353. case "mysql", "postgresql", "postgres":
  354. fmt.Printf(" - Host : %s\n", csConfig.DbConfig.Host)
  355. fmt.Printf(" - Port : %d\n", csConfig.DbConfig.Port)
  356. fmt.Printf(" - User : %s\n", csConfig.DbConfig.User)
  357. fmt.Printf(" - DB Name : %s\n", csConfig.DbConfig.DbName)
  358. }
  359. if csConfig.DbConfig.Flush != nil {
  360. if *csConfig.DbConfig.Flush.MaxAge != "" {
  361. fmt.Printf(" - Flush age : %s\n", *csConfig.DbConfig.Flush.MaxAge)
  362. }
  363. if *csConfig.DbConfig.Flush.MaxItems != 0 {
  364. fmt.Printf(" - Flush size : %d\n", *csConfig.DbConfig.Flush.MaxItems)
  365. }
  366. }
  367. }
  368. case "json":
  369. data, err := json.MarshalIndent(csConfig, "", " ")
  370. if err != nil {
  371. log.Fatalf("failed to marshal configuration: %s", err)
  372. }
  373. fmt.Printf("%s\n", string(data))
  374. case "raw":
  375. data, err := yaml.Marshal(csConfig)
  376. if err != nil {
  377. log.Fatalf("failed to marshal configuration: %s", err)
  378. }
  379. fmt.Printf("%s\n", string(data))
  380. }
  381. },
  382. }
  383. cmdConfigShow.Flags().StringVar(&key, "key", "", "Display only this value (Config.API.Server.ListenURI)")
  384. cmdConfig.AddCommand(cmdConfigShow)
  385. var cmdConfigBackup = &cobra.Command{
  386. Use: `backup "directory"`,
  387. Short: "Backup current config",
  388. Long: `Backup the current crowdsec configuration including :
  389. - Main config (config.yaml)
  390. - Simulation config (simulation.yaml)
  391. - Profiles config (profiles.yaml)
  392. - List of scenarios, parsers, postoverflows and collections that are up-to-date
  393. - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections
  394. - Backup of API credentials (local API and online API)`,
  395. Example: `cscli config backup ./my-backup`,
  396. Args: cobra.ExactArgs(1),
  397. DisableAutoGenTag: true,
  398. Run: func(cmd *cobra.Command, args []string) {
  399. var err error
  400. if err := csConfig.LoadHub(); err != nil {
  401. log.Fatal(err)
  402. }
  403. if err = cwhub.GetHubIdx(csConfig.Hub); err != nil {
  404. log.Info("Run 'sudo cscli hub update' to get the hub index")
  405. log.Fatalf("Failed to get Hub index : %v", err)
  406. }
  407. if err = backupConfigToDirectory(args[0]); err != nil {
  408. log.Fatalf("Failed to backup configurations: %s", err)
  409. }
  410. },
  411. }
  412. cmdConfig.AddCommand(cmdConfigBackup)
  413. var cmdConfigRestore = &cobra.Command{
  414. Use: `restore "directory"`,
  415. Short: `Restore config in backup "directory"`,
  416. Long: `Restore the crowdsec configuration from specified backup "directory" including:
  417. - Main config (config.yaml)
  418. - Simulation config (simulation.yaml)
  419. - Profiles config (profiles.yaml)
  420. - List of scenarios, parsers, postoverflows and collections that are up-to-date
  421. - Tainted/local/out-of-date scenarios, parsers, postoverflows and collections
  422. - Backup of API credentials (local API and online API)`,
  423. Args: cobra.ExactArgs(1),
  424. DisableAutoGenTag: true,
  425. Run: func(cmd *cobra.Command, args []string) {
  426. var err error
  427. if err := csConfig.LoadHub(); err != nil {
  428. log.Fatal(err)
  429. }
  430. if err = cwhub.GetHubIdx(csConfig.Hub); err != nil {
  431. log.Info("Run 'sudo cscli hub update' to get the hub index")
  432. log.Fatalf("Failed to get Hub index : %v", err)
  433. }
  434. if err := restoreConfigFromDirectory(args[0]); err != nil {
  435. log.Fatalf("failed restoring configurations from %s : %s", args[0], err)
  436. }
  437. },
  438. }
  439. cmdConfigRestore.PersistentFlags().BoolVar(&restoreOldBackup, "old-backup", false, "To use when you are upgrading crowdsec v0.X to v1.X and you need to restore backup from v0.X")
  440. cmdConfig.AddCommand(cmdConfigRestore)
  441. return cmdConfig
  442. }