Skip to content

Commit

Permalink
feat: Completion of cache pkg rework. Added cache purge command.
Browse files Browse the repository at this point in the history
Signed-off-by: Matthis Holleville <matthish29@gmail.com>
  • Loading branch information
matthisholleville committed Nov 13, 2023
1 parent 210e43c commit 9bd38c4
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 56 deletions.
8 changes: 6 additions & 2 deletions cmd/cache/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,21 @@ var (

// addCmd represents the add command
var addCmd = &cobra.Command{
Use: "add",
Use: "add [cache type]",
Short: "Add a remote cache",
Long: `This command allows you to add a remote cache to store the results of an analysis.
The supported cache types are:
- Azure Blob storage
- Google Cloud storage
- S3`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
color.Red("Error: Please provide a value for cache types. Run k8sgpt cache add --help")
os.Exit(1)
}
fmt.Println(color.YellowString("Adding remote based cache"))
cacheType := args[0]
remoteCache, err := cache.NewCacheProvider(cacheType, bucketname, region, storageAccount, containerName, projectId, false)
remoteCache, err := cache.NewCacheProvider(cacheType, bucketname, region, storageAccount, containerName, projectId)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
Expand Down
54 changes: 54 additions & 0 deletions cmd/cache/purge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
Copyright 2023 The K8sGPT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cache

import (
"fmt"
"os"

"github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
"github.com/spf13/cobra"
)

var purgeCmd = &cobra.Command{
Use: "purge [object name]",
Short: "Purge a remote cache",
Long: "This command allows you to delete/purge one object from the cache",
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
color.Red("Error: Please provide a value for object name. Run k8sgpt cache purge --help")
os.Exit(1)
}
objectKey := args[0]
fmt.Println(color.YellowString("Purging a remote cache."))
c, err := cache.GetCacheConfiguration(false)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}

err = c.Remove(objectKey)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
fmt.Println(color.GreenString("Object deleted."))
},
}

func init() {
CacheCmd.AddCommand(purgeCmd)
}
20 changes: 16 additions & 4 deletions pkg/cache/azuresa_based.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
)

// Generate ICache implementation
Expand All @@ -24,8 +25,8 @@ type AzureCacheConfiguration struct {
ContainerName string `mapstructure:"container" yaml:"container,omitempty"`
}

func (s *AzureCache) Configure(cacheInfo CacheProvider, noCache bool) error {
ctx := context.Background()
func (s *AzureCache) Configure(cacheInfo CacheProvider) error {
s.ctx = context.Background()
if cacheInfo.Azure.ContainerName == "" {
log.Fatal("Azure Container name not configured")
}
Expand All @@ -44,7 +45,7 @@ func (s *AzureCache) Configure(cacheInfo CacheProvider, noCache bool) error {
log.Fatal(err)
}
// Try to create the blob container
_, err = client.CreateContainer(ctx, cacheInfo.Azure.ContainerName, nil)
_, err = client.CreateContainer(s.ctx, cacheInfo.Azure.ContainerName, nil)
if err != nil {
// TODO: Maybe there is a better way to check this?
// docs: https://pkg.go.dev/github.com/Azure/azure-storage-blob-go/azblob
Expand All @@ -56,7 +57,6 @@ func (s *AzureCache) Configure(cacheInfo CacheProvider, noCache bool) error {
}
s.containerName = cacheInfo.Azure.ContainerName
s.session = client
s.noCache = noCache

return nil

Expand Down Expand Up @@ -112,6 +112,14 @@ func (s *AzureCache) List() ([]CacheObjectDetails, error) {
return files, nil
}

func (s *AzureCache) Remove(key string) error {
_, err := s.session.DeleteBlob(s.ctx, s.containerName, key, &blob.DeleteOptions{})
if err != nil {
return err
}
return nil
}

func (s *AzureCache) Exists(key string) bool {
// Check if the object exists in the blob storage
pager := s.session.NewListBlobsFlatPager(s.containerName, &azblob.ListBlobsFlatOptions{
Expand Down Expand Up @@ -141,3 +149,7 @@ func (s *AzureCache) IsCacheDisabled() bool {
func (s *AzureCache) GetName() string {
return "azure"
}

func (s *AzureCache) DisableCache() {
s.noCache = true
}
72 changes: 42 additions & 30 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cache

import (
"errors"
"fmt"
"reflect"

Expand All @@ -19,16 +20,18 @@ var (
)

type ICache interface {
Configure(cacheInfo CacheProvider, noCache bool) error
Configure(cacheInfo CacheProvider) error
Store(key string, data string) error
Load(key string) (string, error)
List() ([]CacheObjectDetails, error)
Remove(key string) error
Exists(key string) bool
IsCacheDisabled() bool
GetName() string
DisableCache()
}

func New(noCache bool, cacheType string) ICache {
func New(cacheType string) ICache {
for _, t := range types {
if cacheType == t.GetName() {
return t
Expand All @@ -37,8 +40,6 @@ func New(noCache bool, cacheType string) ICache {
return &FileBasedCache{}
}

// CacheProvider is the configuration for the cache provider when using a remote cache

func ParseCacheConfiguration() (CacheProvider, error) {
var cacheInfo CacheProvider
err := viper.UnmarshalKey("cache", &cacheInfo)
Expand All @@ -48,8 +49,7 @@ func ParseCacheConfiguration() (CacheProvider, error) {
return cacheInfo, nil
}

func NewCacheProvider(cacheType, bucketname, region, storageAccount, containerName, projectId string, noCache bool) (CacheProvider, error) {
cache := New(false, cacheType)
func NewCacheProvider(cacheType, bucketname, region, storageAccount, containerName, projectId string) (CacheProvider, error) {
cProvider := CacheProvider{}

switch {
Expand All @@ -64,25 +64,26 @@ func NewCacheProvider(cacheType, bucketname, region, storageAccount, containerNa
cProvider.S3.BucketName = bucketname
cProvider.S3.Region = region
default:
return CacheProvider{}, status.Error(codes.Internal, fmt.Sprintf("%s is not a possible option", cacheType))
return CacheProvider{}, status.Error(codes.Internal, fmt.Sprintf("%s is not a valid option", cacheType))
}

err := cache.Configure(cProvider, noCache)
cache := New(cacheType)
err := cache.Configure(cProvider)
if err != nil {
return CacheProvider{}, err
}
return cProvider, nil
}

// If we have set a remote cache, return the remote cache type
// If we have set a remote cache, return the remote cache configuration
func GetCacheConfiguration(noCache bool) (ICache, error) {
// load remote cache if it is configured
var cache ICache
cacheInfo, err := ParseCacheConfiguration()
if err != nil {
return nil, err
}

var cache ICache

switch {
case !reflect.DeepEqual(cacheInfo.GCS, GCSCacheConfiguration{}):
cache = &GCSCache{}
Expand All @@ -94,39 +95,50 @@ func GetCacheConfiguration(noCache bool) (ICache, error) {
cache = &FileBasedCache{}
}

cache.Configure(cacheInfo, noCache)
cache.Configure(cacheInfo)

return cache, nil
}

func HasAnyConfiguration(cacheInfo CacheProvider) bool {
return !reflect.DeepEqual(cacheInfo.GCS, GCSCacheConfiguration{}) ||
!reflect.DeepEqual(cacheInfo.Azure, AzureCacheConfiguration{}) ||
!reflect.DeepEqual(cacheInfo.S3, S3CacheConfiguration{})
}

func AddRemoteCache(cacheInfo CacheProvider) error {
actualConfig, err := ParseCacheConfiguration()
if err != nil {
return err
}

if HasAnyConfiguration(actualConfig) {
return errors.New("Cache configuration already exist. Please use update method.")
}

viper.Set("cache", cacheInfo)

err := viper.WriteConfig()
err = viper.WriteConfig()
if err != nil {
return err
}
return nil
}

func RemoveRemoteCache() error {
var cacheInfo CacheProvider
err := viper.UnmarshalKey("cache", &cacheInfo)
if err != nil {
return status.Error(codes.Internal, "cache unmarshal")
}

cacheInfo = CacheProvider{}
viper.Set("cache", cacheInfo)
err = viper.WriteConfig()
if err != nil {
return status.Error(codes.Internal, "unable to write config")
}

return nil
// var cacheInfo CacheProvider
// err := viper.UnmarshalKey("cache", &cacheInfo)
// if err != nil {
// return status.Error(codes.Internal, "cache unmarshal")
// }
// if cacheInfo.BucketName == "" && cacheInfo.ContainerName == "" && cacheInfo.StorageAccount == "" {
// return status.Error(codes.Internal, "no remote cache configured")
// }

// cacheInfo = CacheProvider{}
// viper.Set("cache", cacheInfo)
// err = viper.WriteConfig()
// if err != nil {
// return status.Error(codes.Internal, "unable to write config")
// }

// return nil

}
21 changes: 19 additions & 2 deletions pkg/cache/file_based.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ type FileBasedCache struct {
noCache bool
}

func (f *FileBasedCache) Configure(cacheInfo CacheProvider, noCache bool) error {
f.noCache = noCache
func (f *FileBasedCache) Configure(cacheInfo CacheProvider) error {
return nil
}

Expand Down Expand Up @@ -84,6 +83,20 @@ func (*FileBasedCache) Load(key string) (string, error) {
return string(data), nil
}

func (*FileBasedCache) Remove(key string) error {
path, err := xdg.CacheFile(filepath.Join("k8sgpt", key))

if err != nil {
return err
}

if err := os.Remove(path); err != nil {
return err
}

return nil
}

func (*FileBasedCache) Store(key string, data string) error {
path, err := xdg.CacheFile(filepath.Join("k8sgpt", key))

Expand All @@ -97,3 +110,7 @@ func (*FileBasedCache) Store(key string, data string) error {
func (s *FileBasedCache) GetName() string {
return "file"
}

func (s *FileBasedCache) DisableCache() {
s.noCache = true
}
Loading

0 comments on commit 9bd38c4

Please sign in to comment.