tokers commented on a change in pull request #1667:
URL: https://github.com/apache/apisix-dashboard/pull/1667#discussion_r617990056



##########
File path: api/cmd/managerapi.go
##########
@@ -59,6 +60,14 @@ func printVersion() {
 
 // NewManagerAPICommand creates the manager-api command.
 func NewManagerAPICommand() *cobra.Command {
+       cobra.OnInitialize(func() {
+               var err error
+               service, err = createService()
+               if err != nil {
+                       fmt.Fprintf(os.Stderr, "error occurred while 
initializing service: %s", err)

Review comment:
       I think we can quit after outputing this message.

##########
File path: api/cmd/managerapi.go
##########
@@ -68,91 +77,136 @@ func NewManagerAPICommand() *cobra.Command {
                                printVersion()
                                os.Exit(0)
                        }
+                       err := manageAPI()
+                       return err
+               },
+       }
 
-                       conf.InitConf()
-                       log.InitLogger()
+       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
+       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
 
-                       if err := utils.WritePID(conf.PIDPath); err != nil {
-                               log.Errorf("failed to write pid: %s", err)
-                               panic(err)
-                       }
-                       utils.AppendToClosers(func() error {
-                               if err := os.Remove(conf.PIDPath); err != nil {
-                                       log.Errorf("failed to remove pid path: 
%s", err)
-                                       return err
-                               }
-                               return nil
-                       })
-
-                       droplet.Option.Orchestrator = func(mws 
[]droplet.Middleware) []droplet.Middleware {
-                               var newMws []droplet.Middleware
-                               // default middleware order: resp_reshape, 
auto_input, traffic_log
-                               // We should put err_transform at second to 
catch all error
-                               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
-                               newMws = append(newMws, mws[1:]...)
-                               return newMws
-                       }
+       cmd.AddCommand(newStartCommand(), newInstallCommand(), 
newStatusCommand(), newStopCommand(), newRemoveCommand())
+       return cmd
+}
 
-                       if err := storage.InitETCDClient(conf.ETCDConfig); err 
!= nil {
-                               log.Errorf("init etcd client fail: %w", err)
-                               panic(err)
-                       }
-                       if err := store.InitStores(); err != nil {
-                               log.Errorf("init stores fail: %w", err)
-                               panic(err)
-                       }
+func manageAPI() error {
+       conf.InitConf()
+       log.InitLogger()
 
-                       // routes
-                       r := internal.SetUpRouter()
-                       addr := fmt.Sprintf("%s:%d", conf.ServerHost, 
conf.ServerPort)
-                       s := &http.Server{
-                               Addr:         addr,
-                               Handler:      r,
-                               ReadTimeout:  time.Duration(1000) * 
time.Millisecond,
-                               WriteTimeout: time.Duration(5000) * 
time.Millisecond,
-                       }
+       if err := utils.WritePID(conf.PIDPath); err != nil {
+               log.Errorf("failed to write pid: %s", err)
+               panic(err)
+       }
+       utils.AppendToClosers(func() error {
+               if err := os.Remove(conf.PIDPath); err != nil {
+                       log.Errorf("failed to remove pid path: %s", err)
+                       return err
+               }
+               return nil
+       })
+
+       droplet.Option.Orchestrator = func(mws []droplet.Middleware) 
[]droplet.Middleware {
+               var newMws []droplet.Middleware
+               // default middleware order: resp_reshape, auto_input, 
traffic_log
+               // We should put err_transform at second to catch all error
+               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
+               newMws = append(newMws, mws[1:]...)
+               return newMws
+       }
 
-                       log.Infof("The Manager API is listening on %s", addr)
+       if err := storage.InitETCDClient(conf.ETCDConfig); err != nil {
+               log.Errorf("init etcd client fail: %w", err)
+               panic(err)
+       }
+       if err := store.InitStores(); err != nil {
+               log.Errorf("init stores fail: %w", err)
+               panic(err)
+       }
 
-                       quit := make(chan os.Signal, 1)
-                       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       // routes
+       r := internal.SetUpRouter()
+       addr := fmt.Sprintf("%s:%d", conf.ServerHost, conf.ServerPort)
+       s := &http.Server{
+               Addr:         addr,
+               Handler:      r,
+               ReadTimeout:  time.Duration(1000) * time.Millisecond,
+               WriteTimeout: time.Duration(5000) * time.Millisecond,
+       }
 
-                       go func() {
-                               if err := s.ListenAndServe(); err != nil && err 
!= http.ErrServerClosed {
-                                       utils.CloseAll()
-                                       log.Fatalf("listen and serv fail: %s", 
err)
-                               }
-                       }()
+       log.Infof("The Manager API is listening on %s", addr)
 
-                       printInfo()
+       quit := make(chan os.Signal, 1)
+       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       defer signal.Stop(quit)
 
-                       sig := <-quit
-                       log.Infof("The Manager API server receive %s and start 
shutting down", sig.String())
+       go func() {
+               if err := s.ListenAndServe(); err != nil && err != 
http.ErrServerClosed {
+                       utils.CloseAll()
+                       log.Fatalf("listen and serv fail: %s", err)
+               }
+       }()
 
-                       ctx, cancel := context.WithTimeout(context.TODO(), 
5*time.Second)
-                       defer cancel()
+       printInfo()
 
-                       if err := s.Shutdown(ctx); err != nil {
-                               log.Errorf("Shutting down server error: %s", 
err)
-                       }
+       sig := <-quit
+       log.Infof("The Manager API server receive %s and start shutting down", 
sig.String())
 
-                       log.Infof("The Manager API server exited")
+       ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
+       defer cancel()
 
-                       utils.CloseAll()
-                       return nil
-               },
+       if err := s.Shutdown(ctx); err != nil {
+               log.Errorf("Shutting down server error: %s", err)
        }
 
-       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
-       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
+       log.Infof("The Manager API server exited")
 
-       cmd.AddCommand(newStopCommand())
-       return cmd
+       utils.CloseAll()
+       return nil
 }
 
+func newStartCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "start",
+               Short: "start Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.startService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}
+func newInstallCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "install",
+               Short: "reinstall Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.installService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}

Review comment:
       Style: keep an empty line here.

##########
File path: api/cmd/managerapi.go
##########
@@ -68,91 +77,136 @@ func NewManagerAPICommand() *cobra.Command {
                                printVersion()
                                os.Exit(0)
                        }
+                       err := manageAPI()
+                       return err
+               },
+       }
 
-                       conf.InitConf()
-                       log.InitLogger()
+       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
+       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
 
-                       if err := utils.WritePID(conf.PIDPath); err != nil {
-                               log.Errorf("failed to write pid: %s", err)
-                               panic(err)
-                       }
-                       utils.AppendToClosers(func() error {
-                               if err := os.Remove(conf.PIDPath); err != nil {
-                                       log.Errorf("failed to remove pid path: 
%s", err)
-                                       return err
-                               }
-                               return nil
-                       })
-
-                       droplet.Option.Orchestrator = func(mws 
[]droplet.Middleware) []droplet.Middleware {
-                               var newMws []droplet.Middleware
-                               // default middleware order: resp_reshape, 
auto_input, traffic_log
-                               // We should put err_transform at second to 
catch all error
-                               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
-                               newMws = append(newMws, mws[1:]...)
-                               return newMws
-                       }
+       cmd.AddCommand(newStartCommand(), newInstallCommand(), 
newStatusCommand(), newStopCommand(), newRemoveCommand())
+       return cmd
+}
 
-                       if err := storage.InitETCDClient(conf.ETCDConfig); err 
!= nil {
-                               log.Errorf("init etcd client fail: %w", err)
-                               panic(err)
-                       }
-                       if err := store.InitStores(); err != nil {
-                               log.Errorf("init stores fail: %w", err)
-                               panic(err)
-                       }
+func manageAPI() error {
+       conf.InitConf()
+       log.InitLogger()
 
-                       // routes
-                       r := internal.SetUpRouter()
-                       addr := fmt.Sprintf("%s:%d", conf.ServerHost, 
conf.ServerPort)
-                       s := &http.Server{
-                               Addr:         addr,
-                               Handler:      r,
-                               ReadTimeout:  time.Duration(1000) * 
time.Millisecond,
-                               WriteTimeout: time.Duration(5000) * 
time.Millisecond,
-                       }
+       if err := utils.WritePID(conf.PIDPath); err != nil {
+               log.Errorf("failed to write pid: %s", err)
+               panic(err)
+       }
+       utils.AppendToClosers(func() error {
+               if err := os.Remove(conf.PIDPath); err != nil {
+                       log.Errorf("failed to remove pid path: %s", err)
+                       return err
+               }
+               return nil
+       })
+
+       droplet.Option.Orchestrator = func(mws []droplet.Middleware) 
[]droplet.Middleware {
+               var newMws []droplet.Middleware
+               // default middleware order: resp_reshape, auto_input, 
traffic_log
+               // We should put err_transform at second to catch all error
+               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
+               newMws = append(newMws, mws[1:]...)
+               return newMws
+       }
 
-                       log.Infof("The Manager API is listening on %s", addr)
+       if err := storage.InitETCDClient(conf.ETCDConfig); err != nil {
+               log.Errorf("init etcd client fail: %w", err)
+               panic(err)
+       }
+       if err := store.InitStores(); err != nil {
+               log.Errorf("init stores fail: %w", err)
+               panic(err)
+       }
 
-                       quit := make(chan os.Signal, 1)
-                       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       // routes
+       r := internal.SetUpRouter()
+       addr := fmt.Sprintf("%s:%d", conf.ServerHost, conf.ServerPort)
+       s := &http.Server{
+               Addr:         addr,
+               Handler:      r,
+               ReadTimeout:  time.Duration(1000) * time.Millisecond,
+               WriteTimeout: time.Duration(5000) * time.Millisecond,
+       }
 
-                       go func() {
-                               if err := s.ListenAndServe(); err != nil && err 
!= http.ErrServerClosed {
-                                       utils.CloseAll()
-                                       log.Fatalf("listen and serv fail: %s", 
err)
-                               }
-                       }()
+       log.Infof("The Manager API is listening on %s", addr)
 
-                       printInfo()
+       quit := make(chan os.Signal, 1)
+       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       defer signal.Stop(quit)
 
-                       sig := <-quit
-                       log.Infof("The Manager API server receive %s and start 
shutting down", sig.String())
+       go func() {
+               if err := s.ListenAndServe(); err != nil && err != 
http.ErrServerClosed {
+                       utils.CloseAll()
+                       log.Fatalf("listen and serv fail: %s", err)
+               }
+       }()
 
-                       ctx, cancel := context.WithTimeout(context.TODO(), 
5*time.Second)
-                       defer cancel()
+       printInfo()
 
-                       if err := s.Shutdown(ctx); err != nil {
-                               log.Errorf("Shutting down server error: %s", 
err)
-                       }
+       sig := <-quit
+       log.Infof("The Manager API server receive %s and start shutting down", 
sig.String())
 
-                       log.Infof("The Manager API server exited")
+       ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
+       defer cancel()
 
-                       utils.CloseAll()
-                       return nil
-               },
+       if err := s.Shutdown(ctx); err != nil {
+               log.Errorf("Shutting down server error: %s", err)
        }
 
-       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
-       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
+       log.Infof("The Manager API server exited")
 
-       cmd.AddCommand(newStopCommand())
-       return cmd
+       utils.CloseAll()
+       return nil
 }
 
+func newStartCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "start",
+               Short: "start Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.startService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}
+func newInstallCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "install",
+               Short: "reinstall Apache APISIX Dashboard service",

Review comment:
       ```suggestion
                Short: "re-install Apache APISIX Dashboard service",
   ```

##########
File path: api/cmd/managerapi.go
##########
@@ -68,91 +77,136 @@ func NewManagerAPICommand() *cobra.Command {
                                printVersion()
                                os.Exit(0)
                        }
+                       err := manageAPI()
+                       return err
+               },
+       }
 
-                       conf.InitConf()
-                       log.InitLogger()
+       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
+       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
 
-                       if err := utils.WritePID(conf.PIDPath); err != nil {
-                               log.Errorf("failed to write pid: %s", err)
-                               panic(err)
-                       }
-                       utils.AppendToClosers(func() error {
-                               if err := os.Remove(conf.PIDPath); err != nil {
-                                       log.Errorf("failed to remove pid path: 
%s", err)
-                                       return err
-                               }
-                               return nil
-                       })
-
-                       droplet.Option.Orchestrator = func(mws 
[]droplet.Middleware) []droplet.Middleware {
-                               var newMws []droplet.Middleware
-                               // default middleware order: resp_reshape, 
auto_input, traffic_log
-                               // We should put err_transform at second to 
catch all error
-                               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
-                               newMws = append(newMws, mws[1:]...)
-                               return newMws
-                       }
+       cmd.AddCommand(newStartCommand(), newInstallCommand(), 
newStatusCommand(), newStopCommand(), newRemoveCommand())
+       return cmd
+}
 
-                       if err := storage.InitETCDClient(conf.ETCDConfig); err 
!= nil {
-                               log.Errorf("init etcd client fail: %w", err)
-                               panic(err)
-                       }
-                       if err := store.InitStores(); err != nil {
-                               log.Errorf("init stores fail: %w", err)
-                               panic(err)
-                       }
+func manageAPI() error {
+       conf.InitConf()
+       log.InitLogger()
 
-                       // routes
-                       r := internal.SetUpRouter()
-                       addr := fmt.Sprintf("%s:%d", conf.ServerHost, 
conf.ServerPort)
-                       s := &http.Server{
-                               Addr:         addr,
-                               Handler:      r,
-                               ReadTimeout:  time.Duration(1000) * 
time.Millisecond,
-                               WriteTimeout: time.Duration(5000) * 
time.Millisecond,
-                       }
+       if err := utils.WritePID(conf.PIDPath); err != nil {
+               log.Errorf("failed to write pid: %s", err)
+               panic(err)
+       }
+       utils.AppendToClosers(func() error {
+               if err := os.Remove(conf.PIDPath); err != nil {
+                       log.Errorf("failed to remove pid path: %s", err)
+                       return err
+               }
+               return nil
+       })
+
+       droplet.Option.Orchestrator = func(mws []droplet.Middleware) 
[]droplet.Middleware {
+               var newMws []droplet.Middleware
+               // default middleware order: resp_reshape, auto_input, 
traffic_log
+               // We should put err_transform at second to catch all error
+               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
+               newMws = append(newMws, mws[1:]...)
+               return newMws
+       }
 
-                       log.Infof("The Manager API is listening on %s", addr)
+       if err := storage.InitETCDClient(conf.ETCDConfig); err != nil {
+               log.Errorf("init etcd client fail: %w", err)
+               panic(err)
+       }
+       if err := store.InitStores(); err != nil {
+               log.Errorf("init stores fail: %w", err)
+               panic(err)
+       }
 
-                       quit := make(chan os.Signal, 1)
-                       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       // routes
+       r := internal.SetUpRouter()
+       addr := fmt.Sprintf("%s:%d", conf.ServerHost, conf.ServerPort)
+       s := &http.Server{
+               Addr:         addr,
+               Handler:      r,
+               ReadTimeout:  time.Duration(1000) * time.Millisecond,
+               WriteTimeout: time.Duration(5000) * time.Millisecond,
+       }
 
-                       go func() {
-                               if err := s.ListenAndServe(); err != nil && err 
!= http.ErrServerClosed {
-                                       utils.CloseAll()
-                                       log.Fatalf("listen and serv fail: %s", 
err)
-                               }
-                       }()
+       log.Infof("The Manager API is listening on %s", addr)
 
-                       printInfo()
+       quit := make(chan os.Signal, 1)
+       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       defer signal.Stop(quit)
 
-                       sig := <-quit
-                       log.Infof("The Manager API server receive %s and start 
shutting down", sig.String())
+       go func() {
+               if err := s.ListenAndServe(); err != nil && err != 
http.ErrServerClosed {
+                       utils.CloseAll()
+                       log.Fatalf("listen and serv fail: %s", err)
+               }
+       }()
 
-                       ctx, cancel := context.WithTimeout(context.TODO(), 
5*time.Second)
-                       defer cancel()
+       printInfo()
 
-                       if err := s.Shutdown(ctx); err != nil {
-                               log.Errorf("Shutting down server error: %s", 
err)
-                       }
+       sig := <-quit
+       log.Infof("The Manager API server receive %s and start shutting down", 
sig.String())
 
-                       log.Infof("The Manager API server exited")
+       ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
+       defer cancel()
 
-                       utils.CloseAll()
-                       return nil
-               },
+       if err := s.Shutdown(ctx); err != nil {
+               log.Errorf("Shutting down server error: %s", err)
        }
 
-       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
-       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
+       log.Infof("The Manager API server exited")
 
-       cmd.AddCommand(newStopCommand())
-       return cmd
+       utils.CloseAll()
+       return nil
 }
 
+func newStartCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "start",
+               Short: "start Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.startService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}
+func newInstallCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "install",
+               Short: "reinstall Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.installService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}
+func newStatusCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "status",
+               Short: "status of Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.status = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)

Review comment:
       ```suggestion
                        fmt.Println(status)
   ```

##########
File path: api/cmd/managerapi.go
##########
@@ -68,91 +77,136 @@ func NewManagerAPICommand() *cobra.Command {
                                printVersion()
                                os.Exit(0)
                        }
+                       err := manageAPI()
+                       return err
+               },
+       }
 
-                       conf.InitConf()
-                       log.InitLogger()
+       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
+       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
 
-                       if err := utils.WritePID(conf.PIDPath); err != nil {
-                               log.Errorf("failed to write pid: %s", err)
-                               panic(err)
-                       }
-                       utils.AppendToClosers(func() error {
-                               if err := os.Remove(conf.PIDPath); err != nil {
-                                       log.Errorf("failed to remove pid path: 
%s", err)
-                                       return err
-                               }
-                               return nil
-                       })
-
-                       droplet.Option.Orchestrator = func(mws 
[]droplet.Middleware) []droplet.Middleware {
-                               var newMws []droplet.Middleware
-                               // default middleware order: resp_reshape, 
auto_input, traffic_log
-                               // We should put err_transform at second to 
catch all error
-                               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
-                               newMws = append(newMws, mws[1:]...)
-                               return newMws
-                       }
+       cmd.AddCommand(newStartCommand(), newInstallCommand(), 
newStatusCommand(), newStopCommand(), newRemoveCommand())
+       return cmd
+}
 
-                       if err := storage.InitETCDClient(conf.ETCDConfig); err 
!= nil {
-                               log.Errorf("init etcd client fail: %w", err)
-                               panic(err)
-                       }
-                       if err := store.InitStores(); err != nil {
-                               log.Errorf("init stores fail: %w", err)
-                               panic(err)
-                       }
+func manageAPI() error {
+       conf.InitConf()
+       log.InitLogger()
 
-                       // routes
-                       r := internal.SetUpRouter()
-                       addr := fmt.Sprintf("%s:%d", conf.ServerHost, 
conf.ServerPort)
-                       s := &http.Server{
-                               Addr:         addr,
-                               Handler:      r,
-                               ReadTimeout:  time.Duration(1000) * 
time.Millisecond,
-                               WriteTimeout: time.Duration(5000) * 
time.Millisecond,
-                       }
+       if err := utils.WritePID(conf.PIDPath); err != nil {
+               log.Errorf("failed to write pid: %s", err)
+               panic(err)
+       }
+       utils.AppendToClosers(func() error {
+               if err := os.Remove(conf.PIDPath); err != nil {
+                       log.Errorf("failed to remove pid path: %s", err)
+                       return err
+               }
+               return nil
+       })
+
+       droplet.Option.Orchestrator = func(mws []droplet.Middleware) 
[]droplet.Middleware {
+               var newMws []droplet.Middleware
+               // default middleware order: resp_reshape, auto_input, 
traffic_log
+               // We should put err_transform at second to catch all error
+               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
+               newMws = append(newMws, mws[1:]...)
+               return newMws
+       }
 
-                       log.Infof("The Manager API is listening on %s", addr)
+       if err := storage.InitETCDClient(conf.ETCDConfig); err != nil {
+               log.Errorf("init etcd client fail: %w", err)
+               panic(err)
+       }
+       if err := store.InitStores(); err != nil {
+               log.Errorf("init stores fail: %w", err)
+               panic(err)
+       }
 
-                       quit := make(chan os.Signal, 1)
-                       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       // routes
+       r := internal.SetUpRouter()
+       addr := fmt.Sprintf("%s:%d", conf.ServerHost, conf.ServerPort)
+       s := &http.Server{
+               Addr:         addr,
+               Handler:      r,
+               ReadTimeout:  time.Duration(1000) * time.Millisecond,
+               WriteTimeout: time.Duration(5000) * time.Millisecond,
+       }
 
-                       go func() {
-                               if err := s.ListenAndServe(); err != nil && err 
!= http.ErrServerClosed {
-                                       utils.CloseAll()
-                                       log.Fatalf("listen and serv fail: %s", 
err)
-                               }
-                       }()
+       log.Infof("The Manager API is listening on %s", addr)
 
-                       printInfo()
+       quit := make(chan os.Signal, 1)
+       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       defer signal.Stop(quit)
 
-                       sig := <-quit
-                       log.Infof("The Manager API server receive %s and start 
shutting down", sig.String())
+       go func() {
+               if err := s.ListenAndServe(); err != nil && err != 
http.ErrServerClosed {
+                       utils.CloseAll()
+                       log.Fatalf("listen and serv fail: %s", err)
+               }
+       }()
 
-                       ctx, cancel := context.WithTimeout(context.TODO(), 
5*time.Second)
-                       defer cancel()
+       printInfo()
 
-                       if err := s.Shutdown(ctx); err != nil {
-                               log.Errorf("Shutting down server error: %s", 
err)
-                       }
+       sig := <-quit
+       log.Infof("The Manager API server receive %s and start shutting down", 
sig.String())
 
-                       log.Infof("The Manager API server exited")
+       ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
+       defer cancel()
 
-                       utils.CloseAll()
-                       return nil
-               },
+       if err := s.Shutdown(ctx); err != nil {
+               log.Errorf("Shutting down server error: %s", err)
        }
 
-       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
-       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
+       log.Infof("The Manager API server exited")
 
-       cmd.AddCommand(newStopCommand())
-       return cmd
+       utils.CloseAll()
+       return nil
 }
 
+func newStartCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "start",
+               Short: "start Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.startService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}

Review comment:
       Style: keep an empty line.

##########
File path: api/cmd/managerapi.go
##########
@@ -68,91 +77,136 @@ func NewManagerAPICommand() *cobra.Command {
                                printVersion()
                                os.Exit(0)
                        }
+                       err := manageAPI()
+                       return err
+               },
+       }
 
-                       conf.InitConf()
-                       log.InitLogger()
+       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
+       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
 
-                       if err := utils.WritePID(conf.PIDPath); err != nil {
-                               log.Errorf("failed to write pid: %s", err)
-                               panic(err)
-                       }
-                       utils.AppendToClosers(func() error {
-                               if err := os.Remove(conf.PIDPath); err != nil {
-                                       log.Errorf("failed to remove pid path: 
%s", err)
-                                       return err
-                               }
-                               return nil
-                       })
-
-                       droplet.Option.Orchestrator = func(mws 
[]droplet.Middleware) []droplet.Middleware {
-                               var newMws []droplet.Middleware
-                               // default middleware order: resp_reshape, 
auto_input, traffic_log
-                               // We should put err_transform at second to 
catch all error
-                               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
-                               newMws = append(newMws, mws[1:]...)
-                               return newMws
-                       }
+       cmd.AddCommand(newStartCommand(), newInstallCommand(), 
newStatusCommand(), newStopCommand(), newRemoveCommand())
+       return cmd
+}
 
-                       if err := storage.InitETCDClient(conf.ETCDConfig); err 
!= nil {
-                               log.Errorf("init etcd client fail: %w", err)
-                               panic(err)
-                       }
-                       if err := store.InitStores(); err != nil {
-                               log.Errorf("init stores fail: %w", err)
-                               panic(err)
-                       }
+func manageAPI() error {
+       conf.InitConf()
+       log.InitLogger()
 
-                       // routes
-                       r := internal.SetUpRouter()
-                       addr := fmt.Sprintf("%s:%d", conf.ServerHost, 
conf.ServerPort)
-                       s := &http.Server{
-                               Addr:         addr,
-                               Handler:      r,
-                               ReadTimeout:  time.Duration(1000) * 
time.Millisecond,
-                               WriteTimeout: time.Duration(5000) * 
time.Millisecond,
-                       }
+       if err := utils.WritePID(conf.PIDPath); err != nil {
+               log.Errorf("failed to write pid: %s", err)
+               panic(err)
+       }
+       utils.AppendToClosers(func() error {
+               if err := os.Remove(conf.PIDPath); err != nil {
+                       log.Errorf("failed to remove pid path: %s", err)
+                       return err
+               }
+               return nil
+       })
+
+       droplet.Option.Orchestrator = func(mws []droplet.Middleware) 
[]droplet.Middleware {
+               var newMws []droplet.Middleware
+               // default middleware order: resp_reshape, auto_input, 
traffic_log
+               // We should put err_transform at second to catch all error
+               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
+               newMws = append(newMws, mws[1:]...)
+               return newMws
+       }
 
-                       log.Infof("The Manager API is listening on %s", addr)
+       if err := storage.InitETCDClient(conf.ETCDConfig); err != nil {
+               log.Errorf("init etcd client fail: %w", err)
+               panic(err)
+       }
+       if err := store.InitStores(); err != nil {
+               log.Errorf("init stores fail: %w", err)
+               panic(err)
+       }
 
-                       quit := make(chan os.Signal, 1)
-                       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       // routes
+       r := internal.SetUpRouter()
+       addr := fmt.Sprintf("%s:%d", conf.ServerHost, conf.ServerPort)
+       s := &http.Server{
+               Addr:         addr,
+               Handler:      r,
+               ReadTimeout:  time.Duration(1000) * time.Millisecond,
+               WriteTimeout: time.Duration(5000) * time.Millisecond,
+       }
 
-                       go func() {
-                               if err := s.ListenAndServe(); err != nil && err 
!= http.ErrServerClosed {
-                                       utils.CloseAll()
-                                       log.Fatalf("listen and serv fail: %s", 
err)
-                               }
-                       }()
+       log.Infof("The Manager API is listening on %s", addr)
 
-                       printInfo()
+       quit := make(chan os.Signal, 1)
+       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       defer signal.Stop(quit)
 
-                       sig := <-quit
-                       log.Infof("The Manager API server receive %s and start 
shutting down", sig.String())
+       go func() {
+               if err := s.ListenAndServe(); err != nil && err != 
http.ErrServerClosed {
+                       utils.CloseAll()
+                       log.Fatalf("listen and serv fail: %s", err)
+               }
+       }()
 
-                       ctx, cancel := context.WithTimeout(context.TODO(), 
5*time.Second)
-                       defer cancel()
+       printInfo()
 
-                       if err := s.Shutdown(ctx); err != nil {
-                               log.Errorf("Shutting down server error: %s", 
err)
-                       }
+       sig := <-quit
+       log.Infof("The Manager API server receive %s and start shutting down", 
sig.String())
 
-                       log.Infof("The Manager API server exited")
+       ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
+       defer cancel()
 
-                       utils.CloseAll()
-                       return nil
-               },
+       if err := s.Shutdown(ctx); err != nil {
+               log.Errorf("Shutting down server error: %s", err)
        }
 
-       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
-       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
+       log.Infof("The Manager API server exited")
 
-       cmd.AddCommand(newStopCommand())
-       return cmd
+       utils.CloseAll()
+       return nil
 }
 
+func newStartCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "start",
+               Short: "start Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.startService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}
+func newInstallCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "install",
+               Short: "reinstall Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.installService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}
+func newStatusCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "status",
+               Short: "status of Apache APISIX Dashboard service",

Review comment:
       ```suggestion
                Short: "check out the status of Apache APISIX Dashboard 
service",
   ```

##########
File path: api/cmd/managerapi.go
##########
@@ -170,3 +224,16 @@ func newStopCommand() *cobra.Command {
        }
        return cmd
 }
+func newRemoveCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "remove",
+               Short: "remove Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.removeService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)

Review comment:
       ```suggestion
                        fmt.Println(status)
   ```

##########
File path: api/cmd/managerapi.go
##########
@@ -68,91 +77,136 @@ func NewManagerAPICommand() *cobra.Command {
                                printVersion()
                                os.Exit(0)
                        }
+                       err := manageAPI()
+                       return err
+               },
+       }
 
-                       conf.InitConf()
-                       log.InitLogger()
+       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
+       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
 
-                       if err := utils.WritePID(conf.PIDPath); err != nil {
-                               log.Errorf("failed to write pid: %s", err)
-                               panic(err)
-                       }
-                       utils.AppendToClosers(func() error {
-                               if err := os.Remove(conf.PIDPath); err != nil {
-                                       log.Errorf("failed to remove pid path: 
%s", err)
-                                       return err
-                               }
-                               return nil
-                       })
-
-                       droplet.Option.Orchestrator = func(mws 
[]droplet.Middleware) []droplet.Middleware {
-                               var newMws []droplet.Middleware
-                               // default middleware order: resp_reshape, 
auto_input, traffic_log
-                               // We should put err_transform at second to 
catch all error
-                               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
-                               newMws = append(newMws, mws[1:]...)
-                               return newMws
-                       }
+       cmd.AddCommand(newStartCommand(), newInstallCommand(), 
newStatusCommand(), newStopCommand(), newRemoveCommand())
+       return cmd
+}
 
-                       if err := storage.InitETCDClient(conf.ETCDConfig); err 
!= nil {
-                               log.Errorf("init etcd client fail: %w", err)
-                               panic(err)
-                       }
-                       if err := store.InitStores(); err != nil {
-                               log.Errorf("init stores fail: %w", err)
-                               panic(err)
-                       }
+func manageAPI() error {
+       conf.InitConf()
+       log.InitLogger()
 
-                       // routes
-                       r := internal.SetUpRouter()
-                       addr := fmt.Sprintf("%s:%d", conf.ServerHost, 
conf.ServerPort)
-                       s := &http.Server{
-                               Addr:         addr,
-                               Handler:      r,
-                               ReadTimeout:  time.Duration(1000) * 
time.Millisecond,
-                               WriteTimeout: time.Duration(5000) * 
time.Millisecond,
-                       }
+       if err := utils.WritePID(conf.PIDPath); err != nil {
+               log.Errorf("failed to write pid: %s", err)
+               panic(err)
+       }
+       utils.AppendToClosers(func() error {
+               if err := os.Remove(conf.PIDPath); err != nil {
+                       log.Errorf("failed to remove pid path: %s", err)
+                       return err
+               }
+               return nil
+       })
+
+       droplet.Option.Orchestrator = func(mws []droplet.Middleware) 
[]droplet.Middleware {
+               var newMws []droplet.Middleware
+               // default middleware order: resp_reshape, auto_input, 
traffic_log
+               // We should put err_transform at second to catch all error
+               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
+               newMws = append(newMws, mws[1:]...)
+               return newMws
+       }
 
-                       log.Infof("The Manager API is listening on %s", addr)
+       if err := storage.InitETCDClient(conf.ETCDConfig); err != nil {
+               log.Errorf("init etcd client fail: %w", err)
+               panic(err)
+       }
+       if err := store.InitStores(); err != nil {
+               log.Errorf("init stores fail: %w", err)
+               panic(err)
+       }
 
-                       quit := make(chan os.Signal, 1)
-                       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       // routes
+       r := internal.SetUpRouter()
+       addr := fmt.Sprintf("%s:%d", conf.ServerHost, conf.ServerPort)
+       s := &http.Server{
+               Addr:         addr,
+               Handler:      r,
+               ReadTimeout:  time.Duration(1000) * time.Millisecond,
+               WriteTimeout: time.Duration(5000) * time.Millisecond,
+       }
 
-                       go func() {
-                               if err := s.ListenAndServe(); err != nil && err 
!= http.ErrServerClosed {
-                                       utils.CloseAll()
-                                       log.Fatalf("listen and serv fail: %s", 
err)
-                               }
-                       }()
+       log.Infof("The Manager API is listening on %s", addr)
 
-                       printInfo()
+       quit := make(chan os.Signal, 1)
+       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       defer signal.Stop(quit)
 
-                       sig := <-quit
-                       log.Infof("The Manager API server receive %s and start 
shutting down", sig.String())
+       go func() {
+               if err := s.ListenAndServe(); err != nil && err != 
http.ErrServerClosed {
+                       utils.CloseAll()
+                       log.Fatalf("listen and serv fail: %s", err)
+               }
+       }()
 
-                       ctx, cancel := context.WithTimeout(context.TODO(), 
5*time.Second)
-                       defer cancel()
+       printInfo()
 
-                       if err := s.Shutdown(ctx); err != nil {
-                               log.Errorf("Shutting down server error: %s", 
err)
-                       }
+       sig := <-quit
+       log.Infof("The Manager API server receive %s and start shutting down", 
sig.String())
 
-                       log.Infof("The Manager API server exited")
+       ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
+       defer cancel()
 
-                       utils.CloseAll()
-                       return nil
-               },
+       if err := s.Shutdown(ctx); err != nil {
+               log.Errorf("Shutting down server error: %s", err)
        }
 
-       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
-       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
+       log.Infof("The Manager API server exited")
 
-       cmd.AddCommand(newStopCommand())
-       return cmd
+       utils.CloseAll()
+       return nil
 }
 
+func newStartCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "start",
+               Short: "start Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.startService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}
+func newInstallCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "install",
+               Short: "reinstall Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.installService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)
+                       return err
+               },
+       }
+       return cmd
+}
+func newStatusCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "status",
+               Short: "status of Apache APISIX Dashboard service",

Review comment:
       ```suggestion
                Short: "inspect the status of Apache APISIX Dashboard service",
   ```

##########
File path: api/cmd/managerapi.go
##########
@@ -68,91 +77,136 @@ func NewManagerAPICommand() *cobra.Command {
                                printVersion()
                                os.Exit(0)
                        }
+                       err := manageAPI()
+                       return err
+               },
+       }
 
-                       conf.InitConf()
-                       log.InitLogger()
+       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
+       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
 
-                       if err := utils.WritePID(conf.PIDPath); err != nil {
-                               log.Errorf("failed to write pid: %s", err)
-                               panic(err)
-                       }
-                       utils.AppendToClosers(func() error {
-                               if err := os.Remove(conf.PIDPath); err != nil {
-                                       log.Errorf("failed to remove pid path: 
%s", err)
-                                       return err
-                               }
-                               return nil
-                       })
-
-                       droplet.Option.Orchestrator = func(mws 
[]droplet.Middleware) []droplet.Middleware {
-                               var newMws []droplet.Middleware
-                               // default middleware order: resp_reshape, 
auto_input, traffic_log
-                               // We should put err_transform at second to 
catch all error
-                               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
-                               newMws = append(newMws, mws[1:]...)
-                               return newMws
-                       }
+       cmd.AddCommand(newStartCommand(), newInstallCommand(), 
newStatusCommand(), newStopCommand(), newRemoveCommand())
+       return cmd
+}
 
-                       if err := storage.InitETCDClient(conf.ETCDConfig); err 
!= nil {
-                               log.Errorf("init etcd client fail: %w", err)
-                               panic(err)
-                       }
-                       if err := store.InitStores(); err != nil {
-                               log.Errorf("init stores fail: %w", err)
-                               panic(err)
-                       }
+func manageAPI() error {
+       conf.InitConf()
+       log.InitLogger()
 
-                       // routes
-                       r := internal.SetUpRouter()
-                       addr := fmt.Sprintf("%s:%d", conf.ServerHost, 
conf.ServerPort)
-                       s := &http.Server{
-                               Addr:         addr,
-                               Handler:      r,
-                               ReadTimeout:  time.Duration(1000) * 
time.Millisecond,
-                               WriteTimeout: time.Duration(5000) * 
time.Millisecond,
-                       }
+       if err := utils.WritePID(conf.PIDPath); err != nil {
+               log.Errorf("failed to write pid: %s", err)
+               panic(err)
+       }
+       utils.AppendToClosers(func() error {
+               if err := os.Remove(conf.PIDPath); err != nil {
+                       log.Errorf("failed to remove pid path: %s", err)
+                       return err
+               }
+               return nil
+       })
+
+       droplet.Option.Orchestrator = func(mws []droplet.Middleware) 
[]droplet.Middleware {
+               var newMws []droplet.Middleware
+               // default middleware order: resp_reshape, auto_input, 
traffic_log
+               // We should put err_transform at second to catch all error
+               newMws = append(newMws, mws[0], 
&handler.ErrorTransformMiddleware{}, &filter.AuthenticationMiddleware{})
+               newMws = append(newMws, mws[1:]...)
+               return newMws
+       }
 
-                       log.Infof("The Manager API is listening on %s", addr)
+       if err := storage.InitETCDClient(conf.ETCDConfig); err != nil {
+               log.Errorf("init etcd client fail: %w", err)
+               panic(err)
+       }
+       if err := store.InitStores(); err != nil {
+               log.Errorf("init stores fail: %w", err)
+               panic(err)
+       }
 
-                       quit := make(chan os.Signal, 1)
-                       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       // routes
+       r := internal.SetUpRouter()
+       addr := fmt.Sprintf("%s:%d", conf.ServerHost, conf.ServerPort)
+       s := &http.Server{
+               Addr:         addr,
+               Handler:      r,
+               ReadTimeout:  time.Duration(1000) * time.Millisecond,
+               WriteTimeout: time.Duration(5000) * time.Millisecond,
+       }
 
-                       go func() {
-                               if err := s.ListenAndServe(); err != nil && err 
!= http.ErrServerClosed {
-                                       utils.CloseAll()
-                                       log.Fatalf("listen and serv fail: %s", 
err)
-                               }
-                       }()
+       log.Infof("The Manager API is listening on %s", addr)
 
-                       printInfo()
+       quit := make(chan os.Signal, 1)
+       signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+       defer signal.Stop(quit)
 
-                       sig := <-quit
-                       log.Infof("The Manager API server receive %s and start 
shutting down", sig.String())
+       go func() {
+               if err := s.ListenAndServe(); err != nil && err != 
http.ErrServerClosed {
+                       utils.CloseAll()
+                       log.Fatalf("listen and serv fail: %s", err)
+               }
+       }()
 
-                       ctx, cancel := context.WithTimeout(context.TODO(), 
5*time.Second)
-                       defer cancel()
+       printInfo()
 
-                       if err := s.Shutdown(ctx); err != nil {
-                               log.Errorf("Shutting down server error: %s", 
err)
-                       }
+       sig := <-quit
+       log.Infof("The Manager API server receive %s and start shutting down", 
sig.String())
 
-                       log.Infof("The Manager API server exited")
+       ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
+       defer cancel()
 
-                       utils.CloseAll()
-                       return nil
-               },
+       if err := s.Shutdown(ctx); err != nil {
+               log.Errorf("Shutting down server error: %s", err)
        }
 
-       cmd.PersistentFlags().StringVarP(&conf.WorkDir, "work-dir", "p", ".", 
"current work directory")
-       cmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, 
"show manager-api version")
+       log.Infof("The Manager API server exited")
 
-       cmd.AddCommand(newStopCommand())
-       return cmd
+       utils.CloseAll()
+       return nil
 }
 
+func newStartCommand() *cobra.Command {
+       cmd := &cobra.Command{
+               Use:   "start",
+               Short: "start Apache APISIX Dashboard service",
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       ServiceState.startService = true
+                       status, err := service.manageService()
+                       fmt.Printf("%s\n", status)

Review comment:
       ```suggestion
                        fmt.Println(status)
   ```

##########
File path: api/cmd/managerapi.go
##########
@@ -170,3 +224,16 @@ func newStopCommand() *cobra.Command {
        }
        return cmd
 }
+func newRemoveCommand() *cobra.Command {

Review comment:
       Style: keep an empty line.

##########
File path: api/cmd/service.go
##########
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cmd
+
+import (
+       "os"
+       "runtime"
+
+       "github.com/apisix/manager-api/internal/conf"
+       "github.com/takama/daemon"
+)
+
+type Service struct {
+       daemon.Daemon
+}
+
+var ServiceState struct {

Review comment:
       Don't have to export this variable.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to