Skip to content

Commit

Permalink
Merge pull request #21 from chrisliu1995/faet/restart_delete
Browse files Browse the repository at this point in the history
feat: support to delete & restart
  • Loading branch information
ringtail authored Jul 13, 2023
2 parents 35b524c + 340f864 commit 4c43c9c
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 2 deletions.
32 changes: 31 additions & 1 deletion aigc-dashboard/src/components/engine.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ export default {
this.items = response.data
}).catch((error) => {
})
},
del: function () {
let engine = this.engine;
let name = engine.metadata.name;
let namespace = engine.metadata.namespace;
this.axios.delete("/resource/" + namespace + "/" + name).then((response) => {
this.items = response.data
}).catch((error) => {
})
},
restart: function () {
let engine = this.engine;
let name = engine.metadata.name;
let namespace = engine.metadata.namespace;
this.axios.post("/resource/" + namespace + "/" + name + "/restart").then((response) => {
this.items = response.data
}).catch((error) => {
})
}
},
created: function () {
Expand Down Expand Up @@ -146,7 +166,7 @@ export default {
></v-progress-circular>
</v-col>
</v-row>
<v-row v-if="state!=='Pending'">
<v-row>
<v-col cols="6" v-if="state==='Not Installed'">
<v-btn flexbox height="48" width="100%" color="indigo-darken-3"
@click="confirm()">
Expand All @@ -169,6 +189,16 @@ export default {
Pause
</v-btn>
</v-col>
<v-col cols="6" v-if="state!=='Not Installed'">
<v-btn flexbox height="48" width="100%" color="indigo-darken-3" @click="del()">
Uninstall
</v-btn>
</v-col>
<v-col cols="6" v-if="state!=='Not Installed' && state!=='Paused'">
<v-btn flexbox height="48" width="100%" color="indigo-darken-3" @click="restart()">
Restart
</v-btn>
</v-col>
</v-row>
</v-container>
</v-card>
Expand Down
2 changes: 1 addition & 1 deletion aigc-dashboard/src/components/engines.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default {
this.axios.get("/resources").then((response) => {
this.items = response.data
}).catch((error) => {
this.items = [{"kind":"GameServerSet","apiVersion":"game.kruise.io/v1alpha1","metadata":{"name":"stable-diffusion-cpu","namespace":"default","uid":"198242b9-f6c8-4d33-8a80-5bbee44fa353","resourceVersion":"3534496","generation":11,"creationTimestamp":"2023-05-19T11:05:15Z","annotations":{"game.kruise.io/reserve-ids":"3,2,1","kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"game.kruise.io/v1alpha1\",\"kind\":\"GameServerSet\",\"metadata\":{\"annotations\":{},\"name\":\"stable-diffusion-cpu\",\"namespace\":\"default\"},\"spec\":{\"gameServerTemplate\":{\"spec\":{\"containers\":[{\"args\":[\"--listen\",\"--skip-torch-cuda-test\",\"--no-half\"],\"command\":[\"python3\",\"launch.py\"],\"env\":[{\"name\":\"POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"apiVersion\":\"v1\",\"fieldPath\":\"metadata.name\"}}}],\"image\":\"yunqi-registry.cn-shanghai.cr.aliyuncs.com/lab/stable-diffusion:v1.0.0-cpu\",\"name\":\"stable-diffusion\",\"readinessProbe\":{\"failureThreshold\":3,\"initialDelaySeconds\":5,\"periodSeconds\":10,\"successThreshold\":1,\"tcpSocket\":{\"port\":7860},\"timeoutSeconds\":1}}]}},\"network\":{\"networkConf\":[{\"name\":\"IngressClassName\",\"value\":\"nginx\"},{\"name\":\"Port\",\"value\":\"7860\"},{\"name\":\"Host\",\"value\":\"instances\\u003cid\\u003e.c5464a5f2c39341d3b3eda6e2dd37b505.cn-hangzhou.alicontainer.com\"},{\"name\":\"PathType\",\"value\":\"ImplementationSpecific\"},{\"name\":\"Path\",\"value\":\"/\"},{\"name\":\"Annotation\",\"value\":\"nginx.ingress.kubernetes.io/auth-url: https://dashboard.c5464a5f2c39341d3b3eda6e2dd37b505.cn-hangzhou.alicontainer.com/sign-in\"},{\"name\":\"Annotation\",\"value\":\"nginx.ingress.kubernetes.io/auth-signin: https://dashboard.c5464a5f2c39341d3b3eda6e2dd37b505.cn-hangzhou.alicontainer.com/\"}],\"networkType\":\"Kubernetes-Ingress\"},\"replicas\":0,\"scaleStrategy\":{\"scaleDownStrategyType\":\"ReserveIds\"},\"updateStrategy\":{\"rollingUpdate\":{\"maxUnavailable\":\"100%\",\"podUpdatePolicy\":\"InPlaceIfPossible\"}}}}\n"},"managedFields":[{"manager":"manager","operation":"Update","apiVersion":"game.kruise.io/v1alpha1","time":"2023-05-19T11:06:04Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{".":{},"f:availableReplicas":{},"f:currentReplicas":{},"f:labelSelector":{},"f:maintainingReplicas":{},"f:observedGeneration":{},"f:readyReplicas":{},"f:replicas":{},"f:updatedReadyReplicas":{},"f:updatedReplicas":{},"f:waitToBeDeletedReplicas":{}}},"subresource":"status"},{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"game.kruise.io/v1alpha1","time":"2023-05-22T08:05:50Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:spec":{".":{},"f:gameServerTemplate":{".":{},"f:spec":{}},"f:network":{".":{},"f:networkConf":{},"f:networkType":{}},"f:scaleStrategy":{},"f:updateStrategy":{".":{},"f:rollingUpdate":{".":{},"f:maxUnavailable":{},"f:podUpdatePolicy":{}}}}}},{"manager":"manager","operation":"Update","apiVersion":"game.kruise.io/v1alpha1","time":"2023-05-22T08:05:50Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{"f:game.kruise.io/reserve-ids":{}}}}},{"manager":"aigc-gateway","operation":"Update","apiVersion":"game.kruise.io/v1alpha1","time":"2023-05-22T08:12:48Z","fieldsType":"FieldsV1","fieldsV1":{"f:spec":{"f:gameServerTemplate":{"f:metadata":{".":{},"f:creationTimestamp":{}},"f:spec":{"f:containers":{}}},"f:replicas":{},"f:reserveGameServerIds":{}}}}]},"spec":{"replicas":2,"gameServerTemplate":{"metadata":{"creationTimestamp":null},"spec":{"containers":[{"name":"stable-diffusion","image":"yunqi-registry.cn-shanghai.cr.aliyuncs.com/lab/stable-diffusion:v1.0.0-cpu","command":["python3","launch.py"],"args":["--listen","--skip-torch-cuda-test","--no-half"],"env":[{"name":"POD_NAME","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.name"}}}],"resources":{},"readinessProbe":{"tcpSocket":{"port":7860},"initialDelaySeconds":5,"timeoutSeconds":1,"periodSeconds":10,"successThreshold":1,"failureThreshold":3}}]}},"reserveGameServerIds":[3,2,1],"updateStrategy":{"rollingUpdate":{"maxUnavailable":"100%","podUpdatePolicy":"InPlaceIfPossible"}},"scaleStrategy":{},"network":{"networkType":"Kubernetes-Ingress","networkConf":[{"name":"IngressClassName","value":"nginx"},{"name":"Port","value":"7860"},{"name":"Host","value":"instances\u003cid\u003e.c5464a5f2c39341d3b3eda6e2dd37b505.cn-hangzhou.alicontainer.com"},{"name":"PathType","value":"ImplementationSpecific"},{"name":"Path","value":"/"},{"name":"Annotation","value":"nginx.ingress.kubernetes.io/auth-url: https://dashboard.c5464a5f2c39341d3b3eda6e2dd37b505.cn-hangzhou.alicontainer.com/sign-in"},{"name":"Annotation","value":"nginx.ingress.kubernetes.io/auth-signin: https://dashboard.c5464a5f2c39341d3b3eda6e2dd37b505.cn-hangzhou.alicontainer.com/"}]}},"status":{"observedGeneration":11,"replicas":2,"readyReplicas":1,"availableReplicas":1,"currentReplicas":2,"updatedReplicas":2,"updatedReadyReplicas":1,"maintainingReplicas":0,"waitToBeDeletedReplicas":0,"labelSelector":"game.kruise.io/owner-gss=stable-diffusion-cpu"}}]
this.items = []
})
}
},
Expand Down
14 changes: 14 additions & 0 deletions deploy/helm/aigc-gateway/templates/aigc-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@ rules:
- get
- patch
- update
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- delete
- get
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
Expand Down
75 changes: 75 additions & 0 deletions pkg/resources/resource_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
gamekruiseiov1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
"github.com/openkruise/kruise-game/pkg/util"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -214,6 +215,80 @@ func (rm *ResourceManager) RecoverResource(meta *ResourceMeta) (Resource, error)
return gs, nil
}

func (rm *ResourceManager) DeleteResource(meta *ResourceMeta) error {
if err := checkResourceMeta(meta, &metaNeed{ID: true, Name: true, Namespace: true}); err != nil {
return err
}

// get GameServerSet
gss := &gamekruiseiov1alpha1.GameServerSet{}
err := rm.Get(context.Background(), types.NamespacedName{
Name: meta.Name,
Namespace: meta.Namespace,
}, gss)
if err != nil {
return NewResourceError(ApiCallError, "", err.Error())
}

idInt, _ := strconv.Atoi(meta.ID)
// check if gs exist or not
if !util.IsNumInList(idInt, gss.Spec.ReserveGameServerIds) {
// update GameServerSet to delete gs
gss.Spec.Replicas = pointer.Int32(*gss.Spec.Replicas - 1)
gss.Spec.ReserveGameServerIds = append(gss.Spec.ReserveGameServerIds, []int{idInt}...)
err = rm.Update(context.Background(), gss)
if err != nil {
return err
}
}

// delete pvcs related to gss
for _, vct := range gss.Spec.GameServerTemplate.VolumeClaimTemplates {
pvc := &v1.PersistentVolumeClaim{}
err = rm.Get(context.Background(), types.NamespacedName{
Name: vct.GetName() + "-" + meta.Name + "-" + meta.ID,
Namespace: meta.Namespace,
}, pvc)
if err != nil {
if errors.IsNotFound(err) {
return nil
}
return NewResourceError(ApiCallError, "", err.Error())
}
err = rm.Delete(context.Background(), pvc)
if err != nil && !errors.IsNotFound(err) {
return NewResourceError(ApiCallError, "", err.Error())
}
}

return nil
}

func (rm *ResourceManager) RestartResource(meta *ResourceMeta) error {
if err := checkResourceMeta(meta, &metaNeed{ID: true, Name: true, Namespace: true}); err != nil {
return err
}

// delete pod
pod := &v1.Pod{}
err := rm.Get(context.Background(), types.NamespacedName{
Name: meta.Name + "-" + meta.ID,
Namespace: meta.Namespace,
}, pod)
if err != nil {
if errors.IsNotFound(err) {
return nil
}
return NewResourceError(ApiCallError, "", err.Error())
}
err = rm.Delete(context.Background(), pod)
if err != nil && !errors.IsNotFound(err) {
return NewResourceError(ApiCallError, "", err.Error())
}

return nil
}

type metaNeed struct {
ID bool
Name bool
Expand Down
107 changes: 107 additions & 0 deletions pkg/routers/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,113 @@ func RegisterResourceRouters(router *gin.Engine, logtoConfig *client.LogtoConfig
ctx.Status(200)
return
})

router.DELETE("/resource/:namespace/:name", func(ctx *gin.Context) {
name := ctx.Param("name")
namespace := ctx.Param("namespace")

session := sessions.Default(ctx)
logtoClient := client.NewLogtoClient(
logtoConfig,
&mem.SessionStorage{Session: session},
)

userInfo, err := logtoClient.FetchUserInfo()

if err != nil {
ctx.Error(err)
return
}

cm := userInfo.CustomData

key := fmt.Sprintf("%s-%s", namespace, name)
value := cm[key]
if value == nil {
ctx.Status(400)
return
}
valueBytes, err := interfaceToBytes(value)
if err != nil {
ctx.Error(err)
return
}

rm := &resources.ResourceMeta{}
err = json.Unmarshal(valueBytes, rm)
if err != nil {
ctx.Error(err)
return
}

// add json wrapper
resourceManager := resources.NewResourceManager()
err = resourceManager.DeleteResource(rm)
if err != nil {
ctx.Error(err)
}

cm[key] = nil

err = user.UpdateUserMetaData(userInfo.Sub, cm)
if err != nil {
ctx.Error(err)
return
}

ctx.Status(200)
return
})

router.POST("/resource/:namespace/:name/restart", func(ctx *gin.Context) {
name := ctx.Param("name")
namespace := ctx.Param("namespace")

session := sessions.Default(ctx)
logtoClient := client.NewLogtoClient(
logtoConfig,
&mem.SessionStorage{Session: session},
)

userInfo, err := logtoClient.FetchUserInfo()

if err != nil {
ctx.Error(err)
return
}

cm := userInfo.CustomData

key := fmt.Sprintf("%s-%s", namespace, name)
value := cm[key]
if value == nil {
ctx.Status(400)
return
}
valueBytes, err := interfaceToBytes(value)
if err != nil {
ctx.Error(err)
return
}

rm := &resources.ResourceMeta{}
err = json.Unmarshal(valueBytes, rm)
if err != nil {
ctx.Error(err)
return
}

// add json wrapper
resourceManager := resources.NewResourceManager()
err = resourceManager.RestartResource(rm)
if err != nil {
ctx.Error(err)
return
}

ctx.Status(200)
return
})
}

func interfaceToBytes(data interface{}) ([]byte, error) {
Expand Down
3 changes: 3 additions & 0 deletions pkg/routers/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ func RegisterSignRouters(router *gin.Engine, logtoConfig *client.LogtoConfig) {
resourceManager := resources.NewResourceManager()

for _, info := range userInfo.CustomData {
if info == nil {
continue
}
valueBytes, err := interfaceToBytes(info)
if err != nil {
ctx.Error(err)
Expand Down

0 comments on commit 4c43c9c

Please sign in to comment.