From 24fba0106fee86d9621eb641b46d5b52a48b4008 Mon Sep 17 00:00:00 2001 From: samson <845534486@qq.com> Date: Wed, 30 Aug 2023 21:50:11 +0800 Subject: [PATCH 1/2] fix bugs --- chaosmeta-platform/conf/app.yaml | 8 +- chaosmeta-platform/config/config.go | 12 +- chaosmeta-platform/config/orm.go | 2 +- .../v1alpha1/experiment/experiment.go | 32 +- .../apiserver/v1alpha1/experiment/type.go | 10 +- .../experiment_instance.go | 9 +- .../apiserver/v1alpha1/kube/deployment.go | 2 +- .../apiserver/v1alpha1/kube/namespace.go | 2 +- .../gateway/apiserver/v1alpha1/kube/node.go | 2 +- .../gateway/apiserver/v1alpha1/kube/pod.go | 2 +- .../apiserver/v1alpha1/namespace/namespace.go | 54 ++- .../apiserver/v1alpha1/namespace/overview.go | 41 +++ .../apiserver/v1alpha1/namespace/type.go | 6 + .../gateway/apiserver/v1alpha1/node/node.go | 339 ------------------ .../gateway/apiserver/v1alpha1/node/type.go | 54 --- .../pkg/models/common/page/parser.go | 6 + .../pkg/models/experiment/args_value.go | 3 + .../pkg/models/experiment/experiment.go | 60 +++- .../pkg/models/experiment/label_experiment.go | 3 + .../experiment_instance.go | 88 ++++- .../label_experiment_instance.go | 4 + .../pkg/models/inject/basic/flow_inject.go | 78 ++++ .../pkg/models/inject/basic/measure_inject.go | 80 +++++ .../pkg/models/namespace/cluster_namespace.go | 3 + .../pkg/models/namespace/label.go | 4 + .../pkg/models/namespace/namespace.go | 46 +++ .../pkg/models/namespace/user_namespace.go | 20 +- chaosmeta-platform/pkg/models/user/user.go | 3 + .../experiment/chaosmeta_flow_inject.go | 197 ++++++++++ .../experiment/chaosmeta_flow_inject_type.go | 63 ++++ .../pkg/service/experiment/experiment.go | 179 ++++----- .../pkg/service/experiment/experiment_flow.go | 149 ++++---- .../pkg/service/experiment/routine.go | 92 ++--- .../experiment_instance.go | 27 +- chaosmeta-platform/pkg/service/inject/flow.go | 47 +++ .../pkg/service/inject/inject.go | 11 +- .../pkg/service/inject/measure.go | 17 + .../pkg/service/namespace/namespace.go | 199 +++++----- .../pkg/service/namespace/overview.go | 37 ++ chaosmeta-platform/pkg/service/user/user.go | 4 +- .../quick-start/platform/configmap.yaml | 5 +- .../quick-start/platform/deployment.yaml | 7 +- .../quick-start/platform/rbac.yaml | 22 +- .../quick-start/platform/service.yaml | 4 +- .../quick-start/quick-start.yaml | 54 +-- chaosmeta-platform/routers/namespace.go | 2 + 46 files changed, 1275 insertions(+), 814 deletions(-) create mode 100644 chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/overview.go delete mode 100644 chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/node/node.go delete mode 100644 chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/node/type.go create mode 100644 chaosmeta-platform/pkg/models/inject/basic/flow_inject.go create mode 100644 chaosmeta-platform/pkg/models/inject/basic/measure_inject.go create mode 100644 chaosmeta-platform/pkg/service/experiment/chaosmeta_flow_inject.go create mode 100644 chaosmeta-platform/pkg/service/experiment/chaosmeta_flow_inject_type.go create mode 100644 chaosmeta-platform/pkg/service/inject/flow.go create mode 100644 chaosmeta-platform/pkg/service/inject/measure.go create mode 100644 chaosmeta-platform/pkg/service/namespace/overview.go diff --git a/chaosmeta-platform/conf/app.yaml b/chaosmeta-platform/conf/app.yaml index f6e6ab8..e796961 100644 --- a/chaosmeta-platform/conf/app.yaml +++ b/chaosmeta-platform/conf/app.yaml @@ -1,9 +1,11 @@ secretkey: chaosmeta1234567 +argoWorkflowNamespace: chaosmeta +workflowNamespace: chaosmeta db: - name: chaosmeta - user: root + name: chaosmeta_platform + user: chaosmeta passwd: chaosmeta - url: chaosmeta-platform:3306 + url: 127.0.0.1:3306 maxidle: 30 maxconn: 30 debug: false diff --git a/chaosmeta-platform/config/config.go b/chaosmeta-platform/config/config.go index 05ee7e9..9b9a2b9 100644 --- a/chaosmeta-platform/config/config.go +++ b/chaosmeta-platform/config/config.go @@ -44,8 +44,10 @@ func (r RunMode) Int() int { } type Config struct { - SecretKey string `yaml:"secretkey"` - DB struct { + SecretKey string `yaml:"secretkey"` + ArgoWorkflowNamespace string `yaml:"argoWorkflowNamespace"` + WorkflowNamespace string `yaml:"workflowNamespace"` + DB struct { Name string `yaml:"name"` User string `yaml:"user"` Passwd string `yaml:"passwd"` @@ -84,6 +86,12 @@ func InitConfig() { if err := viper.Unmarshal(DefaultRunOptIns); err != nil { log.Panic(err) } + if DefaultRunOptIns.ArgoWorkflowNamespace == "" { + DefaultRunOptIns.ArgoWorkflowNamespace = "default" + } + if DefaultRunOptIns.WorkflowNamespace == "" { + DefaultRunOptIns.WorkflowNamespace = "chaosmeta-inject" + } } func getCurrentPath() string { diff --git a/chaosmeta-platform/config/orm.go b/chaosmeta-platform/config/orm.go index d367033..e19ad19 100644 --- a/chaosmeta-platform/config/orm.go +++ b/chaosmeta-platform/config/orm.go @@ -35,7 +35,7 @@ func Setup() { new(namespace.ClusterNamespace), new(namespace.Label), new(namespace.Namespace), new(namespace.UserNamespace), new(user.User), new(cluster.Cluster), new(agent.Agent), - new(basic.Scope), new(basic.Target), new(basic.Fault), new(basic.Args), + new(basic.Scope), new(basic.Target), new(basic.Fault), new(basic.FlowInject), new(basic.MeasureInject), new(basic.Args), new(experiment.WorkflowNode), new(experiment.LabelExperiment), new(experiment.FaultRange), new(experiment.Experiment), new(experiment.ArgsValue), new(experiment_instance.WorkflowNodeInstance), new(experiment_instance.LabelExperimentInstance), new(experiment_instance.FaultRangeInstance), new(experiment_instance.ExperimentInstance), new(experiment_instance.ArgsValueInstance), ) diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment/experiment.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment/experiment.go index 46479ef..58f9ad7 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment/experiment.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment/experiment.go @@ -18,10 +18,13 @@ package experiment import ( "chaosmeta-platform/pkg/gateway/apiserver/v1alpha1" + experimentModel "chaosmeta-platform/pkg/models/experiment" "chaosmeta-platform/pkg/service/experiment" "chaosmeta-platform/pkg/service/user" + "chaosmeta-platform/util/log" "encoding/json" "errors" + "fmt" beego "github.com/beego/beego/v2/server/web" "time" ) @@ -36,8 +39,9 @@ func (c *ExperimentController) GetExperimentList() { scheduleType := c.GetString("schedule_type") namespaceID, _ := c.GetInt("namespace_id") name := c.GetString("name") - creator, _ := c.GetInt("creator", 0) + creator := c.GetString("creator") timeType := c.GetString("time_type") + timeSearchField := c.GetString("time_search_field") recentDays, _ := c.GetInt("recent_days", 0) startTime, _ := time.Parse(experiment.TimeLayout, c.GetString("start_time")) endTime, _ := time.Parse(experiment.TimeLayout, c.GetString("end_time")) @@ -46,7 +50,7 @@ func (c *ExperimentController) GetExperimentList() { pageSize, _ := c.GetInt("page_size", 10) experimentService := experiment.ExperimentService{} - total, experimentList, err := experimentService.SearchExperiments(lastInstanceStatus, namespaceID, creator, name, scheduleType, timeType, recentDays, startTime, endTime, orderBy, page, pageSize) + total, experimentList, err := experimentService.SearchExperiments(lastInstanceStatus, namespaceID, creator, name, scheduleType, timeType, timeSearchField, recentDays, startTime, endTime, orderBy, page, pageSize) if err != nil { c.Error(&c.Controller, err) return @@ -85,7 +89,7 @@ func (c *ExperimentController) CreateExperiment() { return } - var createExperimentRequest experiment.Experiment + var createExperimentRequest experiment.ExperimentCreate if err := json.Unmarshal(c.Ctx.Input.RequestBody, &createExperimentRequest); err != nil { c.Error(&c.Controller, err) return @@ -106,7 +110,7 @@ func (c *ExperimentController) UpdateExperiment() { uuid := c.Ctx.Input.Param(":uuid") experimentService := experiment.ExperimentService{} - var updateExperimentRequest experiment.Experiment + var updateExperimentRequest experiment.ExperimentCreate if err := json.Unmarshal(c.Ctx.Input.RequestBody, &updateExperimentRequest); err != nil { c.Error(&c.Controller, err) return @@ -121,7 +125,25 @@ func (c *ExperimentController) UpdateExperiment() { func (c *ExperimentController) StartExperiment() { uuid := c.Ctx.Input.Param(":uuid") - if err := experiment.StartExperiment(uuid); err != nil { + username := c.Ctx.Input.GetData("userName").(string) + experimentService := experiment.ExperimentService{} + experimentGet, err := experimentService.GetExperimentByUUID(uuid) + if err != nil { + c.Error(&c.Controller, err) + return + } + if experimentGet.ScheduleType != string(experimentModel.ManualMode) { + c.Error(&c.Controller, fmt.Errorf("manual mode is required to perform the walkthrough")) + return + } + + if err := experimentService.UpdateExperimentStatusAndLastInstance(uuid, int(experimentModel.ToBeExecuted), time.Now().Format(experimentModel.TimeLayout)); err != nil { + log.Error(err) + } + if err := experiment.StartExperiment(uuid, username); err != nil { + if err := experimentService.UpdateExperimentStatusAndLastInstance(uuid, int(experimentModel.Executed), time.Now().Format(experimentModel.TimeLayout)); err != nil { + log.Error(err) + } c.Error(&c.Controller, err) return } diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment/type.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment/type.go index 5ef234f..1d8acc6 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment/type.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment/type.go @@ -25,12 +25,12 @@ type CreateExperimentResponse struct { } type GetExperimentResponse struct { - Experiment experiment.Experiment `json:"experiments"` + Experiment experiment.ExperimentGet `json:"experiments"` } type ExperimentListResponse struct { - Page int `json:"page"` - PageSize int `json:"pageSize"` - Total int64 `json:"total"` - Experiments []experiment.Experiment `json:"experiments"` + Page int `json:"page"` + PageSize int `json:"pageSize"` + Total int64 `json:"total"` + Experiments []experiment.ExperimentGet `json:"experiments"` } diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment_instance/experiment_instance.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment_instance/experiment_instance.go index 231e920..4a02511 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment_instance/experiment_instance.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/experiment_instance/experiment_instance.go @@ -32,11 +32,14 @@ type ExperimentInstanceController struct { func (c *ExperimentInstanceController) GetExperimentInstances() { lastInstance := c.GetString("last_instance") - scheduleType := c.GetString("schedule_type") + //scheduleType := c.GetString("schedule_type") namespaceId, _ := c.GetInt("namespace_id") + experimentUUID := c.GetString("experiment_uuid") name := c.GetString("name") - creator, _ := c.GetInt("creator", 0) + creatorName := c.GetString("creator_name") timeType := c.GetString("time_type") + timeSearchField := c.GetString("time_search_field") + status := c.GetString("status") recentDays, _ := c.GetInt("recent_days", 0) startTime, _ := time.Parse(experiment.TimeLayout, c.GetString("start_time")) endTime, _ := time.Parse(experiment.TimeLayout, c.GetString("end_time")) @@ -44,7 +47,7 @@ func (c *ExperimentInstanceController) GetExperimentInstances() { page, _ := c.GetInt("page", 1) pageSize, _ := c.GetInt("page_size", 10) es := experiment_instance.ExperimentInstanceService{} - total, experiments, err := es.SearchExperimentInstances(lastInstance, namespaceId, creator, name, scheduleType, timeType, recentDays, startTime, endTime, orderBy, page, pageSize) + total, experiments, err := es.SearchExperimentInstances(lastInstance, experimentUUID, namespaceId, creatorName, name, timeType, timeSearchField, status, recentDays, startTime, endTime, orderBy, page, pageSize) if err != nil { c.Error(&c.Controller, err) return diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/deployment.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/deployment.go index 67c9a5d..1b94f60 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/deployment.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/deployment.go @@ -26,7 +26,7 @@ import ( ) func (c *KubeController) ListDeployments() { - id, _ := c.GetInt(":id") + id, _ := c.GetInt(":id", 0) nsName := c.GetString(":ns_name") clusterService := cluster.ClusterService{} kubeClient, restConfig, err := clusterService.GetRestConfig(context.Background(), id) diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/namespace.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/namespace.go index 3e95447..7b3f533 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/namespace.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/namespace.go @@ -25,7 +25,7 @@ import ( ) func (c *KubeController) ListNamespaces() { - id, _ := c.GetInt(":id") + id, _ := c.GetInt(":id", 0) clusterService := cluster.ClusterService{} kubeClient, _, err := clusterService.GetRestConfig(context.Background(), id) if err != nil { diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/node.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/node.go index b21e751..df397c6 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/node.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/node.go @@ -25,7 +25,7 @@ import ( ) func (c *KubeController) ListNodes() { - id, _ := c.GetInt(":id") + id, _ := c.GetInt(":id", 0) clusterService := cluster.ClusterService{} kubeClient, restConfig, err := clusterService.GetRestConfig(context.Background(), id) if err != nil { diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/pod.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/pod.go index 6c5e646..6a33030 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/pod.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/kube/pod.go @@ -25,7 +25,7 @@ import ( ) func (c *KubeController) ListPods() { - id, _ := c.GetInt(":id") + id, _ := c.GetInt(":id", 0) nsName := c.GetString(":ns_name") clusterService := cluster.ClusterService{} kubeClient, restConfig, err := clusterService.GetRestConfig(context.Background(), id) diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/namespace.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/namespace.go index beab98d..323ed2f 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/namespace.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/namespace.go @@ -19,10 +19,11 @@ package namespace import ( "chaosmeta-platform/pkg/gateway/apiserver/v1alpha1" namespace2 "chaosmeta-platform/pkg/models/namespace" - "chaosmeta-platform/pkg/models/user" "chaosmeta-platform/pkg/service/namespace" + userService "chaosmeta-platform/pkg/service/user" "context" "encoding/json" + "fmt" beego "github.com/beego/beego/v2/server/web" ) @@ -67,6 +68,24 @@ func (c *NamespaceController) Get() { c.Success(&c.Controller, getNamespaceResponse) } +func (c *NamespaceController) GetPermission() { + namespaceId, err := c.GetInt(":id") + if err != nil { + c.Error(&c.Controller, err) + return + } + username := c.Ctx.Input.GetData("userName").(string) + userService := &userService.UserService{} + userGet, err := userService.Get(context.Background(), username) + if err != nil { + c.Error(&c.Controller, fmt.Errorf("unable to identify user")) + return + } + namespace := &namespace.NamespaceService{} + permission := namespace.GetUserPermission(context.Background(), namespaceId, userGet.ID) + c.Success(&c.Controller, permission) +} + func (c *NamespaceController) GetList() { sort := c.GetString("sort") name := c.GetString("name") @@ -93,43 +112,52 @@ func (c *NamespaceController) QueryList() { page, _ := c.GetInt("page", 1) pageSize, _ := c.GetInt("page_size", 10) - sort := c.GetString("sort") - - userGet := user.User{Email: username} - if err := user.GetUser(context.Background(), &userGet); err != nil { - c.Error(&c.Controller, err) + userService := &userService.UserService{} + userGet, errGet := userService.Get(context.Background(), username) + if errGet != nil { + c.Error(&c.Controller, errGet) return } - namespaceService := &namespace.NamespaceService{} + queryUserId := 0 + if userNameQuery != "" { + userGet, errGet := userService.Get(context.Background(), userNameQuery) + if errGet != nil { + c.Error(&c.Controller, fmt.Errorf("no user")) + return + } + queryUserId = userGet.ID + } + var ( total int64 namespaceList []namespace.NamespaceData err error ) + namespaceService := &namespace.NamespaceService{} switch namespaceClass { case "read": - total, namespaceList, err = namespaceService.GroupNamespacesByUsername(context.Background(), userGet.ID, nameSpaceName, userNameQuery, 0, sort, page, pageSize) + total, namespaceList, err = namespaceService.QueryNamespace(context.Background(), userGet.ID, queryUserId, nameSpaceName, 0, page, pageSize) if err != nil { c.Error(&c.Controller, err) return } case "write": - total, namespaceList, err = namespaceService.GroupNamespacesByUsername(context.Background(), userGet.ID, nameSpaceName, userNameQuery, 1, sort, page, pageSize) + total, namespaceList, err = namespaceService.QueryNamespace(context.Background(), userGet.ID, queryUserId, nameSpaceName, 1, page, pageSize) if err != nil { c.Error(&c.Controller, err) return } - case "all": - total, namespaceList, err = namespaceService.GroupAllNamespaces(context.Background(), nameSpaceName, userNameQuery, sort, page, pageSize) + case "relevant": + total, namespaceList, err = namespaceService.QueryNamespace(context.Background(), userGet.ID, queryUserId, nameSpaceName, -1, page, pageSize) if err != nil { c.Error(&c.Controller, err) return } - case "not": - total, namespaceList, err = namespaceService.GroupNamespacesUserNotIn(context.Background(), userGet.ID, nameSpaceName, userNameQuery, sort, page, pageSize) + case "all": + total, namespaceList, err = namespaceService.GroupAllNamespaces(context.Background(), userGet.ID, queryUserId, nameSpaceName, page, pageSize) if err != nil { c.Error(&c.Controller, err) return diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/overview.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/overview.go new file mode 100644 index 0000000..6990c35 --- /dev/null +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/overview.go @@ -0,0 +1,41 @@ +/* + * Copyright 2022-2023 Chaos Meta Authors. + * + * Licensed 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 namespace + +import ( + "chaosmeta-platform/pkg/service/namespace" + "context" +) + +func (c *NamespaceController) GetOverview() { + recentDays, err := c.GetInt("recent_day", 7) + if err != nil { + c.Error(&c.Controller, err) + return + } + namespaceId, _ := c.GetInt(":id", 0) + + namespace := &namespace.NamespaceService{} + totalExperimentCount, totalExperimentInstancesCount, failedExperimentInstancesCount, err := namespace.GetOverview(context.Background(), namespaceId, recentDays) + if err != nil { + c.Error(&c.Controller, err) + return + } + + response := GetOverviewResponse{TotalExperiments: totalExperimentCount, TotalExperimentInstances: totalExperimentInstancesCount, FailedExperimentInstances: failedExperimentInstancesCount} + c.Success(&c.Controller, response) +} diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/type.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/type.go index a8c6fa0..c63c245 100644 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/type.go +++ b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/namespace/type.go @@ -136,3 +136,9 @@ type GetNamespaceListResponse struct { Total int64 `json:"total"` Namespaces []namespace.UserNamespaceData `json:"namespaces,omitempty"` } + +type GetOverviewResponse struct { + TotalExperiments int64 `json:"total_experiments"` + TotalExperimentInstances int64 `json:"total_experiment_instances"` + FailedExperimentInstances int64 `json:"failed_experiment_instances"` +} diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/node/node.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/node/node.go deleted file mode 100644 index 49cda17..0000000 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/node/node.go +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright 2022-2023 Chaos Meta Authors. - * - * Licensed 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 node - -import ( - "chaosmeta-platform/pkg/gateway/apiserver/v1alpha1" - beego "github.com/beego/beego/v2/server/web" -) - -type NodeController struct { - v1alpha1.BeegoOutputController - beego.Controller -} - -/* -func (n *NodeController) ListNode() { - cluster := n.GetString("cluster") - dsQuery := page.ParseDataSelectPathParameter(gc) - - nodeController, err := kube.NewNodeService(cluster) - if err != nil { - n.Error(gc, err) - return - } - - nodes, err := nodeController.List(dsQuery) - if err != nil { - n.Error(gc, err) - return - } - - monCtrl, err := n.clientset.GetPrometheusClient(cluster) - if err != nil { - n.Error(gc, err) - return - } - - if monCtrl != nil { - defer func() { - if err != nil { - n.ErrorWithMessage(gc, fmt.Sprintf("fail when get node metrics|%v", err)) - return - } - }() - - var ( - wg sync.WaitGroup - gp *ants.Pool - lth = len(nodes.List) - ech = make(chan error, lth) - pch = make(chan map[string][]monitor2.Metric, lth) - ) - gp, err = ants.NewPool(20) - if err != nil { - n.ErrorWithMessage(gc, fmt.Sprintf("fail to new goroutine pool, caused by: %v", err)) - return - } - defer gp.Release() - - for _, node := range nodes.List { - wg.Add(1) - node := node - err = gp.Submit(func() { - defer wg.Done() - - metric := monCtrl.GetNamedMetrics([]string{ - "node_cpu_utilisation", - "node_cpu_total", - "node_cpu_usage", - "node_memory_utilisation", - "node_memory_available", - "node_memory_total", - "node_disk_size_capacity", - "node_disk_size_available", - "node_disk_size_usage", - "node_disk_size_utilisation", - "node_pod_count", - "node_pod_quota", - "node_pod_utilisation", - "node_pod_running_count", - "node_pod_succeeded_count", - "node_pod_abnormal_count", - "node_load1", - "node_load5", - "node_load15", - "node_pod_abnormal_ratio", - }, time.Now(), monitor2.NodeOption{ - NodeName: node.Name, - }) - res := make(map[string][]monitor2.Metric) - res[node.Name] = metric - pch <- res - }) - if err != nil { - n.Error(gc, fmt.Errorf("fail to add task to goroutine pool, caused by: %v", err)) - return - } - } - wg.Wait() - close(pch) - select { - case err = <-ech: - return - default: - // do nothing - } - - for p := range pch { - for k, v := range p { - for i, n := range nodes.List { - if k == n.Name { - nodes.List[i].Metrics = v - } - } - } - } - } - n.Success(gc, nodes) -} - -func (n *NodeController) GetNode(gc *gin.Context) { - var nodeInfo NodeInfo - - cluster := gc.Param("cluster") - nodeName := gc.Param("node") - - nodeController, err := n.clientset.NewNodeController(cluster) - if err != nil { - n.Error(gc, err) - return - } - - node, err := nodeController.Get(nodeName) - if err != nil { - n.Error(gc, err) - return - } - - nodeInfo.Node = node.Node - nodeInfo.AllocatedResources = node.AllocatedResources - ackController, err := n.clientset.NewACKController(cluster) - if err != nil { - n.Success(gc, nodeInfo) - return - } - cloudInfo, err := ackController.GetNodeDetail("", nodeName) - if err != nil { - n.Error(gc, err) - return - } - - nodeInfo.CloudInfo = cloudInfo - n.Success(gc, nodeInfo) - return -} - -func (n *NodeController) ScheduleNode(gc *gin.Context) { - jwtHeader := gc.GetHeader(constants.GwJWTHeader) - user, err := sv1alpha1.GetUser(jwtHeader) - if err != nil { - n.ErrorWithMessage(gc, fmt.Sprintf("failed to parse params, error: %s", err)) - return - } - // 更改nodeschedule - nodeInfo := Node{} - err = gc.ShouldBindJSON(&nodeInfo) - if err != nil { - n.Error(gc, err) - return - } - - if nodeInfo.Cluster == "" || nodeInfo.NodeName == "" { - n.ErrorWithMessage(gc, "missing cluster or node") - return - } - - node := v1alpha1.GalaxyNode{ - ObjectMeta: v1.ObjectMeta{ - Name: fmt.Sprintf("node-schedule-%v", time.Now().Unix()), - }, - Spec: v1alpha1.GalaxyNodeSpec{ - User: fmt.Sprintf("%s(%s)", user.RealmName, user.NickNameCn), - Cluster: nodeInfo.Cluster, - Env: nodeInfo.Env, - Operate: v1alpha1.GalaxyNodeOperate{ - Type: v1alpha1.ScheduleGalaxyNode, - Node: nodeInfo.NodeName, - OperateParams: v1alpha1.OperateParams{ - Schedule: nodeInfo.UnSchedule, - }, - }, - }, - } - err = n.galaxyNodeController.Create(&node) - if err != nil { - n.Error(gc, err) - return - } - n.SuccessNoData(gc) -} - -func (n *NodeController) PatchNode(gc *gin.Context) { - jwtHeader := gc.GetHeader(constants.GwJWTHeader) - user, err := sv1alpha1.GetUser(jwtHeader) - if err != nil { - n.ErrorWithMessage(gc, fmt.Sprintf("failed to parse params, error: %s", err)) - return - } - // 更新node的label或者annotation - nodePatch := kube.ReplaceNodeInfoParam{} - - err = gc.ShouldBindJSON(&nodePatch) - if err != nil { - n.Error(gc, err) - return - } - - node := v1alpha1.GalaxyNode{ - ObjectMeta: v1.ObjectMeta{ - Name: fmt.Sprintf("node-patch-%v", time.Now().Unix()), - }, - Spec: v1alpha1.GalaxyNodeSpec{ - User: fmt.Sprintf("%s(%s)", user.RealmName, user.NickNameCn), - Env: nodePatch.Env, - Cluster: nodePatch.Cluster, - Operate: v1alpha1.GalaxyNodeOperate{ - Type: v1alpha1.PatchGalaxyNode, - Node: nodePatch.NodeName, - OperateParams: v1alpha1.OperateParams{ - LabelOrAnnotation: v1alpha1.ParamMeta{ - Path: nodePatch.OperatorPath, - Data: nodePatch.OperatorData, - }, - }, - }, - }, - } - err = n.galaxyNodeController.Create(&node) - if err != nil { - n.Error(gc, err) - return - } - n.SuccessNoData(gc) -} - -func (n *nodeService) TaintNode(gc *gin.Context) { - jwtHeader := gc.GetHeader(constants.GwJWTHeader) - user, err := sv1alpha1.GetUser(jwtHeader) - if err != nil { - n.ErrorWithMessage(gc, fmt.Sprintf("failed to parse params, error: %s", err)) - return - - } - nodeTaint := PatchNodeTaint{} - - err = gc.ShouldBindJSON(&nodeTaint) - if err != nil { - n.Error(gc, err) - return - } - - node := v1alpha1.GalaxyNode{ - ObjectMeta: v1.ObjectMeta{ - Name: fmt.Sprintf("node-taint-%v", time.Now().Unix()), - }, - Spec: v1alpha1.GalaxyNodeSpec{ - User: fmt.Sprintf("%s(%s)", user.RealmName, user.NickNameCn), - Cluster: nodeTaint.Cluster, - Env: nodeTaint.Env, - Operate: v1alpha1.GalaxyNodeOperate{ - Type: v1alpha1.TaintGalaxyNode, - Node: nodeTaint.NodeName, - OperateParams: v1alpha1.OperateParams{ - Taints: nodeTaint.Taints, - }, - }, - }, - } - err = n.galaxyNodeController.Create(&node) - if err != nil { - n.Error(gc, err) - return - } - n.SuccessNoData(gc) -} - -func (n *nodeService) GetNodePods(gc *gin.Context) { - cluster := gc.Param("cluster") - nodeName := gc.Param("node") - dsQuery := n.ParseDataSelectPathParameter(gc) - - nodeController, err := n.clientset.NewNodeController(cluster) - if err != nil { - n.Error(gc, err) - return - } - - pods, err := nodeController.GetPods(nodeName, dsQuery) - if err != nil { - n.Error(gc, err) - return - } - n.Success(gc, pods) -} - -func (n *NodeController) GetNodeEvents(gc *gin.Context) { - cluster := gc.Param("cluster") - node := gc.Param("node") - dsQuery := page.ParseDataSelectPathParameter(gc) - - nodeController, err := n.clientset.NewNodeController(cluster) - if err != nil { - n.Error(gc, err) - return - } - - eventList, err := nodeController.GetEvents(node, dsQuery) - if err != nil { - n.Error(gc, err) - return - } - n.Success(gc, eventList) -} - -*/ diff --git a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/node/type.go b/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/node/type.go deleted file mode 100644 index 72c1772..0000000 --- a/chaosmeta-platform/pkg/gateway/apiserver/v1alpha1/node/type.go +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2022-2023 Chaos Meta Authors. - * - * Licensed 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 node - -import ( - "chaosmeta-platform/pkg/service/kubernetes/kube" - corev1 "k8s.io/api/core/v1" -) - -type Node struct { - Env string `json:"env" description:"env"` - Cluster string `json:"cluster" description:"cluster"` - NodeName string `json:"nodeName" description:"nodeName"` - UnSchedule bool `json:"unSchedule" description:"unSchedule"` -} - -type PatchNodeTaint struct { - Env string `json:"env" description:"env"` - Cluster string `json:"cluster" description:"cluster"` - NodeName string `json:"nodeName" description:"nodeName"` - Taints []corev1.Taint `json:"taints" description:"taints"` -} - -type NodeInfo struct { - kube.NodeDetail `json:",inline"` -} - -type ListNodeResponse struct { - Total int `json:"total"` - Current int `json:"current"` - PageSize int `json:"pageSize"` - List []struct { - corev1.Node `json:",inline"` - AllocatedResources kube.NodeAllocatedResources `json:"allocatedResources,omitempty"` - } `json:"list"` -} - -type GetNodePodsResponse kube.PodResponse - -type GetNodeEventsResponse kube.EventResponse diff --git a/chaosmeta-platform/pkg/models/common/page/parser.go b/chaosmeta-platform/pkg/models/common/page/parser.go index 0172fb9..90b3b44 100644 --- a/chaosmeta-platform/pkg/models/common/page/parser.go +++ b/chaosmeta-platform/pkg/models/common/page/parser.go @@ -47,3 +47,9 @@ func ParseDataSelectPathParameter(c *beego.Controller) *DataSelectQuery { filterQuery := parseFilterPathParameter(c) return NewDataSelectQuery(paginationQuery, sortQuery, filterQuery) } + +func ParseDataSelectPathParameterTest() *DataSelectQuery { + itemsPerPage := 10 + page := 1 + return NewDataSelectQuery(NewPaginationQuery(itemsPerPage, int(page-1)), NewSortQuery(nil), NewFilterQuery(nil)) +} diff --git a/chaosmeta-platform/pkg/models/experiment/args_value.go b/chaosmeta-platform/pkg/models/experiment/args_value.go index 7e4db5b..ffaab9b 100644 --- a/chaosmeta-platform/pkg/models/experiment/args_value.go +++ b/chaosmeta-platform/pkg/models/experiment/args_value.go @@ -87,6 +87,9 @@ func GetArgsValuesByWorkflowNodeUUID(workflowNodeUUID string) ([]*ArgsValue, err o := models.GetORM() var argsValues []*ArgsValue _, err := o.QueryTable(new(ArgsValue).TableName()).Filter("workflow_node_uuid", workflowNodeUUID).OrderBy("-create_time").All(&argsValues) + if err == orm.ErrNoRows { + return nil, nil + } if err != nil { return nil, err } diff --git a/chaosmeta-platform/pkg/models/experiment/experiment.go b/chaosmeta-platform/pkg/models/experiment/experiment.go index e5a3fc2..e0d7d38 100644 --- a/chaosmeta-platform/pkg/models/experiment/experiment.go +++ b/chaosmeta-platform/pkg/models/experiment/experiment.go @@ -28,6 +28,7 @@ import ( type ( ExperimentStatus int ScheduleType string + TimeType string ) const ( @@ -39,6 +40,11 @@ const ( ManualMode = ScheduleType("manual") //手动模式 OnceMode = ScheduleType("once") //自动模式 CronMode = ScheduleType("cron") + + RecentDayType = TimeType("recent") + RangeTimeType = TimeType("range") + + TimeLayout = "2006-01-02 15:04:05" ) type Experiment struct { @@ -142,10 +148,14 @@ func ListExperimentsByScheduleTypeAndStatus(scheduleType ScheduleType, experimen experimentQuery.OrderBy("create_time") _, err = experimentQuery.GetOamQuerySeter().All(&experiments) + if err == orm.ErrNoRows { + return 0, nil, nil + } + return totalCount, experiments, err } -func SearchExperiments(lastInstance string, namespaceId int, creator int, name string, scheduleType string, timeType string, recentDays int, startTime, endTime time.Time, orderBy string, page, pageSize int) (int64, []*Experiment, error) { +func SearchExperiments(lastInstance string, namespaceId int, creator int, name string, scheduleType string, timeType string, timeSearchField string, recentDays int, startTime, endTime time.Time, orderBy string, page, pageSize int) (int64, []*Experiment, error) { o := models.GetORM() experiments := []*Experiment{} qs := o.QueryTable(new(Experiment).TableName()) @@ -170,15 +180,19 @@ func SearchExperiments(lastInstance string, namespaceId int, creator int, name s if name != "" { experimentQuery.Filter("name", models.CONTAINS, true, name) } - if timeType != "" { + if timeSearchField == "" { + timeSearchField = "create_time" + } + if timeType == string(RecentDayType) { if recentDays > 0 { - start := time.Now().Add(time.Duration(-recentDays*24) * time.Hour).Format("2006-01-02 15:04:05") - experimentQuery.Filter("create_time", models.GTE, false, start) + start := time.Now().Add(time.Duration(-recentDays*24) * time.Hour).Format(TimeLayout) + experimentQuery.Filter(timeSearchField, models.GTE, false, start) } - + } + if timeType == string(RangeTimeType) { if !startTime.IsZero() && !endTime.IsZero() { - experimentQuery.Filter("create_time", models.GTE, false, startTime) - experimentQuery.Filter("create_time", models.LTE, false, endTime) + experimentQuery.Filter(timeSearchField, models.GTE, false, startTime.Format(TimeLayout)) + experimentQuery.Filter(timeSearchField, models.LTE, false, endTime.Format(TimeLayout)) } } @@ -188,11 +202,11 @@ func SearchExperiments(lastInstance string, namespaceId int, creator int, name s return 0, nil, err } - orderByList := []string{"uuid"} - if len(orderBy) > 0 { - orderByList = append(orderByList, orderBy) + orderByStr := "uuid" + if orderBy != "" { + orderByStr = orderBy } - experimentQuery.OrderBy(orderByList...) + experimentQuery.OrderBy(orderByStr) if err := experimentQuery.Limit(pageSize, (page-1)*pageSize); err != nil { return 0, nil, err } @@ -215,3 +229,27 @@ func acquireLock(o orm.Ormer, uuid string) bool { } return affected > 0 } + +func CountExperiments(namespaceID int, status int, recentDays int) (int64, error) { + o := models.GetORM() + qs := o.QueryTable(new(Experiment).TableName()) + + if namespaceID != 0 { + qs = qs.Filter("namespace_id", namespaceID) + } + + if status >= 0 { + qs = qs.Filter("status", status) + } + + if recentDays > 0 { + start := time.Now().Add(time.Duration(-recentDays*24) * time.Hour).Format(TimeLayout) + qs = qs.Filter("create_time__gte", start) + } + + total, err := qs.Count() + if err == orm.ErrNoRows { + return 0, nil + } + return total, err +} diff --git a/chaosmeta-platform/pkg/models/experiment/label_experiment.go b/chaosmeta-platform/pkg/models/experiment/label_experiment.go index a9b6895..7ab4667 100644 --- a/chaosmeta-platform/pkg/models/experiment/label_experiment.go +++ b/chaosmeta-platform/pkg/models/experiment/label_experiment.go @@ -57,6 +57,9 @@ func ListLabelIDsByExperimentUUID(experimentUUID string) ([]int, error) { } func AddLabelIDsToExperiment(experimentUUID string, labelIDs []int) error { + if len(labelIDs) == 0 { + return nil + } o := models.GetORM() labelExperiments := make([]*LabelExperiment, len(labelIDs)) for i, id := range labelIDs { diff --git a/chaosmeta-platform/pkg/models/experiment_instance/experiment_instance.go b/chaosmeta-platform/pkg/models/experiment_instance/experiment_instance.go index 9957460..e9f34b6 100644 --- a/chaosmeta-platform/pkg/models/experiment_instance/experiment_instance.go +++ b/chaosmeta-platform/pkg/models/experiment_instance/experiment_instance.go @@ -25,7 +25,10 @@ import ( "time" ) -type ExperimentInstanceStatus string +type ( + ExperimentInstanceStatus string + TimeType string +) const ( TablePrefix = "experiment_" @@ -34,6 +37,9 @@ const ( Running = ExperimentInstanceStatus("Running") //执行中 TimeLayout = "2006-01-02 15:04:05" + + RecentDayType = TimeType("recent") + RangeTimeType = TimeType("range") ) type ExperimentInstance struct { @@ -43,7 +49,7 @@ type ExperimentInstance struct { Description string `json:"description" orm:"column(description);size(1024)"` ExperimentUUID string `json:"experiment_uuid,omitempty" orm:"column(experiment_uuid);size(128);index"` Creator int `json:"creator" orm:"index;column(creator)"` - Status string `json:"status" orm:"column(status);default(to_be_executed);size(32);index"` + Status string `json:"status" orm:"column(status);size(32);index"` Message string `json:"message" orm:"column(message);size(1024)"` Version int `json:"-" orm:"column(version);default(0);version"` models.BaseTimeModel @@ -121,7 +127,7 @@ func DeleteExperimentInstanceByUUID(uuid string) error { return err } -func SearchExperimentInstances(lastInstance string, namespaceId int, creator int, name string, scheduleType string, timeType string, recentDays int, startTime, endTime time.Time, orderBy string, page, pageSize int) (int64, []*ExperimentInstance, error) { +func SearchExperimentInstances(lastInstance string, experimentUUID string, namespaceId int, creator int, name string, timeType string, timeSearchField string, status string, recentDays int, startTime, endTime time.Time, orderBy string, page, pageSize int) (int64, []*ExperimentInstance, error) { o := models.GetORM() experiments := []*ExperimentInstance{} qs := o.QueryTable(new(ExperimentInstance).TableName()) @@ -131,30 +137,42 @@ func SearchExperimentInstances(lastInstance string, namespaceId int, creator int return 0, nil, err } - if creator > 0 { + if creator != 0 { experimentQuery.Filter("creator", models.NEGLECT, false, creator) } + if experimentUUID != "" { + experimentQuery.Filter("experiment_uuid", models.NEGLECT, false, experimentUUID) + } if lastInstance != "" { experimentQuery.Filter("last_instance", models.NEGLECT, false, lastInstance) } if namespaceId > 0 { experimentQuery.Filter("namespace_id", models.NEGLECT, false, namespaceId) } - if scheduleType != "" { - experimentQuery.Filter("schedule_type", models.NEGLECT, false, scheduleType) + if status != "" { + if status == "null" { + status = "" + } + experimentQuery.Filter("status", models.NEGLECT, false, status) } if name != "" { experimentQuery.Filter("name", models.CONTAINS, true, name) } - if timeType != "" { + + if timeSearchField == "" { + timeSearchField = "create_time" + } + + if timeType == string(RecentDayType) { if recentDays > 0 { - start := time.Now().Add(time.Duration(-recentDays*24) * time.Hour).Format("2006-01-02 15:04:05") - experimentQuery.Filter("create_time", models.GTE, false, start) + start := time.Now().Add(time.Duration(-recentDays*24) * time.Hour).Format(TimeLayout) + experimentQuery.Filter(timeSearchField, models.GTE, false, start) } - + } + if timeType == string(RangeTimeType) { if !startTime.IsZero() && !endTime.IsZero() { - experimentQuery.Filter("create_time", models.GTE, false, startTime) - experimentQuery.Filter("create_time", models.LTE, false, endTime) + experimentQuery.Filter(timeSearchField, models.GTE, false, startTime.Format(TimeLayout)) + experimentQuery.Filter(timeSearchField, models.LTE, false, endTime.Format(TimeLayout)) } } @@ -164,15 +182,18 @@ func SearchExperimentInstances(lastInstance string, namespaceId int, creator int return 0, nil, err } - orderByList := []string{"uuid"} - if len(orderBy) > 0 { - orderByList = append(orderByList, orderBy) + orderByStr := "uuid" + if orderBy != "" { + orderByStr = orderBy } - experimentQuery.OrderBy(orderByList...) + experimentQuery.OrderBy(orderByStr) if err := experimentQuery.Limit(pageSize, (page-1)*pageSize); err != nil { return 0, nil, err } _, err = experimentQuery.GetOamQuerySeter().All(&experiments) + if err == orm.ErrNoRows { + return 0, nil, nil + } return totalCount, experiments, err } @@ -238,3 +259,38 @@ func CountExperimentInstance(namespaceId, day int) (map[string]int64, int64, err return result, total, nil } + +type ExperimentInstanceStatusCount struct { + PendingCount int64 + RunningCount int64 + SucceededCount int64 + FailedCount int64 + ErrorCount int64 + OtherCount int64 +} + +func CountExperimentInstances(namespaceID int, experimentUUID string, status string, recentDays int) (int64, error) { + o := models.GetORM() + qs := o.QueryTable(new(ExperimentInstance).TableName()) + + if namespaceID != 0 { + qs = qs.Filter("namespace_id", namespaceID) + } + + if experimentUUID != "" { + qs = qs.Filter("experiment_uuid", experimentUUID) + } + if status != "" { + qs = qs.Filter("status", status) + } + + if recentDays > 0 { + start := time.Now().Add(time.Duration(-recentDays*24) * time.Hour).Format(TimeLayout) + qs = qs.Filter("create_time__gte", start) + } + total, err := qs.Count() + if err == orm.ErrNoRows { + return 0, nil + } + return total, err +} diff --git a/chaosmeta-platform/pkg/models/experiment_instance/label_experiment_instance.go b/chaosmeta-platform/pkg/models/experiment_instance/label_experiment_instance.go index 05f9eeb..15188ef 100644 --- a/chaosmeta-platform/pkg/models/experiment_instance/label_experiment_instance.go +++ b/chaosmeta-platform/pkg/models/experiment_instance/label_experiment_instance.go @@ -23,6 +23,7 @@ import ( ) type LabelExperimentInstance struct { + ID int `json:"id,omitempty" orm:"pk;auto;column(id)"` LabelID int `json:"label_id" orm:"column(label_id);index"` ExperimentInstanceUUID string `json:"experiment_instance_uuid" orm:"column(experiment_instance_uuid);index"` models.BaseTimeModel @@ -62,6 +63,9 @@ func ListLabelsByExperimentInstanceUUID(experimentUUID string) ([]*LabelExperime } func AddLabelIDsToExperiment(experimentUUID string, labelIDs []int) error { + if len(labelIDs) == 0 { + return nil + } o := models.GetORM() labelExperiments := make([]*LabelExperimentInstance, len(labelIDs)) for i, id := range labelIDs { diff --git a/chaosmeta-platform/pkg/models/inject/basic/flow_inject.go b/chaosmeta-platform/pkg/models/inject/basic/flow_inject.go new file mode 100644 index 0000000..78ae162 --- /dev/null +++ b/chaosmeta-platform/pkg/models/inject/basic/flow_inject.go @@ -0,0 +1,78 @@ +/* + * Copyright 2022-2023 Chaos Meta Authors. + * + * Licensed 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 basic + +import models "chaosmeta-platform/pkg/models/common" + +type FlowInject struct { + Id int `json:"id" orm:"column(id);pk"` + Name string `json:"name" orm:"column(name);size(255)"` + NameCn string `json:"name_cn" orm:"column(name_cn);size(255)"` + Description string `json:"description" orm:"column(description);size(1024)"` + DescriptionCn string `json:"description_cn" orm:"column(description_cn);size(1024)"` +} + +func (m *FlowInject) TableName() string { + return TablePrefix + "flow_inject" +} + +func GetFlowInjectByID(id int) (FlowInject, error) { + FlowInject := FlowInject{Id: id} + err := models.GetORM().Read(&FlowInject) + return FlowInject, err +} + +func ListFlowInjects(orderBy string, page, pageSize int) (int64, []FlowInject, error) { + flowInject, flowInjects := FlowInject{}, new([]FlowInject) + querySeter := models.GetORM().QueryTable(flowInject.TableName()) + FlowInjectQuery, err := models.NewDataSelectQuery(&querySeter) + if err != nil { + return 0, nil, err + } + + var totalCount int64 + totalCount, err = FlowInjectQuery.GetOamQuerySeter().Count() + + orderByList := []string{"id"} + if len(orderBy) > 0 { + orderByList = append(orderByList, orderBy) + } + FlowInjectQuery.OrderBy(orderByList...) + if err := FlowInjectQuery.Limit(pageSize, (page-1)*pageSize); err != nil { + return 0, nil, err + } + + _, err = FlowInjectQuery.GetOamQuerySeter().All(flowInjects) + return totalCount, *flowInjects, err +} + +func InsertFlowInject(FlowInject *FlowInject) error { + _, err := models.GetORM().Insert(FlowInject) + return err +} + +func UpdateFlowInject(FlowInject *FlowInject) error { + _, err := models.GetORM().Update(FlowInject) + return err +} + +// DeleteFlowInject deletes a Flow_inject by its ID +func DeleteFlowInject(id int) error { + FlowInject := FlowInject{Id: id} + _, err := models.GetORM().Delete(&FlowInject) + return err +} diff --git a/chaosmeta-platform/pkg/models/inject/basic/measure_inject.go b/chaosmeta-platform/pkg/models/inject/basic/measure_inject.go new file mode 100644 index 0000000..b9e5bfb --- /dev/null +++ b/chaosmeta-platform/pkg/models/inject/basic/measure_inject.go @@ -0,0 +1,80 @@ +/* + * Copyright 2022-2023 Chaos Meta Authors. + * + * Licensed 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 basic + +import models "chaosmeta-platform/pkg/models/common" + +type MeasureInject struct { + Id int `json:"id" orm:"column(id);pk"` + Name string `json:"name" orm:"column(name);size(255)"` + NameCn string `json:"name_cn" orm:"column(name_cn);size(255)"` + Description string `json:"description" orm:"column(description);size(1024)"` + DescriptionCn string `json:"description_cn" orm:"column(description_cn);size(1024)"` +} + +func (m *MeasureInject) TableName() string { + return TablePrefix + "measure_inject" +} + +func GetMeasureInjectByID(id int) (MeasureInject, error) { + measureInject := MeasureInject{Id: id} + err := models.GetORM().Read(&measureInject) + return measureInject, err +} + +// GetAllMeasureInjects retrieves all measure_injects +func GetAllMeasureInjects(orderBy string, page, pageSize int) (int64, []MeasureInject, error) { + measureInject, measureInjects := MeasureInject{}, new([]MeasureInject) + querySeter := models.GetORM().QueryTable(measureInject.TableName()) + measureInjectQuery, err := models.NewDataSelectQuery(&querySeter) + if err != nil { + return 0, nil, err + } + + var totalCount int64 + totalCount, err = measureInjectQuery.GetOamQuerySeter().Count() + + orderByList := []string{"id"} + if len(orderBy) > 0 { + orderByList = append(orderByList, orderBy) + } + measureInjectQuery.OrderBy(orderByList...) + if err := measureInjectQuery.Limit(pageSize, (page-1)*pageSize); err != nil { + return 0, nil, err + } + + _, err = measureInjectQuery.GetOamQuerySeter().All(measureInjects) + return totalCount, *measureInjects, err +} + +// CreateMeasureInject creates a new measure_inject +func CreateMeasureInject(measureInject *MeasureInject) error { + _, err := models.GetORM().Insert(measureInject) + return err +} + +func UpdateMeasureInject(measureInject *MeasureInject) error { + _, err := models.GetORM().Update(measureInject) + return err +} + +// DeleteMeasureInject deletes a measure_inject by its ID +func DeleteMeasureInject(id int) error { + measureInject := MeasureInject{Id: id} + _, err := models.GetORM().Delete(&measureInject) + return err +} diff --git a/chaosmeta-platform/pkg/models/namespace/cluster_namespace.go b/chaosmeta-platform/pkg/models/namespace/cluster_namespace.go index 7648db6..1797210 100644 --- a/chaosmeta-platform/pkg/models/namespace/cluster_namespace.go +++ b/chaosmeta-platform/pkg/models/namespace/cluster_namespace.go @@ -42,6 +42,9 @@ func GetClusterIDsByNamespaceID(namespaceID int) ([]int, error) { clusterNamespace := ClusterNamespace{} var clusterIDs orm.ParamsList _, err := models.GetORM().QueryTable(clusterNamespace.TableName()).Filter("namespace_id", namespaceID).ValuesFlat(&clusterIDs, "cluster_id") + if err == orm.ErrNoRows { + return nil, nil + } if err != nil { return nil, err } diff --git a/chaosmeta-platform/pkg/models/namespace/label.go b/chaosmeta-platform/pkg/models/namespace/label.go index 258b99c..d19effe 100644 --- a/chaosmeta-platform/pkg/models/namespace/label.go +++ b/chaosmeta-platform/pkg/models/namespace/label.go @@ -20,6 +20,7 @@ import ( "chaosmeta-platform/pkg/models/common" "context" "errors" + "github.com/beego/beego/v2/client/orm" ) const TimeLayout = "2006-01-02 15:04:05" @@ -107,5 +108,8 @@ func QueryLabels(ctx context.Context, nameSpaceId int, name, creator string, ord } _, err = labelQuery.GetOamQuerySeter().All(labelList) + if err == orm.ErrNoRows { + return 0, nil, nil + } return totalCount, *labelList, err } diff --git a/chaosmeta-platform/pkg/models/namespace/namespace.go b/chaosmeta-platform/pkg/models/namespace/namespace.go index dee6d78..995d865 100644 --- a/chaosmeta-platform/pkg/models/namespace/namespace.go +++ b/chaosmeta-platform/pkg/models/namespace/namespace.go @@ -20,6 +20,7 @@ import ( "chaosmeta-platform/pkg/models/common" "context" "errors" + "github.com/beego/beego/v2/client/orm" ) type Namespace struct { @@ -73,6 +74,9 @@ func GetDefaultNamespace(ctx context.Context, namespace *Namespace) error { func GetAllNamespaces() ([]*Namespace, error) { var namespaces []*Namespace _, err := models.GetORM().QueryTable("namespace").All(&namespaces) + if err == orm.ErrNoRows { + return nil, nil + } if err != nil { return nil, err } @@ -108,5 +112,47 @@ func QueryNamespaces(ctx context.Context, name, creator, orderBy string, page, p } totalCount, err := namespaceQuery.GetOamQuerySeter().All(namespaceList) + if err == orm.ErrNoRows { + return 0, nil, nil + } + return totalCount, *namespaceList, err +} + +func ListNamespaces(ctx context.Context, namespaceId []int, name string, creator, orderBy string, page, pageSize int) (int64, []Namespace, error) { + ns, namespaceList := Namespace{}, new([]Namespace) + querySeter := models.GetORM().QueryTable(ns.TableName()) + namespaceQuery, err := models.NewDataSelectQuery(&querySeter) + if err != nil { + return 0, nil, err + } + + if len(namespaceId) > 0 { + namespaceQuery.Filter("id", models.IN, false, namespaceId) + } + if len(name) > 0 { + namespaceQuery.Filter("name", models.CONTAINS, true, name) + } + + if len(creator) > 0 { + namespaceQuery.Filter("creator", models.NEGLECT, false, creator) + } + + orderByList := []string{} + if orderBy != "" { + orderByList = append(orderByList, orderBy) + } else { + orderByList = append(orderByList, "id") + } + namespaceQuery.OrderBy(orderByList...) + + if err := namespaceQuery.Limit(pageSize, (page-1)*pageSize); err != nil { + return 0, nil, err + } + totalCount, _ := namespaceQuery.GetOamQuerySeter().Count() + + _, err = namespaceQuery.GetOamQuerySeter().All(namespaceList) + if err == orm.ErrNoRows { + return 0, nil, nil + } return totalCount, *namespaceList, err } diff --git a/chaosmeta-platform/pkg/models/namespace/user_namespace.go b/chaosmeta-platform/pkg/models/namespace/user_namespace.go index a9e2ce2..5b5390e 100644 --- a/chaosmeta-platform/pkg/models/namespace/user_namespace.go +++ b/chaosmeta-platform/pkg/models/namespace/user_namespace.go @@ -18,6 +18,8 @@ package namespace import ( "chaosmeta-platform/pkg/models/common" + "chaosmeta-platform/pkg/models/user" + "chaosmeta-platform/util/log" "context" "errors" "fmt" @@ -82,19 +84,24 @@ type UserNamespaceData struct { } type UserDataNamespace struct { - UserId int `json:"userId"` + UserId int `json:"user_id"` + UserName string `json:"user_name"` Permission Permission `json:"permission"` CreateTime string `json:"create_time"` UpdateTime string `json:"update_time"` } -func GetNamespacesFromUser(ctx context.Context, userId int, permission int, orderBy string, page, pageSize int) (int64, []UserNamespaceData, error) { +func GetNamespacesFromUser(ctx context.Context, userIdList []int, permission int, orderBy string, page, pageSize int) (int64, []UserNamespaceData, error) { u := UserNamespace{} var ( namespaceDataList []UserNamespaceData userNamespaces []*UserNamespace ) - qs := models.GetORM().QueryTable(u.TableName()).Filter("user_id", userId) + qs := models.GetORM().QueryTable(u.TableName()) + if len(userIdList) > 0 { + qs = qs.Filter("user_id__in", userIdList) + } + if permission >= 0 { qs = qs.Filter("permission", permission) } @@ -129,7 +136,7 @@ func GetUsersFromNamespace(ctx context.Context, namespaceId int) (int64, []UserD userNamespaces []*UserNamespace userDataList []UserDataNamespace ) - qs := models.GetORM().QueryTable(u.TableName()).Filter("namespace_id", namespaceId).OrderBy("id") + qs := models.GetORM().QueryTable(u.TableName()).Filter("namespace_id", namespaceId).Filter("permission", 1).OrderBy("id") totalCount, err := qs.Count() if err != nil { @@ -140,8 +147,13 @@ func GetUsersFromNamespace(ctx context.Context, namespaceId int) (int64, []UserD return 0, nil, err } for _, userNamespace := range userNamespaces { + userGet := user.User{ID: userNamespace.UserId} + if err := user.GetUserById(context.Background(), &userGet); err != nil { + log.Error(err) + } userDataList = append(userDataList, UserDataNamespace{ UserId: userNamespace.UserId, + UserName: userGet.Email, Permission: userNamespace.Permission, CreateTime: userNamespace.CreateTime.Format(TimeLayout), UpdateTime: userNamespace.UpdateTime.Format(TimeLayout), diff --git a/chaosmeta-platform/pkg/models/user/user.go b/chaosmeta-platform/pkg/models/user/user.go index a817f75..5d8a57a 100644 --- a/chaosmeta-platform/pkg/models/user/user.go +++ b/chaosmeta-platform/pkg/models/user/user.go @@ -124,6 +124,9 @@ func QueryUser(ctx context.Context, name, role, orderBy string, page, pageSize i } _, err = userQuery.GetOamQuerySeter().All(users) + if err == orm.ErrNoRows { + return 0, nil, nil + } return totalCount, *users, err } diff --git a/chaosmeta-platform/pkg/service/experiment/chaosmeta_flow_inject.go b/chaosmeta-platform/pkg/service/experiment/chaosmeta_flow_inject.go new file mode 100644 index 0000000..94533b4 --- /dev/null +++ b/chaosmeta-platform/pkg/service/experiment/chaosmeta_flow_inject.go @@ -0,0 +1,197 @@ +/* + * Copyright 2022-2023 Chaos Meta Authors. + * + * Licensed 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 experiment + +import ( + "chaosmeta-platform/util/log" + "context" + "encoding/json" + "errors" + gyaml "github.com/ghodss/yaml" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + yamlutil "k8s.io/apimachinery/pkg/runtime/serializer/yaml" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" +) + +type ChaosmetaFlowInjectInterface interface { + Get(ctx context.Context, namespace, name string) (result *LoadTest, err error) + List(ctx context.Context) (*LoadTestList, error) + Create(ctx context.Context, ChaosmetaFlowInject *LoadTest) (*LoadTest, error) + Update(ctx context.Context, ChaosmetaFlowInject *LoadTest) (*LoadTest, error) + Delete(ctx context.Context, name string) error + Patch(ctx context.Context, name string, pt types.PatchType, data []byte) error + DeleteExpiredList(ctx context.Context) error +} + +type ChaosmetaFlowInjectService struct { + Config *rest.Config + Client dynamic.Interface +} + +func NewChaosmetaFlowInjectService(config *rest.Config) ChaosmetaFlowInjectInterface { + client, err := dynamic.NewForConfig(config) + if err != nil { + return nil + } + + return &ChaosmetaFlowInjectService{ + Config: config, Client: client, + } +} + +func (c *ChaosmetaFlowInjectService) Get(ctx context.Context, namespace, name string) (result *LoadTest, err error) { + cb, err := c.Client.Resource(gvr).Namespace(namespace).Get(ctx, name, v1.GetOptions{}) + if err != nil { + return nil, err + } + + data, err := cb.MarshalJSON() + if err != nil { + return nil, err + } + + var experiment LoadTest + if err := json.Unmarshal(data, &experiment); err != nil { + return nil, err + } + + return &experiment, nil +} + +func (c *ChaosmetaFlowInjectService) List(ctx context.Context) (*LoadTestList, error) { + list, err := c.Client.Resource(gvr).List(ctx, v1.ListOptions{}) + if err != nil { + return nil, err + } + + data, err := list.MarshalJSON() + if err != nil { + return nil, err + } + + var exList LoadTestList + if err := json.Unmarshal(data, &exList); err != nil { + return nil, err + } + + return &exList, nil +} + +func (c *ChaosmetaFlowInjectService) Create(ctx context.Context, ChaosmetaFlowInject *LoadTest) (*LoadTest, error) { + d, err := json.Marshal(ChaosmetaFlowInject) + if err != nil { + return nil, err + } + + y, err := gyaml.JSONToYAML(d) + if err != nil { + return nil, err + } + + decoder := yamlutil.NewDecodingSerializer(unstructured.UnstructuredJSONScheme) + obj := &unstructured.Unstructured{} + if _, _, err := decoder.Decode(y, &gvk, obj); err != nil { + return nil, err + } + + utd, err := c.Client.Resource(gvr).Create(ctx, obj, v1.CreateOptions{}) + if err != nil { + return nil, err + } + data, err := utd.MarshalJSON() + if err != nil { + return nil, err + } + var experiment LoadTest + if err := json.Unmarshal(data, &experiment); err != nil { + return nil, err + } + if len(experiment.Status) > 0 { + if experiment.Status == FailedStatus { + return nil, errors.New("ChaosmetaFlowInject failed to execute") + } + } + return &experiment, nil +} + +func (c *ChaosmetaFlowInjectService) Update(ctx context.Context, ChaosmetaFlowInject *LoadTest) (*LoadTest, error) { + d, err := json.Marshal(ChaosmetaFlowInject) + if err != nil { + return nil, err + } + + y, err := gyaml.JSONToYAML(d) + if err != nil { + return nil, err + } + decoder := yamlutil.NewDecodingSerializer(unstructured.UnstructuredJSONScheme) + obj := &unstructured.Unstructured{} + if _, _, err := decoder.Decode(y, &gvk, obj); err != nil { + return nil, err + } + + utd, err := c.Client.Resource(gvr).Get(ctx, obj.GetName(), v1.GetOptions{}) + if err != nil { + return nil, err + } + obj.SetResourceVersion(utd.GetResourceVersion()) + utd, err = c.Client.Resource(gvr).Update(ctx, obj, v1.UpdateOptions{}) + if err != nil { + return nil, err + } + + data, err := utd.MarshalJSON() + if err != nil { + return nil, err + } + var experiment LoadTest + if err := json.Unmarshal(data, &experiment); err != nil { + return nil, err + } + return &experiment, nil +} + +func (c *ChaosmetaFlowInjectService) Delete(ctx context.Context, name string) error { + return c.Client.Resource(gvr).Delete(ctx, name, v1.DeleteOptions{}) +} + +func (c *ChaosmetaFlowInjectService) Patch(ctx context.Context, name string, pt types.PatchType, data []byte) error { + _, err := c.Client.Resource(gvr).Patch(ctx, name, pt, data, v1.PatchOptions{}) + return err +} + +func (c *ChaosmetaFlowInjectService) DeleteExpiredList(ctx context.Context) error { + ChaosmetaFlowInjectList, err := c.List(ctx) + if err != nil { + return err + } + for _, experiment := range ChaosmetaFlowInjectList.Items { + if experiment.Status == SuccessStatus { + err := c.Delete(ctx, experiment.Name) + if err != nil { + log.Errorf("failed to delete ChaosmetaFlowInject experiment %s: %v", experiment.Name, err.Error()) + return err + } else { + log.Errorf("ChaosmetaFlowInject experiment %s deleted", experiment.Name) + } + } + } + return nil +} diff --git a/chaosmeta-platform/pkg/service/experiment/chaosmeta_flow_inject_type.go b/chaosmeta-platform/pkg/service/experiment/chaosmeta_flow_inject_type.go new file mode 100644 index 0000000..391d0ca --- /dev/null +++ b/chaosmeta-platform/pkg/service/experiment/chaosmeta_flow_inject_type.go @@ -0,0 +1,63 @@ +/* + * Copyright 2022-2023 Chaos Meta Authors. + * + * Licensed 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 experiment + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// flow +type LoadTest struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec LoadTestSpec `json:"spec,omitempty"` + Status StatusFlowType `json:"status,omitempty"` +} + +type LoadTestSpec struct { + FlowType FlowType `json:"flowType"` + Duration string `json:"duration"` + Parallelism int `json:"parallelism"` + Source int `json:"source"` + Stopped bool `json:"stopped"` + Args []FlowArgs `json:"args"` +} + +type LoadTestList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []LoadTest `json:"items"` +} + +type FlowType string + +const ( + HTTPFlowType FlowType = "HTTP" +) + +type FlowArgs struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type StatusFlowType string + +const ( + CreatedStatus StatusFlowType = "created" + RunningStatus StatusFlowType = "running" + SuccessStatus StatusFlowType = "success" + FailedStatus StatusFlowType = "failed" +) diff --git a/chaosmeta-platform/pkg/service/experiment/experiment.go b/chaosmeta-platform/pkg/service/experiment/experiment.go index 2f5cb19..0e90052 100644 --- a/chaosmeta-platform/pkg/service/experiment/experiment.go +++ b/chaosmeta-platform/pkg/service/experiment/experiment.go @@ -18,6 +18,7 @@ package experiment import ( "chaosmeta-platform/pkg/models/experiment" + "chaosmeta-platform/pkg/models/experiment_instance" "chaosmeta-platform/pkg/models/namespace" "chaosmeta-platform/pkg/models/user" "chaosmeta-platform/util/log" @@ -51,16 +52,16 @@ type ExperimentInfo struct { UpdateTime time.Time `json:"update_time,omitempty"` } -type Label struct { +type LabelGet struct { Id int `json:"id"` Name string `json:"name"` Color string `json:"color"` NamespaceId int `json:"namespaceId"` } -type Experiment struct { +type ExperimentCreate struct { ExperimentInfo - Labels []Label `json:"labels,omitempty"` + Labels []int `json:"labels,omitempty"` WorkflowNodes []*WorkflowNode `json:"workflow_nodes,omitempty"` } @@ -71,10 +72,16 @@ type ExperimentGet struct { ScheduleType string `json:"schedule_type"` ScheduleRule string `json:"schedule_rule"` NamespaceID int `json:"namespace_id"` - Creator string `json:"creator,omitempty"` + Creator int `json:"creator,omitempty"` + NextExec time.Time `json:"next_exec,omitempty"` + CreatorName string `json:"creator_name,omitempty"` Status int `json:"status"` - Labels []Label `json:"labels,omitempty"` + LastInstance string `json:"last_instance"` + CreateTime time.Time `json:"create_time,omitempty"` + UpdateTime time.Time `json:"update_time,omitempty"` + Labels []LabelGet `json:"labels,omitempty"` WorkflowNodes []*WorkflowNode `json:"workflow_nodes,omitempty"` + Number int64 `json:"number,omitempty"` } type WorkflowNode struct { @@ -95,7 +102,7 @@ func (es *ExperimentService) createUUID(creator int, typeStr string) string { return fmt.Sprintf("%d%d", nodeSnow.Generate(), creator) } -func getLabelIdsFromExperiment(labels []Label) []int { +func getLabelIdsFromLabelGet(labels []LabelGet) []int { labelIds := make([]int, len(labels)) for i, label := range labels { labelIds[i] = label.Id @@ -103,39 +110,26 @@ func getLabelIdsFromExperiment(labels []Label) []int { return labelIds } -func (es *ExperimentService) CreateExperiment(experimentParam *Experiment) (string, error) { +func (es *ExperimentService) CreateExperiment(experimentParam *ExperimentCreate) (string, error) { if experimentParam == nil { return "", errors.New("experimentParam is nil") } - experimentCreate := experiment.Experiment{ - UUID: es.createUUID(experimentParam.Creator, ""), - Name: experimentParam.Name, - NamespaceID: experimentParam.NamespaceID, - Description: experimentParam.Description, - ScheduleType: experimentParam.ScheduleType, - ScheduleRule: experimentParam.ScheduleRule, - Creator: experimentParam.Creator, - } - - // experiment - if err := experiment.CreateExperiment(&experimentCreate); err != nil { - return "", err - } + experimentUUid := es.createUUID(experimentParam.Creator, "") //label if len(experimentParam.Labels) > 0 { - if err := experiment.AddLabelIDsToExperiment(experimentCreate.UUID, getLabelIdsFromExperiment(experimentParam.Labels)); err != nil { - return experimentCreate.UUID, err + if err := experiment.AddLabelIDsToExperiment(experimentUUid, experimentParam.Labels); err != nil { + return "", err } } //workflow_nodes for _, node := range experimentParam.WorkflowNodes { - node.ExperimentUUID = experimentCreate.UUID + node.ExperimentUUID = experimentUUid workflowNodeCreate := experiment.WorkflowNode{ UUID: node.UUID, Name: node.Name, - ExperimentUUID: experimentCreate.UUID, + ExperimentUUID: experimentUUid, Row: node.Row, Column: node.Column, Duration: node.Duration, @@ -145,13 +139,13 @@ func (es *ExperimentService) CreateExperiment(experimentParam *Experiment) (stri ExecID: node.ExecID, } if err := experiment.CreateWorkflowNode(&workflowNodeCreate); err != nil { - return experimentCreate.UUID, err + return "", err } //args_value if len(node.ArgsValue) > 0 { if err := experiment.BatchInsertArgsValues(node.UUID, node.ArgsValue); err != nil { - return experimentCreate.UUID, err + return "", err } } @@ -159,14 +153,28 @@ func (es *ExperimentService) CreateExperiment(experimentParam *Experiment) (stri if node.FaultRange != nil { node.FaultRange.WorkflowNodeInstanceUUID = node.UUID if err := experiment.CreateFaultRange(node.FaultRange); err != nil { - return experimentCreate.UUID, err + return "", err } } } + + // experiment + experimentCreate := experiment.Experiment{ + UUID: experimentUUid, + Name: experimentParam.Name, + NamespaceID: experimentParam.NamespaceID, + Description: experimentParam.Description, + ScheduleType: experimentParam.ScheduleType, + ScheduleRule: experimentParam.ScheduleRule, + Creator: experimentParam.Creator, + } + if err := experiment.CreateExperiment(&experimentCreate); err != nil { + return "", err + } return experimentCreate.UUID, nil } -func (es *ExperimentService) UpdateExperiment(uuid string, experimentParam *Experiment) error { +func (es *ExperimentService) UpdateExperiment(uuid string, experimentParam *ExperimentCreate) error { if experimentParam == nil { return errors.New("experimentParam is nil") } @@ -181,6 +189,20 @@ func (es *ExperimentService) UpdateExperiment(uuid string, experimentParam *Expe return err } +func (es *ExperimentService) UpdateExperimentStatusAndLastInstance(uuid string, status int, lastInstance string) error { + experimentGet, err := experiment.GetExperimentByUUID(uuid) + if err != nil || experimentGet == nil { + return fmt.Errorf("no experiment") + } + if status >= 0 { + experimentGet.Status = experiment.ExperimentStatus(status) + } + if lastInstance != "" { + experimentGet.LastInstance = lastInstance + } + return experiment.UpdateExperiment(experimentGet) +} + func (es *ExperimentService) DeleteExperimentByUUID(uuid string) error { if err := experiment.ClearLabelIDsByExperimentUUID(uuid); err != nil { return err @@ -188,7 +210,7 @@ func (es *ExperimentService) DeleteExperimentByUUID(uuid string) error { workflowNodes, err := experiment.GetWorkflowNodesByExperimentUUID(uuid) if err != nil { - return err + log.Error(err) } for _, workflowNode := range workflowNodes { @@ -207,7 +229,7 @@ func (es *ExperimentService) DeleteExperimentByUUID(uuid string) error { return experiment.DeleteExperimentByUUID(uuid) } -func (es *ExperimentService) GetExperimentByUUID(uuid string) (*Experiment, error) { +func (es *ExperimentService) GetExperimentByUUID(uuid string) (*ExperimentGet, error) { experimentGet, err := experiment.GetExperimentByUUID(uuid) if err != nil || experimentGet == nil { return nil, fmt.Errorf("no experiment") @@ -215,68 +237,37 @@ func (es *ExperimentService) GetExperimentByUUID(uuid string) (*Experiment, erro userGet := user.User{ID: experimentGet.Creator} if err := user.GetUserById(context.Background(), &userGet); err != nil { - log.Error(err) + log.Errorf("can not find user, [user-id: %s]", err) } - experimentReturn := Experiment{ - ExperimentInfo: ExperimentInfo{ - UUID: experimentGet.UUID, - Name: experimentGet.Name, - Description: experimentGet.Description, - ScheduleType: experimentGet.ScheduleType, - ScheduleRule: experimentGet.ScheduleRule, - NamespaceID: experimentGet.NamespaceID, - Creator: experimentGet.Creator, - CreatorName: userGet.Email, - Status: int(experimentGet.Status), - CreateTime: experimentGet.CreateTime, - UpdateTime: experimentGet.UpdateTime, - }, + experimentReturn := ExperimentGet{ + UUID: experimentGet.UUID, + Name: experimentGet.Name, + Description: experimentGet.Description, + ScheduleType: experimentGet.ScheduleType, + ScheduleRule: experimentGet.ScheduleRule, + NamespaceID: experimentGet.NamespaceID, + CreatorName: userGet.Email, + Creator: experimentGet.Creator, + NextExec: experimentGet.NextExec, + Status: int(experimentGet.Status), + LastInstance: experimentGet.LastInstance, + CreateTime: experimentGet.CreateTime, + UpdateTime: experimentGet.UpdateTime, } + experimentCount, _ := experiment_instance.CountExperimentInstances(0, experimentGet.UUID, "", 0) + experimentReturn.Number = experimentCount if err := es.GetLabelByExperiment(uuid, &experimentReturn); err != nil { return &experimentReturn, nil } return &experimentReturn, es.GetWorkflowNodesByExperiment(uuid, &experimentReturn) -} - -func (es *ExperimentService) GetExperimentByModelExperiment(experimentGet *experiment.Experiment) (*Experiment, error) { - if experimentGet == nil { - return nil, errors.New("experimentGet is nil") - } - if experimentGet.UUID == "" { - return nil, errors.New("experiment uuid is empty") - } - userGet := user.User{ID: experimentGet.Creator} - if err := user.GetUserById(context.Background(), &userGet); err != nil { - log.Error(err) - } - - experimentReturn := Experiment{ - ExperimentInfo: ExperimentInfo{ - UUID: experimentGet.UUID, - Name: experimentGet.Name, - Description: experimentGet.Description, - ScheduleType: experimentGet.ScheduleType, - ScheduleRule: experimentGet.ScheduleRule, - NamespaceID: experimentGet.NamespaceID, - Creator: experimentGet.Creator, - CreatorName: userGet.Email, - Status: int(experimentGet.Status), - CreateTime: experimentGet.CreateTime, - UpdateTime: experimentGet.UpdateTime, - }, - } - - if err := es.GetLabelByExperiment(experimentGet.UUID, &experimentReturn); err != nil { - return &experimentReturn, nil - } - return &experimentReturn, es.GetWorkflowNodesByExperiment(experimentGet.UUID, &experimentReturn) + //CountExperimentInstances() } -func (es *ExperimentService) GetLabelByExperiment(uuid string, experimentReturn *Experiment) error { +func (es *ExperimentService) GetLabelByExperiment(uuid string, experimentReturn *ExperimentGet) error { labelList, err := experiment.ListLabelIDsByExperimentUUID(uuid) if err != nil { return err @@ -288,7 +279,7 @@ func (es *ExperimentService) GetLabelByExperiment(uuid string, experimentReturn log.Error(err) continue } - experimentReturn.Labels = append(experimentReturn.Labels, Label{ + experimentReturn.Labels = append(experimentReturn.Labels, LabelGet{ Id: labelId, Name: getLabel.Name, Color: getLabel.Color, @@ -298,7 +289,7 @@ func (es *ExperimentService) GetLabelByExperiment(uuid string, experimentReturn return nil } -func (es *ExperimentService) GetWorkflowNodesByExperiment(uuid string, experimentReturn *Experiment) error { +func (es *ExperimentService) GetWorkflowNodesByExperiment(uuid string, experimentReturn *ExperimentGet) error { if experimentReturn == nil { return errors.New("experimentReturn is nil") } @@ -332,10 +323,9 @@ func (es *ExperimentService) GetWorkflowNodesByExperiment(uuid string, experimen faultRange, err := experiment.GetFaultRangeByWorkflowNodeInstanceUUID(workflowNodeGet.UUID) if err != nil { - return err + log.Error(err) } nodeResult.FaultRange = faultRange - workflowNodes = append(workflowNodes, &nodeResult) } @@ -343,14 +333,25 @@ func (es *ExperimentService) GetWorkflowNodesByExperiment(uuid string, experimen return nil } -func (es *ExperimentService) SearchExperiments(lastInstance string, namespaceId int, creator int, name string, scheduleType string, timeType string, recentDays int, startTime, endTime time.Time, orderBy string, page, pageSize int) (int64, []Experiment, error) { - var experimentList []Experiment - total, experiments, err := experiment.SearchExperiments(lastInstance, namespaceId, creator, name, scheduleType, timeType, recentDays, startTime, endTime, orderBy, page, pageSize) +func (es *ExperimentService) SearchExperiments(lastInstance string, namespaceId int, creatorName string, name string, scheduleType string, timeType string, timeSearchField string, recentDays int, startTime, endTime time.Time, orderBy string, page, pageSize int) (int64, []ExperimentGet, error) { + log.Error(lastInstance, namespaceId, creatorName, name, scheduleType, timeType, timeSearchField, recentDays, startTime, endTime, orderBy, page, pageSize) + var experimentList []ExperimentGet + creator := 0 + if creatorName != "" { + userGet := user.User{Email: creatorName} + if err := user.GetUser(context.Background(), &userGet); err != nil { + log.Error(err) + } else { + creator = userGet.ID + } + } + + total, experiments, err := experiment.SearchExperiments(lastInstance, namespaceId, creator, name, scheduleType, timeType, timeSearchField, recentDays, startTime, endTime, orderBy, page, pageSize) if err != nil { return 0, nil, err } for _, experiment := range experiments { - experimentGet, err := es.GetExperimentByModelExperiment(experiment) + experimentGet, err := es.GetExperimentByUUID(experiment.UUID) if err != nil { return 0, nil, err } diff --git a/chaosmeta-platform/pkg/service/experiment/experiment_flow.go b/chaosmeta-platform/pkg/service/experiment/experiment_flow.go index fe7137d..675d0bd 100644 --- a/chaosmeta-platform/pkg/service/experiment/experiment_flow.go +++ b/chaosmeta-platform/pkg/service/experiment/experiment_flow.go @@ -17,6 +17,7 @@ package experiment import ( + "chaosmeta-platform/config" "chaosmeta-platform/pkg/models/inject/basic" "chaosmeta-platform/pkg/service/experiment_instance" "chaosmeta-platform/pkg/service/kubernetes" @@ -39,9 +40,7 @@ var ( ) const ( - ArgoWorkflowNamespace = "default" - WorkflowNamespace = "chaosmeta-inject" - WorkflowMainStep = "main" + WorkflowMainStep = "main" ) var Manifest = ` @@ -49,72 +48,6 @@ var Manifest = ` path: /spec/targetPhase value: recover ` -var workflow = v1alpha1.Workflow{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "argoproj.io/v1alpha1", - Kind: "Workflow", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "", - Namespace: ArgoWorkflowNamespace, - }, - Spec: v1alpha1.WorkflowSpec{ - ServiceAccountName: kubernetes.ServiceAccount, - Entrypoint: WorkflowMainStep, - Templates: []v1alpha1.Template{ - { - Name: string(ExperimentInject), - Inputs: v1alpha1.Inputs{ - Parameters: []v1alpha1.Parameter{ - { - Name: "experiment", - }, - }, - }, - Resource: &v1alpha1.ResourceTemplate{ - Action: "create", - FailureCondition: "status.status == failed", - SuccessCondition: "status.phase == recover,status.status == success", - Manifest: "{{inputs.parameters.experiment}}", - }, - }, - { - Name: string(RawSuspend), - Inputs: v1alpha1.Inputs{ - Parameters: []v1alpha1.Parameter{ - { - Name: "time", - }, - }, - }, - Suspend: &v1alpha1.SuspendTemplate{ - Duration: "{{inputs.parameters.time}}", - }, - }, - { - Name: "experiment-recover", - Inputs: v1alpha1.Inputs{ - Parameters: []v1alpha1.Parameter{ - { - Name: "experiment", - }, - }, - }, - Resource: &v1alpha1.ResourceTemplate{ - Action: "patch", - FailureCondition: "status.status == failed", - SuccessCondition: "status.phase == recover,status.status == success", - MergeStrategy: "json", - Flags: []string{ - "experiments.chaosmeta.io", - "{{inputs.parameters.experiment}}", - }, - Manifest: Manifest, - }, - }, - }, - }, -} type ExecType string @@ -130,7 +63,72 @@ func getWorFlowName(experimentInstanceId string) string { } func GetWorkflowStruct(experimentInstanceId string, nodes []*experiment_instance.WorkflowNodesDetail) *v1alpha1.Workflow { - newWorkflow := workflow + var newWorkflow = v1alpha1.Workflow{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "argoproj.io/v1alpha1", + Kind: "Workflow", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "", + Namespace: config.DefaultRunOptIns.ArgoWorkflowNamespace, + }, + Spec: v1alpha1.WorkflowSpec{ + ServiceAccountName: kubernetes.ServiceAccount, + Entrypoint: WorkflowMainStep, + Templates: []v1alpha1.Template{ + { + Name: string(ExperimentInject), + Inputs: v1alpha1.Inputs{ + Parameters: []v1alpha1.Parameter{ + { + Name: "experiment", + }, + }, + }, + Resource: &v1alpha1.ResourceTemplate{ + Action: "create", + FailureCondition: "status.status == failed", + SuccessCondition: "status.phase == recover,status.status == success", + Manifest: "{{inputs.parameters.experiment}}", + }, + }, + { + Name: string(RawSuspend), + Inputs: v1alpha1.Inputs{ + Parameters: []v1alpha1.Parameter{ + { + Name: "time", + }, + }, + }, + Suspend: &v1alpha1.SuspendTemplate{ + Duration: "{{inputs.parameters.time}}", + }, + }, + { + Name: "experiment-recover", + Inputs: v1alpha1.Inputs{ + Parameters: []v1alpha1.Parameter{ + { + Name: "experiment", + }, + }, + }, + Resource: &v1alpha1.ResourceTemplate{ + Action: "patch", + FailureCondition: "status.status == failed", + SuccessCondition: "status.phase == recover,status.status == success", + MergeStrategy: "json", + Flags: []string{ + "experiments.chaosmeta.io", + "{{inputs.parameters.experiment}}", + }, + Manifest: Manifest, + }, + }, + }, + }, + } newWorkflow.Name = getWorFlowName(experimentInstanceId) newWorkflow.Spec.Templates = append(newWorkflow.Spec.Templates, v1alpha1.Template{ Name: WorkflowMainStep, @@ -199,7 +197,7 @@ func getInjectStep(experimentInstanceUUID string, node *experiment_instance.Work ObjectMeta: metav1.ObjectMeta{ Name: injectStep.Name, - Namespace: WorkflowNamespace, + Namespace: config.DefaultRunOptIns.WorkflowNamespace, }, Spec: ExperimentSpec{ @@ -266,6 +264,15 @@ func getInjectStep(experimentInstanceUUID string, node *experiment_instance.Work return &injectStep } +func getFlowInjectStepName(flowInjectName, experimentInstanceUUID, nodeID string) string { + return fmt.Sprintf("inject-flow-%s-%s-%s", flowInjectName, experimentInstanceUUID, nodeID) +} + +func getFlowInjectStep(experimentInstanceUUID string, node *experiment_instance.WorkflowNodesDetail, phaseType PhaseType) *v1alpha1.WorkflowStep { + + return nil +} + func convertToSteps(experimentInstanceId string, nodes []*experiment_instance.WorkflowNodesDetail) []v1alpha1.ParallelSteps { maxRow, maxColumn := getMaxRowAndColumn(nodes) steps := make([]v1alpha1.ParallelSteps, maxRow+1) diff --git a/chaosmeta-platform/pkg/service/experiment/routine.go b/chaosmeta-platform/pkg/service/experiment/routine.go index ed06d1e..c89a176 100644 --- a/chaosmeta-platform/pkg/service/experiment/routine.go +++ b/chaosmeta-platform/pkg/service/experiment/routine.go @@ -22,6 +22,7 @@ import ( experimentInstanceModel "chaosmeta-platform/pkg/models/experiment_instance" "chaosmeta-platform/pkg/service/cluster" "chaosmeta-platform/pkg/service/experiment_instance" + "chaosmeta-platform/pkg/service/user" "chaosmeta-platform/util/log" "context" "encoding/json" @@ -41,7 +42,7 @@ type ExperimentRoutine struct { localCron *cron.Cron } -func convertToExperimentInstance(experiment *Experiment, status string) *experiment_instance.ExperimentInstance { +func convertToExperimentInstance(experiment *ExperimentGet, status string) *experiment_instance.ExperimentInstance { experimentInstance := &experiment_instance.ExperimentInstance{ ExperimentInstanceInfo: experiment_instance.ExperimentInstanceInfo{ UUID: experiment.UUID, @@ -51,7 +52,7 @@ func convertToExperimentInstance(experiment *Experiment, status string) *experim NamespaceId: experiment.NamespaceID, Status: status, }, - Labels: getLabelIdsFromExperiment(experiment.Labels), + Labels: getLabelIdsFromLabelGet(experiment.Labels), } for _, node := range experiment.WorkflowNodes { @@ -69,15 +70,18 @@ func convertToExperimentInstance(experiment *Experiment, status string) *experim }, Subtasks: &experimentInstanceModel.FaultRangeInstance{ WorkflowNodeInstanceUUID: node.UUID, - TargetName: node.FaultRange.TargetName, - TargetIP: node.FaultRange.TargetIP, - TargetHostname: node.FaultRange.TargetHostname, - TargetLabel: node.FaultRange.TargetLabel, - TargetApp: node.FaultRange.TargetApp, - TargetNamespace: node.FaultRange.TargetNamespace, - RangeType: node.FaultRange.RangeType, }, } + + if node.FaultRange != nil { + workflowNodeDetail.Subtasks.TargetName = node.FaultRange.TargetName + workflowNodeDetail.Subtasks.TargetIP = node.FaultRange.TargetIP + workflowNodeDetail.Subtasks.TargetHostname = node.FaultRange.TargetHostname + workflowNodeDetail.Subtasks.TargetLabel = node.FaultRange.TargetLabel + workflowNodeDetail.Subtasks.TargetApp = node.FaultRange.TargetApp + workflowNodeDetail.Subtasks.TargetNamespace = node.FaultRange.TargetNamespace + workflowNodeDetail.Subtasks.RangeType = node.FaultRange.RangeType + } for _, arg := range node.ArgsValue { workflowNodeDetail.ArgsValues = append(workflowNodeDetail.ArgsValues, experiment_instance.ArgsValue{ArgsId: arg.ArgsID, Value: arg.Value}) } @@ -85,11 +89,11 @@ func convertToExperimentInstance(experiment *Experiment, status string) *experim } experimentInstanceBytes, _ := json.Marshal(experimentInstance) - log.Error("convertToExperimentInstance------------", string(experimentInstanceBytes)) + log.Error("convertToExperimentInstance:", string(experimentInstanceBytes)) return experimentInstance } -func StartExperiment(experimentID string) error { +func StartExperiment(experimentID string, creatorName string) error { experimentService := ExperimentService{} experimentGet, err := experimentService.GetExperimentByUUID(experimentID) if err != nil || experimentGet == nil { @@ -97,9 +101,16 @@ func StartExperiment(experimentID string) error { } experimentInstance := convertToExperimentInstance(experimentGet, string(experimentInstanceModel.Running)) - + if creatorName != "" { + creatorId, err := user.GetIdByName(creatorName) + if err != nil { + log.Error(err) + return err + } + experimentInstance.Creator = creatorId + } experimentInstanceService := experiment_instance.ExperimentInstanceService{} - experimentInstanceId, err := experimentInstanceService.CreateExperimentInstance(experimentInstance) + experimentInstanceId, err := experimentInstanceService.CreateExperimentInstance(experimentInstance, "Pending") if err != nil { return err } @@ -110,7 +121,7 @@ func StartExperiment(experimentID string) error { return err } - argoWorkFlowCtl, err := NewArgoWorkFlowService(restConfig, ArgoWorkflowNamespace) + argoWorkFlowCtl, err := NewArgoWorkFlowService(restConfig, config.DefaultRunOptIns.ArgoWorkflowNamespace) if err != nil { return err } @@ -127,10 +138,10 @@ func StartExperiment(experimentID string) error { func StopExperiment(experimentInstanceID string) error { experimentInstanceInfo, err := experimentInstanceModel.GetExperimentInstanceByUUID(experimentInstanceID) - if err != nil { - return err + if err != nil || experimentInstanceInfo == nil { + return fmt.Errorf("can not find experimentInstance") } - if experimentInstanceInfo.Status == "Succeeded" || experimentInstanceInfo.Status == "Failed" || experimentInstanceInfo.Status == "Error" { + if experimentInstanceInfo.Status == "Succeeded" { return errors.New("walkthrough is over") } @@ -140,7 +151,7 @@ func StopExperiment(experimentInstanceID string) error { return err } - argoWorkFlowCtl, err := NewArgoWorkFlowService(restConfig, WorkflowNamespace) + argoWorkFlowCtl, err := NewArgoWorkFlowService(restConfig, config.DefaultRunOptIns.WorkflowNamespace) if err != nil { log.Error(err) return err @@ -151,14 +162,14 @@ func StopExperiment(experimentInstanceID string) error { log.Error(err) return nil } - if status == "Succeeded" || status == "Failed" || status == "Error" { + if status == "Succeeded" { return errors.New("experiment has ended") } chaosmetaService := NewChaosmetaService(restConfig) for _, node := range workFlowGet.Status.Nodes { if isInjectStepName(node.DisplayName) { - chaosmetaCR, err := chaosmetaService.Get(context.Background(), WorkflowNamespace, node.DisplayName) + chaosmetaCR, err := chaosmetaService.Get(context.Background(), config.DefaultRunOptIns.WorkflowNamespace, node.DisplayName) if err != nil { log.Error(err) return err @@ -201,11 +212,12 @@ func (e *ExperimentRoutine) DealOnceExperiment() { nextExec, _ := time.Parse(DefaultFormat, experimentGet.ScheduleRule) if time.Now().After(nextExec) { log.Error("create an experiment") - if err := StartExperiment(experimentGet.UUID); err != nil { + if err := StartExperiment(experimentGet.UUID, ""); err != nil { log.Error(err) continue } experimentGet.Status = experiment.Executed + experimentGet.LastInstance = time.Now().Format(TimeLayout) if err := experiment.UpdateExperiment(experimentGet); err != nil { log.Error(err) continue @@ -246,18 +258,12 @@ func (e *ExperimentRoutine) DealCronExperiment() { continue } - log.Error(6) - if err := StartExperiment(experimentGet.UUID); err != nil { + if err := StartExperiment(experimentGet.UUID, ""); err != nil { log.Error(err) - experimentGet.Status = experiment.ToBeExecuted - if err := experiment.UpdateExperiment(experimentGet); err != nil { - log.Error(err) - continue - } - continue } - log.Error(7) + experimentGet.Status = experiment.ToBeExecuted + experimentGet.LastInstance = time.Now().Format(TimeLayout) if err := experiment.UpdateExperiment(experimentGet); err != nil { log.Error(err) continue @@ -306,7 +312,7 @@ func (e *ExperimentRoutine) SyncExperimentsStatus() { return } - argoWorkFlowCtl, err := NewArgoWorkFlowService(restConfig, ArgoWorkflowNamespace) + argoWorkFlowCtl, err := NewArgoWorkFlowService(restConfig, config.DefaultRunOptIns.ArgoWorkflowNamespace) pendingArgos, finishArgos, err := argoWorkFlowCtl.ListPendingAndFinishWorkflows() if err != nil { log.Error(err) @@ -330,8 +336,10 @@ func (e *ExperimentRoutine) SyncExperimentsStatus() { if err := e.syncExperimentStatus(argo); err != nil { errCh <- err } - if err := argoWorkFlowCtl.Delete(argo.Name); err != nil { - errCh <- err + if argo.Status.Phase == "Succeeded" { + if err := argoWorkFlowCtl.Delete(argo.Name); err != nil { + errCh <- err + } } }(*finishArgo) } @@ -362,23 +370,19 @@ func (e *ExperimentRoutine) DeleteExecutedInstanceCR() { return } - //argoWorkFlowCtl, err := workflow_channel.NewArgoWorkFlowService(restConfig, WorkflowNamespace) - //if err != nil { - // log.Error(err) - // return - //} - //if err := argoWorkFlowCtl.DeleteExpiredList(); err != nil { - // log.Error(err) - // return - //} log.Info("expired Workflows have been deleted successfully.") + ctx := context.Background() chaosmetaService := NewChaosmetaService(restConfig) - if err := chaosmetaService.DeleteExpiredList(context.Background()); err != nil { + if err := chaosmetaService.DeleteExpiredList(ctx); err != nil { log.Error(err) - return } log.Info("expired chaosmeta experiment have been deleted successfully.") + chaosmetaFlowInjectService := NewChaosmetaFlowInjectService(restConfig) + if err := chaosmetaFlowInjectService.DeleteExpiredList(ctx); err != nil { + log.Error(err) + } + log.Info("expired chaosmeta flow experiment have been deleted successfully.") } diff --git a/chaosmeta-platform/pkg/service/experiment_instance/experiment_instance.go b/chaosmeta-platform/pkg/service/experiment_instance/experiment_instance.go index ff0ecf9..b71e717 100644 --- a/chaosmeta-platform/pkg/service/experiment_instance/experiment_instance.go +++ b/chaosmeta-platform/pkg/service/experiment_instance/experiment_instance.go @@ -19,6 +19,7 @@ package experiment_instance import ( "chaosmeta-platform/pkg/models/experiment_instance" "chaosmeta-platform/pkg/models/namespace" + "chaosmeta-platform/pkg/models/user" "chaosmeta-platform/util/log" "chaosmeta-platform/util/snowflake" "context" @@ -48,7 +49,7 @@ func (s *ExperimentInstanceService) createUUID(creator int, typeStr string) stri return fmt.Sprintf("%d%d%d%s", nodeSnow.Generate(), creator, time.Now().Unix(), typeStr) } -func (s *ExperimentInstanceService) CreateExperimentInstance(experimentParam *ExperimentInstance) (string, error) { +func (s *ExperimentInstanceService) CreateExperimentInstance(experimentParam *ExperimentInstance, status string) (string, error) { experimentCreate := experiment_instance.ExperimentInstance{ UUID: s.createUUID(experimentParam.Creator, "experiment"), Name: experimentParam.Name, @@ -57,6 +58,7 @@ func (s *ExperimentInstanceService) CreateExperimentInstance(experimentParam *Ex ExperimentUUID: experimentParam.UUID, Creator: experimentParam.Creator, Message: experimentParam.Message, + Status: status, } // experiment @@ -124,6 +126,7 @@ type ExperimentInstanceInfo struct { Name string `json:"name"` Description string `json:"description"` Creator int `json:"creator"` + CreatorName string `json:"creator_name,omitempty"` NamespaceId int `json:"namespace_id"` CreateTime string `json:"create_time"` @@ -146,11 +149,17 @@ func (s *ExperimentInstanceService) GetExperimentInstanceByUUID(uuid string) (*E return nil, err } + userGet := user.User{ID: exp.Creator} + if err := user.GetUserById(context.Background(), &userGet); err != nil { + log.Error(err) + } + expData := ExperimentInstanceInfo{ UUID: exp.UUID, Name: exp.Name, Description: exp.Description, Creator: exp.Creator, + CreatorName: userGet.Email, NamespaceId: exp.NamespaceID, CreateTime: exp.CreateTime.Format(time.RFC3339), UpdateTime: exp.UpdateTime.Format(time.RFC3339), @@ -357,9 +366,16 @@ func (s *ExperimentInstanceService) DeleteExperimentInstancesByUUID(uuids []stri return nil } -func (s *ExperimentInstanceService) SearchExperimentInstances(lastInstance string, namespaceId int, creator int, name string, scheduleType string, timeType string, recentDays int, startTime, endTime time.Time, orderBy string, page, pageSize int) (int64, []*ExperimentInstanceInfo, error) { +func (s *ExperimentInstanceService) SearchExperimentInstances(lastInstance string, experimentUUID string, namespaceId int, creatorName string, name string, timeType string, timeSearchField string, status string, recentDays int, startTime, endTime time.Time, orderBy string, page, pageSize int) (int64, []*ExperimentInstanceInfo, error) { var experimentInstanceInfoList []*ExperimentInstanceInfo - total, experiments, err := experiment_instance.SearchExperimentInstances(lastInstance, namespaceId, creator, name, scheduleType, timeType, recentDays, startTime, endTime, orderBy, page, pageSize) + creator := 0 + userGet := user.User{Email: creatorName} + if err := user.GetUser(context.Background(), &userGet); err != nil { + log.Error(err) + } else { + creator = userGet.ID + } + total, experiments, err := experiment_instance.SearchExperimentInstances(lastInstance, experimentUUID, namespaceId, creator, name, timeType, timeSearchField, status, recentDays, startTime, endTime, orderBy, page, pageSize) if err != nil { return 0, nil, err } @@ -368,12 +384,17 @@ func (s *ExperimentInstanceService) SearchExperimentInstances(lastInstance strin if err != nil { log.Error(err) } + userGet := user.User{ID: experiment.Creator} + if err := user.GetUserById(context.Background(), &userGet); err != nil { + log.Error(err) + } expData := ExperimentInstanceInfo{ UUID: experiment.UUID, Name: experiment.Name, Description: experiment.Description, Creator: experiment.Creator, + CreatorName: userGet.Email, NamespaceId: experiment.NamespaceID, CreateTime: experiment.CreateTime.Format(time.RFC3339), UpdateTime: experiment.UpdateTime.Format(time.RFC3339), diff --git a/chaosmeta-platform/pkg/service/inject/flow.go b/chaosmeta-platform/pkg/service/inject/flow.go new file mode 100644 index 0000000..7748c87 --- /dev/null +++ b/chaosmeta-platform/pkg/service/inject/flow.go @@ -0,0 +1,47 @@ +/* + * Copyright 2022-2023 Chaos Meta Authors. + * + * Licensed 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 inject + +import ( + "chaosmeta-platform/pkg/models/inject/basic" + "context" +) + +func (i *InjectService) ListFlowInjects(ctx context.Context, orderBy string, page, pageSize int) (int64, []basic.FlowInject, error) { + total, targets, err := basic.ListFlowInjects(orderBy, page, pageSize) + return total, targets, err +} + +func InitHttpFlow(ctx context.Context) error { + var ( + httpFlow = basic.FlowInject{Name: "HTTP", NameCn: "HTTP", Description: "continuously inject http request traffic to the target http server", DescriptionCn: "对目标 http 服务器持续注入 http 请求流量"} + ) + if err := basic.InsertFlowInject(&httpFlow); err != nil { + return err + } + return InitHttpFlowArgs(ctx, httpFlow) +} + +func InitHttpFlowArgs(ctx context.Context, flowInject basic.FlowInject) error { + argsHost := basic.Args{InjectId: flowInject.Id, ExecType: ExecFlow, Key: "host", KeyCn: "目标机器", ValueType: "string", DefaultValue: "", Required: false, Description: "目标端口,可选值:ip、域名", DescriptionCn: "Destination port:optional values: ip, domain name"} + argsPort := basic.Args{InjectId: flowInject.Id, ExecType: ExecFlow, Key: "port", KeyCn: "端口", ValueType: "string", DefaultValue: "目标端口", Required: true, DescriptionCn: "目标端口, 单个端口号", Description: "destination port, a single port number"} + argsPath := basic.Args{InjectId: flowInject.Id, ExecType: ExecFlow, Key: "path", KeyCn: "请求path", ValueType: "string", DefaultValue: "", Required: true, DescriptionCn: "请求path", Description: "request path"} + argsHeader := basic.Args{InjectId: flowInject.Id, ExecType: ExecFlow, Key: "header", KeyCn: "请求header", ValueType: "string", DefaultValue: "", Required: false, Description: "List of key-value pairs, format: 'k1:v1,k2:v2'", DescriptionCn: "键值对列表,格式:'k1:v1,k2:v2'"} + argsMethod := basic.Args{InjectId: flowInject.Id, ExecType: ExecFlow, Key: "method", KeyCn: "方法", ValueType: "string", ValueRule: "GET,POST", DefaultValue: "", Required: true, Description: "request method", DescriptionCn: "请求方法"} + argsBody := basic.Args{InjectId: flowInject.Id, ExecType: ExecInject, Key: "body", KeyCn: "请求数据", ValueType: "string", DefaultValue: "", Description: "request data", DescriptionCn: "请求数据"} + return basic.InsertArgsMulti(ctx, []*basic.Args{&argsHost, &argsPort, &argsPath, &argsHeader, &argsMethod, &argsBody}) +} diff --git a/chaosmeta-platform/pkg/service/inject/inject.go b/chaosmeta-platform/pkg/service/inject/inject.go index 8cb0d8d..39a2af3 100644 --- a/chaosmeta-platform/pkg/service/inject/inject.go +++ b/chaosmeta-platform/pkg/service/inject/inject.go @@ -33,12 +33,13 @@ const ( KubernetesScopeType ScopeType = "kubernetes" ExecInject = "inject" + ExecFlow = "flow" ) var ( - PodScope = basic.Scope{Name: string(PodScopeType), NameCn: "容器组", Description: "fault injection can be performed on any Pod in the Kubernetes cluster", DescriptionCn: "可以对 Kubernetes 集群中的任意 Pod 进行故障注入"} - NodeScope = basic.Scope{Name: string(NodeScopeType), NameCn: "节点", Description: "fault injection can be performed on any Node in the Kubernetes cluster", DescriptionCn: "可以对 Kubernetes 集群中的任意 Node 进行故障注入"} - KubernetesScope = basic.Scope{Name: string(KubernetesScopeType), NameCn: "节点", Description: "faults can be injected into Kubernetes resource instances such as pod, deployment, and node to achieve the exception of the Kubernetes cluster itself or the exception of the operator application", DescriptionCn: "可以对 pod、deployment、node 等Kubernetes资源实例注入故障,达到 Kubernetes 集群自身的异常或者 operator 应用的异常"} + PodScope = basic.Scope{Name: string(PodScopeType), NameCn: "Pod", Description: "fault injection can be performed on any Pod in the Kubernetes cluster", DescriptionCn: "可以对 Kubernetes 集群中的任意 Pod 进行故障注入"} + NodeScope = basic.Scope{Name: string(NodeScopeType), NameCn: "Node", Description: "fault injection can be performed on any Node in the Kubernetes cluster", DescriptionCn: "可以对 Kubernetes 集群中的任意 Node 进行故障注入"} + KubernetesScope = basic.Scope{Name: string(KubernetesScopeType), NameCn: "Kubernetes", Description: "faults can be injected into Kubernetes resource instances such as pod, deployment, and node to achieve the exception of the Kubernetes cluster itself or the exception of the operator application", DescriptionCn: "可以对 pod、deployment、node 等Kubernetes资源实例注入故障,达到 Kubernetes 集群自身的异常或者 operator 应用的异常"} ) func Init() error { @@ -185,8 +186,8 @@ func InitCpuFault(ctx context.Context, cpuTarget basic.Target) error { func InitCpuTargetArgsBurn(ctx context.Context, cpuFault basic.Fault) error { var ( CpuArgsPercent = basic.Args{InjectId: cpuFault.ID, ExecType: ExecInject, Key: "percent", KeyCn: "使用率", Unit: "%", UnitCn: "%", Description: "target cpu usage", DescriptionCn: "目标cpu使用率", ValueType: "int", Required: true, ValueRule: "1-100"} - CpuArgsCount = basic.Args{InjectId: cpuFault.ID, ExecType: ExecInject, Key: "count", KeyCn: "核", Unit: "core", UnitCn: "大于等于0的整数,0表示全部核", DefaultValue: "0", Description: "number of faulty CPU cores", DescriptionCn: "故障cpu核数", ValueType: "int", ValueRule: ">0"} - CpuArgsList = basic.Args{InjectId: cpuFault.ID, ExecType: ExecInject, Key: "list", KeyCn: "列表", Unit: "", UnitCn: "", Description: "cpu fault list", DescriptionCn: "故障cpu列表,逗号分隔的核编号列表,可以从/proc/cpuinfo确认", ValueType: "stringlist"} + CpuArgsCount = basic.Args{InjectId: cpuFault.ID, ExecType: ExecInject, Key: "count", KeyCn: "核", Unit: "core", UnitCn: "大于等于0的整数,0表示全部核", DefaultValue: "0", Description: "number of faulty CPU cores", DescriptionCn: "故障cpu核数", ValueType: "int", ValueRule: ">=0"} + CpuArgsList = basic.Args{InjectId: cpuFault.ID, ExecType: ExecInject, Key: "list", KeyCn: "列表", Unit: "", UnitCn: "", Description: "cpu fault list", DescriptionCn: "故障cpu列表,逗号分隔的核编号列表,可以从/proc/cpuinfo确认", ValueType: "string"} ) return basic.InsertArgsMulti(ctx, []*basic.Args{&CpuArgsPercent, &CpuArgsCount, &CpuArgsList}) } diff --git a/chaosmeta-platform/pkg/service/inject/measure.go b/chaosmeta-platform/pkg/service/inject/measure.go new file mode 100644 index 0000000..8202101 --- /dev/null +++ b/chaosmeta-platform/pkg/service/inject/measure.go @@ -0,0 +1,17 @@ +/* + * Copyright 2022-2023 Chaos Meta Authors. + * + * Licensed 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 inject diff --git a/chaosmeta-platform/pkg/service/namespace/namespace.go b/chaosmeta-platform/pkg/service/namespace/namespace.go index 34d6ad6..279d862 100644 --- a/chaosmeta-platform/pkg/service/namespace/namespace.go +++ b/chaosmeta-platform/pkg/service/namespace/namespace.go @@ -17,7 +17,7 @@ package namespace import ( - "chaosmeta-platform/pkg/models/experiment_instance" + "chaosmeta-platform/pkg/models/experiment" namespaceModel "chaosmeta-platform/pkg/models/namespace" "chaosmeta-platform/pkg/models/user" "chaosmeta-platform/util/log" @@ -34,7 +34,7 @@ func Init() { } defaultNamespace := &namespaceModel.Namespace{ - Name: "default namespace", + Name: "默认空间", Description: "This is the default namespace", Creator: 1, IsDefault: true, @@ -162,10 +162,11 @@ func (s *NamespaceService) GroupedUserInNamespaces(ctx context.Context, namespac } type NamespaceData struct { - NamespaceInfo namespaceModel.NamespaceInfo `json:"namespaceInfo"` - users []namespaceModel.NamespaceData `json:"users"` - UserData UserDataInNamespace `json:"userData"` - ExperimentData ExperimentInstanceDataInNamespace `json:"experimentrData"` + Permission int `json:"permission"` + NamespaceInfo namespaceModel.Namespace `json:"namespaceInfo"` + Users []namespaceModel.UserDataNamespace `json:"users"` + UserTotal int64 `json:"userTotal"` + ExperimentTotal int64 `json:"experimentTotal"` } type UserDataInNamespace struct { @@ -174,108 +175,112 @@ type UserDataInNamespace struct { Users []namespaceModel.UserDataNamespace `json:"users"` } -func (s *NamespaceService) getUserData(ctx context.Context, userId int, namespaceId int) (UserDataInNamespace, error) { - userDataInNamespace := UserDataInNamespace{} - permission, err := namespaceModel.IsUserInNamespace(userId, namespaceId) - if err != nil { - return userDataInNamespace, err - } - userDataInNamespace.Permission = int(permission) - - total, users, err := namespaceModel.GetUsersFromNamespace(ctx, namespaceId) - userDataInNamespace.ToTal = int(total) - userDataInNamespace.Users = append(userDataInNamespace.Users, users...) - return userDataInNamespace, err -} - type ExperimentInstanceDataInNamespace struct { ToTal int64 `json:"toTal"` StatusMap map[string]int64 `json:"statusCount"` } -func (s *NamespaceService) getExperimentInstanceData(ctx context.Context, namespaceId int) (ExperimentInstanceDataInNamespace, error) { - statusMap, total, err := experiment_instance.CountExperimentInstance(namespaceId, 0) - return ExperimentInstanceDataInNamespace{ToTal: total, StatusMap: statusMap}, err -} +func (s *NamespaceService) getUserAndExperimentInstanceData(ctx context.Context, namespaceId int) ([]namespaceModel.UserDataNamespace, int64, int64) { + userTotal, userList, err := namespaceModel.GetUsersFromNamespace(ctx, namespaceId) + if err != nil { + log.Error(err) + } -func (s *NamespaceService) getUserAndExperimentInstanceData(ctx context.Context, users []namespaceModel.NamespaceData, namespaceData *NamespaceData) error { - if users == nil { - return nil + totalExperiment, err := experiment.CountExperiments(namespaceId, -1, 0) + if err != nil { + log.Error(err) } - if namespaceData == nil { - return errors.New("namespaceData is nil") + + return userList, userTotal, totalExperiment +} + +// 全部空间,包括管理员 +func (s *NamespaceService) GroupAllNamespaces(ctx context.Context, userId, queryUserId int, namespaceName string, page, pageSize int) (int64, []NamespaceData, error) { + if userId == 0 { + return 0, nil, errors.New("invalid user id") } - var err error - for _, user := range users { - namespaceData.UserData, err = s.getUserData(ctx, user.Id, namespaceData.NamespaceInfo.ID) - if err != nil { - return err + + var nameSpaceIdList []int + if queryUserId > 0 { + var userIdList = []int{} + if !s.IsGlobalAdmin(ctx, userId) { + userIdList = append(userIdList, userId) } - namespaceData.ExperimentData, err = s.getExperimentInstanceData(ctx, namespaceData.NamespaceInfo.ID) + userIdList = append(userIdList, queryUserId) + _, namespaces, err := namespaceModel.GetNamespacesFromUser(ctx, userIdList, -1, "", 1, 100) if err != nil { - return err + log.Error(err) + return 0, nil, errors.New("can not find namespaces") + } + + for _, namespace := range namespaces { + nameSpaceIdList = append(nameSpaceIdList, namespace.NamespaceId) } } - return err -} -// 未加入 -func (s *NamespaceService) GroupNamespacesUserNotIn(ctx context.Context, userId int, namespaceName string, userName string, orderBy string, page, pageSize int) (int64, []NamespaceData, error) { - total, namesapceList, err := namespaceModel.GroupNamespacesUserNotIn(userId, namespaceName, userName, orderBy, page, pageSize) + var namespaceDataList []NamespaceData + total, namespaceList, err := namespaceModel.ListNamespaces(ctx, nameSpaceIdList, namespaceName, "", "", page, pageSize) if err != nil { - return 0, nil, err + log.Error(err) + return 0, nil, errors.New("can not list namespaces") } - var namespaceDataList []NamespaceData - for _, namespace := range namesapceList { - namespaceData := NamespaceData{NamespaceInfo: namespace} - _, userList, err := namespaceModel.GroupedUserInNamespaces(namespace.ID, "", "", -1, "", 1, 20) - if err != nil { - continue - } - if err := s.getUserAndExperimentInstanceData(ctx, userList, &namespaceData); err == nil { - namespaceDataList = append(namespaceDataList, namespaceData) + + for _, namespace := range namespaceList { + users, userTotal, experimentTotal := s.getUserAndExperimentInstanceData(ctx, namespace.Id) + namespaceData := NamespaceData{ + Permission: s.GetUserPermission(ctx, namespace.Id, userId), + NamespaceInfo: namespace, + Users: users, + UserTotal: userTotal, + ExperimentTotal: experimentTotal, } + + namespaceDataList = append(namespaceDataList, namespaceData) } return total, namespaceDataList, nil } -// 全部 -func (s *NamespaceService) GroupAllNamespaces(ctx context.Context, namespaceName string, userName string, orderBy string, page, pageSize int) (int64, []NamespaceData, error) { - total, namesapceList, err := namespaceModel.GroupAllNamespaces(namespaceName, userName, orderBy, page, pageSize) +// 搜索空间, 不是全局管理员 +func (s *NamespaceService) QueryNamespace(ctx context.Context, userId int, queryUserId int, namespace string, permission int, page, pageSize int) (int64, []NamespaceData, error) { + if userId == 0 { + return 0, nil, errors.New("invalid user id") + } + + var userIdList = []int{userId} + //if !s.IsGlobalAdmin(ctx, userId) { + // userIdList = append(userIdList, userId) + //} + if queryUserId > 0 { + userIdList = append(userIdList, queryUserId) + } + _, namespaces, err := namespaceModel.GetNamespacesFromUser(ctx, userIdList, permission, "", 1, 100) if err != nil { - return 0, nil, err + log.Error(err) + return 0, nil, errors.New("can not find namespaces") } - var namespaceDataList []NamespaceData - for _, namespace := range namesapceList { - namespaceData := NamespaceData{NamespaceInfo: namespace} - var err error - _, userList, err := namespaceModel.GroupedUserInNamespaces(namespace.ID, "", "", -1, "", 1, 20) - if err != nil { - continue - } - if err := s.getUserAndExperimentInstanceData(ctx, userList, &namespaceData); err == nil { - namespaceDataList = append(namespaceDataList, namespaceData) - } + if permission >= 0 && namespaces == nil { + return 0, nil, nil + } + var nameSpaceIdList []int + for _, namespace := range namespaces { + nameSpaceIdList = append(nameSpaceIdList, namespace.NamespaceId) } - return total, namespaceDataList, nil -} -// 已加入 -func (s *NamespaceService) GroupNamespacesByUsername(ctx context.Context, userId int, namespace string, userName string, permission int, orderBy string, page, pageSize int) (int64, []NamespaceData, error) { - total, namesapceList, err := namespaceModel.GroupAllNamespacesByUserName(userId, namespace, userName, permission, orderBy, page, pageSize) + var namespaceDataList []NamespaceData + total, namespaceList, err := namespaceModel.ListNamespaces(ctx, nameSpaceIdList, namespace, "", "", page, pageSize) if err != nil { - return 0, nil, err + log.Error(err) + return 0, nil, errors.New("can not list namespaces") } - var namespaceDataList []NamespaceData - for _, namespace := range namesapceList { - namespaceData := NamespaceData{NamespaceInfo: namespace} - _, userList, err := namespaceModel.GroupedUserInNamespaces(namespace.ID, "", "", -1, "", 1, 20) - if err != nil { - continue - } - if err := s.getUserAndExperimentInstanceData(ctx, userList, &namespaceData); err == nil { - namespaceDataList = append(namespaceDataList, namespaceData) - } + + for _, namespace := range namespaceList { + users, userTotal, experimentTotal := s.getUserAndExperimentInstanceData(ctx, namespace.Id) + namespaceDataList = append(namespaceDataList, NamespaceData{ + Permission: s.GetUserPermission(ctx, namespace.Id, userId), + NamespaceInfo: namespace, + Users: users, + UserTotal: userTotal, + ExperimentTotal: experimentTotal}) } return total, namespaceDataList, nil } @@ -329,22 +334,42 @@ func (s *NamespaceService) IsAdmin(ctx context.Context, namespaceId int, userNam return false } -func (s *NamespaceService) IsUserJoin(ctx context.Context, namespaceId int, userId int) (bool, int) { +func (s *NamespaceService) IsGlobalAdmin(ctx context.Context, userId int) bool { userGet := user.User{ID: userId} if err := user.GetUserById(ctx, &userGet); err != nil { - return false, -1 + return false } if userGet.Role == user.AdminRole { - return true, 1 + return true + } + return false +} + +func (s *NamespaceService) IsUserJoin(ctx context.Context, namespaceId int, userId int) (bool, int) { + permission := s.GetUserPermission(ctx, namespaceId, userId) + if permission < 0 { + return false, -1 + } + return true, permission +} + +func (s *NamespaceService) GetUserPermission(ctx context.Context, namespaceId int, userId int) int { + if s.IsGlobalAdmin(ctx, userId) { + return 1 + } + + userGet := user.User{ID: userId} + if err := user.GetUserById(ctx, &userGet); err != nil { + return -1 } un := namespaceModel.UserNamespace{ NamespaceId: namespaceId, UserId: userGet.ID, } if err := namespaceModel.GetUserNamespace(&un); err != nil { - return false, -1 + return -1 } - return true, int(un.Permission) + return int(un.Permission) } type UserInfoInNamespace struct { diff --git a/chaosmeta-platform/pkg/service/namespace/overview.go b/chaosmeta-platform/pkg/service/namespace/overview.go new file mode 100644 index 0000000..b475a34 --- /dev/null +++ b/chaosmeta-platform/pkg/service/namespace/overview.go @@ -0,0 +1,37 @@ +/* + * Copyright 2022-2023 Chaos Meta Authors. + * + * Licensed 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 namespace + +import ( + "chaosmeta-platform/pkg/models/experiment" + "chaosmeta-platform/pkg/models/experiment_instance" + "context" +) + +func (s *NamespaceService) GetOverview(ctx context.Context, namespaceID int, recentDays int) (int64, int64, int64, error) { + totalExperimentCount, err := experiment.CountExperiments(namespaceID, -1, recentDays) + if err != nil { + return totalExperimentCount, 0, 0, err + } + + totalExperimentInstancesCount, err := experiment_instance.CountExperimentInstances(namespaceID, "", "", recentDays) + if err != nil { + return totalExperimentCount, totalExperimentInstancesCount, 0, err + } + failedExperimentInstancesCount, err := experiment_instance.CountExperimentInstances(namespaceID, "", "Failed", recentDays) + return totalExperimentCount, totalExperimentInstancesCount, failedExperimentInstancesCount, err +} diff --git a/chaosmeta-platform/pkg/service/user/user.go b/chaosmeta-platform/pkg/service/user/user.go index 53b71a5..d96fd93 100644 --- a/chaosmeta-platform/pkg/service/user/user.go +++ b/chaosmeta-platform/pkg/service/user/user.go @@ -52,7 +52,7 @@ func Init() { log.Error(err) return } - _, err = us.Create(ctx, "admin", "admin", string(AdminRole)) + _, err = us.Create(ctx, "admin", "21232f297a57a5a743894a0e4a801fc3", string(AdminRole)) if err != nil { log.Error(err) } @@ -178,7 +178,7 @@ type UserNamespaceData struct { func (a *UserService) getUserNamespaceList(ctx context.Context, userId int, permission int, orderBy string, page, pageSize int) (int64, []UserNamespaceData, error) { var userNamespaceDatas []UserNamespaceData - total, namespaces, err := namespace2.GetNamespacesFromUser(ctx, userId, permission, orderBy, page, pageSize) + total, namespaces, err := namespace2.GetNamespacesFromUser(ctx, []int{userId}, permission, orderBy, page, pageSize) if err != nil { return 0, nil, err } diff --git a/chaosmeta-platform/quick-start/platform/configmap.yaml b/chaosmeta-platform/quick-start/platform/configmap.yaml index 838edcc..efb4139 100644 --- a/chaosmeta-platform/quick-start/platform/configmap.yaml +++ b/chaosmeta-platform/quick-start/platform/configmap.yaml @@ -14,6 +14,8 @@ data: copyrequestbody = true app.yaml: |- secretkey: chaosmeta1234567 + argoWorkflowNamespace: default + workflowNamespace: chaosmeta-inject db: name: chaosmeta user: root @@ -23,4 +25,5 @@ data: maxconn: 30 log: path: ./chaosmeta-platform.log - level: info \ No newline at end of file + level: info + runmode: ServiceAccount \ No newline at end of file diff --git a/chaosmeta-platform/quick-start/platform/deployment.yaml b/chaosmeta-platform/quick-start/platform/deployment.yaml index 11ad818..c98d86a 100644 --- a/chaosmeta-platform/quick-start/platform/deployment.yaml +++ b/chaosmeta-platform/quick-start/platform/deployment.yaml @@ -20,7 +20,7 @@ spec: containers: - name: chaosmeta-platform imagePullPolicy: Always - image: registry.cn-hangzhou.aliyuncs.com/chaosmeta/chaosmeta-platform:v0.0.2 + image: registry.cn-hangzhou.aliyuncs.com/chaosmeta/chaosmeta-platform:v0.0.3 resources: requests: cpu: "1" @@ -31,6 +31,11 @@ spec: volumeMounts: - name: chaosmeta-config mountPath: /home/admin/conf + - name: chaosmeta-platform-frontend + imagePullPolicy: Always + image: registry.cn-hangzhou.aliyuncs.com/chaosmeta/chaosmeta-platform-frontend:v0.0.1 + ports: + - containerPort: 8000 volumes: - name: chaosmeta-config configMap: diff --git a/chaosmeta-platform/quick-start/platform/rbac.yaml b/chaosmeta-platform/quick-start/platform/rbac.yaml index 2e15944..deb4a90 100644 --- a/chaosmeta-platform/quick-start/platform/rbac.yaml +++ b/chaosmeta-platform/quick-start/platform/rbac.yaml @@ -9,22 +9,16 @@ kind: ClusterRole metadata: name: chaosmeta-platform rules: - - apiGroups: ["apps", "batch", "", "extensions", "networking.k8s.io", "rbac.authorization.k8s.io", "apiextensions.k8s.io"] - resources: ["nodes", "pods", "services", "deployments", "jobs", "ingresses", "configmaps", - "pods/exec", "replicasets", "statefulsets", "namespaces", "pods/log", "events", "serviceaccounts", - "secrets", "clusterroles", "clusterrolebindings", "customresourcedefinitions", "pods/ephemeralcontainers", - "daemonsets"] - verbs: ["*"] - - apiGroups: ["inject.chaosmeta.io"] + - apiGroups: ["*"] resources: ["*"] - verbs: ["*"] - - apiGroups: [""] - resources: ["events"] verbs: - - create - - update - - patch - - apiGroups: ["monitoring.coreos.com"] + - get + - list + - watch + - apiGroups: ["argoproj.io"] + resources: ["*"] + verbs: ["*"] + - apiGroups: ["chaosmeta.io"] resources: ["*"] verbs: ["*"] - apiGroups: ["coordination.k8s.io"] diff --git a/chaosmeta-platform/quick-start/platform/service.yaml b/chaosmeta-platform/quick-start/platform/service.yaml index b5c98f1..b63dabb 100644 --- a/chaosmeta-platform/quick-start/platform/service.yaml +++ b/chaosmeta-platform/quick-start/platform/service.yaml @@ -25,8 +25,8 @@ metadata: spec: ports: - name: http - port: 7001 - targetPort: 7001 + port: 81 + targetPort: 8001 selector: app: chaosmeta-platform sessionAffinity: None diff --git a/chaosmeta-platform/quick-start/quick-start.yaml b/chaosmeta-platform/quick-start/quick-start.yaml index 20ce72f..f88d0b3 100644 --- a/chaosmeta-platform/quick-start/quick-start.yaml +++ b/chaosmeta-platform/quick-start/quick-start.yaml @@ -14,6 +14,8 @@ data: copyrequestbody = true app.yaml: |- secretkey: chaosmeta1234567 + argoWorkflowNamespace: default + workflowNamespace: chaosmeta-inject db: name: chaosmeta user: root @@ -24,7 +26,7 @@ data: log: path: ./chaosmeta-platform.log level: info - + runmode: ServiceAccount --- apiVersion: v1 kind: ServiceAccount @@ -37,22 +39,16 @@ kind: ClusterRole metadata: name: chaosmeta-platform rules: - - apiGroups: ["apps", "batch", "", "extensions", "networking.k8s.io", "rbac.authorization.k8s.io", "apiextensions.k8s.io"] - resources: ["nodes", "pods", "services", "deployments", "jobs", "ingresses", "configmaps", - "pods/exec", "replicasets", "statefulsets", "namespaces", "pods/log", "events", "serviceaccounts", - "secrets", "clusterroles", "clusterrolebindings", "customresourcedefinitions", "pods/ephemeralcontainers", - "daemonsets"] - verbs: ["*"] - - apiGroups: ["inject.chaosmeta.io"] + - apiGroups: ["*"] resources: ["*"] - verbs: ["*"] - - apiGroups: [""] - resources: ["events"] verbs: - - create - - update - - patch - - apiGroups: ["monitoring.coreos.com"] + - get + - list + - watch + - apiGroups: ["argoproj.io"] + resources: ["*"] + verbs: ["*"] + - apiGroups: ["chaosmeta.io"] resources: ["*"] verbs: ["*"] - apiGroups: ["coordination.k8s.io"] @@ -168,7 +164,7 @@ spec: containers: - name: chaosmeta-platform imagePullPolicy: Always - image: registry.cn-hangzhou.aliyuncs.com/chaosmeta/chaosmeta-platform:v0.0.2 + image: registry.cn-hangzhou.aliyuncs.com/chaosmeta/chaosmeta-platform:v0.0.3 resources: requests: cpu: "1" @@ -179,6 +175,11 @@ spec: volumeMounts: - name: chaosmeta-config mountPath: /home/admin/conf + - name: chaosmeta-platform-frontend + imagePullPolicy: Always + image: registry.cn-hangzhou.aliyuncs.com/chaosmeta/chaosmeta-platform-frontend:v0.0.1 + ports: + - containerPort: 8000 volumes: - name: chaosmeta-config configMap: @@ -191,23 +192,6 @@ spec: --- apiVersion: v1 kind: Service -metadata: - labels: - app: chaosmeta-platform-mysql - name: chaosmeta-platform-mysql - namespace: chaosmeta-platform -spec: - ports: - - port: 3306 - protocol: TCP - targetPort: 3306 - selector: - app: chaosmeta-platform-mysql - sessionAffinity: None - type: ClusterIP ---- -apiVersion: v1 -kind: Service metadata: labels: app: chaosmeta-platform @@ -216,8 +200,8 @@ metadata: spec: ports: - name: http - port: 7001 - targetPort: 7001 + port: 8000 + targetPort: 8000 selector: app: chaosmeta-platform sessionAffinity: None diff --git a/chaosmeta-platform/routers/namespace.go b/chaosmeta-platform/routers/namespace.go index 8aaac85..a23d578 100644 --- a/chaosmeta-platform/routers/namespace.go +++ b/chaosmeta-platform/routers/namespace.go @@ -24,6 +24,8 @@ import ( func nameSpaceInit() { beego.Router(NewWebServicePath("namespaces"), &namespace.NamespaceController{}, "post:Create") beego.Router(NewWebServicePath("namespaces/:id"), &namespace.NamespaceController{}, "get:Get") + beego.Router(NewWebServicePath("namespaces/:id/permission"), &namespace.NamespaceController{}, "get:GetPermission") + beego.Router(NewWebServicePath("namespaces/:id/overview"), &namespace.NamespaceController{}, "get:GetOverview") beego.Router(NewWebServicePath("namespaces/list"), &namespace.NamespaceController{}, "get:GetList") beego.Router(NewWebServicePath("namespaces/query"), &namespace.NamespaceController{}, "get:QueryList") beego.Router(NewWebServicePath("namespaces/:id"), &namespace.NamespaceController{}, "post:Update") From 530c22693de1a131ce7a595d7d54489a50a731cf Mon Sep 17 00:00:00 2001 From: samson <845534486@qq.com> Date: Wed, 30 Aug 2023 23:03:52 +0800 Subject: [PATCH 2/2] fix bug --- .../pkg/service/experiment/chaosmeta_inject.go | 6 ++++-- .../pkg/service/experiment/experiment_flow.go | 2 +- chaosmeta-platform/pkg/service/experiment/routine.go | 3 ++- chaosmeta-platform/quick-start/platform/rbac.yaml | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/chaosmeta-platform/pkg/service/experiment/chaosmeta_inject.go b/chaosmeta-platform/pkg/service/experiment/chaosmeta_inject.go index 541206e..b1cba9c 100644 --- a/chaosmeta-platform/pkg/service/experiment/chaosmeta_inject.go +++ b/chaosmeta-platform/pkg/service/experiment/chaosmeta_inject.go @@ -161,12 +161,14 @@ func (c *ChaosmetaService) Update(ctx context.Context, chaosmeta *ExperimentInje return nil, err } - utd, err := c.Client.Resource(gvr).Get(ctx, obj.GetName(), v1.GetOptions{}) + utd, err := c.Client.Resource(gvr).Namespace(obj.GetNamespace()).Get(ctx, obj.GetName(), v1.GetOptions{}) if err != nil { + log.Error(err) return nil, err } + obj.SetResourceVersion(utd.GetResourceVersion()) - utd, err = c.Client.Resource(gvr).Update(ctx, obj, v1.UpdateOptions{}) + utd, err = c.Client.Resource(gvr).Namespace(obj.GetNamespace()).Update(ctx, obj, v1.UpdateOptions{}) if err != nil { return nil, err } diff --git a/chaosmeta-platform/pkg/service/experiment/experiment_flow.go b/chaosmeta-platform/pkg/service/experiment/experiment_flow.go index 675d0bd..c34f6da 100644 --- a/chaosmeta-platform/pkg/service/experiment/experiment_flow.go +++ b/chaosmeta-platform/pkg/service/experiment/experiment_flow.go @@ -322,7 +322,7 @@ func getExperimentInstanceIdFromWorkflowName(workflowName string) (string, error } func getExperimentUUIDAndNodeIDFromStepName(name string) (string, string, error) { - log.Error("ExperimentUUIDAndNodeIDFromStepName:", name) + log.Info("ExperimentUUIDAndNodeIDFromStepName:", name) var reg *regexp.Regexp var match []string diff --git a/chaosmeta-platform/pkg/service/experiment/routine.go b/chaosmeta-platform/pkg/service/experiment/routine.go index c89a176..db6138a 100644 --- a/chaosmeta-platform/pkg/service/experiment/routine.go +++ b/chaosmeta-platform/pkg/service/experiment/routine.go @@ -174,8 +174,9 @@ func StopExperiment(experimentInstanceID string) error { log.Error(err) return err } - chaosmetaCR.Status.Phase = "recover" + chaosmetaCR.Spec.TargetPhase = "recover" if _, err := chaosmetaService.Update(context.Background(), chaosmetaCR); err != nil { + log.Error(err) return err } _, nodeId, err := getExperimentUUIDAndNodeIDFromStepName(node.DisplayName) diff --git a/chaosmeta-platform/quick-start/platform/rbac.yaml b/chaosmeta-platform/quick-start/platform/rbac.yaml index deb4a90..afaa226 100644 --- a/chaosmeta-platform/quick-start/platform/rbac.yaml +++ b/chaosmeta-platform/quick-start/platform/rbac.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ServiceAccount metadata: name: chaosmeta-platform - namespace: default + namespace: chaosmeta --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole