Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KIALI-686: Adding documentation to validation system #210

Merged
merged 1 commit into from May 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion handlers/services.go
Expand Up @@ -91,7 +91,9 @@ func ServiceHealth(w http.ResponseWriter, r *http.Request) {
RespondWithJSON(w, http.StatusOK, health)
}

// ServiceIstioValidations is the API handler to get istio validations of a single service
// ServiceIstioValidations is the API handler to get istio validations of a single service that returns
// an IstioValidation object which contains for each object type (i.e.: routerule, pod, destinationpolicy,...)
// one validation per each detected object in the current cluster that have an error/warning in its configuration.
func ServiceIstioValidations(w http.ResponseWriter, r *http.Request) {
// Get business layer
business, err := business.Get()
Expand Down
5 changes: 3 additions & 2 deletions services/business/checkers/pod_checker.go
Expand Up @@ -12,12 +12,12 @@ type PodChecker struct {

const podsCheckerType = "pod"

// Runs all checkers for Pod objects passed into the PodChecker
func (checker PodChecker) Check() *models.IstioTypeValidations {
// The only available checker test for missing
// sidecars in a service. Only individual checks makes sense for now.
return checker.runIndividualChecks()
}

// Runs individual checks for each pod in pod checker.
func (checker PodChecker) runIndividualChecks() *models.IstioTypeValidations {
typeValidations := models.IstioTypeValidations{}
if len(checker.Pods) == 0 {
Expand Down Expand Up @@ -47,6 +47,7 @@ func (checker PodChecker) runIndividualChecks() *models.IstioTypeValidations {
return &typeValidations
}

// Returns a list of all individual enabled checkers
func (checker *PodChecker) enabledCheckersFor(object *v1.Pod) []Checker {
return []Checker{
pods.SidecarPresenceChecker{Pod: object},
Expand Down
2 changes: 2 additions & 0 deletions services/business/checkers/pods/sidecar_presence_checker.go
Expand Up @@ -12,6 +12,8 @@ type SidecarPresenceChecker struct {
Pod *v1.Pod
}

// A Checker checks individual objects and builds an IstioCheck whenever the check fails.
// SidecarPresenceChecker checks if the current Pod has an Istio Sidecar installed.
func (checker SidecarPresenceChecker) Check() ([]*models.IstioCheck, bool) {
for _, container := range checker.Pod.Spec.Containers {
if strings.HasPrefix(container.Image, SidecarContainerImage) {
Expand Down
9 changes: 9 additions & 0 deletions services/business/checkers/route_rule_checker.go
Expand Up @@ -18,6 +18,10 @@ type RouteRuleChecker struct {
RouteRules []kubernetes.IstioObject
}

// An Object Checker runs all checkers for an specific object type (i.e.: pod, route rule,...)
// It run two kinds of checkers:
// 1. Individual checks: validating individual objects.
// 2. Group checks: validating behaviour between configurations.
func (in RouteRuleChecker) Check() *models.IstioTypeValidations {
typeValidations := models.IstioTypeValidations{}

Expand All @@ -27,6 +31,7 @@ func (in RouteRuleChecker) Check() *models.IstioTypeValidations {
return &typeValidations
}

// Runs individual checks for each route rule
func (in RouteRuleChecker) runIndividualChecks() *models.IstioTypeValidations {
typeValidations := models.IstioTypeValidations{}
var wg sync.WaitGroup
Expand All @@ -42,17 +47,20 @@ func (in RouteRuleChecker) runIndividualChecks() *models.IstioTypeValidations {
return &typeValidations
}

// runGroupChecks runs group checks for all route rules
func (in *RouteRuleChecker) runGroupChecks() *models.IstioTypeValidations {
return &models.IstioTypeValidations{}
}

// enabledCheckersFor returns the list of all individual enabled checkers
func enabledCheckersFor(object kubernetes.IstioObject) []Checker {
return []Checker{
route_rules.RouteChecker{object},
route_rules.PrecedenceChecker{object},
}
}

// runChecks runs all the individual checks for a single route rule and it appends the result into typeValidations
func runChecks(routeRule kubernetes.IstioObject, typeValidations *models.IstioTypeValidations, wg *sync.WaitGroup) {
defer (*wg).Done()
var checkersWg sync.WaitGroup
Expand All @@ -74,6 +82,7 @@ func runChecks(routeRule kubernetes.IstioObject, typeValidations *models.IstioTy
checkersWg.Wait()
}

// runChecker runs the specific checker and store its result into nameValidations under objectName map.
func runChecker(checker Checker, objectName string, nameValidations *models.IstioNameValidations, wg *sync.WaitGroup) {
defer (*wg).Done()

Expand Down
2 changes: 2 additions & 0 deletions services/business/checkers/route_rules/precedence_checker.go
Expand Up @@ -10,6 +10,8 @@ import (

type PrecedenceChecker struct{ kubernetes.IstioObject }

// Check returns both an array of IstioCheck objects and a boolean telling if the route rule is valid.
// Each IstioCheck represent an error or warning detected when validating the precedence field.
func (route PrecedenceChecker) Check() ([]*models.IstioCheck, bool) {
valid := true
validations := make([]*models.IstioCheck, 0)
Expand Down
6 changes: 6 additions & 0 deletions services/business/checkers/route_rules/route_checker.go
Expand Up @@ -11,6 +11,12 @@ import (

type RouteChecker struct{ kubernetes.IstioObject }

// Check returns both an array of IstioCheck and a boolean indicating if the current route rule is valid.
// The array of IstioChecks contains the result of running the following validations:
// 1. All weights with a numeric number.
// 2. All weights have value between 0 and 100.
// 3. Sum of all weights are 100 (if only one weight, then it assumes that is 100).
// 4. All the route has to have weight label.
func (route RouteChecker) Check() ([]*models.IstioCheck, bool) {
validations := make([]*models.IstioCheck, 0)

Expand Down
5 changes: 4 additions & 1 deletion services/business/istio_validations.go
Expand Up @@ -16,6 +16,8 @@ type ObjectChecker interface {
Check() *models.IstioTypeValidations
}

// GetServiceValidations returns an IstioTypeValidations object with all the checks found when running
// all the enabled checkers.
func (in *IstioValidationsService) GetServiceValidations(namespace, service string) (models.IstioTypeValidations, error) {
// Get all the Istio objects from a Namespace and service
istioDetails, err := in.k8s.GetIstioDetails(namespace, service)
Expand Down Expand Up @@ -49,10 +51,11 @@ func (in *IstioValidationsService) GetServiceValidations(namespace, service stri
objectTypeValidations.MergeValidations(<-validation)
}

// Get groupal validations for same kind istio objects
return objectTypeValidations, nil
}

// enabledCheckersFor returns the list of ObjectCheckers that will be run for istioDetails and pods
// objects passed by parameters
func enabledCheckersFor(istioDetails *kubernetes.IstioDetails, pods *v1.PodList) []ObjectChecker {
return []ObjectChecker{
checkers.RouteRuleChecker{istioDetails.RouteRules},
Expand Down
16 changes: 8 additions & 8 deletions services/models/istio_validation.go
@@ -1,6 +1,6 @@
package models

// IstioTypeValidations represents a set of IstioNameValidations grouper per Istio ObjectType.
// IstioTypeValidations represents a set of IstioNameValidations grouped per Istio ObjectType.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

// It is possible that different object types have same name, but names per ObjectType are unique.
type IstioTypeValidations map[string]*IstioNameValidations

Expand All @@ -9,16 +9,16 @@ type IstioTypeValidations map[string]*IstioNameValidations
type IstioNameValidations map[string]*IstioValidation

type IstioValidation struct {
Name string `json:"name"`
ObjectType string `json:"object_type"`
Valid bool `json:"valid"`
Checks []*IstioCheck `json:"checks"`
Name string `json:"name"` // Name of the object itself
ObjectType string `json:"object_type"` // Type of the object
Valid bool `json:"valid"` // Represents validity of the object: in case of warning, validity remainds as true
Checks []*IstioCheck `json:"checks"` // Array of checks
}

type IstioCheck struct {
Message string `json:"message"`
Severity string `json:"severity"`
Path string `json:"path"`
Message string `json:"message"` // Description of the check
Severity string `json:"severity"` // Indicates the level of importance: error or warning
Path string `json:"path"` // String that describes where in the yaml file is the check located
}

func BuildCheck(message, severity, path string) IstioCheck {
Expand Down