Skip to content

Commit

Permalink
support experiment deletion (chaos-mesh#524)
Browse files Browse the repository at this point in the history
Signed-off-by: yeya24 <[email protected]>
  • Loading branch information
yeya24 authored May 22, 2020
1 parent 19eecf4 commit 15ceb64
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 40 deletions.
12 changes: 0 additions & 12 deletions api/v1alpha1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,6 @@ import (
const (
// PauseAnnotationKey defines the annotation used to pause a chaos
PauseAnnotationKey = "experiment.pingcap.com/pause"
// KindPodChaos is the kind for pod chaos
KindPodChaos = "PodChaos"
// KindNetworkChaos is the kind for network chaos
KindNetworkChaos = "NetworkChaos"
// KindIOChaos is the kind for io chaos
KindIOChaos = "IoChaos"
// KindKernelChaos is the kind for kernel chaos
KindKernelChaos = "KernelChaos"
// KindStressChaos is the kind for stress chaos
KindStressChaos = "StressChaos"
// KindTimeChaos is the kind for time chaos
KindTimeChaos = "TimeChaos"
)

// SelectorSpec defines the some selectors to select objects.
Expand Down
51 changes: 51 additions & 0 deletions api/v1alpha1/kinds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2020 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha1

import "k8s.io/apimachinery/pkg/runtime"

const (
// KindPodChaos is the kind for pod chaos
KindPodChaos = "PodChaos"
// KindNetworkChaos is the kind for network chaos
KindNetworkChaos = "NetworkChaos"
// KindIOChaos is the kind for io chaos
KindIOChaos = "IoChaos"
// KindKernelChaos is the kind for kernel chaos
KindKernelChaos = "KernelChaos"
// KindStressChaos is the kind for stress chaos
KindStressChaos = "StressChaos"
// KindTimeChaos is the kind for time chaos
KindTimeChaos = "TimeChaos"
)

var (
// Kinds is a collection to keep chaos kind name and its type
Kinds = map[string]*ChaosKind{
KindPodChaos: {Chaos: &PodChaos{}, ChaosList: &PodChaosList{}},
KindNetworkChaos: {Chaos: &NetworkChaos{}, ChaosList: &NetworkChaosList{}},
KindIOChaos: {Chaos: &IoChaos{}, ChaosList: &IoChaosList{}},
KindKernelChaos: {Chaos: &KernelChaos{}, ChaosList: &KernelChaosList{}},
KindTimeChaos: {Chaos: &TimeChaos{}, ChaosList: &TimeChaosList{}},
KindStressChaos: {Chaos: &StressChaos{}, ChaosList: &StressChaosList{}},
}
)

// +kubebuilder:object:generate=false

// ChaosKind includes one kind of chaos and its list type
type ChaosKind struct {
Chaos runtime.Object
ChaosList
}
62 changes: 61 additions & 1 deletion doc/docs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2020-05-21 16:20:50.668813 -0400 EDT m=+0.531426849
// 2020-05-22 09:37:02.78346 -0400 EDT m=+0.535775997

package docs

Expand Down Expand Up @@ -255,6 +255,66 @@ var doc = `{
}
}
}
},
"/api/experiments/{kind}/{namespace}/{name}": {
"delete": {
"description": "Delete the specified chaos experiment.",
"produces": [
"application/json"
],
"tags": [
"experiments"
],
"summary": "Delete the specified chaos experiment.",
"parameters": [
{
"type": "string",
"description": "namespace",
"name": "namespace",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name",
"name": "name",
"in": "path",
"required": true
},
{
"enum": [
"PodChaos",
"IoChaos",
"NetworkChaos",
"TimeChaos",
"KernelChaos",
"StressChaos"
],
"type": "string",
"description": "kind",
"name": "kind",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "delete ok"
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/utils.APIError"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/utils.APIError"
}
}
}
}
}
},
"definitions": {
Expand Down
91 changes: 64 additions & 27 deletions pkg/apiserver/experiment/experiment.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,12 @@ import (
"github.com/pingcap/chaos-mesh/pkg/config"
"github.com/pingcap/chaos-mesh/pkg/core"

apierrors "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var log = ctrl.Log.WithName("experiment api")

var (
// TODO(yeya24): don't hardcode this if it is possible
kinds = map[string]v1alpha1.ChaosList{
v1alpha1.KindPodChaos: &v1alpha1.PodChaosList{},
v1alpha1.KindNetworkChaos: &v1alpha1.NetworkChaosList{},
v1alpha1.KindStressChaos: &v1alpha1.StressChaosList{},
v1alpha1.KindIOChaos: &v1alpha1.IoChaosList{},
v1alpha1.KindKernelChaos: &v1alpha1.KernelChaosList{},
v1alpha1.KindTimeChaos: &v1alpha1.TimeChaosList{},
}
)

// Experiment defines the basic information of an experiment
type Experiment struct {
Name string `json:"name"`
Expand Down Expand Up @@ -94,17 +81,11 @@ func Register(r *gin.RouterGroup, s *Service) {
// TODO: add more api handlers
endpoint.GET("", s.listExperiments)
endpoint.POST("/new", s.createExperiment)
endpoint.DELETE("/detail/:ns/:name", s.deleteExperiment)
endpoint.GET("/delete/:ns/:name", s.getExperimentDetail)
endpoint.GET("/detail/:namespace/:name", s.getExperimentDetail)
endpoint.DELETE("/:kind/:namespace/:name", s.deleteExperiment)
endpoint.GET("/state", s.state)
}

// TODO: need to be implemented
func (s *Service) getExperimentDetail(c *gin.Context) {}

// TODO: need to be implemented
func (s *Service) deleteExperiment(c *gin.Context) {}

// ExperimentInfo defines a form data of Experiment from API.
type ExperimentInfo struct {
Name string `json:"name" binding:"required,NameValid"`
Expand Down Expand Up @@ -490,11 +471,11 @@ func (s *Service) listExperiments(c *gin.Context) {
status := c.Query("status")

data := make([]*Experiment, 0)
for key, list := range kinds {
for key, list := range v1alpha1.Kinds {
if kind != "" && key != kind {
continue
}
if err := s.kubeCli.List(context.Background(), list, &client.ListOptions{Namespace: ns}); err != nil {
if err := s.kubeCli.List(context.Background(), list.ChaosList, &client.ListOptions{Namespace: ns}); err != nil {
c.Status(http.StatusInternalServerError)
_ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err))
return
Expand All @@ -519,6 +500,62 @@ func (s *Service) listExperiments(c *gin.Context) {
c.JSON(http.StatusOK, data)
}

// TODO: need to be implemented
func (s *Service) getExperimentDetail(c *gin.Context) {}

// @Summary Delete the specified chaos experiment.
// @Description Delete the specified chaos experiment.
// @Tags experiments
// @Produce json
// @Param namespace path string true "namespace"
// @Param name path string true "name"
// @Param kind path string true "kind" Enums(PodChaos, IoChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos)
// @Success 200 "delete ok"
// @Router /api/experiments/{kind}/{namespace}/{name} [delete]
// @Failure 400 {object} utils.APIError
// @Failure 500 {object} utils.APIError
func (s *Service) deleteExperiment(c *gin.Context) {
kind := c.Param("kind")
ns := c.Param("namespace")
name := c.Param("name")

ctx := context.TODO()
chaosKey := types.NamespacedName{Namespace: ns, Name: name}

var (
chaosKind *v1alpha1.ChaosKind
ok bool
)
if chaosKind, ok = v1alpha1.Kinds[kind]; !ok {
c.Status(http.StatusBadRequest)
_ = c.Error(utils.ErrInvalidRequest.New(kind + " is not supported"))
return
}
if err := s.kubeCli.Get(ctx, chaosKey, chaosKind.Chaos); err != nil {
if apierrors.IsNotFound(err) {
c.Status(http.StatusNotFound)
_ = c.Error(utils.ErrNotFound.NewWithNoMessage())
} else {
c.Status(http.StatusInternalServerError)
_ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err))
}
return
}

if err := s.kubeCli.Delete(ctx, chaosKind.Chaos, &client.DeleteOptions{}); err != nil {
if apierrors.IsNotFound(err) {
c.Status(http.StatusNotFound)
_ = c.Error(utils.ErrNotFound.NewWithNoMessage())
} else {
c.Status(http.StatusInternalServerError)
_ = c.Error(utils.ErrInternalServer.WrapWithNoMessage(err))
}
return
}

c.JSON(http.StatusOK, nil)
}

// @Summary Get chaos experiments state from Kubernetes cluster.
// @Description Get chaos experiments state from Kubernetes cluster.
// @Tags experiments
Expand All @@ -531,8 +568,8 @@ func (s *Service) state(c *gin.Context) {

g, ctx := errgroup.WithContext(context.Background())
m := &sync.Mutex{}
for index := range kinds {
list := kinds[index]
for index := range v1alpha1.Kinds {
list := v1alpha1.Kinds[index].ChaosList
g.Go(func() error {
if err := s.kubeCli.List(ctx, list); err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions pkg/apiserver/utils/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
ErrOther = ErrNS.NewType("other")
ErrInvalidRequest = ErrNS.NewType("invalid_request")
ErrInternalServer = ErrNS.NewType("internal_server_error")
ErrNotFound = ErrNS.NewType("resource_not_found")
)

type APIError struct {
Expand Down

0 comments on commit 15ceb64

Please sign in to comment.