Skip to content

Commit

Permalink
Protected namespaces (chaos-mesh#661)
Browse files Browse the repository at this point in the history
Signed-off-by: Gallardot <tttick@163.com>
  • Loading branch information
Gallardot committed Jun 30, 2020
1 parent 86d50c5 commit 153a2c4
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 45 deletions.
2 changes: 2 additions & 0 deletions helm/chaos-mesh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ The following tables list the configurable parameters of the Chaos Mesh chart an
| `controllerManager.tolerations` | Toleration labels for chaos-controller-manager pod assignment | `[]` |
| `controllerManager.affinity` | Map of chaos-controller-manager node/pod affinities | `{}` |
| `controllerManager.podAnnotations` | Pod annotations of chaos-controller-manager | `{}`|
| `controllerManager.allowedNamespaces` | A regular expression, and matching namespace will allow the chaos task to be performed | ``|
| `controllerManager.ignoredNamespaces` | A regular expression, and the chaos task will be ignored by a matching namespace. Configuring `allowedNamespaces` at the same time will ignore this configuration. | ``|
| `chaosDaemon.image` | docker image for chaos-daemon | `pingcap/chaos-mesh:latest` |
| `chaosDaemon.imagePullPolicy` | image pull policy | `Always` |
| `chaosDaemon.grpcPort` | The port which grpc server listens on | `31767` |
Expand Down
8 changes: 8 additions & 0 deletions helm/chaos-mesh/templates/controller-manager-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ spec:
value: "app.kubernetes.io/component:template"
- name: CONFIGMAP_LABELS
value: "app.kubernetes.io/component:webhook"
{{- if .Values.controllerManager.allowedNamespaces }}
- name: ALLOWED_NAMESPACES
value: {{ .Values.controllerManager.allowedNamespaces }}
{{- end }}
{{- if .Values.controllerManager.ignoredNamespaces }}
- name: IGNORED_NAMESPACES
value: {{ .Values.controllerManager.ignoredNamespaces }}
{{- end }}
{{- if .Values.enableProfiling }}
- name: PPROF_ADDR
value: ":10081"
Expand Down
3 changes: 3 additions & 0 deletions helm/chaos-mesh/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ controllerManager:
nameOverride: ""
fullnameOverride: ""

allowedNamespaces: ""
ignoredNamespaces: ""

service:
type: ClusterIP

Expand Down
4 changes: 4 additions & 0 deletions pkg/config/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ type ChaosControllerConfig struct {
EnableLeaderElection bool `envconfig:"ENABLE_LEADER_ELECTION" default:"false"`
// CertsDir is the directory for storing certs key file and cert file
CertsDir string `envconfig:"CERTS_DIR" default:"/etc/webhook/certs"`
// AllowedNamespaces is a regular expression, and matching namespace will allow the chaos task to be performed
AllowedNamespaces string `envconfig:"ALLOWED_NAMESPACES" default:""`
// AllowedNamespaces is a regular expression, and the chaos task will be ignored by a matching namespace
IgnoredNamespaces string `envconfig:"IGNORED_NAMESPACES" default:""`
// RPCTimeout is timeout of RPC between controllers and chaos-operator
RPCTimeout time.Duration `envconfig:"RPC_TIMEOUT" default:"1m"`
WatcherConfig *watcher.Config
Expand Down
39 changes: 0 additions & 39 deletions pkg/utils/consts.go

This file was deleted.

50 changes: 46 additions & 4 deletions pkg/utils/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import (
"fmt"
"math"
"math/rand"
"regexp"
"strconv"
"strings"

"github.com/pingcap/chaos-mesh/api/v1alpha1"
"github.com/pingcap/chaos-mesh/controllers/common"
"github.com/pingcap/chaos-mesh/pkg/label"
"github.com/pingcap/chaos-mesh/pkg/mock"

Expand Down Expand Up @@ -82,6 +84,9 @@ func SelectPods(ctx context.Context, c client.Client, selector v1alpha1.Selector
// pods are specifically specified
if len(selector.Pods) > 0 {
for ns, names := range selector.Pods {
if !IsAllowedNamespaces(ns) {
log.Info("filter pod by namespaces", "namespace", ns)
}
for _, name := range names {
var pod v1.Pod
err := c.Get(ctx, types.NamespacedName{
Expand Down Expand Up @@ -120,11 +125,13 @@ func SelectPods(ctx context.Context, c client.Client, selector v1alpha1.Selector

pods = append(pods, podList.Items...)

pods = filterByNamespaces(pods)

namespaceSelector, err := parseSelector(strings.Join(selector.Namespaces, ","))
if err != nil {
return nil, err
}
pods, err = filterByNamespaces(pods, namespaceSelector)
pods, err = filterByNamespaceSelector(pods, namespaceSelector)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -193,7 +200,7 @@ func CheckPodMeetSelector(pod v1.Pod, selector v1alpha1.SelectorSpec) (bool, err
return false, err
}

pods, err = filterByNamespaces(pods, namespaceSelector)
pods, err = filterByNamespaceSelector(pods, namespaceSelector)
if err != nil {
return false, err
}
Expand Down Expand Up @@ -365,8 +372,43 @@ func filterByPhaseSelector(pods []v1.Pod, phases labels.Selector) ([]v1.Pod, err
return filteredList, nil
}

// filterByNamespaces filters a list of pods by a given namespace selector.
func filterByNamespaces(pods []v1.Pod, namespaces labels.Selector) ([]v1.Pod, error) {
func filterByNamespaces(pods []v1.Pod) []v1.Pod {
var filteredList []v1.Pod

for _, pod := range pods {
if IsAllowedNamespaces(pod.Namespace) {
filteredList = append(filteredList, pod)
} else {
log.Info("filter pod by namespaces",
"pod", pod.Name, "namespace", pod.Namespace)
}
}
return filteredList
}

// IsAllowedNamespaces returns whether namespace allows the execution of a chaos task
func IsAllowedNamespaces(namespace string) bool {
if common.ControllerCfg.AllowedNamespaces != "" {
matched, err := regexp.MatchString(common.ControllerCfg.AllowedNamespaces, namespace)
if err != nil {
return false
}
return matched
}

if common.ControllerCfg.IgnoredNamespaces != "" {
matched, err := regexp.MatchString(common.ControllerCfg.IgnoredNamespaces, namespace)
if err != nil {
return false
}
return !matched
}

return true
}

// filterByNamespaceSelector filters a list of pods by a given namespace selector.
func filterByNamespaceSelector(pods []v1.Pod, namespaces labels.Selector) ([]v1.Pod, error) {
// empty filter returns original list
if namespaces.Empty() {
return pods, nil
Expand Down
67 changes: 65 additions & 2 deletions pkg/utils/selector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
. "github.com/onsi/gomega"

"github.com/pingcap/chaos-mesh/api/v1alpha1"
"github.com/pingcap/chaos-mesh/controllers/common"
"github.com/pingcap/chaos-mesh/pkg/label"

v1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -405,7 +406,69 @@ func TestFilterByAnnotations(t *testing.T) {
}
}

func TestFilterNamespace(t *testing.T) {
func TestIsAllowedNamespaces(t *testing.T) {
g := NewGomegaWithT(t)
type TestCase struct {
name string
pods []v1.Pod
ret []bool
allow string
ignore string
}
pods := []v1.Pod{
newPod("p1", v1.PodRunning, "allow", nil, nil),
newPod("p1", v1.PodRunning, "allow-app", nil, nil),
newPod("p1", v1.PodRunning, "app-allow", nil, nil),
newPod("p1", v1.PodRunning, "ignore", nil, nil),
newPod("p1", v1.PodRunning, "ignore-app", nil, nil),
newPod("p1", v1.PodRunning, "app-ignore", nil, nil),
}

allowRet := []bool{true, true, true, false, false, false}

var tcs []TestCase
tcs = append(tcs, TestCase{
name: "only set allow",
pods: pods,
ret: allowRet,
allow: "allow",
})

tcs = append(tcs, TestCase{
name: "only set ignore",
pods: pods,
ret: allowRet,
ignore: "ignore",
})

tcs = append(tcs, TestCase{
name: "only set allow",
pods: pods,
ret: allowRet,
allow: "allow",
ignore: "ignore",
})

setRule := func(allow string, ignore string) {
common.ControllerCfg.AllowedNamespaces = allow
common.ControllerCfg.IgnoredNamespaces = ignore
}

clean := func() {
common.ControllerCfg.AllowedNamespaces = ""
common.ControllerCfg.IgnoredNamespaces = ""
}

for _, tc := range tcs {
setRule(tc.allow, tc.ignore)
for index, pod := range tc.pods {
g.Expect(IsAllowedNamespaces(pod.Namespace)).Should(Equal(tc.ret[index]))
}
clean()
}
}

func TestFilterNamespaceSelector(t *testing.T) {
g := NewGomegaWithT(t)

type TestCase struct {
Expand Down Expand Up @@ -470,7 +533,7 @@ func TestFilterNamespace(t *testing.T) {
})

for _, tc := range tcs {
g.Expect(filterByNamespaces(tc.pods, tc.filterSelector)).To(Equal(tc.filteredPods), tc.name)
g.Expect(filterByNamespaceSelector(tc.pods, tc.filterSelector)).To(Equal(tc.filteredPods), tc.name)
}
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/webhook/inject/inject.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ func injectRequired(metadata *metav1.ObjectMeta, cli client.Client, cfg *config.
return "", false
}
}
if !utils.IsAllowedNamespaces(metadata.Namespace) {
log.Info("Skip mutation for it' in special namespace", "name", metadata.Name, "namespace", metadata.Namespace)
return "", false
}

log.V(4).Info("meta", "meta", metadata)

Expand Down

0 comments on commit 153a2c4

Please sign in to comment.