2020-07-27 11:47:32 +00:00
|
|
|
package cwhub
|
|
|
|
|
2023-11-06 16:35:33 +00:00
|
|
|
// Enable/disable items already downloaded
|
2023-10-20 12:32:35 +00:00
|
|
|
|
2020-07-27 11:47:32 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
// enable creates a symlink between actual config file at hub.HubDir and hub.ConfigDir
|
2023-10-20 12:32:35 +00:00
|
|
|
// Handles collections recursively
|
2023-11-09 14:19:38 +00:00
|
|
|
func (i *Item) enable() error {
|
|
|
|
parentDir := filepath.Clean(i.hub.local.InstallDir + "/" + i.Type + "/" + i.Stage + "/")
|
2023-10-20 12:32:35 +00:00
|
|
|
|
|
|
|
// create directories if needed
|
2023-11-09 14:19:38 +00:00
|
|
|
if i.Installed {
|
|
|
|
if i.Tainted {
|
|
|
|
return fmt.Errorf("%s is tainted, won't enable unless --force", i.Name)
|
2023-10-20 12:32:35 +00:00
|
|
|
}
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
if i.IsLocal() {
|
|
|
|
return fmt.Errorf("%s is local, won't enable", i.Name)
|
2023-10-20 12:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// if it's a collection, check sub-items even if the collection file itself is up-to-date
|
2023-11-09 14:19:38 +00:00
|
|
|
if i.UpToDate && !i.HasSubItems() {
|
|
|
|
log.Tracef("%s is installed and up-to-date, skip.", i.Name)
|
2023-10-20 12:32:35 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-31 15:32:29 +00:00
|
|
|
if _, err := os.Stat(parentDir); os.IsNotExist(err) {
|
2023-10-20 12:32:35 +00:00
|
|
|
log.Infof("%s doesn't exist, create", parentDir)
|
|
|
|
|
|
|
|
if err = os.MkdirAll(parentDir, os.ModePerm); err != nil {
|
|
|
|
return fmt.Errorf("while creating directory: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-09 10:34:14 +00:00
|
|
|
// install sub-items if any
|
2023-11-09 14:19:38 +00:00
|
|
|
for _, sub := range i.SubItems() {
|
|
|
|
val, ok := i.hub.Items[sub.Type][sub.Name]
|
2023-11-06 16:35:33 +00:00
|
|
|
if !ok {
|
2023-11-09 14:19:38 +00:00
|
|
|
return fmt.Errorf("required %s %s of %s doesn't exist, abort", sub.Type, sub.Name, i.Name)
|
2023-11-06 16:35:33 +00:00
|
|
|
}
|
2023-10-20 12:32:35 +00:00
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
if err := val.enable(); err != nil {
|
2023-11-06 16:35:33 +00:00
|
|
|
return fmt.Errorf("while installing %s: %w", sub.Name, err)
|
2023-10-20 12:32:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if file already exists where it should in configdir (eg /etc/crowdsec/collections/)
|
2023-11-09 14:19:38 +00:00
|
|
|
if _, err := os.Lstat(parentDir + "/" + i.FileName); !os.IsNotExist(err) {
|
|
|
|
log.Infof("%s already exists.", parentDir+"/"+i.FileName)
|
2023-10-20 12:32:35 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// hub.ConfigDir + target.RemotePath
|
2023-11-09 14:19:38 +00:00
|
|
|
srcPath, err := filepath.Abs(i.hub.local.HubDir + "/" + i.RemotePath)
|
2023-10-20 12:32:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("while getting source path: %w", err)
|
|
|
|
}
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
dstPath, err := filepath.Abs(parentDir + "/" + i.FileName)
|
2023-10-20 12:32:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("while getting destination path: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = os.Symlink(srcPath, dstPath); err != nil {
|
|
|
|
return fmt.Errorf("while creating symlink from %s to %s: %w", srcPath, dstPath, err)
|
|
|
|
}
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
log.Infof("Enabled %s: %s", i.Type, i.Name)
|
|
|
|
i.Installed = true
|
2023-10-20 12:32:35 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
// purge removes the actual config file that was downloaded
|
|
|
|
func (i *Item) purge() error {
|
|
|
|
itempath := i.hub.local.HubDir + "/" + i.RemotePath
|
2022-10-25 12:10:51 +00:00
|
|
|
|
|
|
|
// disable hub file
|
2023-10-04 08:34:10 +00:00
|
|
|
if err := os.Remove(itempath); err != nil {
|
2023-11-09 14:19:38 +00:00
|
|
|
return fmt.Errorf("while removing file: %w", err)
|
2022-10-25 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
i.Downloaded = false
|
|
|
|
log.Infof("Removed source file [%s]: %s", i.Name, itempath)
|
2023-10-03 09:20:56 +00:00
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
return nil
|
2022-10-25 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
// disable removes the symlink to the downloaded content, also removes the content if purge is true
|
|
|
|
func (i *Item) disable(purge bool, force bool) error {
|
2023-10-31 15:32:29 +00:00
|
|
|
// XXX: should return the number of disabled/purged items to inform the upper layer whether to reload or not
|
2022-10-25 12:10:51 +00:00
|
|
|
var err error
|
|
|
|
|
2023-10-09 11:26:34 +00:00
|
|
|
// already disabled, noop unless purge
|
2023-11-09 14:19:38 +00:00
|
|
|
if !i.Installed {
|
2022-10-25 12:10:51 +00:00
|
|
|
if purge {
|
2023-11-09 14:19:38 +00:00
|
|
|
err = i.purge()
|
2022-10-25 12:10:51 +00:00
|
|
|
if err != nil {
|
2023-10-09 11:26:34 +00:00
|
|
|
return err
|
2022-10-25 12:10:51 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-03 09:20:56 +00:00
|
|
|
|
2023-10-09 11:26:34 +00:00
|
|
|
return nil
|
2022-10-25 12:10:51 +00:00
|
|
|
}
|
2020-11-30 09:37:17 +00:00
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
if i.IsLocal() {
|
|
|
|
return fmt.Errorf("%s isn't managed by hub. Please delete manually", i.Name)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
if i.Tainted && !force {
|
|
|
|
return fmt.Errorf("%s is tainted, use '--force' to overwrite", i.Name)
|
2020-12-03 11:05:27 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 16:35:33 +00:00
|
|
|
// disable sub-items if any - it's a collection
|
2023-11-09 14:19:38 +00:00
|
|
|
for _, sub := range i.SubItems() {
|
2023-11-07 09:27:33 +00:00
|
|
|
// XXX: we do this already when syncing, do we really need to do consistency checks here and there?
|
2023-11-09 14:19:38 +00:00
|
|
|
val, ok := i.hub.Items[sub.Type][sub.Name]
|
2023-11-06 16:35:33 +00:00
|
|
|
if !ok {
|
2023-11-09 14:19:38 +00:00
|
|
|
log.Errorf("Referred %s %s in collection %s doesn't exist.", sub.Type, sub.Name, i.Name)
|
2023-11-06 16:35:33 +00:00
|
|
|
continue
|
|
|
|
}
|
2023-10-20 12:32:35 +00:00
|
|
|
|
2023-11-06 16:35:33 +00:00
|
|
|
// check if the item doesn't belong to another collection before removing it
|
|
|
|
toRemove := true
|
2023-10-20 12:32:35 +00:00
|
|
|
|
2023-11-06 16:35:33 +00:00
|
|
|
for _, collection := range val.BelongsToCollections {
|
2023-11-09 14:19:38 +00:00
|
|
|
if collection != i.Name {
|
2023-11-06 16:35:33 +00:00
|
|
|
toRemove = false
|
|
|
|
break
|
2023-10-20 12:32:35 +00:00
|
|
|
}
|
2023-11-06 16:35:33 +00:00
|
|
|
}
|
2023-10-20 12:32:35 +00:00
|
|
|
|
2023-11-06 16:35:33 +00:00
|
|
|
if toRemove {
|
2023-11-09 14:19:38 +00:00
|
|
|
if err = val.disable(purge, force); err != nil {
|
2023-11-06 16:35:33 +00:00
|
|
|
return fmt.Errorf("while disabling %s: %w", sub.Name, err)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
2023-11-06 16:35:33 +00:00
|
|
|
} else {
|
|
|
|
log.Infof("%s was not removed because it belongs to another collection", val.Name)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
syml, err := filepath.Abs(i.hub.local.InstallDir + "/" + i.Type + "/" + i.Stage + "/" + i.FileName)
|
2023-10-09 11:26:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-07-27 11:47:32 +00:00
|
|
|
stat, err := os.Lstat(syml)
|
|
|
|
if os.IsNotExist(err) {
|
2023-10-09 11:26:34 +00:00
|
|
|
// we only accept to "delete" non existing items if it's a forced purge
|
|
|
|
if !purge && !force {
|
2023-11-09 14:19:38 +00:00
|
|
|
return fmt.Errorf("can't delete %s: %s doesn't exist", i.Name, syml)
|
2020-11-30 09:37:17 +00:00
|
|
|
}
|
2020-07-27 11:47:32 +00:00
|
|
|
} else {
|
2023-10-05 07:35:03 +00:00
|
|
|
// if it's managed by hub, it's a symlink to csconfig.GConfig.hub.HubDir / ...
|
2020-07-27 11:47:32 +00:00
|
|
|
if stat.Mode()&os.ModeSymlink == 0 {
|
2023-11-09 14:19:38 +00:00
|
|
|
log.Warningf("%s (%s) isn't a symlink, can't disable", i.Name, syml)
|
|
|
|
return fmt.Errorf("%s isn't managed by hub", i.Name)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
2023-10-04 08:34:10 +00:00
|
|
|
|
2020-07-27 11:47:32 +00:00
|
|
|
hubpath, err := os.Readlink(syml)
|
|
|
|
if err != nil {
|
2023-10-09 11:26:34 +00:00
|
|
|
return fmt.Errorf("while reading symlink: %w", err)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
2023-10-04 08:34:10 +00:00
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
absPath, err := filepath.Abs(i.hub.local.HubDir + "/" + i.RemotePath)
|
2020-07-27 11:47:32 +00:00
|
|
|
if err != nil {
|
2023-10-09 11:26:34 +00:00
|
|
|
return fmt.Errorf("while abs path: %w", err)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
2023-10-04 08:34:10 +00:00
|
|
|
|
2020-07-27 11:47:32 +00:00
|
|
|
if hubpath != absPath {
|
2023-11-09 14:19:38 +00:00
|
|
|
log.Warningf("%s (%s) isn't a symlink to %s", i.Name, syml, absPath)
|
|
|
|
return fmt.Errorf("%s isn't managed by hub", i.Name)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
|
|
|
|
2023-10-05 07:35:03 +00:00
|
|
|
// remove the symlink
|
2020-07-27 11:47:32 +00:00
|
|
|
if err = os.Remove(syml); err != nil {
|
2023-10-09 11:26:34 +00:00
|
|
|
return fmt.Errorf("while removing symlink: %w", err)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
2023-10-04 08:34:10 +00:00
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
log.Infof("Removed symlink [%s]: %s", i.Name, syml)
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
2023-10-03 09:20:56 +00:00
|
|
|
|
2023-11-09 14:19:38 +00:00
|
|
|
i.Installed = false
|
2020-07-27 11:47:32 +00:00
|
|
|
|
|
|
|
if purge {
|
2023-11-09 14:19:38 +00:00
|
|
|
err = i.purge()
|
2022-10-25 12:10:51 +00:00
|
|
|
if err != nil {
|
2023-10-09 11:26:34 +00:00
|
|
|
return err
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-03 09:20:56 +00:00
|
|
|
|
2023-10-09 11:26:34 +00:00
|
|
|
return nil
|
2020-07-27 11:47:32 +00:00
|
|
|
}
|