create deployment
This commit is contained in:
parent
ef982d7a05
commit
04dae7da4e
4
Makefile
4
Makefile
|
|
@ -14,3 +14,7 @@ install: docker
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
kubectl delete -f install.yaml
|
kubectl delete -f install.yaml
|
||||||
|
|
||||||
|
restart: docker
|
||||||
|
kubectl delete -f install.yaml
|
||||||
|
kubectl apply -f install.yaml
|
||||||
|
|
|
||||||
16
go.mod
16
go.mod
|
|
@ -3,7 +3,14 @@ module k8s-manager
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/gin-gonic/gin v1.8.2
|
github.com/gin-gonic/gin v1.8.2
|
||||||
|
github.com/go-logr/logr v1.2.3 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||||
|
github.com/go-openapi/swag v0.19.14 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.0
|
||||||
gorm.io/driver/mysql v1.4.6
|
gorm.io/driver/mysql v1.4.6
|
||||||
|
|
@ -11,17 +18,9 @@ require (
|
||||||
k8s.io/api v0.26.1
|
k8s.io/api v0.26.1
|
||||||
k8s.io/apimachinery v0.26.1
|
k8s.io/apimachinery v0.26.1
|
||||||
k8s.io/client-go v0.26.1
|
k8s.io/client-go v0.26.1
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
||||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
|
||||||
github.com/go-logr/logr v1.2.3 // indirect
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
|
||||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
|
||||||
github.com/go-openapi/swag v0.19.14 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
||||||
|
|
@ -44,6 +43,7 @@ require (
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||||
|
github.com/thoas/go-funk v0.9.3 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.9 // indirect
|
github.com/ugorji/go/codec v1.2.9 // indirect
|
||||||
golang.org/x/crypto v0.6.0 // indirect
|
golang.org/x/crypto v0.6.0 // indirect
|
||||||
golang.org/x/net v0.6.0 // indirect
|
golang.org/x/net v0.6.0 // indirect
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -194,6 +194,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
|
||||||
|
github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||||
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
|
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
|
||||||
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,13 @@ spec:
|
||||||
image: docker.educg.net/k8s/manager:dev
|
image: docker.educg.net/k8s/manager:dev
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8080
|
- containerPort: 8080
|
||||||
|
env:
|
||||||
|
- name: DB_HOST
|
||||||
|
value: 192.168.131.191
|
||||||
|
- name: DB_USER
|
||||||
|
value: app
|
||||||
|
- name: DB_PASS
|
||||||
|
value: 1PQlNf9*9Ulo
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
|
|
@ -35,4 +42,4 @@ spec:
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
nodePort: 30001
|
nodePort: 30001
|
||||||
selector:
|
selector:
|
||||||
app: k8s-manager-deployment
|
app: k8s-manager
|
||||||
7
main.go
7
main.go
|
|
@ -14,7 +14,8 @@ import (
|
||||||
var f embed.FS
|
var f embed.FS
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go m.ListPods()
|
m.InitClient()
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
r.SetFuncMap(template.FuncMap{
|
r.SetFuncMap(template.FuncMap{
|
||||||
|
|
@ -35,6 +36,10 @@ func main() {
|
||||||
r.POST("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
|
r.POST("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
|
||||||
r.PUT("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
|
r.PUT("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
|
||||||
r.DELETE("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
|
r.DELETE("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
|
||||||
|
|
||||||
|
r.POST("/dep", m.JWTAuthMiddleware, m.CreateDeleteDeployment)
|
||||||
|
r.DELETE("/dep", m.JWTAuthMiddleware, m.CreateDeleteDeployment)
|
||||||
|
|
||||||
r.GET("/login/:username", Test)
|
r.GET("/login/:username", Test)
|
||||||
err := r.Run()
|
err := r.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,12 @@ func GetApps(username string) []AppModel {
|
||||||
return ans
|
return ans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AppModel) Fill() error {
|
||||||
|
db := DB()
|
||||||
|
res := db.First(a, a.Id)
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
|
||||||
func (a *AppModel) Update() error {
|
func (a *AppModel) Update() error {
|
||||||
db := DB()
|
db := DB()
|
||||||
db.Save(a)
|
db.Save(a)
|
||||||
|
|
@ -59,6 +65,9 @@ func (a *AppModel) ContainerName() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppModel) ServiceName() string {
|
func (a *AppModel) ServiceName() string {
|
||||||
|
if strings.TrimSpace(a.SvcName) != "" {
|
||||||
|
return a.SvcName
|
||||||
|
}
|
||||||
return fmt.Sprintf("%s-service", a.NamePrefix())
|
return fmt.Sprintf("%s-service", a.NamePrefix())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,28 +3,71 @@ package k8s_manager
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/thoas/go-funk"
|
||||||
|
v1 "k8s.io/api/apps/v1"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppViewModel struct {
|
type AppViewModel struct {
|
||||||
|
*AppModel
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppsViewModel struct {
|
||||||
Username string
|
Username string
|
||||||
Apps []AppModel
|
Apps []AppViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusString(status *v1.DeploymentStatus, err error) string {
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "not found") {
|
||||||
|
return "Stopped"
|
||||||
|
}
|
||||||
|
return err.Error()
|
||||||
|
} else {
|
||||||
|
if status.AvailableReplicas > 0 {
|
||||||
|
return "Running"
|
||||||
|
} else {
|
||||||
|
return "Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppPage(c *gin.Context) {
|
func AppPage(c *gin.Context) {
|
||||||
username := c.MustGet("username").(string)
|
username := c.MustGet("username").(string)
|
||||||
vm := &AppViewModel{
|
appsvm := funk.Map(GetApps(username), func(a AppModel) AppViewModel { return AppViewModel{AppModel: &a} }).([]AppViewModel)
|
||||||
|
for i := range appsvm {
|
||||||
|
a := &appsvm[i]
|
||||||
|
d, e := K.GetAppStatus(a.AppModel)
|
||||||
|
a.Status = statusString(d, e)
|
||||||
|
}
|
||||||
|
vm := &AppsViewModel{
|
||||||
Username: username,
|
Username: username,
|
||||||
Apps: GetApps(username),
|
Apps: appsvm,
|
||||||
}
|
}
|
||||||
c.HTML(http.StatusOK, "app_view.html", vm)
|
c.HTML(http.StatusOK, "app_view.html", vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AppMiddleware(c *gin.Context) {
|
||||||
|
app := &AppModel{}
|
||||||
|
err := c.ShouldBindJSON(&app)
|
||||||
|
if err == nil {
|
||||||
|
username := c.MustGet("username")
|
||||||
|
if app.UserName != username {
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{"msg": "user error."})
|
||||||
|
c.Abort()
|
||||||
|
}
|
||||||
|
c.Set("app", app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CreateUpdateDeleteApp(c *gin.Context) {
|
func CreateUpdateDeleteApp(c *gin.Context) {
|
||||||
app := &AppModel{}
|
app := &AppModel{}
|
||||||
err := c.BindJSON(app)
|
err := c.BindJSON(app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("AddApp")
|
log.WithError(err).Error("CreateUpdateDeleteApp")
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"msg": "Cannot get data."})
|
c.JSON(http.StatusBadRequest, gin.H{"msg": "Cannot get data."})
|
||||||
} else {
|
} else {
|
||||||
username := c.MustGet("username").(string)
|
username := c.MustGet("username").(string)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package k8s_manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"k8s.io/api/apps/v1"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var K *K8sClient = nil
|
||||||
|
|
||||||
|
func InitClient() {
|
||||||
|
K = CreateClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeployStatusObject struct {
|
||||||
|
E string `json:"e"`
|
||||||
|
S *v1.DeploymentStatus `json:"s"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateDeleteDeployment(c *gin.Context) {
|
||||||
|
tokenUsername := c.MustGet("username").(string)
|
||||||
|
id := c.Query("id")
|
||||||
|
if strings.TrimSpace(id) == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"msg": "no app id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appId, err := strconv.Atoi(id)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"msg": "wrong id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app := AppModel{Id: appId}
|
||||||
|
if app.Fill() != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"msg": "wrong id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if app.UserName != tokenUsername {
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{"msg": "user error."})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.Request.Method == http.MethodPost {
|
||||||
|
K.CreateApp(&app)
|
||||||
|
} else if c.Request.Method == http.MethodDelete {
|
||||||
|
K.DeleteApp(&app)
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusMethodNotAllowed, gin.H{"msg": "unsupported method"})
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"msg": "ok"})
|
||||||
|
}
|
||||||
|
|
@ -3,8 +3,9 @@ package k8s_manager
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/goccy/go-json"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"k8s.io/api/apps/v1beta1"
|
appv1 "k8s.io/api/apps/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
|
@ -16,7 +17,7 @@ type K8sClient struct {
|
||||||
Namespace string
|
Namespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitClient() *K8sClient {
|
func CreateClient() *K8sClient {
|
||||||
var err error
|
var err error
|
||||||
config, err := rest.InClusterConfig()
|
config, err := rest.InClusterConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -40,17 +41,22 @@ func (c *K8sClient) ListPods() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *K8sClient) CreateApp(app *AppModel) {
|
func (c *K8sClient) GetAppStatus(app *AppModel) (*appv1.DeploymentStatus, error) {
|
||||||
|
get, err := c.AppsV1().Deployments(c.Namespace).Get(context.Background(), app.DeploymentName(), metav1.GetOptions{})
|
||||||
|
// log.WithError(err).WithField("dep", get).WithField("name", app.DeploymentName()).Info("GetAppStatus")
|
||||||
|
return &get.Status, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *K8sClient) CreateApp(app *AppModel) {
|
||||||
var rep int32 = 1
|
var rep int32 = 1
|
||||||
labelKey, labelValue := app.GetLabel()
|
labelKey, labelValue := app.GetLabel()
|
||||||
labels := map[string]string{labelKey: labelValue}
|
labels := map[string]string{labelKey: labelValue}
|
||||||
deployment := &v1beta1.Deployment{
|
deployment := &appv1.Deployment{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: app.DeploymentName(),
|
Name: app.DeploymentName(),
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
},
|
},
|
||||||
Spec: v1beta1.DeploymentSpec{
|
Spec: appv1.DeploymentSpec{
|
||||||
Replicas: &rep,
|
Replicas: &rep,
|
||||||
Selector: &metav1.LabelSelector{
|
Selector: &metav1.LabelSelector{
|
||||||
MatchLabels: labels,
|
MatchLabels: labels,
|
||||||
|
|
@ -71,8 +77,10 @@ func (c *K8sClient) CreateApp(app *AppModel) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
deployment, err := c.AppsV1beta1().Deployments(c.Namespace).Create(context.Background(), deployment, metav1.CreateOptions{})
|
deployment, err := c.AppsV1().Deployments(c.Namespace).Create(context.Background(), deployment, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
d, _ := json.Marshal(deployment)
|
||||||
|
fmt.Println(string(d))
|
||||||
log.WithError(err).Error("Create Deployment error.")
|
log.WithError(err).Error("Create Deployment error.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,6 +90,7 @@ func (c *K8sClient) CreateApp(app *AppModel) {
|
||||||
},
|
},
|
||||||
Spec: v1.ServiceSpec{
|
Spec: v1.ServiceSpec{
|
||||||
Type: v1.ServiceTypeClusterIP,
|
Type: v1.ServiceTypeClusterIP,
|
||||||
|
ClusterIP: "None",
|
||||||
Selector: labels,
|
Selector: labels,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -91,3 +100,11 @@ func (c *K8sClient) CreateApp(app *AppModel) {
|
||||||
log.WithError(err).Error("Create Service ")
|
log.WithError(err).Error("Create Service ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *K8sClient) DeleteApp(app *AppModel) {
|
||||||
|
err := c.AppsV1().Deployments(c.Namespace).Delete(context.Background(), app.DeploymentName(), metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Delete error ", app.DeploymentName())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
<th>镜像名</th>
|
<th>镜像名</th>
|
||||||
<th>启动命令</th>
|
<th>启动命令</th>
|
||||||
<th>环境变量</th>
|
<th>环境变量</th>
|
||||||
|
<th>状态</th>
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -46,8 +47,11 @@
|
||||||
<td class="app-field-image"> {{ $v.Image }}</td>
|
<td class="app-field-image"> {{ $v.Image }}</td>
|
||||||
<td class="app-field-cmd"> {{ $v.Command }}</td>
|
<td class="app-field-cmd"> {{ $v.Command }}</td>
|
||||||
<td class="app-field-env"> {{ $v.Env }}</td>
|
<td class="app-field-env"> {{ $v.Env }}</td>
|
||||||
|
<td class="app-field-status" id="app-status-{{ $v.Id }}"> {{ $v.Status }} </td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-success" onclick="startApp('{{$v.Id}}')">启动</button>
|
||||||
|
<button class="btn btn-dark" onclick="stopApp('{{$v.Id}}')">停止</button>
|
||||||
<button class="btn btn-primary" onclick="showModal('app-list-{{ $v.Id }}')">修改</button>
|
<button class="btn btn-primary" onclick="showModal('app-list-{{ $v.Id }}')">修改</button>
|
||||||
<button class="btn btn-danger" onclick="deleteApp('{{ $v.Id }}')">删除</button>
|
<button class="btn btn-danger" onclick="deleteApp('{{ $v.Id }}')">删除</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -202,5 +206,17 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startApp(id) {
|
||||||
|
axios.post("dep?id=" + id).then(e=>{
|
||||||
|
console.log(e.data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopApp(id) {
|
||||||
|
axios.delete("dep?id=" + id).then(e=>{
|
||||||
|
console.log(e.data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in New Issue