chaosblade
135 строк · 4.4 Кб
1/*
2* Copyright 1999-2020 Alibaba Group Holding Ltd.
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17package cplus
18
19import (
20"context"
21"fmt"
22"github.com/chaosblade-io/chaosblade-spec-go/log"
23"path"
24"strings"
25"time"
26
27"github.com/chaosblade-io/chaosblade-spec-go/channel"
28"github.com/chaosblade-io/chaosblade-spec-go/spec"
29"github.com/chaosblade-io/chaosblade-spec-go/util"
30)
31
32const ApplicationName = "chaosblade-exec-cplus"
33const RemoveAction = "remove"
34
35var cplusBinPath = path.Join(util.GetLibHome(), "cplus", ApplicationName)
36var scriptDefaultPath = path.Join(util.GetLibHome(), "cplus", "script")
37
38// 启动 spring boot application,需要校验程序是否已启动
39func Prepare(ctx context.Context, port, ip string) *spec.Response {
40
41response := preCheck(ctx, port)
42if !response.Success {
43return response
44}
45response = startProxy(ctx, port, ip)
46if !response.Success {
47return response
48}
49return postCheck(ctx, port)
50}
51
52func preCheck(ctx context.Context, port string) *spec.Response {
53// check spring boot application
54if processExists(port) {
55return spec.ReturnSuccess("the server proxy has been started")
56}
57// check chaosblade-exec-cplus.jar file exists or not
58if !util.IsExist(cplusBinPath) {
59log.Errorf(ctx, spec.ChaosbladeFileNotFound.Sprintf(cplusBinPath))
60return spec.ResponseFailWithFlags(spec.ChaosbladeFileNotFound, cplusBinPath)
61}
62// check script file
63if !util.IsExist(scriptDefaultPath) {
64log.Errorf(ctx, spec.ChaosbladeFileNotFound.Sprintf(scriptDefaultPath))
65return spec.ResponseFailWithFlags(spec.ChaosbladeFileNotFound, scriptDefaultPath)
66}
67// check the port has been used or not
68portInUse := util.CheckPortInUse(port)
69if portInUse {
70log.Errorf(ctx, spec.ParameterInvalid.Sprintf("port", port, "the port has been used"))
71return spec.ResponseFailWithFlags(spec.ParameterInvalid, port, "the port has been used")
72}
73return spec.ReturnSuccess("success")
74}
75
76func processExists(port string) bool {
77ctx := context.WithValue(context.Background(), channel.ProcessKey, port)
78pids, _ := channel.NewLocalChannel().GetPidsByProcessName(ApplicationName, ctx)
79if pids != nil && len(pids) > 0 {
80return true
81}
82return false
83}
84
85func startProxy(ctx context.Context, port, ip string) *spec.Response {
86args := fmt.Sprintf("--port %s", port)
87if ip != "" {
88args = fmt.Sprintf("%s --ip %s", args, ip)
89}
90return channel.NewLocalChannel().Run(ctx, cplusBinPath, args)
91}
92
93func postCheck(ctx context.Context, port string) *spec.Response {
94url := getProxyServiceUrl(port, "status")
95result, err, _ := util.Curl(ctx, url)
96if err != nil {
97log.Errorf(ctx, spec.HttpExecFailed.Sprintf(url, err))
98return spec.ResponseFailWithFlags(spec.HttpExecFailed, url, err)
99}
100return spec.ReturnSuccess(result)
101}
102
103// 停止 spring boot application
104func Revoke(ctx context.Context, port string) *spec.Response {
105// check process
106if !processExists(port) {
107return spec.ReturnSuccess("process not exists")
108}
109// Get http://127.0.0.1:xxx/remove: EOF, doesn't to check the result
110util.Curl(ctx, getProxyServiceUrl(port, RemoveAction))
111time.Sleep(time.Second)
112ctx = context.WithValue(ctx, channel.ExcludeProcessKey, "blade")
113pids, err := channel.NewLocalChannel().GetPidsByProcessName(ApplicationName, ctx)
114if err != nil {
115log.Errorf(ctx, spec.ProcessIdByNameFailed.Sprintf(ApplicationName, err))
116return spec.ResponseFailWithFlags(spec.ProcessIdByNameFailed, ApplicationName, err)
117}
118if len(pids) > 0 {
119response := channel.NewLocalChannel().Run(context.Background(), "kill", fmt.Sprintf("-9 %s", strings.Join(pids, " ")))
120if !response.Success {
121return response
122}
123}
124// revoke failed if the check operation returns success
125response := postCheck(ctx, port)
126if response.Success {
127log.Errorf(ctx, spec.HttpExecFailed.Sprintf(getProxyServiceUrl(port, RemoveAction), "process exists"))
128}
129return spec.ReturnSuccess("success")
130}
131
132func getProxyServiceUrl(port, action string) string {
133return fmt.Sprintf("http://127.0.0.1:%s/%s",
134port, action)
135}
136