enable.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. package cwhub
  2. // Enable/disable items already installed (no downloading here)
  3. // This file is not named install.go to avoid confusion with the functions in helpers.go
  4. import (
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. log "github.com/sirupsen/logrus"
  9. )
  10. // creates symlink between actual config file at hub.HubDir and hub.ConfigDir
  11. // Handles collections recursively
  12. func (h *Hub) EnableItem(target *Item) error {
  13. var err error
  14. parentDir := filepath.Clean(h.cfg.InstallDir + "/" + target.Type + "/" + target.Stage + "/")
  15. // create directories if needed
  16. if target.Installed {
  17. if target.Tainted {
  18. return fmt.Errorf("%s is tainted, won't enable unless --force", target.Name)
  19. }
  20. if target.Local {
  21. return fmt.Errorf("%s is local, won't enable", target.Name)
  22. }
  23. // if it's a collection, check sub-items even if the collection file itself is up-to-date
  24. if target.UpToDate && target.Type != COLLECTIONS {
  25. log.Tracef("%s is installed and up-to-date, skip.", target.Name)
  26. return nil
  27. }
  28. }
  29. if _, err = os.Stat(parentDir); os.IsNotExist(err) {
  30. log.Infof("%s doesn't exist, create", parentDir)
  31. if err = os.MkdirAll(parentDir, os.ModePerm); err != nil {
  32. return fmt.Errorf("while creating directory: %w", err)
  33. }
  34. }
  35. // install sub-items if it's a collection
  36. if target.Type == COLLECTIONS {
  37. for _, sub := range target.SubItems() {
  38. val, ok := h.Items[sub.Type][sub.Name]
  39. if !ok {
  40. return fmt.Errorf("required %s %s of %s doesn't exist, abort", sub.Type, sub.Name, target.Name)
  41. }
  42. err = h.EnableItem(&val)
  43. if err != nil {
  44. return fmt.Errorf("while installing %s: %w", sub.Name, err)
  45. }
  46. }
  47. }
  48. // check if file already exists where it should in configdir (eg /etc/crowdsec/collections/)
  49. if _, err = os.Lstat(parentDir + "/" + target.FileName); !os.IsNotExist(err) {
  50. log.Infof("%s already exists.", parentDir+"/"+target.FileName)
  51. return nil
  52. }
  53. // hub.ConfigDir + target.RemotePath
  54. srcPath, err := filepath.Abs(h.cfg.HubDir + "/" + target.RemotePath)
  55. if err != nil {
  56. return fmt.Errorf("while getting source path: %w", err)
  57. }
  58. dstPath, err := filepath.Abs(parentDir + "/" + target.FileName)
  59. if err != nil {
  60. return fmt.Errorf("while getting destination path: %w", err)
  61. }
  62. if err = os.Symlink(srcPath, dstPath); err != nil {
  63. return fmt.Errorf("while creating symlink from %s to %s: %w", srcPath, dstPath, err)
  64. }
  65. log.Infof("Enabled %s : %s", target.Type, target.Name)
  66. target.Installed = true
  67. h.Items[target.Type][target.Name] = *target
  68. return nil
  69. }
  70. func (h *Hub) purgeItem(target Item) (Item, error) {
  71. itempath := h.cfg.HubDir + "/" + target.RemotePath
  72. // disable hub file
  73. if err := os.Remove(itempath); err != nil {
  74. return target, fmt.Errorf("while removing file: %w", err)
  75. }
  76. target.Downloaded = false
  77. log.Infof("Removed source file [%s]: %s", target.Name, itempath)
  78. h.Items[target.Type][target.Name] = target
  79. return target, nil
  80. }
  81. // DisableItem to disable an item managed by the hub, removes the symlink if purge is true
  82. func (h *Hub) DisableItem(target *Item, purge bool, force bool) error {
  83. var err error
  84. // already disabled, noop unless purge
  85. if !target.Installed {
  86. if purge {
  87. *target, err = h.purgeItem(*target)
  88. if err != nil {
  89. return err
  90. }
  91. }
  92. return nil
  93. }
  94. if target.Local {
  95. return fmt.Errorf("%s isn't managed by hub. Please delete manually", target.Name)
  96. }
  97. if target.Tainted && !force {
  98. return fmt.Errorf("%s is tainted, use '--force' to overwrite", target.Name)
  99. }
  100. // for a COLLECTIONS, disable sub-items
  101. if target.Type == COLLECTIONS {
  102. for _, sub := range target.SubItems() {
  103. val, ok := h.Items[sub.Type][sub.Name]
  104. if !ok {
  105. log.Errorf("Referred %s %s in collection %s doesn't exist.", sub.Type, sub.Name, target.Name)
  106. continue
  107. }
  108. // check if the item doesn't belong to another collection before removing it
  109. toRemove := true
  110. for _, collection := range val.BelongsToCollections {
  111. if collection != target.Name {
  112. toRemove = false
  113. break
  114. }
  115. }
  116. if toRemove {
  117. err = h.DisableItem(&val, purge, force)
  118. if err != nil {
  119. return fmt.Errorf("while disabling %s: %w", sub.Name, err)
  120. }
  121. } else {
  122. log.Infof("%s was not removed because it belongs to another collection", val.Name)
  123. }
  124. }
  125. }
  126. syml, err := filepath.Abs(h.cfg.InstallDir + "/" + target.Type + "/" + target.Stage + "/" + target.FileName)
  127. if err != nil {
  128. return err
  129. }
  130. stat, err := os.Lstat(syml)
  131. if os.IsNotExist(err) {
  132. // we only accept to "delete" non existing items if it's a forced purge
  133. if !purge && !force {
  134. return fmt.Errorf("can't delete %s : %s doesn't exist", target.Name, syml)
  135. }
  136. } else {
  137. // if it's managed by hub, it's a symlink to csconfig.GConfig.hub.HubDir / ...
  138. if stat.Mode()&os.ModeSymlink == 0 {
  139. log.Warningf("%s (%s) isn't a symlink, can't disable", target.Name, syml)
  140. return fmt.Errorf("%s isn't managed by hub", target.Name)
  141. }
  142. hubpath, err := os.Readlink(syml)
  143. if err != nil {
  144. return fmt.Errorf("while reading symlink: %w", err)
  145. }
  146. absPath, err := filepath.Abs(h.cfg.HubDir + "/" + target.RemotePath)
  147. if err != nil {
  148. return fmt.Errorf("while abs path: %w", err)
  149. }
  150. if hubpath != absPath {
  151. log.Warningf("%s (%s) isn't a symlink to %s", target.Name, syml, absPath)
  152. return fmt.Errorf("%s isn't managed by hub", target.Name)
  153. }
  154. // remove the symlink
  155. if err = os.Remove(syml); err != nil {
  156. return fmt.Errorf("while removing symlink: %w", err)
  157. }
  158. log.Infof("Removed symlink [%s] : %s", target.Name, syml)
  159. }
  160. target.Installed = false
  161. if purge {
  162. *target, err = h.purgeItem(*target)
  163. if err != nil {
  164. return err
  165. }
  166. }
  167. h.Items[target.Type][target.Name] = *target
  168. return nil
  169. }