main.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // main handles deployment of the plugin to a development server using the Client4 API.
  2. package main
  3. import (
  4. "errors"
  5. "fmt"
  6. "log"
  7. "net"
  8. "os"
  9. "github.com/mattermost/mattermost-server/v5/model"
  10. )
  11. const helpText = `
  12. Usage:
  13. pluginctl deploy <plugin id> <bundle path>
  14. pluginctl disable <plugin id>
  15. pluginctl enable <plugin id>
  16. pluginctl reset <plugin id>
  17. `
  18. func main() {
  19. err := pluginctl()
  20. if err != nil {
  21. fmt.Printf("Failed: %s\n", err.Error())
  22. fmt.Print(helpText)
  23. os.Exit(1)
  24. }
  25. }
  26. func pluginctl() error {
  27. if len(os.Args) < 3 {
  28. return errors.New("invalid number of arguments")
  29. }
  30. client, err := getClient()
  31. if err != nil {
  32. return err
  33. }
  34. switch os.Args[1] {
  35. case "deploy":
  36. if len(os.Args) < 4 {
  37. return errors.New("invalid number of arguments")
  38. }
  39. return deploy(client, os.Args[2], os.Args[3])
  40. case "disable":
  41. return disablePlugin(client, os.Args[2])
  42. case "enable":
  43. return enablePlugin(client, os.Args[2])
  44. case "reset":
  45. return resetPlugin(client, os.Args[2])
  46. default:
  47. return errors.New("invalid second argument")
  48. }
  49. }
  50. func getClient() (*model.Client4, error) {
  51. socketPath := os.Getenv("MM_LOCALSOCKETPATH")
  52. if socketPath == "" {
  53. socketPath = model.LOCAL_MODE_SOCKET_PATH
  54. }
  55. client, connected := getUnixClient(socketPath)
  56. if connected {
  57. log.Printf("Connecting using local mode over %s", socketPath)
  58. return client, nil
  59. }
  60. if os.Getenv("MM_LOCALSOCKETPATH") != "" {
  61. log.Printf("No socket found at %s for local mode deployment. Attempting to authenticate with credentials.", socketPath)
  62. }
  63. siteURL := os.Getenv("MM_SERVICESETTINGS_SITEURL")
  64. adminToken := os.Getenv("MM_ADMIN_TOKEN")
  65. adminUsername := os.Getenv("MM_ADMIN_USERNAME")
  66. adminPassword := os.Getenv("MM_ADMIN_PASSWORD")
  67. if siteURL == "" {
  68. return nil, errors.New("MM_SERVICESETTINGS_SITEURL is not set")
  69. }
  70. client = model.NewAPIv4Client(siteURL)
  71. if adminToken != "" {
  72. log.Printf("Authenticating using token against %s.", siteURL)
  73. client.SetToken(adminToken)
  74. return client, nil
  75. }
  76. if adminUsername != "" && adminPassword != "" {
  77. client := model.NewAPIv4Client(siteURL)
  78. log.Printf("Authenticating as %s against %s.", adminUsername, siteURL)
  79. _, resp := client.Login(adminUsername, adminPassword)
  80. if resp.Error != nil {
  81. return nil, fmt.Errorf("failed to login as %s: %w", adminUsername, resp.Error)
  82. }
  83. return client, nil
  84. }
  85. return nil, errors.New("one of MM_ADMIN_TOKEN or MM_ADMIN_USERNAME/MM_ADMIN_PASSWORD must be defined")
  86. }
  87. func getUnixClient(socketPath string) (*model.Client4, bool) {
  88. _, err := net.Dial("unix", socketPath)
  89. if err != nil {
  90. return nil, false
  91. }
  92. return model.NewAPIv4SocketClient(socketPath), true
  93. }
  94. // deploy attempts to upload and enable a plugin via the Client4 API.
  95. // It will fail if plugin uploads are disabled.
  96. func deploy(client *model.Client4, pluginID, bundlePath string) error {
  97. pluginBundle, err := os.Open(bundlePath)
  98. if err != nil {
  99. return fmt.Errorf("failed to open %s: %w", bundlePath, err)
  100. }
  101. defer pluginBundle.Close()
  102. log.Print("Uploading plugin via API.")
  103. _, resp := client.UploadPluginForced(pluginBundle)
  104. if resp.Error != nil {
  105. return fmt.Errorf("failed to upload plugin bundle: %s", resp.Error.Error())
  106. }
  107. log.Print("Enabling plugin.")
  108. _, resp = client.EnablePlugin(pluginID)
  109. if resp.Error != nil {
  110. return fmt.Errorf("failed to enable plugin: %s", resp.Error.Error())
  111. }
  112. return nil
  113. }
  114. // disablePlugin attempts to disable the plugin via the Client4 API.
  115. func disablePlugin(client *model.Client4, pluginID string) error {
  116. log.Print("Disabling plugin.")
  117. _, resp := client.DisablePlugin(pluginID)
  118. if resp.Error != nil {
  119. return fmt.Errorf("failed to disable plugin: %w", resp.Error)
  120. }
  121. return nil
  122. }
  123. // enablePlugin attempts to enable the plugin via the Client4 API.
  124. func enablePlugin(client *model.Client4, pluginID string) error {
  125. log.Print("Enabling plugin.")
  126. _, resp := client.EnablePlugin(pluginID)
  127. if resp.Error != nil {
  128. return fmt.Errorf("failed to enable plugin: %w", resp.Error)
  129. }
  130. return nil
  131. }
  132. // resetPlugin attempts to reset the plugin via the Client4 API.
  133. func resetPlugin(client *model.Client4, pluginID string) error {
  134. err := disablePlugin(client, pluginID)
  135. if err != nil {
  136. return err
  137. }
  138. err = enablePlugin(client, pluginID)
  139. if err != nil {
  140. return err
  141. }
  142. return nil
  143. }