bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/cmd/synsec-cli/dashboard.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "os/user" 8 "path/filepath" 9 "strconv" 10 "strings" 11 12 "github.com/AlecAivazis/survey/v2" 13 "bitbucket.org/Aishee/synsec/pkg/metabase" 14 15 log "github.com/sirupsen/logrus" 16 "github.com/spf13/cobra" 17 ) 18 19 var ( 20 metabaseUser = "synsec@synsec.net" 21 metabasePassword string 22 metabaseDbPath string 23 metabaseConfigPath string 24 metabaseConfigFolder = "metabase/" 25 metabaseConfigFile = "metabase.yaml" 26 metabaseImage = "metabase/metabase" 27 /**/ 28 metabaseListenAddress = "127.0.0.1" 29 metabaseListenPort = "3000" 30 metabaseContainerID = "/synsec-metabase" 31 synsecGroup = "synsec" 32 33 forceYes bool 34 35 dockerGatewayIPAddr = "172.17.0.1" 36 /*informations needed to setup a random password on user's behalf*/ 37 ) 38 39 func NewDashboardCmd() *cobra.Command { 40 /* ---- UPDATE COMMAND */ 41 var cmdDashboard = &cobra.Command{ 42 Use: "dashboard [command]", 43 Short: "Manage your metabase dashboard container", 44 Long: `Install/Start/Stop/Remove a metabase container exposing dashboard and metrics.`, 45 Args: cobra.ExactArgs(1), 46 Example: ` 47 ccscli dashboard setup 48 ccscli dashboard start 49 ccscli dashboard stop 50 ccscli dashboard remove 51 `, 52 PersistentPreRun: func(cmd *cobra.Command, args []string) { 53 metabaseConfigFolderPath := filepath.Join(csConfig.ConfigPaths.ConfigDir, metabaseConfigFolder) 54 metabaseConfigPath = filepath.Join(metabaseConfigFolderPath, metabaseConfigFile) 55 if err := os.MkdirAll(metabaseConfigFolderPath, os.ModePerm); err != nil { 56 log.Fatalf(err.Error()) 57 } 58 if err := csConfig.LoadDBConfig(); err != nil { 59 log.Fatalf(err.Error()) 60 } 61 62 }, 63 } 64 65 var force bool 66 var cmdDashSetup = &cobra.Command{ 67 Use: "setup", 68 Short: "Setup a metabase container.", 69 Long: `Perform a metabase docker setup, download standard dashboards, create a fresh user and start the container`, 70 Args: cobra.ExactArgs(0), 71 Example: ` 72 ccscli dashboard setup 73 ccscli dashboard setup --listen 0.0.0.0 74 ccscli dashboard setup -l 0.0.0.0 -p 443 --password <password> 75 `, 76 Run: func(cmd *cobra.Command, args []string) { 77 if metabaseDbPath == "" { 78 metabaseDbPath = csConfig.ConfigPaths.DataDir 79 } 80 81 if metabasePassword == "" { 82 metabasePassword = generatePassword(16) 83 } 84 var answer bool 85 groupExist := false 86 dockerGroup, err := user.LookupGroup(synsecGroup) 87 if err == nil { 88 groupExist = true 89 } 90 if !forceYes && !groupExist { 91 prompt := &survey.Confirm{ 92 Message: fmt.Sprintf("For metabase docker to be able to access SQLite file we need to add a new group called '%s' to the system, is it ok for you ?", synsecGroup), 93 Default: true, 94 } 95 if err := survey.AskOne(prompt, &answer); err != nil { 96 log.Fatalf("unable to ask to force: %s", err) 97 } 98 } 99 if !answer && !forceYes && !groupExist { 100 log.Fatalf("unable to continue without creating '%s' group", synsecGroup) 101 } 102 if !groupExist { 103 groupAddCmd, err := exec.LookPath("groupadd") 104 if err != nil { 105 log.Fatalf("unable to find 'groupadd' command, can't continue") 106 } 107 108 groupAdd := &exec.Cmd{Path: groupAddCmd, Args: []string{groupAddCmd, synsecGroup}} 109 if err := groupAdd.Run(); err != nil { 110 log.Fatalf("unable to add group '%s': %s", dockerGroup, err) 111 } 112 dockerGroup, err = user.LookupGroup(synsecGroup) 113 if err != nil { 114 log.Fatalf("unable to lookup '%s' group: %+v", dockerGroup, err) 115 } 116 } 117 intID, err := strconv.Atoi(dockerGroup.Gid) 118 if err != nil { 119 log.Fatalf("unable to convert group ID to int: %s", err) 120 } 121 if err := os.Chown(csConfig.DbConfig.DbPath, 0, intID); err != nil { 122 log.Fatalf("unable to chown sqlite db file '%s': %s", csConfig.DbConfig.DbPath, err) 123 } 124 125 mb, err := metabase.SetupMetabase(csConfig.API.Server.DbConfig, metabaseListenAddress, metabaseListenPort, metabaseUser, metabasePassword, metabaseDbPath, dockerGroup.Gid) 126 if err != nil { 127 log.Fatalf(err.Error()) 128 } 129 130 if err := mb.DumpConfig(metabaseConfigPath); err != nil { 131 log.Fatalf(err.Error()) 132 } 133 134 log.Infof("Metabase is ready") 135 fmt.Println() 136 fmt.Printf("\tURL : '%s'\n", mb.Config.ListenURL) 137 fmt.Printf("\tusername : '%s'\n", mb.Config.Username) 138 fmt.Printf("\tpassword : '%s'\n", mb.Config.Password) 139 }, 140 } 141 cmdDashSetup.Flags().BoolVarP(&force, "force", "f", false, "Force setup : override existing files.") 142 cmdDashSetup.Flags().StringVarP(&metabaseDbPath, "dir", "d", "", "Shared directory with metabase container.") 143 cmdDashSetup.Flags().StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container") 144 cmdDashSetup.Flags().StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container") 145 cmdDashSetup.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") 146 //cmdDashSetup.Flags().StringVarP(&metabaseUser, "user", "u", "synsec@synsec.net", "metabase user") 147 cmdDashSetup.Flags().StringVar(&metabasePassword, "password", "", "metabase password") 148 149 cmdDashboard.AddCommand(cmdDashSetup) 150 151 var cmdDashStart = &cobra.Command{ 152 Use: "start", 153 Short: "Start the metabase container.", 154 Long: `Stats the metabase container using docker.`, 155 Args: cobra.ExactArgs(0), 156 Run: func(cmd *cobra.Command, args []string) { 157 mb, err := metabase.NewMetabase(metabaseConfigPath) 158 if err != nil { 159 log.Fatalf(err.Error()) 160 } 161 if err := mb.Container.Start(); err != nil { 162 log.Fatalf("Failed to start metabase container : %s", err) 163 } 164 log.Infof("Started metabase") 165 log.Infof("url : http://%s:%s", metabaseListenAddress, metabaseListenPort) 166 }, 167 } 168 cmdDashboard.AddCommand(cmdDashStart) 169 170 var cmdDashStop = &cobra.Command{ 171 Use: "stop", 172 Short: "Stops the metabase container.", 173 Long: `Stops the metabase container using docker.`, 174 Args: cobra.ExactArgs(0), 175 Run: func(cmd *cobra.Command, args []string) { 176 if err := metabase.StopContainer(metabaseContainerID); err != nil { 177 log.Fatalf("unable to stop container '%s': %s", metabaseContainerID, err) 178 } 179 }, 180 } 181 cmdDashboard.AddCommand(cmdDashStop) 182 183 var cmdDashRemove = &cobra.Command{ 184 Use: "remove", 185 Short: "removes the metabase container.", 186 Long: `removes the metabase container using docker.`, 187 Args: cobra.ExactArgs(0), 188 Example: ` 189 ccscli dashboard remove 190 ccscli dashboard remove --force 191 `, 192 Run: func(cmd *cobra.Command, args []string) { 193 answer := true 194 if !forceYes { 195 prompt := &survey.Confirm{ 196 Message: "Do you really want to remove synsec dashboard? (all your changes will be lost)", 197 Default: true, 198 } 199 if err := survey.AskOne(prompt, &answer); err != nil { 200 log.Fatalf("unable to ask to force: %s", err) 201 } 202 } 203 if answer { 204 if metabase.IsContainerExist(metabaseContainerID) { 205 log.Debugf("Stopping container %s", metabaseContainerID) 206 if err := metabase.StopContainer(metabaseContainerID); err != nil { 207 log.Warningf("unable to stop container '%s': %s", metabaseContainerID, err) 208 } 209 dockerGroup, err := user.LookupGroup(synsecGroup) 210 if err == nil { // if group exist, remove it 211 groupDelCmd, err := exec.LookPath("groupdel") 212 if err != nil { 213 log.Fatalf("unable to find 'groupdel' command, can't continue") 214 } 215 216 groupDel := &exec.Cmd{Path: groupDelCmd, Args: []string{groupDelCmd, synsecGroup}} 217 if err := groupDel.Run(); err != nil { 218 log.Errorf("unable to delete group '%s': %s", dockerGroup, err) 219 } 220 } 221 log.Debugf("Removing container %s", metabaseContainerID) 222 if err := metabase.RemoveContainer(metabaseContainerID); err != nil { 223 log.Warningf("unable to remove container '%s': %s", metabaseContainerID, err) 224 } 225 log.Infof("container %s stopped & removed", metabaseContainerID) 226 } 227 log.Debugf("Removing metabase db %s", csConfig.ConfigPaths.DataDir) 228 if err := metabase.RemoveDatabase(csConfig.ConfigPaths.DataDir); err != nil { 229 log.Warningf("failed to remove metabase internal db : %s", err) 230 } 231 if force { 232 if err := metabase.RemoveImageContainer(); err != nil { 233 if !strings.Contains(err.Error(), "No such image") { 234 log.Fatalf("removing docker image: %s", err) 235 } 236 } 237 } 238 } 239 }, 240 } 241 cmdDashRemove.Flags().BoolVarP(&force, "force", "f", false, "Remove also the metabase image") 242 cmdDashRemove.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes") 243 cmdDashboard.AddCommand(cmdDashRemove) 244 245 return cmdDashboard 246 }