diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index f579358..77850d4 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -13,7 +13,7 @@ env: jobs: prepare: - runs-on: [self-hosted, X64] + runs-on: [self-hosted, ubuntu-2204-arm64] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -29,7 +29,7 @@ jobs: git config --global user.email "punqs@mogenius.com" git config --global user.name "punq" git config --global credential.helper cache - semantic-release + npx semantic-release VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) echo "VERSION=$VERSION" >> $GITHUB_ENV COMMIT_HASH=$(git rev-parse --short HEAD) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 279853f..711023c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ env: jobs: prepare: - runs-on: [self-hosted, X64] + runs-on: [self-hosted, ubuntu-2204-arm64] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -29,7 +29,7 @@ jobs: git config --global user.email "punqs@mogenius.com" git config --global user.name "punq" git config --global credential.helper cache - semantic-release + npx semantic-release VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) echo "VERSION=$VERSION" >> $GITHUB_ENV COMMIT_HASH=$(git rev-parse --short HEAD) diff --git a/Dockerfile-Operator b/Dockerfile-Operator index 9931146..6326771 100644 --- a/Dockerfile-Operator +++ b/Dockerfile-Operator @@ -1,4 +1,4 @@ -FROM golang:1.21-alpine AS builder +FROM golang:1.22-alpine AS builder ARG GOOS ARG GOARCH @@ -33,7 +33,7 @@ FROM alpine:latest ARG GOOS ARG GOARCH -RUN apk add --no-cache curl bash +RUN apk add --no-cache curl RUN echo "${GOOS} ${GOARCH}" diff --git a/Makefile b/Makefile index ec59a61..8b3a274 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ GO=go GOBUILD=$(GO) build GOCLEAN=$(GO) clean GOGET=$(GO) get +CGO_ENABLED=0 # Ensure linker embeds versioning information VERSION=${shell git describe --tags $(git rev-list --tags --max-count=1)} diff --git a/Makefile-dev b/Makefile-dev index 16ab5e7..5571a9b 100644 --- a/Makefile-dev +++ b/Makefile-dev @@ -5,6 +5,7 @@ GOBUILD=$(GO) build GOCLEAN=$(GO) clean GOTEST=$(GO) test GOGET=$(GO) get +CGO_ENABLED=0 # Ensure linker embeds versioning information VERSION=${shell git describe --tags $(git rev-list --tags --max-count=1)} diff --git a/README.md b/README.md index f811728..0360b9c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ # punq - Punq streamlines Kubernetes cluster management through an intuitive WebApp and a user-friendly CLI, designed to simplify the lives of DevOps professionals. It offers unified team collaboration, comprehensive log access, and a sophisticated workload editor, facilitates seamless oversight and manipulation of clusters spanning various infrastructures. diff --git a/go.mod b/go.mod index 8129994..44e2a5b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/mogenius/punq -go 1.21 +go 1.22 require ( github.com/cert-manager/cert-manager v1.12.3 @@ -99,12 +99,12 @@ require ( github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect golang.org/x/arch v0.5.0 // indirect - golang.org/x/crypto v0.12.0 - golang.org/x/net v0.14.0 // indirect + golang.org/x/crypto v0.20.0 + golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.9.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.11.0 - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 406d279..5217212 100644 --- a/go.sum +++ b/go.sum @@ -284,8 +284,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -301,8 +301,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -327,21 +327,21 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/kubernetes/nodes.go b/kubernetes/nodes.go index 8eeec34..a65a1b6 100644 --- a/kubernetes/nodes.go +++ b/kubernetes/nodes.go @@ -36,6 +36,10 @@ func GetNodeStats(contextId *string) []dtos.NodeStat { break } } + if nodeMetric == nil { + logger.Log.Errorf("Failed to find node metrics for node %s", node.Name) + continue + } // CPU cpuUsage, works := nodeMetric.Usage.Cpu().AsDec().Unscaled() diff --git a/kubernetes/persistent-volume.go b/kubernetes/persistent-volume.go index 65a6723..396a3bc 100644 --- a/kubernetes/persistent-volume.go +++ b/kubernetes/persistent-volume.go @@ -12,6 +12,23 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +func AllPersistentVolumesRaw(contextId *string) []core.PersistentVolume { + result := []core.PersistentVolume{} + + provider, err := NewKubeProvider(contextId) + if err != nil { + return result + } + pvList, err := provider.ClientSet.CoreV1().PersistentVolumes().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + logger.Log.Errorf("AllPersistentVolumesRaw ERROR: %s", err.Error()) + return result + } + result = append(result, pvList.Items...) + + return result +} + func AllPersistentVolumes(contextId *string) utils.K8sWorkloadResult { result := []core.PersistentVolume{} diff --git a/kubernetes/utils.go b/kubernetes/utils.go index 9e459c4..c6a2483 100644 --- a/kubernetes/utils.go +++ b/kubernetes/utils.go @@ -444,7 +444,13 @@ func IsDeploymentInstalled(namespaceName string, name string) (string, error) { return "", err } - return strings.Split(ownDeployment.Spec.Template.Spec.Containers[0].Image, ":")[1], nil + result := "" + split := strings.Split(ownDeployment.Spec.Template.Spec.Containers[0].Image, ":") + if len(split) > 1 { + result = split[1] + } + + return result, nil } func IsDaemonSetInstalled(namespaceName string, name string) (string, error) { @@ -453,7 +459,13 @@ func IsDaemonSetInstalled(namespaceName string, name string) (string, error) { return "", err } - return strings.Split(ownDaemonset.Spec.Template.Spec.Containers[0].Image, ":")[1], nil + result := "" + split := strings.Split(ownDaemonset.Spec.Template.Spec.Containers[0].Image, ":") + if len(split) > 1 { + result = split[1] + } + + return result, nil } // TAKEN FROM Kubernetes apimachineryv0.25.1 @@ -643,7 +655,11 @@ func GuessClusterProvider(contextId *string) (dtos.KubernetesProvider, error) { func GuessCluserProviderFromNodeList(nodes *v1.NodeList) (dtos.KubernetesProvider, error) { for _, node := range nodes.Items { - labelsAndAnnotations := utils.MergeMaps(node.GetLabels(), node.GetAnnotations()) + nodeInfo := map[string]string{} + nodeInfo["kubeProxyVersion"] = node.Status.NodeInfo.KubeProxyVersion + nodeInfo["kubeletVersion"] = node.Status.NodeInfo.KubeletVersion + + labelsAndAnnotations := utils.MergeMaps(node.GetLabels(), node.GetAnnotations(), nodeInfo) if LabelsContain(labelsAndAnnotations, "eks.amazonaws.com/") { return dtos.EKS, nil @@ -679,7 +695,7 @@ func GuessCluserProviderFromNodeList(nodes *v1.NodeList) (dtos.KubernetesProvide return dtos.MINIKUBE, nil } else if LabelsContain(labelsAndAnnotations, "io.k8s.sigs.kind/role") { return dtos.KIND, nil - } else if LabelsContain(labelsAndAnnotations, "civo/") { + } else if LabelsContain(labelsAndAnnotations, "civo-node-pool") { return dtos.CIVO, nil } else if LabelsContain(labelsAndAnnotations, "giantswarm.io/") { return dtos.GIANTSWARM, nil @@ -691,6 +707,8 @@ func GuessCluserProviderFromNodeList(nodes *v1.NodeList) (dtos.KubernetesProvide return dtos.HUAWEI, nil } else if LabelsContain(labelsAndAnnotations, "nirmata.io") { return dtos.NIRMATA, nil + } else if LabelsContain(labelsAndAnnotations, "-CCE") || ImagesContain(node.Status.Images, "cce-addons") { + return dtos.OTC, nil } else if LabelsContain(labelsAndAnnotations, "platform9.com/role") { return dtos.PF9, nil } else if LabelsContain(labelsAndAnnotations, "nks.netapp.io") { @@ -717,6 +735,17 @@ func GuessCluserProviderFromNodeList(nodes *v1.NodeList) (dtos.KubernetesProvide return dtos.UNKNOWN, nil } +func ImagesContain(images []v1.ContainerImage, str string) bool { + for _, image := range images { + for _, name := range image.Names { + if strings.Contains(name, str) { + return true + } + } + } + return false +} + func LabelsContain(labels map[string]string, str string) bool { // Keys EQUAL if _, ok := labels[strings.ToLower(str)]; ok { @@ -842,15 +871,20 @@ const ( ) type SystemCheckEntry struct { - CheckName string `json:"checkName"` - Status SystemCheckStatus `json:"status"` - Message string `json:"message"` - InstallPattern string `json:"installPattern"` - UninstallPattern string `json:"uninstallPattern"` - IsRequired bool `json:"isRequired"` + CheckName string `json:"checkName"` + Status SystemCheckStatus `json:"status"` + Message string `json:"message"` + Description string `json:"description"` + InstallPattern string `json:"installPattern"` + UpgradePattern string `json:"upgradePattern"` + UninstallPattern string `json:"uninstallPattern"` + IsRequired bool `json:"isRequired"` + WantsToBeInstalled bool `json:"wantsToBeInstalled"` + VersionInstalled string `json:"versionInstalled"` + VersionAvailable string `json:"versionAvailable"` } -func CreateSystemCheckEntry(checkName string, alreadyInstalled bool, message string, isRequired bool) SystemCheckEntry { +func CreateSystemCheckEntry(checkName string, alreadyInstalled bool, message string, description string, isRequired bool, wantsToBeInstalled bool, versionInstalled string, versionAvailable string) SystemCheckEntry { status := UNKNOWN_STATUS if alreadyInstalled { status = INSTALLED @@ -858,10 +892,14 @@ func CreateSystemCheckEntry(checkName string, alreadyInstalled bool, message str status = NOT_INSTALLED } return SystemCheckEntry{ - CheckName: checkName, - Status: status, - Message: message, - IsRequired: isRequired, + CheckName: checkName, + Status: status, + Message: message, + Description: description, + IsRequired: isRequired, + WantsToBeInstalled: wantsToBeInstalled, + VersionInstalled: versionInstalled, + VersionAvailable: versionAvailable, } } @@ -920,38 +958,40 @@ func SystemCheck() []SystemCheckEntry { // check internet access inetResult, inetErr := utils.CheckInternetAccess() inetMsg := StatusMessage(inetErr, "Check your internet connection.", "Internet access works.") - result = append(result, CreateSystemCheckEntry("Internet Access", inetResult, inetMsg, true)) + result = append(result, CreateSystemCheckEntry("Internet Access", inetResult, inetMsg, "", true, false, "", "")) // check for kubectl kubectlResult, kubectlOutput, kubectlErr := utils.IsKubectlInstalled() kubeCtlMsg := StatusMessage(kubectlErr, "Plase install kubectl (https://kubernetes.io/docs/tasks/tools/) on your system to proceed.", kubectlOutput) - result = append(result, CreateSystemCheckEntry("kubectl", kubectlResult, kubeCtlMsg, true)) + result = append(result, CreateSystemCheckEntry("kubectl", kubectlResult, kubeCtlMsg, "", true, false, "", "")) // check kubernetes version kubernetesVersion := KubernetesVersion(nil) kubernetesVersionResult := kubernetesVersion != nil kubernetesVersionMsg := StatusMessage(kubectlErr, "Cannot determin version of kubernetes.", fmt.Sprintf("Version: %s\nPlatform: %s", kubernetesVersion.String(), kubernetesVersion.Platform)) - result = append(result, CreateSystemCheckEntry("Kubernetes Version", kubernetesVersionResult, kubernetesVersionMsg, true)) + result = append(result, CreateSystemCheckEntry("Kubernetes Version", kubernetesVersionResult, kubernetesVersionMsg, "", true, false, kubernetesVersion.String(), "")) // check for ingresscontroller ingressType, ingressTypeErr := DetermineIngressControllerType(nil) ingressMsg := StatusMessage(ingressTypeErr, "Cannot determin ingress controller type.", ingressType.String()) - result = append(result, CreateSystemCheckEntry("Ingress Controller", ingressTypeErr == nil, ingressMsg, false)) + ingressDescription := "Installs a traefik ingress controller to handle traffic from outside the cluster and more." + result = append(result, CreateSystemCheckEntry("Ingress Controller", ingressTypeErr == nil, ingressMsg, ingressDescription, false, true, "", "")) // check for metrics server metricsResult, metricsVersion, metricsErr := IsMetricsServerAvailable(nil) metricsMsg := 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) - result = append(result, CreateSystemCheckEntry("Metrics Server", metricsResult, metricsMsg, true)) + metricsDescription := "Maintained by Kubernetes-SIGs, handles metrics for built-in autoscaling pipelines." + result = append(result, CreateSystemCheckEntry("Metrics Server", metricsResult, metricsMsg, metricsDescription, true, true, metricsVersion, "")) // check for helm helmResult, helmOutput, helmErr := utils.IsHelmInstalled() helmMsg := StatusMessage(helmErr, "Plase install helm (https://helm.sh/docs/intro/install/) on your system to proceed.", helmOutput) - result = append(result, CreateSystemCheckEntry("Helm", helmResult, helmMsg, true)) + result = append(result, CreateSystemCheckEntry("Helm", helmResult, helmMsg, "", true, false, helmOutput, "")) // check cluster provider clusterProvOutput, clusterProvErr := GuessClusterProvider(nil) clusterProviderMsg := StatusMessage(clusterProvErr, "We could not determine the provider of this cluster.", string(clusterProvOutput)) - result = append(result, CreateSystemCheckEntry("Cluster Provider", clusterProvErr == nil, clusterProviderMsg, false)) + result = append(result, CreateSystemCheckEntry("Cluster Provider", clusterProvErr == nil, clusterProviderMsg, "", false, false, "", "")) // API Versions apiVerResult, apiVerErr := ApiVersions(nil) @@ -961,7 +1001,7 @@ func SystemCheck() []SystemCheckEntry { } apiVersStr = strings.TrimRight(apiVersStr, "\n\r") apiVersMsg := StatusMessage(apiVerErr, "Metrics Server might be missing. Install the metrics server and try again.", apiVersStr) - result = append(result, CreateSystemCheckEntry("API Versions", len(apiVerResult) > 0, apiVersMsg, true)) + result = append(result, CreateSystemCheckEntry("API Versions", len(apiVerResult) > 0, apiVersMsg, "", true, false, "", "")) // check cluster provider countryResult, countryErr := utils.GuessClusterCountry() @@ -970,7 +1010,7 @@ func SystemCheck() []SystemCheckEntry { countryName = countryResult.Name } countryMsg := StatusMessage(countryErr, "We could not determine the location of the cluster.", countryName) - result = append(result, CreateSystemCheckEntry("Cluster Country", countryErr == nil, countryMsg, false)) + result = append(result, CreateSystemCheckEntry("Cluster Country", countryErr == nil, countryMsg, "", false, false, "", "")) lbName := "LoadBalancer IPs/Hosts" loadbalancerIps := GetClusterExternalIps(nil) @@ -978,7 +1018,7 @@ func SystemCheck() []SystemCheckEntry { if len(loadbalancerIps) == 0 { lbIpsMsg = "No external IPs/Hosts.\nMaybe you don't have TREAFIK or NGINX ingress controller installed." } - result = append(result, CreateSystemCheckEntry(lbName, len(loadbalancerIps) > 0, lbIpsMsg, false)) + result = append(result, CreateSystemCheckEntry(lbName, len(loadbalancerIps) > 0, lbIpsMsg, "", false, false, "", "")) return result } diff --git a/punq-dev.json b/punq-dev.json index fcd5413..c579339 100644 --- a/punq-dev.json +++ b/punq-dev.json @@ -1,14 +1,14 @@ { - "version": "1.5.0-develop.28", + "version": "1.5.0-develop.57", "license": "MIT", "homepage": "https://punq.dev", "bin": "punq-dev.exe", - "pre_install": "Rename-Item \"$dir\\punq-dev-v1.5.0-develop.28-windows-amd64\" punq-dev.exe", + "pre_install": "Rename-Item \"$dir\\punq-dev-v1.5.0-develop.57-windows-amd64\" punq-dev.exe", "description": "A slim open-source workload manager for Kubernetes with team collaboration, WebApp, and CLI.", "architecture": { "64bit": { - "url": "https://github.com/mogenius/punq/releases/download/v1.5.0-develop.28/punq-v1.5.0-develop.28-windows-amd64", - "hash": "04e92d80bdf24f0edd4b1e1f1df863617883a5d2e0c3b0b8611aada9c70b8e16" + "url": "https://github.com/mogenius/punq/releases/download/v1.5.0-develop.57/punq-v1.5.0-develop.57-windows-amd64", + "hash": "9e048121e036634f911c7c4515e67c28ad0874f3f190f567840fce8537a48614" } } } diff --git a/structs/command.go b/structs/command.go index 329ab32..83cda87 100644 --- a/structs/command.go +++ b/structs/command.go @@ -10,30 +10,31 @@ import ( ) type Command struct { - Id string `json:"id"` - JobId string `json:"jobId"` - ProjectId string `json:"projectId"` - NamespaceId *string `json:"namespaceId,omitempty"` - ServiceId *string `json:"serviceId,omitempty"` - Title string `json:"title"` - Message string `json:"message,omitempty"` - StartedAt string `json:"startedAt"` - State string `json:"state"` - DurationMs int64 `json:"durationMs"` - MustSucceed bool `json:"mustSucceed"` - ReportToNotificationSvc bool `json:"reportToNotificationService"` - IgnoreError bool `json:"ignoreError"` + Id string `json:"id"` + JobId string `json:"jobId"` + ProjectId string `json:"projectId"` + NamespaceId *string `json:"namespaceId,omitempty"` + ServiceId *string `json:"serviceId,omitempty"` + Title string `json:"title"` + Message string `json:"message,omitempty"` + StartedAt string `json:"startedAt"` + State JobStateEnum `json:"state"` + DurationMs int64 `json:"durationMs"` + MustSucceed bool `json:"mustSucceed"` + ReportToNotificationSvc bool `json:"reportToNotificationService"` + IgnoreError bool `json:"ignoreError"` + BuildId int `json:"buildId,omitempty"` Started time.Time } -func ExecuteBashCommandSilent(title string, shellCmd string) { +func ExecuteShellCommandSilent(title string, shellCmd string) { var err error - _, err = utils.RunOnLocalShell(shellCmd).Output() + output, err := utils.RunOnLocalShell(shellCmd).Output() if exitErr, ok := err.(*exec.ExitError); ok { exitCode := exitErr.ExitCode() errorMsg := string(exitErr.Stderr) logger.Log.Error(shellCmd) - logger.Log.Errorf("%d: %s", exitCode, errorMsg) + logger.Log.Errorf("ExitCode: %d - Error: '%s' -> Output: '%s'", exitCode, errorMsg, string(output)) } else if err != nil { logger.Log.Errorf("ERROR: '%s': %s\n", title, err.Error()) } else { @@ -43,10 +44,10 @@ func ExecuteBashCommandSilent(title string, shellCmd string) { } } -func ExecuteBashCommandWithResponse(title string, shellCmd string) string { +func ExecuteShellCommandWithResponse(title string, shellCmd string) string { var err error var returnStr []byte - _, err = utils.RunOnLocalShell(shellCmd).Output() + returnStr, err = utils.RunOnLocalShell(shellCmd).Output() if exitErr, ok := err.(*exec.ExitError); ok { exitCode := exitErr.ExitCode() errorMsg := string(exitErr.Stderr) diff --git a/structs/enums.go b/structs/enums.go new file mode 100644 index 0000000..3c872a4 --- /dev/null +++ b/structs/enums.go @@ -0,0 +1,12 @@ +package structs + +type JobStateEnum string + +const ( + JobStateFailed JobStateEnum = "FAILED" + JobStateSucceeded JobStateEnum = "SUCCEEDED" + JobStateStarted JobStateEnum = "STARTED" + JobStatePending JobStateEnum = "PENDING" + JobStateCanceled JobStateEnum = "CANCELED" + JobStateTimeout JobStateEnum = "TIMEOUT" +) diff --git a/utils/format.go b/utils/format.go index 0da6799..16b9e43 100644 --- a/utils/format.go +++ b/utils/format.go @@ -123,6 +123,14 @@ func NanoId() string { return id() } +func NanoIdSmallLowerCase() string { + id, err := nanoid.Custom("abcdefghijklmnopqrstuvwxyz1234567890", 10) + if err != nil { + logger.Log.Error(err) + } + return id() +} + func NanoIdExtraLong() string { id, err := nanoid.Custom("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 21) if err != nil { @@ -230,19 +238,16 @@ func HumanDuration(d time.Duration) string { return fmt.Sprintf("%dy", int(hours/24/365)) } -func MergeMaps(map1, map2 map[string]string) map[string]string { +func MergeMaps(maps ...map[string]string) map[string]string { resultMap := make(map[string]string) - for key, value := range map1 { - resultMap[key] = value - } - - // Add all elements from the second map, this could potentially overwrite - // values from the first map if there are matching keys. - for key, value := range map2 { - resultMap[key] = value + // Iterate over the slice of maps + for _, m := range maps { + // Add all elements from each map, potentially overwriting + for key, value := range m { + resultMap[key] = value + } } - return resultMap } diff --git a/utils/parse-yaml.go b/utils/parse-yaml.go index 2bba9bc..79ccd35 100644 --- a/utils/parse-yaml.go +++ b/utils/parse-yaml.go @@ -322,38 +322,6 @@ func InitPunqService() core.Service { return app } -func InitUpgradeConfigMap() core.ConfigMap { - yaml, err := YamlTemplatesFolder.ReadFile("yaml-templates/upgrade-configmap.yaml") - if err != nil { - panic(err.Error()) - } - - s := json.NewYAMLSerializer(json.DefaultMetaFactory, scheme.Scheme, scheme.Scheme) - - var app core.ConfigMap - _, _, err = s.Decode(yaml, nil, &app) - if err != nil { - panic(err) - } - return app -} - -func InitUpgradeJob() v1job.Job { - yaml, err := YamlTemplatesFolder.ReadFile("yaml-templates/upgrade-job.yaml") - if err != nil { - panic(err.Error()) - } - - s := json.NewYAMLSerializer(json.DefaultMetaFactory, scheme.Scheme, scheme.Scheme) - - var app v1job.Job - _, _, err = s.Decode(yaml, nil, &app) - if err != nil { - panic(err) - } - return app -} - func InitVolumeAttachmentYaml() string { yaml, err := YamlTemplatesFolder.ReadFile("yaml-templates/volumeattachment.yaml") if err != nil { diff --git a/utils/utils.go b/utils/utils.go index fcafcd5..994a413 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -265,13 +265,13 @@ func OpenBrowser(url string) { func RunOnLocalShell(cmd string) *exec.Cmd { switch runtime.GOOS { case "linux": - return exec.Command("/bin/bash", "-c", cmd) + return exec.Command("/bin/sh", "-c", cmd) case "windows": return exec.Command("cmd", "/C", cmd) case "darwin": return exec.Command("/bin/zsh", "-c", cmd) default: - return exec.Command("/bin/bash", "-c", cmd) + return exec.Command("/bin/sh", "-c", cmd) } } diff --git a/utils/yaml-templates/deployment.yaml b/utils/yaml-templates/deployment.yaml index e87d212..f50d572 100644 --- a/utils/yaml-templates/deployment.yaml +++ b/utils/yaml-templates/deployment.yaml @@ -26,7 +26,7 @@ spec: # topologyKey: kubernetes.io/hostname containers: - name: mo-default-gateway - image: ghcr.io/mogenius/mo-build-backend:latest + image: ports: - containerPort: 1337 resources: diff --git a/utils/yaml-templates/upgrade-configmap.yaml b/utils/yaml-templates/upgrade-configmap.yaml deleted file mode 100644 index 0b6ab65..0000000 --- a/utils/yaml-templates/upgrade-configmap.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - labels: - app.kubernetes.io/managed-by: Helm - name: updater-cm -data: - values.command: | - # helm repo add mogenius https://helm.mogenius.com/public - # helm repo update - # helm upgrade mogenius mogenius/mogenius-platform -n default --set global.cluster_name="gcp1" \ - # --set global.api_key="mo_5a7c89c8-2386-4216-8643-e1cbc4b3f48b_osrhrjjvsq6qelkrdqaw" \ - # --set global.namespace="mogenius" \ - # --set k8smanager.enabled=true \ - # --set metrics.enabled=false \ - # --set traffic-collector.enabled=true \ - # --set pod-stats-collector.enabled=true \ - # --set ingress-nginx.enabled=true \ - # --set ingress-nginx.defaultBackend.image.registry=cinaq \ - # --set ingress-nginx.defaultBackend.image.image=default-backend \ - # --set ingress-nginx.defaultBackend.image.tag=1.2 \ - # --set ingress-nginx.defaultBackend.enabled=true \ - # --set certmanager.enabled=true \ - # --set cert-manager.startupapicheck.enabled=false \ - # --set certmanager.namespace="cert-manager" \ - # --set cert-manager.namespace=cert-manager \ - # --set cert-manager.installCRDs=true \ No newline at end of file diff --git a/utils/yaml-templates/upgrade-job.yaml b/utils/yaml-templates/upgrade-job.yaml deleted file mode 100644 index d9a5b42..0000000 --- a/utils/yaml-templates/upgrade-job.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: mo-updater -spec: - backoffLimit: 4 - completionMode: NonIndexed - completions: 1 - parallelism: 1 - template: - spec: - volumes: - - name: updater-cm - configMap: - name: updater-cm - items: - - key: values.command - path: values.command - containers: - - image: ghcr.io/mogenius/mogenius-updater:latest - imagePullPolicy: Always - name: mo-updater - volumeMounts: - - mountPath: /kubeconfig - readOnly: true - name: updater-cm - resources: {} - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - restartPolicy: OnFailure - schedulerName: default-scheduler - serviceAccount: mogenius-k8s-manager-service-account-app - serviceAccountName: mogenius-k8s-manager-service-account-app - securityContext: - runAsNonRoot: false - seccompProfile: - type: RuntimeDefault - terminationGracePeriodSeconds: 30 \ No newline at end of file