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

Kr/rewrite #182

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changes/unreleased/Dependency-20230510-114414.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Dependency
body: update to golang 1.19
time: 2023-05-10T11:44:14.094698-05:00
3 changes: 3 additions & 0 deletions .changes/unreleased/Dependency-20230510-114427.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Dependency
body: update github actions for nodejs deprecation
time: 2023-05-10T11:44:27.77425-05:00
3 changes: 3 additions & 0 deletions .changes/unreleased/Deprecated-20230831-194916.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Deprecated
body: Remove the 'account' commands as they have been deprecated
time: 2023-08-31T19:49:16.232024-05:00
3 changes: 3 additions & 0 deletions .changes/unreleased/Refactor-20230831-194854.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Refactor
body: Refactor the entire codebase to be easier to test and update
time: 2023-08-31T19:48:54.653125-05:00
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ jobs:
git tag -f ${{ steps.version.outputs.RELEASE_VERSION }} -m "Cut Release '${{ steps.version.outputs.RELEASE_VERSION }}'"
git push -f origin refs/tags/${{ steps.version.outputs.RELEASE_VERSION }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2.7.0
uses: goreleaser/goreleaser-action@v4.3.0
with:
args: release --rm-dist --release-notes=../.changes/${{ steps.version.outputs.RELEASE_VERSION }}.md
workdir: ./src
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/kubectl-opslevel
src/dist
.idea
.DS_Store
52 changes: 0 additions & 52 deletions src/cmd/account.go

This file was deleted.

21 changes: 5 additions & 16 deletions src/cmd/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,13 @@ import (
"time"

"github.com/opslevel/kubectl-opslevel/common"
"github.com/opslevel/kubectl-opslevel/config"
"github.com/opslevel/kubectl-opslevel/jq"
"github.com/opslevel/kubectl-opslevel/k8sutils"
"github.com/opslevel/kubectl-opslevel/pkg/config"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
collectResyncInterval int
collectBatchSize int
)

var collectCmd = &cobra.Command{
Use: "collect",
Short: "Acts as a kubernetes controller to collect resources for submission to OpsLevel as custom event check payloads",
Expand All @@ -27,20 +21,15 @@ var collectCmd = &cobra.Command{
}

func init() {
rootCmd.AddCommand(collectCmd)
runCmd.AddCommand(collectCmd)

collectCmd.Flags().StringP("integration-url", "i", "", "OpsLevel integration url (OPSLEVEL_INTEGRATION_URL)")
collectCmd.Flags().IntVar(&collectResyncInterval, "resync", 24, "The amount (in hours) before a full resync of the kubernetes cluster happens with OpsLevel. [default: 24]")
collectCmd.Flags().IntVar(&collectBatchSize, "batch", 500, "The max amount of k8s resources to batch process. Helps to speedup initial startup. [default: 500]")

viper.BindEnv("integration-url", "OPSLEVEL_INTEGRATION_URL")
}

func runCollect(cmd *cobra.Command, args []string) {
config, configErr := config.New()
cobra.CheckErr(configErr)

jq.ValidateInstalled()
config := getCfgFile()

integrationUrl := viper.GetString("integration-url")
if len(integrationUrl) <= 0 {
Expand All @@ -49,7 +38,7 @@ func runCollect(cmd *cobra.Command, args []string) {

k8sClient := k8sutils.CreateKubernetesClient()

resync := time.Hour * time.Duration(reconcileResyncInterval)
resync := time.Hour * time.Duration(resyncInterval)
collectQueue := make(chan string, 1)

for i, importConfig := range config.Service.Collect {
Expand All @@ -64,7 +53,7 @@ func runCollect(cmd *cobra.Command, args []string) {
continue
}
callback := createCollectHandler(fmt.Sprintf("service.import[%d]", i), importConfig, collectQueue)
controller := k8sutils.NewController(*gvr, resync, reconcileBatchSize)
controller := k8sutils.NewController(*gvr, resync, batchSize)
controller.OnAdd = callback
controller.OnUpdate = callback
go controller.Start(1)
Expand Down
112 changes: 3 additions & 109 deletions src/cmd/config.go
Original file line number Diff line number Diff line change
@@ -1,99 +1,17 @@
package cmd

import (
"bytes"
"encoding/json"
"fmt"

yaml "gopkg.in/yaml.v3"

"github.com/alecthomas/jsonschema"
"github.com/opslevel/kubectl-opslevel/config"
"github.com/opslevel/kubectl-opslevel/pkg/config"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// Make sure we only use spaces inside of these samples
var configSimple = []byte(`#Simple Opslevel CLI Config
version: "1.2.0"
service:
import:
- selector: # This limits what data we look at in Kubernetes
apiVersion: apps/v1 # only supports resources found in 'kubectl api-resources --verbs="get,list"'
kind: Deployment
excludes: # filters out resources if any expression returns truthy
- .metadata.namespace == "kube-system"
- .metadata.annotations."opslevel.com/ignore"
opslevel: # This is how you map your kubernetes data to opslevel service
name: .metadata.name
owner: .metadata.namespace
aliases: # This are how we identify the services again during reconciliation - please make sure they are very unique
- '"k8s:\(.metadata.name)-\(.metadata.namespace)"'
tags:
assign: # tag with the same key name but with a different value will be updated on the service
- '{"imported": "kubectl-opslevel"}'
- .metadata.labels
create: # tag with the same key name but with a different value with be added to the service
- '{"environment": .spec.template.metadata.labels.environment}'
collect:
- selector: # This limits what data we look at in Kubernetes
apiVersion: apps/v1 # only supports resources found in 'kubectl api-resources --verbs="get,list"'
kind: Deployment
excludes: # filters out resources if any expression returns truthy
- .metadata.namespace == "kube-system"
- .metadata.annotations."opslevel.com/ignore"
`)

var configSample = []byte(`#Sample Opslevel CLI Config
version: "1.2.0"
service:
import:
- selector: # This limits what data we look at in Kubernetes
apiVersion: apps/v1 # only supports resources found in 'kubectl api-resources --verbs="get,list"'
kind: Deployment
excludes: # filters out resources if any expression returns truthy
- .metadata.namespace == "kube-system"
- .metadata.annotations."opslevel.com/ignore"
opslevel: # This is how you map your kubernetes data to opslevel service
name: .metadata.name
description: .metadata.annotations."opslevel.com/description"
owner: .metadata.annotations."opslevel.com/owner"
lifecycle: .metadata.annotations."opslevel.com/lifecycle"
tier: .metadata.annotations."opslevel.com/tier"
product: .metadata.annotations."opslevel.com/product"
language: .metadata.annotations."opslevel.com/language"
framework: .metadata.annotations."opslevel.com/framework"
aliases: # This are how we identify the services again during reconciliation - please make sure they are very unique
- '"k8s:\(.metadata.name)-\(.metadata.namespace)"'
tags:
assign: # tag with the same key name but with a different value will be updated on the service
- '{"imported": "kubectl-opslevel"}'
# find annoations with format: opslevel.com/tags.<key name>: <value>
- '.metadata.annotations | to_entries | map(select(.key | startswith("opslevel.com/tags"))) | map({(.key | split(".")[2]): .value})'
- .metadata.labels
create: # tag with the same key name but with a different value with be added to the service
- '{"environment": .spec.template.metadata.labels.environment}'
tools:
- '{"category": "other", "environment": "production", "displayName": "my-cool-tool", "url": .metadata.annotations."example.com/my-cool-tool"} | if .url then . else empty end'
# find annotations with format: opslevel.com/tools.<category>.<displayname>: <url>
- '.metadata.annotations | to_entries | map(select(.key | startswith("opslevel.com/tools"))) | map({"category": .key | split(".")[2], "displayName": .key | split(".")[3], "url": .value})'
# OR find annotations with format: opslevel.com/tools.<category>.<environment>.<displayname>: <url>
# - '.metadata.annotations | to_entries | map(select(.key | startswith("opslevel.com/tools"))) | map({"category": .key | split(".")[2], "environment": .key | split(".")[3], "displayName": .key | split(".")[4], "url": .value})'
repositories: # attach repositories to the service using the opslevel repo alias - IE github.com:hashicorp/vault
- '{"name": "My Cool Repo", "directory": "/", "repo": .metadata.annotations.repo} | if .repo then . else empty end'
# if just the alias is returned as a single string we'll build the name for you and set the directory to "/"
- .metadata.annotations.repo
# find annotations with format: opslevel.com/repo.<displayname>.<repo.subpath.dots.turned.to.forwardslash>: <opslevel repo alias>
- '.metadata.annotations | to_entries | map(select(.key | startswith("opslevel.com/repos"))) | map({"name": .key | split(".")[2], "directory": .key | split(".")[3:] | join("/"), "repo": .value})'
collect:
- selector: # This limits what data we look at in Kubernetes
apiVersion: apps/v1 # only supports resources found in 'kubectl api-resources --verbs="get,list"'
kind: Deployment
excludes: # filters out resources if any expression returns truthy
- .metadata.namespace == "kube-system"
- .metadata.annotations."opslevel.com/ignore"
`)

var configCmd = &cobra.Command{
Use: "config",
Short: "Commands for working with the opslevel configuration",
Expand All @@ -117,8 +35,7 @@ var configViewCmd = &cobra.Command{
Short: "Print the final configuration result",
Long: "Print the final configuration after loading all the overrides and defaults",
Run: func(cmd *cobra.Command, args []string) {
conf, err := config.New()
cobra.CheckErr(err)
conf := getCfgFile()
output, err2 := yaml.Marshal(conf)
cobra.CheckErr(err2)
fmt.Println(string(output))
Expand All @@ -130,7 +47,7 @@ var configSampleCmd = &cobra.Command{
Short: "Print a sample config file",
Long: "Print a sample config file which could be used",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(getSample(viper.GetBool("simple")))
fmt.Println(config.GetSample(viper.GetBool("simple")))
},
}

Expand All @@ -145,26 +62,3 @@ func init() {
configSampleCmd.Flags().Bool("simple", false, "Adjust the sample config to a bit simpler")
viper.BindPFlags(configSampleCmd.Flags())
}

func getSample(simple bool) string {
var sample []byte
if simple == true {
sample = configSimple
} else {
sample = configSample
}
// we use yaml unmarshal to prove that the samples are valid yaml
var nodes yaml.Node
unmarshalErr := yaml.Unmarshal(sample, &nodes)
if unmarshalErr != nil {
return unmarshalErr.Error()
}
var b bytes.Buffer
yamlEncoder := yaml.NewEncoder(&b)
yamlEncoder.SetIndent(2)
encodeErr := yamlEncoder.Encode(&nodes)
if encodeErr != nil {
return encodeErr.Error()
}
return string(b.Bytes())
}
9 changes: 2 additions & 7 deletions src/cmd/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"sync"

"github.com/opslevel/kubectl-opslevel/common"
"github.com/opslevel/kubectl-opslevel/config"
"github.com/opslevel/kubectl-opslevel/jq"
"github.com/opslevel/opslevel-go/v2023"

"github.com/rs/zerolog/log"
Expand All @@ -20,14 +18,11 @@ var importCmd = &cobra.Command{
}

func init() {
serviceCmd.AddCommand(importCmd)
rootCmd.AddCommand(importCmd)
}

func runImport(cmd *cobra.Command, args []string) {
config, configErr := config.New()
cobra.CheckErr(configErr)

jq.ValidateInstalled()
config := getCfgFile()

services, servicesErr := common.GetAllServices(config)
cobra.CheckErr(servicesErr)
Expand Down
22 changes: 11 additions & 11 deletions src/cmd/preview.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ import (
"time"

"github.com/opslevel/kubectl-opslevel/common"
"github.com/opslevel/kubectl-opslevel/config"
"github.com/opslevel/kubectl-opslevel/jq"

_ "github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
Expand All @@ -28,7 +25,7 @@ If SAMPLES_COUNT=0 this will print out everything.`,
}

func init() {
serviceCmd.AddCommand(previewCmd)
rootCmd.AddCommand(previewCmd)
}

func runPreview(cmd *cobra.Command, args []string) {
Expand All @@ -39,10 +36,7 @@ func runPreview(cmd *cobra.Command, args []string) {
}
}

config, err := config.New()
cobra.CheckErr(err)

jq.ValidateInstalled()
config := getCfgFile()

services, err2 := common.GetAllServices(config)
cobra.CheckErr(err2)
Expand All @@ -51,7 +45,9 @@ func runPreview(cmd *cobra.Command, args []string) {
samples = servicesCount
}

if IsTextOutput() { fmt.Print("The following data was found in your Kubernetes cluster ...\n\n") }
if IsTextOutput() {
fmt.Print("The following data was found in your Kubernetes cluster ...\n\n")
}
if len(services) == 0 {
fmt.Printf("[]\n")
} else {
Expand All @@ -61,11 +57,15 @@ func runPreview(cmd *cobra.Command, args []string) {
}
fmt.Printf("%s\n", string(prettyJSON))
if samples < servicesCount {
if IsTextOutput() { fmt.Printf("\nShowing %v / %v resources\n", samples, servicesCount) }
if IsTextOutput() {
fmt.Printf("\nShowing %v / %v resources\n", samples, servicesCount)
}
}
}

if IsTextOutput() { fmt.Println("\nIf you're happy with the above data you can reconcile it with OpsLevel by running:\n\n OPSLEVEL_API_TOKEN=XXX kubectl opslevel service import\n\nOtherwise, please adjust the config file and rerun this command") }
if IsTextOutput() {
fmt.Println("\nIf you're happy with the above data you can reconcile it with OpsLevel by running:\n\n OPSLEVEL_API_TOKEN=XXX kubectl opslevel service import\n\nOtherwise, please adjust the config file and rerun this command")
}
}

func sample(data []common.ServiceRegistration, samples int) []common.ServiceRegistration {
Expand Down
Loading
Loading