diff --git a/cnb-builder-shim/cmd/dev-launcher/launch/supervisorctl.go b/cnb-builder-shim/cmd/dev-launcher/launch/supervisorctl.go index 0fd9664231..272b673bfd 100644 --- a/cnb-builder-shim/cmd/dev-launcher/launch/supervisorctl.go +++ b/cnb-builder-shim/cmd/dev-launcher/launch/supervisorctl.go @@ -60,7 +60,7 @@ redirect_stderr = true var reloadScript = fmt.Sprintf(`#!/bin/bash socket_file="%[1]s/supervisor.sock" -# 检查supervisor的socket文件是否存在 +# 检查 supervisor 的 socket 文件是否存在 if [ -S "$socket_file" ]; then echo "supervisord is already running. update and restart processes..." supervisorctl -c %[2]s reload @@ -70,6 +70,15 @@ else fi `, supervisorDir, confFilePath) +var statusScript = fmt.Sprintf(`#!/bin/bash + +socket_file="%[1]s/supervisor.sock" +# 检查 supervisor 的 socket 文件是否存在 +if [ -S "$socket_file" ]; then + supervisorctl -c %[2]s status +fi +`, supervisorDir, confFilePath) + // ProcessConf is a process config type ProcessConf struct { Process @@ -161,6 +170,18 @@ func (ctl *SupervisorCtl) reload() error { return cmd.Run() } +// Status get the status of all processes by running 'supervisorctl status'. +func (ctl *SupervisorCtl) Status() error { + cmd := exec.Command("bash") + + cmd.Env = os.Environ() + cmd.Stdin = bytes.NewBufferString(statusScript) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + + return cmd.Run() +} + // validateEnvironment validates the environment variables for supervisor conf. // // see detail environment conf in http://supervisord.org/configuration.html diff --git a/cnb-builder-shim/cmd/dev-launcher/main.go b/cnb-builder-shim/cmd/dev-launcher/main.go index f94db4b64e..34979eef70 100644 --- a/cnb-builder-shim/cmd/dev-launcher/main.go +++ b/cnb-builder-shim/cmd/dev-launcher/main.go @@ -19,39 +19,9 @@ package main import ( - "os" - "path/filepath" - - "github.com/BurntSushi/toml" - "github.com/buildpacks/lifecycle/launch" - - devlaunch "github.com/TencentBlueking/bkpaas/cnb-builder-shim/cmd/dev-launcher/launch" - "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/appdesc" - "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/logging" - "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/utils" + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/cmd/dev-launcher/subcmd" ) -// DefaultAppDir default app dir -var DefaultAppDir = utils.EnvOrDefault("CNB_APP_DIR", "/app") - func main() { - logger := logging.Default() - - var md launch.Metadata - - if _, err := toml.DecodeFile(launch.GetMetadataFilePath("/layers"), &md); err != nil { - logger.Error(err, "read metadata") - os.Exit(1) - } - - appDesc, err := appdesc.UnmarshalToAppDesc(filepath.Join(DefaultAppDir, "app_desc.yaml")) - if err != nil { - logger.Error(err, "parse invalid app_desc.yaml") - os.Exit(1) - } - - if err = devlaunch.Run(md.Processes, appDesc); err != nil { - logger.Error(err, "hot launch") - os.Exit(1) - } + subcmd.Execute() } diff --git a/cnb-builder-shim/cmd/dev-launcher/subcmd/launch.go b/cnb-builder-shim/cmd/dev-launcher/subcmd/launch.go new file mode 100644 index 0000000000..c3a41ff151 --- /dev/null +++ b/cnb-builder-shim/cmd/dev-launcher/subcmd/launch.go @@ -0,0 +1,66 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package subcmd + +import ( + "path/filepath" + + "github.com/BurntSushi/toml" + "github.com/buildpacks/lifecycle/launch" + "github.com/spf13/cobra" + + devlaunch "github.com/TencentBlueking/bkpaas/cnb-builder-shim/cmd/dev-launcher/launch" + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/appdesc" + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/logging" + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/utils" +) + +var DefaultAppDir = utils.EnvOrDefault("CNB_APP_DIR", "/app") + +var reloadCmd = &cobra.Command{ + Use: "reload", + Short: "reload processes.", + Long: "reload the given launch.Process list.", + RunE: func(cmd *cobra.Command, args []string) error { + logger := logging.Default() + + var md launch.Metadata + + if _, err := toml.DecodeFile(launch.GetMetadataFilePath("/layers"), &md); err != nil { + logger.Error(err, "read metadata") + return err + } + + appDesc, err := appdesc.UnmarshalToAppDesc(filepath.Join(DefaultAppDir, "app_desc.yaml")) + if err != nil { + logger.Error(err, "parse invalid app_desc.yaml") + return err + } + + if err = devlaunch.Run(md.Processes, appDesc); err != nil { + logger.Error(err, "failed to hot launch") + return err + } + return nil + }, +} + +func init() { + rootCmd.AddCommand(reloadCmd) +} diff --git a/cnb-builder-shim/cmd/dev-launcher/subcmd/root.go b/cnb-builder-shim/cmd/dev-launcher/subcmd/root.go new file mode 100644 index 0000000000..b2ca0b31be --- /dev/null +++ b/cnb-builder-shim/cmd/dev-launcher/subcmd/root.go @@ -0,0 +1,41 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package subcmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "dev-launcher", + Short: "dev-launcher cli", + Long: `Manage processes defined by app_desc, including reload, getting status.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("dev-launcher manages processes defined by app_desc") + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + os.Exit(1) + } +} diff --git a/cnb-builder-shim/cmd/dev-launcher/subcmd/status.go b/cnb-builder-shim/cmd/dev-launcher/subcmd/status.go new file mode 100644 index 0000000000..aa0a5d1de7 --- /dev/null +++ b/cnb-builder-shim/cmd/dev-launcher/subcmd/status.go @@ -0,0 +1,38 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package subcmd + +import ( + "github.com/spf13/cobra" + + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/cmd/dev-launcher/launch" +) + +var statusCmd = &cobra.Command{ + Use: "status", + Short: "process status.", + Long: "Get status of all processes.", + RunE: func(cmd *cobra.Command, args []string) error { + return launch.NewSupervisorCtl().Status() + }, +} + +func init() { + rootCmd.AddCommand(statusCmd) +} diff --git a/cnb-builder-shim/go.mod b/cnb-builder-shim/go.mod index bcb3b121fe..ee5fe1bb2c 100644 --- a/cnb-builder-shim/go.mod +++ b/cnb-builder-shim/go.mod @@ -45,6 +45,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/iand/logfmtr v0.2.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.1 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect @@ -62,6 +63,7 @@ require ( github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/cobra v1.8.1 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect diff --git a/cnb-builder-shim/go.sum b/cnb-builder-shim/go.sum index 7a920de8f6..783bb37904 100644 --- a/cnb-builder-shim/go.sum +++ b/cnb-builder-shim/go.sum @@ -32,6 +32,7 @@ github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -107,6 +108,8 @@ github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/iand/logfmtr v0.2.1 h1:y677w6gmOdGXaPbIGjQhGZdmezpCo0AyxXC74scyDk0= github.com/iand/logfmtr v0.2.1/go.mod h1:J1K526bF1o/E0Xq01J0vk7pLEfHkgGs8vmdbxH4wqwU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -174,12 +177,15 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= github.com/shabbywu/logfmtr v0.2.3 h1:RFkAyvcY93lIAl0tkjWz3ludHODZMRJCwihSgVn3b6A= github.com/shabbywu/logfmtr v0.2.3/go.mod h1:cGpwyHM894YO5s/XwNvcm+bUuXTSoWg9jAaOV00qMMI= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/cnb-builder-shim/internal/devsandbox/phase/launcher.go b/cnb-builder-shim/internal/devsandbox/phase/launcher.go index 1a8efc66d6..de0f6f598d 100644 --- a/cnb-builder-shim/internal/devsandbox/phase/launcher.go +++ b/cnb-builder-shim/internal/devsandbox/phase/launcher.go @@ -27,8 +27,8 @@ import ( const DefaultDevLauncherPath = "/cnb/devsandbox/bin/dev-launcher" // MakeLauncherCmd make launcher cmd -func MakeLauncherCmd() *exec.Cmd { - cmd := exec.Command(DefaultDevLauncherPath) +func MakeLauncherCmd(subCommand string) *exec.Cmd { + cmd := exec.Command(DefaultDevLauncherPath, subCommand) cmd.Env = os.Environ() return cmd } diff --git a/cnb-builder-shim/internal/devsandbox/reload.go b/cnb-builder-shim/internal/devsandbox/reload.go index e4f801e823..9e9d19d7a8 100644 --- a/cnb-builder-shim/internal/devsandbox/reload.go +++ b/cnb-builder-shim/internal/devsandbox/reload.go @@ -34,6 +34,8 @@ var ( ReloadDir = "/cnb/devsandbox/reload" // ReloadLogDir used to store reload log ReloadLogDir = path.Join(ReloadDir, "log") + // reload sub command of dev-launcher + reloadSubCommand = "reload" ) // ReloadStatus is the status of a reload operation. @@ -74,7 +76,7 @@ func (m HotReloadManager) Rebuild(reloadID string) error { // Relaunch ... func (m HotReloadManager) Relaunch(reloadID string) error { - cmd := phase.MakeLauncherCmd() + cmd := phase.MakeLauncherCmd(reloadSubCommand) return m.runCmd(reloadID, cmd) } diff --git a/cnb-builder-shim/internal/devsandbox/status.go b/cnb-builder-shim/internal/devsandbox/status.go new file mode 100644 index 0000000000..ce9e3c65fa --- /dev/null +++ b/cnb-builder-shim/internal/devsandbox/status.go @@ -0,0 +1,90 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * 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. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package devsandbox + +import ( + "bytes" + "os" + "strings" + + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/phase" +) + +var statusSubCommand = "status" + +// Status returns the status of all processes. +func Status() (map[string]string, error) { + statusOutput, err := status() + if err != nil { + return nil, err + } + return parseStatusOutput(statusOutput), nil +} + +func status() (string, error) { + var outBuffer bytes.Buffer + + cmd := phase.MakeLauncherCmd(statusSubCommand) + cmd.Stdin = os.Stdin + cmd.Stdout = &outBuffer + cmd.Stderr = os.Stderr + + err := cmd.Run() + if err != nil { + return "", err + } + return outBuffer.String(), nil +} + +// parses the output from the `supervisorctl status` command. +// The expected format of each line in the output is: +// +// +// Parameters: +// - output: A string containing the entire output from the `supervisorctl status` command. +// +// Returns: +// - A map with process names as keys and their states as values. +func parseStatusOutput(output string) map[string]string { + result := make(map[string]string) + + // 按行分割输出 + lines := strings.Split(output, "\n") + for _, line := range lines { + // 移除空白符并检查是否为空行 + line = strings.TrimSpace(line) + if line == "" { + continue + } + + // 按空格分割,格式为 " ..." + parts := strings.Fields(line) + if len(parts) < 2 { + // 如果格式不符合预期,跳过该行 + continue + } + // 提取进程名称和状态 + processName := parts[0] + processState := parts[1] + + result[processName] = processState + } + + return result +} diff --git a/cnb-builder-shim/internal/devsandbox/webserver/server.go b/cnb-builder-shim/internal/devsandbox/webserver/server.go index 96e7519659..36e0fcf9ca 100644 --- a/cnb-builder-shim/internal/devsandbox/webserver/server.go +++ b/cnb-builder-shim/internal/devsandbox/webserver/server.go @@ -36,6 +36,7 @@ import ( "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/config" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/webserver/service" + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/appdesc" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/utils" ) @@ -87,6 +88,8 @@ func New(lg *logr.Logger) (*WebServer, error) { r.POST("/deploys", DeployHandler(s, mgr)) r.GET("/deploys/:deployID/results", ResultHandler(mgr)) r.GET("/app_logs", AppLogHandler()) + r.GET("/processes/status", ProcessStatusHandler()) + r.GET("/processes/list", ProcessListHandler()) return s, nil } @@ -230,4 +233,30 @@ func AppLogHandler() gin.HandlerFunc { } } +// ProcessStatusHandler ... +func ProcessStatusHandler() gin.HandlerFunc { + return func(c *gin.Context) { + status, err := devsandbox.Status() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"message": fmt.Sprintf("get status error: %s", err.Error())}) + return + } + c.JSON(http.StatusOK, gin.H{"status": status}) + } +} + +// ProcessListHandler ... +func ProcessListHandler() gin.HandlerFunc { + return func(c *gin.Context) { + appDescFilePath := path.Join(config.G.SourceCode.Workspace, "app_desc.yaml") + appDesc, err := appdesc.UnmarshalToAppDesc(appDescFilePath) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"message": fmt.Sprintf("list process error: %s", err.Error())}) + return + } + + c.JSON(http.StatusOK, gin.H{"processes": appDesc.Module.Processes}) + } +} + var _ devsandbox.DevWatchServer = (*WebServer)(nil)