asteris-llc/converge

View on GitHub
resource/health_status.go

Summary

Maintainability
A
0 mins
Test Coverage
// Copyright © 2016 Asteris, LLC
//
// 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 resource

import (
    "bytes"
    "errors"
    "fmt"
)

const (
    // StatusHealthy indicates a passing health check
    StatusHealthy HealthStatusCode = iota
    // StatusWarning indicates a change is needed
    StatusWarning
    // StatusError indicates that a module is non-functional
    StatusError
)

const defaultDisplayLevel = StatusWarning

// HealthStatusCode is a status indicator for health level.  It should be one of:
//   StatusHealth
//   StatusWarning
//   StatusError
type HealthStatusCode int

// HealthStatus contains a status level, display threshold, and status message
type HealthStatus struct {
    TaskStatus
    WarningLevel HealthStatusCode
    DisplayLevel *HealthStatusCode
    FailingDeps  map[string]string
}

// HasFailingDeps returns true of FailingDeps is not empty
func (h *HealthStatus) HasFailingDeps() bool {
    return len(h.FailingDeps) > 0
}

// UpgradeWarning will increase the warning level to at least `level`, but will
// not decrease it if it's already higher.
func (h *HealthStatus) UpgradeWarning(level HealthStatusCode) {
    if h.WarningLevel < level {
        h.WarningLevel = level
    }
}

// IsWarning returns true if the warning level is StatusWarning
func (h *HealthStatus) IsWarning() bool {
    return h.WarningLevel == StatusWarning
}

// IsError returns true if the warning level is StatusError
func (h *HealthStatus) IsError() bool {
    return h.WarningLevel == StatusError
}

// ShouldDisplay returns true if the warning level is at least the display level
func (h *HealthStatus) ShouldDisplay() bool {
    var threshold HealthStatusCode
    if h.DisplayLevel == nil {
        threshold = defaultDisplayLevel
    } else {
        threshold = *h.DisplayLevel
    }
    return h.WarningLevel >= threshold
}

// Messages returns health status messages
func (h *HealthStatus) Messages() []string {
    var messages []string
    if statusCode := h.TaskStatus.StatusCode(); statusCode != 0 {
        messages = append(messages, fmt.Sprintf("Check returned %d", statusCode))
    }
    if h.TaskStatus.HasChanges() {
        messages = append(messages, "Check indicates changes are required")
    }
    if depCount := len(h.FailingDeps); depCount > 0 {
        messages = append(messages, fmt.Sprintf("%d failing dependencies", depCount))
    }
    return messages
}

// Changes returns changes from the underlying TaskStatus diffs
func (h *HealthStatus) Changes() map[string]Diff {
    return h.Diffs()
}

// HasChanges returns true if the status indicates that there are changes
func (h *HealthStatus) HasChanges() bool {
    return h.TaskStatus.HasChanges()
}

// Error returns nil on success.  If the health checks or it's dedencies are
// failing an appropriate error is returned.
func (h *HealthStatus) Error() error {
    var msg bytes.Buffer
    var hasError bool
    if h.ShouldDisplay() {
        msg.WriteString("required changes detected")
        hasError = true
    }
    if len(h.FailingDeps) > 0 {
        hasError = true
        if h.ShouldDisplay() {
            msg.WriteString("; ")
        }
        msg.WriteString("required dependencies are failing")
    }
    if hasError {
        return errors.New(msg.String())
    }
    return nil
}