mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
Merge branch 'master' into v1.1.0
This commit is contained in:
commit
10fc1b47ba
28 changed files with 181 additions and 54 deletions
|
@ -28,7 +28,7 @@ This policy requires that all pods have CPU and memory resource requests and lim
|
|||
|
||||
````yaml
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: Policy
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: check-cpu-memory
|
||||
spec:
|
||||
|
@ -62,7 +62,7 @@ This policy sets the imagePullPolicy to Always if the image tag is latest:
|
|||
|
||||
````yaml
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: Policy
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: set-image-pull-policy
|
||||
spec:
|
||||
|
@ -90,7 +90,7 @@ This policy sets the Zookeeper and Kafka connection strings for all namespaces w
|
|||
|
||||
````yaml
|
||||
apiVersion: kyverno.io/v1
|
||||
kind: Policy
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: "zk-kafka-address"
|
||||
spec:
|
||||
|
|
|
@ -447,7 +447,7 @@ spec:
|
|||
image: nirmata/kyvernopre:latest
|
||||
containers:
|
||||
- name: kyverno
|
||||
image: nirmata/kyverno:latest
|
||||
image: nirmata/kyverno:v1.0.0
|
||||
args:
|
||||
- "--filterK8Resources=[Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][*,kyverno,*]"
|
||||
# customize webhook timout
|
||||
|
|
|
@ -26,7 +26,7 @@ func Mutate(policyContext PolicyContext) (response EngineResponse) {
|
|||
defer func() {
|
||||
response.PolicyResponse.ProcessingTime = time.Since(startTime)
|
||||
glog.V(4).Infof("finished applying mutation rules policy %v (%v)", policy.Name, response.PolicyResponse.ProcessingTime)
|
||||
glog.V(4).Infof("Mutation Rules appplied succesfully count %v for policy %q", response.PolicyResponse.RulesAppliedCount, policy.Name)
|
||||
glog.V(4).Infof("Mutation Rules appplied count %v for policy %q", response.PolicyResponse.RulesAppliedCount, policy.Name)
|
||||
}()
|
||||
incrementAppliedRuleCount := func() {
|
||||
// rules applied succesfully count
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
@ -31,12 +32,17 @@ func processOverlay(rule kyverno.Rule, resource unstructured.Unstructured) (resp
|
|||
// resource does not satisfy the overlay pattern, we don't apply this rule
|
||||
if !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||
switch overlayerr.statusCode {
|
||||
// condition key is not present in the resource, don't apply this rule
|
||||
// consider as success
|
||||
case conditionNotPresent:
|
||||
glog.V(3).Infof("Skip applying rule '%s' on resource '%s/%s/%s': %s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
|
||||
response.Success = true
|
||||
return response, resource
|
||||
// conditions are not met, don't apply this rule
|
||||
// consider as failure
|
||||
case conditionFailure:
|
||||
glog.Errorf("Resource %s/%s/%s does not meet the conditions in the rule %s with overlay pattern %s", resource.GetKind(), resource.GetNamespace(), resource.GetName(), rule.Name, rule.Mutation.Overlay)
|
||||
glog.V(3).Infof("Skip applying rule '%s' on resource '%s/%s/%s': %s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName(), overlayerr.ErrorMsg())
|
||||
//TODO: send zero response and not consider this as applied?
|
||||
response.Success = false
|
||||
response.Success = true
|
||||
response.Message = overlayerr.ErrorMsg()
|
||||
return response, resource
|
||||
// rule application failed
|
||||
|
@ -71,7 +77,7 @@ func processOverlay(rule kyverno.Rule, resource unstructured.Unstructured) (resp
|
|||
patchResource, err = ApplyPatches(resourceRaw, patches)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failed to apply JSON patches: %v", err)
|
||||
glog.V(2).Info(msg)
|
||||
glog.V(2).Infof("%s, patches=%s", msg, string(JoinPatches(patches)))
|
||||
response.Success = false
|
||||
response.Message = msg
|
||||
return response, resource
|
||||
|
@ -95,10 +101,16 @@ func processOverlay(rule kyverno.Rule, resource unstructured.Unstructured) (resp
|
|||
|
||||
func processOverlayPatches(resource, overlay interface{}) ([][]byte, overlayError) {
|
||||
if path, overlayerr := meetConditions(resource, overlay); !reflect.DeepEqual(overlayerr, overlayError{}) {
|
||||
if overlayerr.statusCode == conditionFailure {
|
||||
switch overlayerr.statusCode {
|
||||
// anchor key does not exist in the resource, skip applying policy
|
||||
case conditionNotPresent:
|
||||
glog.V(4).Infof("Mutate rule: skip applying policy: %v at %s", overlayerr, path)
|
||||
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, condition tag not present: %v at %s", overlayerr.ErrorMsg(), path))
|
||||
// anchor key is not satisfied in the resource, skip applying policy
|
||||
case conditionFailure:
|
||||
// anchor key is not satisfied in the resource, skip applying policy
|
||||
glog.V(4).Infof("Mutate rule: failed to validate condition at %s, err: %v", path, overlayerr)
|
||||
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Conditions are not met at %s, %v", path, overlayerr))
|
||||
return nil, newOverlayError(overlayerr.statusCode, fmt.Sprintf("Policy not applied, conditions are not met at %s, %v", path, overlayerr))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,10 +345,7 @@ func processSubtree(overlay interface{}, path string, op string) ([]byte, error)
|
|||
path = path[:len(path)-1]
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
path = "/"
|
||||
}
|
||||
|
||||
path = preparePath(path)
|
||||
value := prepareJSONValue(overlay)
|
||||
patchStr := fmt.Sprintf(`{ "op": "%s", "path": "%s", "value": %s }`, op, path, value)
|
||||
|
||||
|
@ -350,6 +359,20 @@ func processSubtree(overlay interface{}, path string, op string) ([]byte, error)
|
|||
return []byte(patchStr), nil
|
||||
}
|
||||
|
||||
func preparePath(path string) string {
|
||||
if path == "" {
|
||||
path = "/"
|
||||
}
|
||||
|
||||
annPath := "/metadata/annotations/"
|
||||
// escape slash in annotation patch
|
||||
if strings.Contains(path, annPath) {
|
||||
p := path[len(annPath):]
|
||||
path = annPath + strings.ReplaceAll(p, "/", "~1")
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// converts overlay to JSON string to be inserted into the JSON Patch
|
||||
func prepareJSONValue(overlay interface{}) string {
|
||||
var err error
|
||||
|
|
|
@ -98,7 +98,7 @@ func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, pat
|
|||
}
|
||||
} else {
|
||||
// noAnchorKey doesn't exist in resource
|
||||
continue
|
||||
return curPath, newOverlayError(conditionNotPresent, fmt.Sprintf("resource field is not present %s", noAnchorKey))
|
||||
}
|
||||
}
|
||||
return "", overlayError{}
|
||||
|
@ -110,8 +110,8 @@ func validateConditionAnchorMap(resourceMap, anchors map[string]interface{}, pat
|
|||
// resource - A: B2
|
||||
func compareOverlay(resource, overlay interface{}, path string) (string, overlayError) {
|
||||
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
|
||||
glog.V(4).Infof("Found anchor on different types of element: overlay %T, resource %T\nSkip processing overlay.", overlay, resource)
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("Found anchor on different types of element: overlay %T, resource %T\nSkip processing overlay.", overlay, resource))
|
||||
glog.V(4).Infof("Found anchor on different types of element: overlay %T, resource %T", overlay, resource)
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("Found anchor on different types of element: overlay %T, resource %T", overlay, resource))
|
||||
}
|
||||
|
||||
switch typedOverlay := overlay.(type) {
|
||||
|
@ -122,7 +122,7 @@ func compareOverlay(resource, overlay interface{}, path string) (string, overlay
|
|||
curPath := path + noAnchorKey + "/"
|
||||
resourceVal, ok := typedResource[noAnchorKey]
|
||||
if !ok {
|
||||
return curPath, newOverlayError(conditionFailure, fmt.Sprintf("field %s is not present", noAnchorKey))
|
||||
return curPath, newOverlayError(conditionFailure, fmt.Sprintf("Field %s is not present", noAnchorKey))
|
||||
}
|
||||
if newPath, err := compareOverlay(resourceVal, overlayVal, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
|
@ -140,10 +140,10 @@ func compareOverlay(resource, overlay interface{}, path string) (string, overlay
|
|||
case string, float64, int, int64, bool, nil:
|
||||
if !ValidateValueWithPattern(resource, overlay) {
|
||||
glog.V(4).Infof("Mutate rule: failed validating value %v with overlay %v", resource, overlay)
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("failed validating value %v with overlay %v", resource, overlay))
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("Failed validating value %v with overlay %v", resource, overlay))
|
||||
}
|
||||
default:
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("overlay has unknown type %T, value %v", overlay, overlay))
|
||||
return path, newOverlayError(conditionFailure, fmt.Sprintf("Overlay has unknown type %T, value %v", overlay, overlay))
|
||||
}
|
||||
|
||||
return "", overlayError{}
|
||||
|
@ -156,12 +156,14 @@ func validateNonAnchorOverlayMap(resourceMap, overlayWithoutAnchor map[string]in
|
|||
curPath := path + key + "/"
|
||||
resourceValue, ok := resourceMap[key]
|
||||
if !ok {
|
||||
if !hasNestedAnchors(overlayValue) {
|
||||
// policy: "(image)": "*:latest",
|
||||
// "imagePullPolicy": "IfNotPresent",
|
||||
// resource: "(image)": "*:latest",
|
||||
// the above case should be allowed
|
||||
continue
|
||||
}
|
||||
}
|
||||
if newPath, err := checkConditions(resourceValue, overlayValue, curPath); !reflect.DeepEqual(err, overlayError{}) {
|
||||
return newPath, err
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ func TestMeetConditions_anchosInSameObject(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.Error(t, err, "[overlayError:0] failed validating value 443 with overlay 444")
|
||||
assert.Error(t, err, "[overlayError:0] Failed validating value 443 with overlay 444")
|
||||
}
|
||||
|
||||
func TestMeetConditions_anchorOnPeer(t *testing.T) {
|
||||
|
@ -444,7 +444,7 @@ func TestMeetConditions_anchorsOnPeer_two(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err := meetConditions(resource, overlay)
|
||||
assert.Error(t, err, "[overlayError:0] failed validating value true with overlay false")
|
||||
assert.Error(t, err, "[overlayError:0] Failed validating value true with overlay false")
|
||||
|
||||
overlayRaw = []byte(`{
|
||||
"spec": {
|
||||
|
@ -594,7 +594,7 @@ func TestMeetConditions_anchorsOnPeer_multiple(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
_, err = meetConditions(resource, overlay)
|
||||
assert.Error(t, err, "[overlayError:0] failed validating value ENV_VALUE with overlay ENV_VALUE1")
|
||||
assert.Error(t, err, "[overlayError:0] Failed validating value ENV_VALUE with overlay ENV_VALUE1")
|
||||
}
|
||||
|
||||
func TestMeetConditions_AtleastOneExist(t *testing.T) {
|
||||
|
|
|
@ -6,6 +6,7 @@ type codeKey int
|
|||
|
||||
const (
|
||||
conditionFailure codeKey = iota
|
||||
conditionNotPresent
|
||||
overlayFailure
|
||||
)
|
||||
|
||||
|
|
|
@ -494,7 +494,7 @@ func TestProcessOverlayPatches_ImagePullPolicy(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
assert.Error(t, err, "[overlayError:0] Conditions are not met at /spec/template/metadata/labels/app/, [overlayError:0] failed validating value nginx with overlay nginx1")
|
||||
assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /spec/template/metadata/labels/app/, [overlayError:0] Failed validating value nginx with overlay nginx1")
|
||||
assert.Assert(t, len(patches) == 0)
|
||||
}
|
||||
|
||||
|
@ -807,7 +807,7 @@ func TestProcessOverlayPatches_anchorOnPeer(t *testing.T) {
|
|||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
patches, err = processOverlayPatches(resource, overlay)
|
||||
assert.Error(t, err, "[overlayError:0] Conditions are not met at /subsets/0/ports/0/port/, [overlayError:0] failed validating value 443 with overlay 444")
|
||||
assert.Error(t, err, "[overlayError:0] Policy not applied, conditions are not met at /subsets/0/ports/0/port/, [overlayError:0] Failed validating value 443 with overlay 444")
|
||||
assert.Assert(t, len(patches) == 0)
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ const (
|
|||
|
||||
func (k MsgKey) String() string {
|
||||
return [...]string{
|
||||
"Policy violation on resource '%s'. The rule(s) '%s' failed to apply",
|
||||
"Policy violation on resource '%s'. The rule(s) '%s' not satisfied",
|
||||
"Failed to process rule '%s' of policy '%s'.",
|
||||
"Policy applied successfully on the resource '%s'",
|
||||
"Rule(s) '%s' of Policy '%s' applied successfully",
|
||||
|
|
|
@ -122,7 +122,7 @@ func applyPolicyOnRaw(policy *kyverno.ClusterPolicy, rawResource []byte, gvk *me
|
|||
for _, r := range engineResponse.PolicyResponse.Rules {
|
||||
glog.Warning(r.Message)
|
||||
}
|
||||
return patchedResource, fmt.Errorf("Failed to apply policy %s on resource %s/%s", policy.Name, rname, rns)
|
||||
return patchedResource, fmt.Errorf("policy %s on resource %s/%s not satisfied", policy.Name, rname, rns)
|
||||
} else if len(engineResponse.PolicyResponse.Rules) > 0 {
|
||||
glog.Infof("Validation from policy %s has applied succesfully to %s %s/%s", policy.Name, gvk.Kind, rname, rns)
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ func generateEventsPerEr(er engine.EngineResponse) []event.Info {
|
|||
e.Namespace = "" // event generate on namespace resource
|
||||
e.Name = er.PolicyResponse.Resource.Name
|
||||
e.Reason = "Failure"
|
||||
e.Message = fmt.Sprintf("policy '%s' (%s) rule '%s' failed to apply. %v", er.PolicyResponse.Policy, rule.Type, rule.Name, rule.Message)
|
||||
e.Message = fmt.Sprintf("policy '%s' (%s) rule '%s' not satisfied. %v", er.PolicyResponse.Policy, rule.Type, rule.Name, rule.Message)
|
||||
eventInfos = append(eventInfos, e)
|
||||
}
|
||||
if er.IsSuccesful() {
|
||||
|
@ -102,6 +102,6 @@ func generateEventsPerEr(er engine.EngineResponse) []event.Info {
|
|||
e.Namespace = ""
|
||||
e.Name = er.PolicyResponse.Policy
|
||||
e.Reason = "Failure"
|
||||
e.Message = fmt.Sprintf("failed to apply policy '%s' rules '%v' on resource '%s/%s/%s'", er.PolicyResponse.Policy, er.GetFailedRules(), er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
|
||||
e.Message = fmt.Sprintf("policy '%s' rules '%v' on resource '%s/%s/%s' not stasified", er.PolicyResponse.Policy, er.GetFailedRules(), er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
|
||||
return eventInfos
|
||||
}
|
||||
|
|
|
@ -108,8 +108,8 @@ func generateEventsPerEr(er engine.EngineResponse) []event.Info {
|
|||
e.Kind = er.PolicyResponse.Resource.Kind
|
||||
e.Namespace = er.PolicyResponse.Resource.Namespace
|
||||
e.Name = er.PolicyResponse.Resource.Name
|
||||
e.Reason = "Failure"
|
||||
e.Message = fmt.Sprintf("policy '%s' (%s) rule '%s' failed to apply. %v", er.PolicyResponse.Policy, rule.Type, rule.Name, rule.Message)
|
||||
e.Reason = event.PolicyViolation.String()
|
||||
e.Message = fmt.Sprintf("policy '%s' (%s) rule '%s' not satisfied. %v", er.PolicyResponse.Policy, rule.Type, rule.Name, rule.Message)
|
||||
eventInfos = append(eventInfos, e)
|
||||
}
|
||||
if er.IsSuccesful() {
|
||||
|
@ -122,8 +122,8 @@ func generateEventsPerEr(er engine.EngineResponse) []event.Info {
|
|||
e.Kind = "ClusterPolicy"
|
||||
e.Namespace = ""
|
||||
e.Name = er.PolicyResponse.Policy
|
||||
e.Reason = "Failure"
|
||||
e.Message = fmt.Sprintf("failed to apply policy '%s' rules '%v' on resource '%s/%s/%s'", er.PolicyResponse.Policy, er.GetFailedRules(), er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
|
||||
e.Reason = event.PolicyViolation.String()
|
||||
e.Message = fmt.Sprintf("policy '%s' rules '%v' not satisfied on resource '%s/%s/%s'", er.PolicyResponse.Policy, er.GetFailedRules(), er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
|
||||
eventInfos = append(eventInfos, e)
|
||||
return eventInfos
|
||||
}
|
||||
|
|
|
@ -251,7 +251,8 @@ func validateResponse(t *testing.T, er engine.PolicyResponse, expected engine.Po
|
|||
|
||||
// rules
|
||||
if len(er.Rules) != len(expected.Rules) {
|
||||
t.Error("rule count: error")
|
||||
t.Errorf("rule count error, er.Rules=%d, expected.Rules=%d", len(er.Rules), len(expected.Rules))
|
||||
return
|
||||
}
|
||||
if len(er.Rules) == len(expected.Rules) {
|
||||
// if there are rules being applied then we compare the rule response
|
||||
|
|
|
@ -112,6 +112,10 @@ func Test_add_safe_to_evict_annotation2(t *testing.T) {
|
|||
testScenario(t, "test/scenarios/samples/best_practices/add_safe_to_evict2.yaml")
|
||||
}
|
||||
|
||||
func Test_add_safe_to_evict_annotation3(t *testing.T) {
|
||||
testScenario(t, "test/scenarios/samples/best_practices/add_safe_to_evict3.yaml")
|
||||
}
|
||||
|
||||
func Test_validate_restrict_automount_sa_token_pass(t *testing.T) {
|
||||
testScenario(t, "test/scenarios/samples/more/restrict_automount_sa_token.yaml")
|
||||
}
|
||||
|
|
|
@ -21,6 +21,11 @@ func generateEvents(engineResponses []engine.EngineResponse, onUpdate bool) []ev
|
|||
// dont create events on success
|
||||
continue
|
||||
}
|
||||
// default behavior is audit
|
||||
reason := event.PolicyViolation
|
||||
if er.PolicyResponse.ValidationFailureAction == Enforce {
|
||||
reason = event.RequestBlocked
|
||||
}
|
||||
failedRules := er.GetFailedRules()
|
||||
filedRulesStr := strings.Join(failedRules, ";")
|
||||
if onUpdate {
|
||||
|
@ -32,7 +37,7 @@ func generateEvents(engineResponses []engine.EngineResponse, onUpdate bool) []ev
|
|||
er.PolicyResponse.Resource.APIVersion,
|
||||
er.PolicyResponse.Resource.Namespace,
|
||||
er.PolicyResponse.Resource.Name,
|
||||
event.RequestBlocked.String(),
|
||||
reason.String(),
|
||||
event.FPolicyApplyBlockUpdate,
|
||||
filedRulesStr,
|
||||
er.PolicyResponse.Policy,
|
||||
|
@ -46,7 +51,7 @@ func generateEvents(engineResponses []engine.EngineResponse, onUpdate bool) []ev
|
|||
kyverno.SchemeGroupVersion.String(),
|
||||
"",
|
||||
er.PolicyResponse.Policy,
|
||||
event.RequestBlocked.String(),
|
||||
reason.String(),
|
||||
event.FPolicyBlockResourceUpdate,
|
||||
er.PolicyResponse.Resource.Namespace+"/"+er.PolicyResponse.Resource.Name,
|
||||
filedRulesStr,
|
||||
|
|
|
@ -88,9 +88,6 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol
|
|||
glog.V(4).Infof("eval: %v %s/%s/%s ", time.Since(evalTime), request.Kind, request.Namespace, request.Name)
|
||||
// report time
|
||||
reportTime := time.Now()
|
||||
// ADD EVENTS
|
||||
events := generateEvents(engineResponses, (request.Operation == v1beta1.Update))
|
||||
ws.eventGen.Add(events...)
|
||||
|
||||
// If Validation fails then reject the request
|
||||
// violations are created with resource owner(if exist) on "enforce"
|
||||
|
@ -102,6 +99,9 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol
|
|||
glog.V(4).Infof("resource %s/%s/%s is blocked\n", newR.GetKind(), newR.GetNamespace(), newR.GetName())
|
||||
pvInfos := generatePV(engineResponses, true)
|
||||
ws.pvGenerator.Add(pvInfos...)
|
||||
// ADD EVENTS
|
||||
events := generateEvents(engineResponses, (request.Operation == v1beta1.Update))
|
||||
ws.eventGen.Add(events...)
|
||||
sendStat(true)
|
||||
return false, getErrorMsg(engineResponses)
|
||||
}
|
||||
|
@ -110,6 +110,9 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol
|
|||
|
||||
pvInfos := generatePV(engineResponses, blocked)
|
||||
ws.pvGenerator.Add(pvInfos...)
|
||||
// ADD EVENTS
|
||||
events := generateEvents(engineResponses, (request.Operation == v1beta1.Update))
|
||||
ws.eventGen.Add(events...)
|
||||
sendStat(false)
|
||||
// report time end
|
||||
glog.V(4).Infof("report: %v %s/%s/%s", time.Since(reportTime), request.Kind, request.Namespace, request.Name)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Configure namespace limits and quotas
|
||||
|
||||
To limit the number of resources like CPU and memory, as well as objects that may be consumed by workloads in a namespace, it is important to configure resource limits and quotas for each namespace.
|
||||
To limit the number of resources like CPU and memory, as well as objects that may be consumed by workloads in a namespace, it is important to configure resource limits and quotas for each namespace. The generated default limitrange sets the default quotas for a container.
|
||||
|
||||
## Additional Information
|
||||
|
||||
|
@ -32,4 +32,22 @@ spec:
|
|||
requests.memory: '16Gi'
|
||||
limits.cpu: '4'
|
||||
limits.memory: '16Gi'
|
||||
- name: generate-limitrange
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Namespace
|
||||
generate:
|
||||
kind: LimitRange
|
||||
name: "default-limitrange"
|
||||
data:
|
||||
spec:
|
||||
limits:
|
||||
- default:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
defaultRequest:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
type: Container
|
||||
````
|
|
@ -14,7 +14,7 @@ This policy matches and mutates pods with `emptyDir` and `hostPath` volumes, to
|
|||
|
||||
````yaml
|
||||
apiVersion: "kyverno.io/v1"
|
||||
kind: "ClusterPolicy"
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: "add-safe-to-evict"
|
||||
spec:
|
||||
|
|
|
@ -8,7 +8,7 @@ The volume of type `hostPath` allows pods to use host bind mounts (i.e. director
|
|||
|
||||
````yaml
|
||||
apiVersion: "kyverno.io/v1"
|
||||
kind: "ClusterPolicy"
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: "disallow-bind-mounts"
|
||||
spec:
|
||||
|
|
|
@ -23,7 +23,7 @@ These policies are highly recommended.
|
|||
13. [Require pod resource requests and limits](RequirePodRequestsLimits.md)
|
||||
14. [Require pod `livenessProbe` and `readinessProbe`](RequirePodProbes.md)
|
||||
15. [Add default network policy](AddDefaultNetworkPolicy.md)
|
||||
16. [Add namespace resource quotas](AddNamespaceResourceQuota.md)
|
||||
16. [Add namespace quotas](AddNamespaceQuotas.md)
|
||||
17. [Add `safe-to-evict` for pods with `emptyDir` and `hostPath` volumes](AddSafeToEvict.md)
|
||||
|
||||
## Additional Policies
|
||||
|
|
|
@ -24,3 +24,21 @@ spec:
|
|||
requests.memory: '16Gi'
|
||||
limits.cpu: '4'
|
||||
limits.memory: '16Gi'
|
||||
- name: generate-limitrange
|
||||
match:
|
||||
resources:
|
||||
kinds:
|
||||
- Namespace
|
||||
generate:
|
||||
kind: LimitRange
|
||||
name: "default-limitrange"
|
||||
data:
|
||||
spec:
|
||||
limits:
|
||||
- default:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
defaultRequest:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
type: Container
|
||||
|
|
|
@ -19,5 +19,5 @@ spec:
|
|||
pattern:
|
||||
spec:
|
||||
=(volumes):
|
||||
=(hostPath):
|
||||
- =(hostPath):
|
||||
path: "!/var/run/docker.sock"
|
17
test/output/pod-with-default-volume.yaml
Normal file
17
test/output/pod-with-default-volume.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-with-default-volume
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/test-webserver
|
||||
name: test-container
|
||||
volumeMounts:
|
||||
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
name: default-token-wkknl
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: default-token-wkknl
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: default-token-wkknl
|
17
test/resources/pod-with-default-volume.yaml
Normal file
17
test/resources/pod-with-default-volume.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-with-default-volume
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/test-webserver
|
||||
name: test-container
|
||||
volumeMounts:
|
||||
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
name: default-token-wkknl
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: default-token-wkknl
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: default-token-wkknl
|
|
@ -19,3 +19,6 @@ expected:
|
|||
- name: generate-resourcequota
|
||||
type: Generation
|
||||
success: true
|
||||
- name: generate-limitrange
|
||||
type: Generation
|
||||
success: true
|
||||
|
|
|
@ -13,7 +13,7 @@ expected:
|
|||
namespace: ''
|
||||
name: pod-with-hostpath
|
||||
rules:
|
||||
- name: annotate-empty-dir
|
||||
- name: annotate-host-path
|
||||
type: Mutation
|
||||
success: true
|
||||
message: "successfully processed overlay"
|
|
@ -0,0 +1,15 @@
|
|||
# file path is relative to project root
|
||||
input:
|
||||
policy: samples/best_practices/add_safe_to_evict.yaml
|
||||
resource: test/resources/pod-with-default-volume.yaml
|
||||
expected:
|
||||
mutation:
|
||||
patchedresource: test/resources/pod-with-default-volume.yaml
|
||||
policyresponse:
|
||||
policy: add-safe-to-evict
|
||||
resource:
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
namespace: ''
|
||||
name: pod-with-default-volume
|
||||
rules:
|
|
@ -14,5 +14,5 @@ expected:
|
|||
rules:
|
||||
- name: validate-docker-sock-mount
|
||||
type: Validation
|
||||
message: "Validation error: Use of the Docker Unix socket is not allowed; Validation rule 'validate-docker-sock-mount' failed at path '/spec/volumes/'"
|
||||
message: "Validation error: Use of the Docker Unix socket is not allowed; Validation rule 'validate-docker-sock-mount' failed at path '/spec/volumes/0/hostPath/path/'"
|
||||
success: false
|
Loading…
Add table
Reference in a new issue