mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2025-08-17 15:26:37 +00:00
commit
5dcc19038f
@ -1,16 +1,12 @@
|
|||||||
package analyze
|
package analyze
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
|
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analysis"
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analysis"
|
||||||
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -33,53 +29,11 @@ var AnalyzeCmd = &cobra.Command{
|
|||||||
provide you with a list of issues that need to be resolved`,
|
provide you with a list of issues that need to be resolved`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
// get ai configuration
|
|
||||||
var configAI ai.AIConfiguration
|
|
||||||
err := viper.UnmarshalKey("ai", &configAI)
|
|
||||||
if err != nil {
|
|
||||||
color.Red("Error: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var aiProvider ai.AIProvider
|
|
||||||
for _, provider := range configAI.Providers {
|
|
||||||
if backend == provider.Name {
|
|
||||||
aiProvider = provider
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if aiProvider.Name == "" {
|
|
||||||
color.Red("Error: AI provider %s not specified in configuration. Please run k8sgpt auth", backend)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
aiClient := ai.NewClient(aiProvider.Name)
|
|
||||||
if err := aiClient.Configure(aiProvider.Password, aiProvider.Model, language); err != nil {
|
|
||||||
color.Red("Error: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
// Get kubernetes client from viper
|
|
||||||
|
|
||||||
kubecontext := viper.GetString("kubecontext")
|
|
||||||
kubeconfig := viper.GetString("kubeconfig")
|
|
||||||
client, err := kubernetes.NewClient(kubecontext, kubeconfig)
|
|
||||||
if err != nil {
|
|
||||||
color.Red("Error initialising kubernetes client: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnalysisResult configuration
|
// AnalysisResult configuration
|
||||||
config := &analysis.Analysis{
|
config, err := analysis.NewAnalysis(backend, language, filters, namespace, nocache, explain)
|
||||||
Namespace: namespace,
|
if err != nil {
|
||||||
NoCache: nocache,
|
color.Red("Error: %v", err)
|
||||||
Filters: filters,
|
os.Exit(1)
|
||||||
Explain: explain,
|
|
||||||
AIClient: aiClient,
|
|
||||||
Client: client,
|
|
||||||
Context: ctx,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.RunAnalysis()
|
err = config.RunAnalysis()
|
||||||
@ -89,11 +43,6 @@ var AnalyzeCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if explain {
|
if explain {
|
||||||
if len(configAI.Providers) == 0 {
|
|
||||||
color.Red("Error: AI provider not specified in configuration. Please run k8sgpt auth")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := config.GetAIResults(output, anonymize)
|
err := config.GetAIResults(output, anonymize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Red("Error: %v", err)
|
color.Red("Error: %v", err)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/cmd/serve"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@ -53,6 +54,7 @@ func init() {
|
|||||||
rootCmd.AddCommand(filters.FiltersCmd)
|
rootCmd.AddCommand(filters.FiltersCmd)
|
||||||
rootCmd.AddCommand(generate.GenerateCmd)
|
rootCmd.AddCommand(generate.GenerateCmd)
|
||||||
rootCmd.AddCommand(integration.IntegrationCmd)
|
rootCmd.AddCommand(integration.IntegrationCmd)
|
||||||
|
rootCmd.AddCommand(serve.ServeCmd)
|
||||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.yaml)")
|
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.k8sgpt.yaml)")
|
||||||
rootCmd.PersistentFlags().StringVar(&kubecontext, "kubecontext", "", "Kubernetes context to use. Only required if out-of-cluster.")
|
rootCmd.PersistentFlags().StringVar(&kubecontext, "kubecontext", "", "Kubernetes context to use. Only required if out-of-cluster.")
|
||||||
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", kubeconfigPath, "Path to a kubeconfig. Only required if out-of-cluster.")
|
rootCmd.PersistentFlags().StringVar(&kubeconfig, "kubeconfig", kubeconfigPath, "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||||
|
60
cmd/serve/serve.go
Normal file
60
cmd/serve/serve.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package serve
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/fatih/color"
|
||||||
|
k8sgptserver "github.com/k8sgpt-ai/k8sgpt/pkg/server"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
port string
|
||||||
|
backend string
|
||||||
|
token string
|
||||||
|
)
|
||||||
|
|
||||||
|
var ServeCmd = &cobra.Command{
|
||||||
|
Use: "serve",
|
||||||
|
Short: "Runs k8sgpt as a server",
|
||||||
|
Long: `Runs k8sgpt as a server to allow for easy integration with other applications.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
|
backendType := viper.GetString("backend_type")
|
||||||
|
if backendType == "" {
|
||||||
|
color.Red("No backend set. Please run k8sgpt auth")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if backend != "" {
|
||||||
|
backendType = backend
|
||||||
|
}
|
||||||
|
|
||||||
|
token := viper.GetString(fmt.Sprintf("%s_key", backendType))
|
||||||
|
// check if nil
|
||||||
|
if token == "" {
|
||||||
|
color.Red("No %s key set. Please run k8sgpt auth", backendType)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
server := k8sgptserver.Config{
|
||||||
|
Backend: backend,
|
||||||
|
Port: port,
|
||||||
|
Token: token,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := server.Serve()
|
||||||
|
if err != nil {
|
||||||
|
color.Red("Error: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
// override the default backend if a flag is provided
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// add flag for backend
|
||||||
|
ServeCmd.Flags().StringVarP(&port, "port", "p", "8080", "Port to run the server on")
|
||||||
|
ServeCmd.Flags().StringVarP(&backend, "backend", "b", "openai", "Backend AI provider")
|
||||||
|
}
|
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.20
|
|||||||
require (
|
require (
|
||||||
github.com/aquasecurity/trivy-operator v0.13.0
|
github.com/aquasecurity/trivy-operator v0.13.0
|
||||||
github.com/fatih/color v1.15.0
|
github.com/fatih/color v1.15.0
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
github.com/magiconair/properties v1.8.7
|
github.com/magiconair/properties v1.8.7
|
||||||
github.com/mittwald/go-helm-client v0.12.1
|
github.com/mittwald/go-helm-client v0.12.1
|
||||||
github.com/sashabaranov/go-openai v1.7.0
|
github.com/sashabaranov/go-openai v1.7.0
|
||||||
|
1
go.sum
1
go.sum
@ -409,6 +409,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
|||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||||
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -33,6 +34,7 @@ func (a *NoOpAIClient) Parse(ctx context.Context, prompt []string, nocache bool)
|
|||||||
inputKey := strings.Join(prompt, " ")
|
inputKey := strings.Join(prompt, " ")
|
||||||
// Check for cached data
|
// Check for cached data
|
||||||
sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey))
|
sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey))
|
||||||
|
cacheKey := util.GetCacheKey(a.GetName(), sEnc)
|
||||||
|
|
||||||
response, err := a.GetCompletion(ctx, inputKey)
|
response, err := a.GetCompletion(ctx, inputKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,8 +42,8 @@ func (a *NoOpAIClient) Parse(ctx context.Context, prompt []string, nocache bool)
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !viper.IsSet(sEnc) {
|
if !viper.IsSet(cacheKey) {
|
||||||
viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response)))
|
viper.Set(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||||
if err := viper.WriteConfig(); err != nil {
|
if err := viper.WriteConfig(); err != nil {
|
||||||
color.Red("error writing config: %v", err)
|
color.Red("error writing config: %v", err)
|
||||||
return "", nil
|
return "", nil
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/util"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
@ -58,10 +59,11 @@ func (a *OpenAIClient) Parse(ctx context.Context, prompt []string, nocache bool)
|
|||||||
inputKey := strings.Join(prompt, " ")
|
inputKey := strings.Join(prompt, " ")
|
||||||
// Check for cached data
|
// Check for cached data
|
||||||
sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey))
|
sEnc := base64.StdEncoding.EncodeToString([]byte(inputKey))
|
||||||
|
cacheKey := util.GetCacheKey(a.GetName(), sEnc)
|
||||||
// find in viper cache
|
// find in viper cache
|
||||||
if viper.IsSet(sEnc) && !nocache {
|
if viper.IsSet(cacheKey) && !nocache {
|
||||||
// retrieve data from cache
|
// retrieve data from cache
|
||||||
response := viper.GetString(sEnc)
|
response := viper.GetString(cacheKey)
|
||||||
if response == "" {
|
if response == "" {
|
||||||
color.Red("error retrieving cached data")
|
color.Red("error retrieving cached data")
|
||||||
return "", nil
|
return "", nil
|
||||||
@ -79,8 +81,8 @@ func (a *OpenAIClient) Parse(ctx context.Context, prompt []string, nocache bool)
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !viper.IsSet(sEnc) {
|
if !viper.IsSet(cacheKey) || nocache {
|
||||||
viper.Set(sEnc, base64.StdEncoding.EncodeToString([]byte(response)))
|
viper.Set(cacheKey, base64.StdEncoding.EncodeToString([]byte(response)))
|
||||||
if err := viper.WriteConfig(); err != nil {
|
if err := viper.WriteConfig(); err != nil {
|
||||||
color.Red("error writing config: %v", err)
|
color.Red("error writing config: %v", err)
|
||||||
return "", nil
|
return "", nil
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
@ -41,8 +42,61 @@ type JsonOutput struct {
|
|||||||
Results []common.Result `json:"results"`
|
Results []common.Result `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Analysis) RunAnalysis() error {
|
func NewAnalysis(backend string, language string, filters []string, namespace string, noCache bool, explain bool) (*Analysis, error) {
|
||||||
|
var configAI ai.AIConfiguration
|
||||||
|
err := viper.UnmarshalKey("ai", &configAI)
|
||||||
|
if err != nil {
|
||||||
|
color.Red("Error: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(configAI.Providers) == 0 && explain {
|
||||||
|
color.Red("Error: AI provider not specified in configuration. Please run k8sgpt auth")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var aiProvider ai.AIProvider
|
||||||
|
for _, provider := range configAI.Providers {
|
||||||
|
if backend == provider.Name {
|
||||||
|
aiProvider = provider
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if aiProvider.Name == "" {
|
||||||
|
color.Red("Error: AI provider %s not specified in configuration. Please run k8sgpt auth", backend)
|
||||||
|
return nil, errors.New("AI provider not specified in configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
aiClient := ai.NewClient(aiProvider.Name)
|
||||||
|
if err := aiClient.Configure(aiProvider.Password, aiProvider.Model, language); err != nil {
|
||||||
|
color.Red("Error: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
// Get kubernetes client from viper
|
||||||
|
|
||||||
|
kubecontext := viper.GetString("kubecontext")
|
||||||
|
kubeconfig := viper.GetString("kubeconfig")
|
||||||
|
client, err := kubernetes.NewClient(kubecontext, kubeconfig)
|
||||||
|
if err != nil {
|
||||||
|
color.Red("Error initialising kubernetes client: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Analysis{
|
||||||
|
Context: ctx,
|
||||||
|
Filters: filters,
|
||||||
|
Client: client,
|
||||||
|
AIClient: aiClient,
|
||||||
|
Namespace: namespace,
|
||||||
|
NoCache: noCache,
|
||||||
|
Explain: explain,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Analysis) RunAnalysis() error {
|
||||||
activeFilters := viper.GetStringSlice("active_filters")
|
activeFilters := viper.GetStringSlice("active_filters")
|
||||||
|
|
||||||
analyzerMap := analyzer.GetAnalyzerMap()
|
analyzerMap := analyzer.GetAnalyzerMap()
|
||||||
|
104
pkg/server/main.go
Normal file
104
pkg/server/main.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
json "encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/k8sgpt-ai/k8sgpt/pkg/analysis"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Port string
|
||||||
|
Backend string
|
||||||
|
Key string
|
||||||
|
Token string
|
||||||
|
Output string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Health struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Success int `json:"success"`
|
||||||
|
Failure int `json:"failure"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var health = Health{
|
||||||
|
Status: "ok",
|
||||||
|
Success: 0,
|
||||||
|
Failure: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Analysis []analysis.Analysis `json:"analysis"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Config) analyzeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
namespace := r.URL.Query().Get("namespace")
|
||||||
|
explain := getBoolParam(r.URL.Query().Get("explain"))
|
||||||
|
anonymize := getBoolParam(r.URL.Query().Get("anonymize"))
|
||||||
|
nocache := getBoolParam(r.URL.Query().Get("nocache"))
|
||||||
|
language := r.URL.Query().Get("language")
|
||||||
|
|
||||||
|
config, err := analysis.NewAnalysis(s.Backend, language, []string{}, namespace, nocache, explain)
|
||||||
|
if err != nil {
|
||||||
|
health.Failure++
|
||||||
|
fmt.Fprintf(w, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = config.RunAnalysis()
|
||||||
|
if err != nil {
|
||||||
|
color.Red("Error: %v", err)
|
||||||
|
health.Failure++
|
||||||
|
fmt.Fprintf(w, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if explain {
|
||||||
|
err := config.GetAIResults(s.Output, anonymize)
|
||||||
|
if err != nil {
|
||||||
|
color.Red("Error: %v", err)
|
||||||
|
health.Failure++
|
||||||
|
fmt.Fprintf(w, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := config.JsonOutput()
|
||||||
|
if err != nil {
|
||||||
|
color.Red("Error: %v", err)
|
||||||
|
health.Failure++
|
||||||
|
fmt.Fprintf(w, err.Error())
|
||||||
|
}
|
||||||
|
health.Success++
|
||||||
|
fmt.Fprintf(w, string(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Config) Serve() error {
|
||||||
|
http.HandleFunc("/analyze", s.analyzeHandler)
|
||||||
|
http.HandleFunc("/healthz", s.healthzHandler)
|
||||||
|
color.Green("Starting server on port %s", s.Port)
|
||||||
|
err := http.ListenAndServe(":"+s.Port, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error starting server: %s\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Config) healthzHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
js, err := json.MarshalIndent(health, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, string(js))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBoolParam(param string) bool {
|
||||||
|
b, err := strconv.ParseBool(strings.ToLower(param))
|
||||||
|
if err != nil {
|
||||||
|
// Handle error if conversion fails
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
@ -129,3 +129,7 @@ func ReplaceIfMatch(text string, pattern string, replacement string) string {
|
|||||||
}
|
}
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetCacheKey(provider string, sEnc string) string {
|
||||||
|
return fmt.Sprintf("%s-%s", provider, sEnc)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user