Skip to content

Commit

Permalink
fix: introduced system check.
Browse files Browse the repository at this point in the history
  • Loading branch information
beneiltis committed Oct 12, 2023
1 parent 8d5d00a commit 5ebf4c0
Show file tree
Hide file tree
Showing 11 changed files with 484 additions and 37 deletions.
14 changes: 12 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,22 @@
"console": "integratedTerminal"
},
{
"name": "test",
"name": "cluster info",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "main.go",
"args": ["cluster", "info"],
"asRoot": false,
"console": "integratedTerminal"
},
{
"name": "system check",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "main.go",
"args": ["system", "test"],
"args": ["system", "check"],
"asRoot": false,
"console": "integratedTerminal"
}
Expand Down
99 changes: 99 additions & 0 deletions cmd/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ package cmd
import (
"fmt"
"os"
"strings"

"github.com/jedib0t/go-pretty/v6/table"
"github.com/mogenius/punq/kubernetes"
"github.com/mogenius/punq/utils"

Expand Down Expand Up @@ -34,6 +36,86 @@ var resetConfig = &cobra.Command{
},
}

var checkCmd = &cobra.Command{
Use: "check",
Short: "Check the system for all required components and offer healing.",
Run: func(cmd *cobra.Command, args []string) {
// check internet access
// check for kubectl
// check kubernetes version
// check for ingresscontroller
// check for metrics server
// check for helm
// check for cluster provider
// check for api versions

t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.AppendHeader(table.Row{"Check", "Status", "Message"})
// check internet access
inetResult, inetErr := utils.CheckInternetAccess()
t.AppendRow(
table.Row{"Internet Access", StatusEmoji(inetResult), StatusMessage(inetErr, "Check your internet connection.", "Internet access works.")},
)
t.AppendSeparator()

// check for kubectl
kubectlResult, kubectlOutput, kubectlErr := utils.IsKubectlInstalled()
t.AppendRow(
table.Row{"kubectl", StatusEmoji(kubectlResult), StatusMessage(kubectlErr, "Plase install kubectl (https://kubernetes.io/docs/tasks/tools/) on your system to proceed.", kubectlOutput)},
)
t.AppendSeparator()

// check kubernetes version
kubernetesVersion := kubernetes.KubernetesVersion(nil)
kubernetesVersionResult := kubernetesVersion != nil
t.AppendRow(
table.Row{"Kubernetes Version", StatusEmoji(kubernetesVersionResult), StatusMessage(kubectlErr, "Cannot determin version of kubernetes.", fmt.Sprintf("Version: %s\nPlatform: %s", kubernetesVersion.String(), kubernetesVersion.Platform))},
)
t.AppendSeparator()

// check for ingresscontroller
ingressType, ingressTypeErr := kubernetes.DetermineIngressControllerType(nil)
t.AppendRow(
table.Row{"Ingress Controller", StatusEmoji(ingressTypeErr == nil), StatusMessage(ingressTypeErr, "Cannot determin ingress controller type.", ingressType.String())},
)
t.AppendSeparator()

// check for metrics server
metricsResult, metricsVersion, metricsErr := kubernetes.IsMetricsServerAvailable(nil)
t.AppendRow(
table.Row{"Metrics Server", StatusEmoji(metricsResult), StatusMessage(metricsErr, "kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml\nNote: Running docker-desktop? Please add '- --kubelet-insecure-tls' to the args sction in the deployment of metrics-server.", metricsVersion)},
)
t.AppendSeparator()

// check for helm
helmResult, helmOutput, helmErr := utils.IsHelmInstalled()
t.AppendRow(
table.Row{"Helm", StatusEmoji(helmResult), StatusMessage(helmErr, "Plase install helm (https://helm.sh/docs/intro/install/) on your system to proceed.", helmOutput)},
)
t.AppendSeparator()

// check cluster provider
clusterProvOutput, clusterProvErr := kubernetes.GuessClusterProvider(nil)
t.AppendRow(
table.Row{"Cluster Provider", StatusEmoji(clusterProvErr == nil), StatusMessage(clusterProvErr, "We could not determine the provider of this cluster.", string(clusterProvOutput))},
)
t.AppendSeparator()

// API Versions
apiVerResult, apiVerErr := kubernetes.ApiVersions(nil)
apiVersStr := ""
for _, entry := range apiVerResult {
apiVersStr += fmt.Sprintf("%s\n", entry)
}
apiVersStr = strings.TrimRight(apiVersStr, "\n\r")
t.AppendRow(
table.Row{"API Versions", StatusEmoji(len(apiVerResult) > 0), StatusMessage(apiVerErr, "Cannot determin API versions.", apiVersStr)},
)
t.Render()
},
}

var infoCmd = &cobra.Command{
Use: "info",
Short: "Print information and exit.",
Expand Down Expand Up @@ -61,4 +143,21 @@ func init() {
systemCmd.AddCommand(resetConfig)
systemCmd.AddCommand(infoCmd)
systemCmd.AddCommand(ingressControllerCmd)
systemCmd.AddCommand(checkCmd)
}

// UTILS

func StatusEmoji(works bool) string {
if works {
return "✅"
}
return "❌"
}

func StatusMessage(err error, solution string, successMsg string) string {
if err != nil {
return fmt.Sprintf("Error: %s\nSolution: %s", err.Error(), solution)
}
return successMsg
}
16 changes: 8 additions & 8 deletions dtos/cluster-status.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import "time"
type ClusterStatusDto struct {
ClusterName string `json:"clusterName"`
Pods int `json:"pods"`
CpuInMilliCores int `json:"cpu"`
CpuLimitInMilliCores int `json:"cpuLimit"`
MemoryInBytes int64 `json:"memoryInBytes"`
MemoryLimitInBytes int64 `json:"memoryLimitInBytes"`
PodCpuUsageInMilliCores int `json:"podCpuUsageInMilliCores"`
PodCpuLimitInMilliCores int `json:"podCpuLimitInMilliCores"`
PodMemoryUsageInBytes int64 `json:"podMemoryUsageInBytes"`
PodMemoryLimitInBytes int64 `json:"podMemoryLimitInBytes"`
EphemeralStorageLimitInBytes int64 `json:"ephemeralStorageLimitInBytes"`
CurrentTime string `json:"currentTime"`
KubernetesVersion string `json:"kubernetesVersion"`
Expand All @@ -19,10 +19,10 @@ func ClusterStatusDtoExmapleData() ClusterStatusDto {
return ClusterStatusDto{
ClusterName: "clusterName",
Pods: 1,
CpuInMilliCores: 1,
CpuLimitInMilliCores: 1,
MemoryInBytes: 123,
MemoryLimitInBytes: 1456,
PodCpuUsageInMilliCores: 1,
PodCpuLimitInMilliCores: 1,
PodMemoryUsageInBytes: 123,
PodMemoryLimitInBytes: 1234,
EphemeralStorageLimitInBytes: 166,
CurrentTime: time.Now().Format(time.RFC3339),
KubernetesVersion: "v1.27.2",
Expand Down
30 changes: 29 additions & 1 deletion dtos/kubernetes-provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
ACK KubernetesProvider = "ACK" // Alibaba Cloud Kubernetes
OKE KubernetesProvider = "OKE" // Oracle Cloud Kubernetes
OTC KubernetesProvider = "OTC" // Telekom cloud
OPEN_SHIFT KubernetesProvider = "OPEN_SHIFT" // Telekom cloud
OPEN_SHIFT KubernetesProvider = "OPEN_SHIFT" // RED HAT OpenShift
GKE_ON_PREM KubernetesProvider = "GKE_ON_PREM" // Google Kubernetes Engine On-Prem
RKE KubernetesProvider = "RKE" // Rancher Kubernetes Engine
KUBEADM KubernetesProvider = "KUBEADM" // Kubeadm
Expand All @@ -36,6 +36,20 @@ const (
STACKIT KubernetesProvider = "SKE" // STACKIT Kubernetes Engine (SKE)
IONOS KubernetesProvider = "IONOS" // IONOS Cloud Managed
SCALEWAY KubernetesProvider = "SCALEWAY" // scaleway
VMWARE KubernetesProvider = "VMWARE" // VMware Tanzu Kubernetes Grid Integrated Edition
MICROK8S KubernetesProvider = "MICROK8S" // MicroK8s
CIVO KubernetesProvider = "CIVO" // Civo Kubernetes
GIANTSWARM KubernetesProvider = "GIANTSWARM" // Giant Swarm Kubernetes
OVHCLOUD KubernetesProvider = "OVHCLOUD" // OVHCloud Kubernetes
GARDENER KubernetesProvider = "GARDENER" // SAP Gardener Kubernetes
HUAWEI KubernetesProvider = "HUAWEI" // Huawei Cloud Kubernetes
NIRMATA KubernetesProvider = "NIRMATA" // Nirmata Kubernetes
PF9 KubernetesProvider = "PF9" // Platform9 Kubernetes
NKS KubernetesProvider = "NKS" // Netapp Kubernetes Service
APPSCODE KubernetesProvider = "APPSCODE" // AppsCode Kubernetes
LOFT KubernetesProvider = "LOFT" // Loft Kubernetes
SPECTROCLOUD KubernetesProvider = "SPECTROCLOUD" // Spectro Cloud Kubernetes
DIAMANTI KubernetesProvider = "DIAMANTI" // Diamanti Kubernetes
)

var ALL_PROVIDER []string = []string{
Expand Down Expand Up @@ -72,4 +86,18 @@ var ALL_PROVIDER []string = []string{
string(STACKIT),
string(IONOS),
string(SCALEWAY),
string(VMWARE),
string(MICROK8S),
string(CIVO),
string(GIANTSWARM),
string(OVHCLOUD),
string(GARDENER),
string(HUAWEI),
string(NIRMATA),
string(PF9),
string(NKS),
string(APPSCODE),
string(LOFT),
string(SPECTROCLOUD),
string(DIAMANTI),
}
24 changes: 13 additions & 11 deletions dtos/nodeStatsDto.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ import (
)

type NodeStat struct {
Name string `json:"name" validate:"required"`
MaschineId string `json:"maschineId" validate:"required"`
Cpus int64 `json:"cpus" validate:"required"`
MemoryInBytes int64 `json:"memoryInBytes" validate:"required"`
EphemeralInBytes int64 `json:"ephemeralInBytes" validate:"required"`
MaxPods int64 `json:"maxPods" validate:"required"`
KubletVersion string `json:"kubletVersion" validate:"required"`
OsType string `json:"osType" validate:"required"`
OsImage string `json:"osImage" validate:"required"`
Architecture string `json:"architecture" validate:"required"`
Name string `json:"name" validate:"required"`
MaschineId string `json:"maschineId" validate:"required"`
CpuInCores int64 `json:"cpuInCores" validate:"required"`
CpuInCoresUtilized float64 `json:"cpuInCoresUtilized" validate:"required"`
MemoryInBytes int64 `json:"memoryInBytes" validate:"required"`
MemoryInBytesUtilized int64 `json:"memoryInBytesUtilized" validate:"required"`
EphemeralInBytes int64 `json:"ephemeralInBytes" validate:"required"`
MaxPods int64 `json:"maxPods" validate:"required"`
KubletVersion string `json:"kubletVersion" validate:"required"`
OsType string `json:"osType" validate:"required"`
OsImage string `json:"osImage" validate:"required"`
Architecture string `json:"architecture" validate:"required"`
}

func (o *NodeStat) PrintPretty() {
Expand All @@ -26,7 +28,7 @@ func (o *NodeStat) PrintPretty() {
o.OsImage,
o.OsType,
o.Architecture,
o.Cpus,
o.CpuInCores,
utils.BytesToHumanReadable(o.MemoryInBytes),
utils.BytesToHumanReadable(o.EphemeralInBytes),
o.MaxPods,
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/ivanpirog/coloredcobra v1.0.1
github.com/jaevor/go-nanoid v1.3.0
github.com/jedib0t/go-pretty v4.3.0+incompatible
github.com/jedib0t/go-pretty/v6 v6.4.6
github.com/jedib0t/go-pretty/v6 v6.4.8
github.com/json-iterator/go v1.1.12
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/spf13/cobra v1.7.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PH
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw=
github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
github.com/jedib0t/go-pretty/v6 v6.4.8 h1:HiNzyMSEpsBaduKhmK+CwcpulEeBrTmxutz4oX/oWkg=
github.com/jedib0t/go-pretty/v6 v6.4.8/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
Expand Down
14 changes: 14 additions & 0 deletions kubernetes/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ func AllDeployments(namespaceName string, contextId *string) []v1.Deployment {
return result
}

func AllDeploymentsIncludeIgnored(namespaceName string, contextId *string) []v1.Deployment {
provider, err := NewKubeProvider(contextId)
if err != nil {
return []v1.Deployment{}
}
deploymentList, err := provider.ClientSet.AppsV1().Deployments(namespaceName).List(context.TODO(), metav1.ListOptions{})
if err != nil {
logger.Log.Errorf("AllDeployments ERROR: %s", err.Error())
return deploymentList.Items
}

return deploymentList.Items
}

func AllK8sDeployments(namespaceName string, contextId *string) utils.K8sWorkloadResult {
result := []v1.Deployment{}

Expand Down
55 changes: 45 additions & 10 deletions kubernetes/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,64 @@ import (

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1metrics "k8s.io/metrics/pkg/apis/metrics/v1beta1"
)

func GetNodeStats(contextId *string) []dtos.NodeStat {
result := []dtos.NodeStat{}
nodes := ListNodes(contextId)
nodeMetrics := ListNodeMetricss(contextId)

for index, node := range nodes {

utilizedCores := float64(0)
utilizedMemory := int64(0)
if len(nodeMetrics) > 0 {
// Find the corresponding node metrics
var nodeMetric *v1metrics.NodeMetrics
for _, nm := range nodeMetrics {
if nm.Name == node.Name {
nodeMetric = &nm
break
}
}

// CPU
cpuUsageDec := nodeMetric.Usage.Cpu().AsDec()
cpuUsage, works := cpuUsageDec.Unscaled()
if !works {
logger.Log.Errorf("Failed to get CPU usage for node %s", node.Name)
}
if cpuUsage == 0 {
cpuUsage = 1
}
utilizedCores = float64(cpuUsage) / 1000000000

// Memory
utilizedMemory, works = nodeMetric.Usage.Memory().AsInt64()
if !works {
logger.Log.Errorf("Failed to get MEMORY usage for node %s", node.Name)
}
}

mem, _ := node.Status.Capacity.Memory().AsInt64()
cpu, _ := node.Status.Capacity.Cpu().AsInt64()
maxPods, _ := node.Status.Capacity.Pods().AsInt64()
ephemeral, _ := node.Status.Capacity.StorageEphemeral().AsInt64()

nodeStat := dtos.NodeStat{
Name: fmt.Sprintf("Node-%d", index+1),
MaschineId: node.Status.NodeInfo.MachineID,
Cpus: cpu,
MemoryInBytes: mem,
EphemeralInBytes: ephemeral,
MaxPods: maxPods,
KubletVersion: node.Status.NodeInfo.KubeletVersion,
OsType: node.Status.NodeInfo.OperatingSystem,
OsImage: node.Status.NodeInfo.OSImage,
Architecture: node.Status.NodeInfo.Architecture,
Name: fmt.Sprintf("Node-%d", index+1),
MaschineId: node.Status.NodeInfo.MachineID,
CpuInCores: cpu,
CpuInCoresUtilized: utilizedCores,
MemoryInBytes: mem,
MemoryInBytesUtilized: utilizedMemory,
EphemeralInBytes: ephemeral,
MaxPods: maxPods,
KubletVersion: node.Status.NodeInfo.KubeletVersion,
OsType: node.Status.NodeInfo.OperatingSystem,
OsImage: node.Status.NodeInfo.OSImage,
Architecture: node.Status.NodeInfo.Architecture,
}
result = append(result, nodeStat)
//nodeStat.PrintPretty()
Expand Down
Loading

0 comments on commit 5ebf4c0

Please sign in to comment.