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

Feature/insights remote lib #28

Merged
merged 10 commits into from
Nov 6, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.13
go-version: ^1.18

- name: Check out code into the Go module directory
uses: actions/checkout@v2
Expand Down
110 changes: 110 additions & 0 deletions cmd/gatherInCluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package cmd

import (
"encoding/json"
"log"
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/uselagoon/lagoon-facts-app/gatherers"
)

var tokenValue string
var tokenFile string
var insightsRemoteEndpoint string

// gatherCmd represents the gather command
var gatherInClusterCmd = &cobra.Command{
Use: "gather-in-cluster",
Short: "Running this command will invoke the registered gatherers in cluster",
Long: `Running all the registered gatherers will inspect the system and write FACT data back to the Lagoon insights system via insights-remote`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
//get the basic env vars
if argStatic && argDynamic {
log.Fatalf("Cannot use both 'static' and 'dynamic' only gatherers - exiting")
}
},
Run: func(cmd *cobra.Command, args []string) {

if tokenValue == "" {
if tokenFile == "" {
log.Fatal("Either a token or a token file needs to be passed as an argument")
}
var err error
tokenValue, err = getTokenFromFile(tokenFile)
if err != nil {
log.Fatalf("Unable to load token: %v - %v", tokenFile, err.Error())
}
}

//set gatherer type to be static by default
gathererTypeArg := gatherers.GATHERER_TYPE_STATIC
if argDynamic {
gathererTypeArg = gatherers.GATHERER_TYPE_DYNAMIC
}

//run the gatherers...
gathererSlice := gatherers.GetGatherers()

var facts []gatherers.GatheredFact

for _, e := range gathererSlice {
if e.GetGathererCmdType() == gathererTypeArg {
if e.AppliesToEnvironment() {
gatheredFacts, err := e.GatherFacts()
if err != nil {
log.Println(err.Error())
continue
}
for _, f := range gatheredFacts {
if verbose := viper.Get("verbose"); verbose == true {
log.Printf("Registering %s", f.Name)
}
}
facts = append(facts, gatheredFacts...)
}
}
}

if !dryRun {
err := gatherers.WriteFactsToInsightsRemote(tokenValue, facts)
if err != nil {
log.Println(err.Error())
}
}

if dryRun {
if facts != nil {
log.Println("---- Dry run ----")
log.Printf("Would post the follow facts to '%s:%s'", projectName, environmentName)
s, _ := json.MarshalIndent(facts, "", "\t")
log.Println(string(s))
}
}
},
}
bomoko marked this conversation as resolved.
Show resolved Hide resolved

func getTokenFromFile(tokenFile string) (string, error) {
_, err := os.Stat(tokenFile)
if err != nil {
return "", err
}

ba, err := os.ReadFile(tokenFile)
if err != nil {
return "", err
}
return string(ba), nil
}

//var GatherCommand = gatherCmd

func init() {
gatherInClusterCmd.PersistentFlags().StringVarP(&tokenValue, "token", "t", "", "The Lagoon insights remote token")
gatherInClusterCmd.PersistentFlags().StringVarP(&tokenFile, "token-file", "", "/var/run/secrets/lagoon/dynamic/insights-token/INSIGHTS_TOKEN", "Read the Lagoon insights remote token from a file")
gatherInClusterCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "d", false, "run gathers and print to screen without running write methods")
gatherInClusterCmd.PersistentFlags().StringVar(&insightsRemoteEndpoint, "insights-remote-endpoint", "http://lagoon-remote-insights-remote.lagoon.svc/facts", "The Lagoon insights remote endpoint")
viper.BindPFlag("insights-remote-endpoint", gatherInClusterCmd.PersistentFlags().Lookup("insights-remote-endpoint"))
rootCmd.AddCommand(gatherInClusterCmd)
}
3 changes: 1 addition & 2 deletions gatherers/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package gatherers
import (
"context"
"fmt"
"log"

"github.com/machinebox/graphql"
"github.com/uselagoon/lagoon-facts-app/utils"
"golang.org/x/oauth2"
"log"
)

const lagoonAPIEndpoint = "https://api.lagoon.amazeeio.cloud/graphql"
Expand Down
62 changes: 62 additions & 0 deletions gatherers/insights-remote-writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package gatherers

import (
"bytes"
"encoding/json"
"fmt"
"github.com/spf13/viper"
insightRemoteLib "github.com/uselagoon/insights-remote-lib"
"io/ioutil"
"log"
"net/http"
)

func WriteFactsToInsightsRemote(token string, facts []GatheredFact) error {

insightsRemoteFacts := insightRemoteLib.Facts{
Facts: []insightRemoteLib.Fact{},
}

for _, fact := range facts {
f := insightRemoteLib.Fact{
Name: fact.Name,
Value: fact.Value,
Source: fact.Source,
Description: fact.Description,
Category: string(fact.Category),
}

insightsRemoteFacts.Facts = append(insightsRemoteFacts.Facts, f)
}

bodyString, err := json.Marshal(insightsRemoteFacts)
if err != nil {
log.Fatal(err.Error())
}

fmt.Printf("Sending %v fact(s) to insights core\n", len(facts))

serviceEndpoint := viper.GetString("insights-remote-endpoint")
req, _ := http.NewRequest(http.MethodPost, serviceEndpoint, bytes.NewBuffer(bodyString))
req.Header.Set("Authorization", token)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
response, err := client.Do(req)
bomoko marked this conversation as resolved.
Show resolved Hide resolved

if err != nil {
return err
}

if response.StatusCode != 200 {
bodyData, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err.Error())
}

log.Fatalf("There was an error sending the facts to '%s': %v- %v \n", serviceEndpoint, response.StatusCode, string(bodyData))
}

defer response.Body.Close()

return err
}
2 changes: 1 addition & 1 deletion gatherers/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ func LoadYamlConfig(yamlFilePath string) ([]byte, error) {
return []byte{}, err
}
return data, nil
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/uselagoon/lagoon-facts-app

go 1.13
go 1.18

require (
github.com/machinebox/graphql v0.2.2
Expand Down
6 changes: 6 additions & 0 deletions go.work
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
go 1.18

use (
.
insightRemoteLib
)
3 changes: 3 additions & 0 deletions insightRemoteLib/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/uselagoon/insights-remote-lib

go 1.18
21 changes: 21 additions & 0 deletions insightRemoteLib/remote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package insightRemoteLib

type Fact struct {
EnvironmentId string `json:"environment"`
ProjectName string `json:"projectName"`
EnvironmentName string `json:"environmentName"`
Name string `json:"name"`
Value string `json:"value"`
Source string `json:"source"`
Description string `json:"description"`
Type string `json:"type"`
Category string `json:"category"`
Service string `json:"service"`
}

type Facts struct {
EnvironmentId int `json:"environment"`
ProjectName string `json:"projectName"`
EnvironmentName string `json:"environmentName"`
Facts []Fact `json:"facts"`
}