-
Notifications
You must be signed in to change notification settings - Fork 0
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
add redis seed #19
add redis seed #19
Changes from 1 commit
dd63fb5
ffae434
5511b7a
38b5505
3b5b0a9
21e4d4f
cb16322
9642a5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright 2024 HUMAN Security. | ||
// Use of this source code is governed by a MIT style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/perimeterx/envite" | ||
"github.com/perimeterx/envite/seed/redis" | ||
) | ||
|
||
// buildRedisSeed is a builder function that constructs a new Redis seed component. | ||
// It takes a byte slice of JSON data as input. | ||
// The function attempts to parse the JSON data into a mongo.SeedConfig struct, which defines the configuration | ||
// for a Redis seed component. If the JSON data is successfully parsed, it then uses this configuration | ||
// to instantiate and return a new MongoDB seed component via the redis.NewSeedComponent function. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MongoDB -> Redis There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
// | ||
// Returns: | ||
// - An envite.Component which is the redis.SeedComponent initialized with the provided configuration. | ||
// - An error if the JSON data cannot be parsed into a redis.SeedConfig struct. | ||
func buildRedisSeed(data []byte, _ flagValues, _ string) (envite.Component, error) { | ||
var config redis.SeedConfig | ||
err := json.Unmarshal(data, &config) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not parse config: %w", err) | ||
} | ||
|
||
return redis.NewSeedComponent(config), nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// Copyright 2024 HUMAN Security. | ||
// Use of this source code is governed by a MIT style | ||
// license that can be found in the LICENSE file. | ||
|
||
package redis | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"github.com/go-redis/redis/v8" | ||
"github.com/perimeterx/envite" | ||
"strconv" | ||
"sync" | ||
"sync/atomic" | ||
"time" | ||
) | ||
|
||
// ComponentType represents the type of the redis seed component. | ||
const ComponentType = "redis seed" | ||
|
||
// SeedComponent is a component for seeding redis with data. | ||
type SeedComponent struct { | ||
lock sync.Mutex | ||
config SeedConfig | ||
status atomic.Value | ||
writer *envite.Writer | ||
} | ||
|
||
// NewSeedComponent creates a new SeedComponent instance. | ||
func NewSeedComponent(config SeedConfig) *SeedComponent { | ||
r := &SeedComponent{config: config} | ||
r.status.Store(envite.ComponentStatusStopped) | ||
return r | ||
} | ||
|
||
func (r *SeedComponent) Type() string { | ||
return ComponentType | ||
} | ||
|
||
func (r *SeedComponent) AttachEnvironment(_ context.Context, _ *envite.Environment, writer *envite.Writer) error { | ||
r.writer = writer | ||
return nil | ||
} | ||
|
||
func (r *SeedComponent) Prepare(context.Context) error { | ||
return nil | ||
} | ||
|
||
func (r *SeedComponent) Start(ctx context.Context) error { | ||
r.lock.Lock() | ||
defer r.lock.Unlock() | ||
|
||
r.status.Store(envite.ComponentStatusStarting) | ||
|
||
err := r.seed(ctx) | ||
if err != nil { | ||
r.status.Store(envite.ComponentStatusFailed) | ||
return err | ||
} | ||
|
||
r.status.Store(envite.ComponentStatusFinished) | ||
|
||
return nil | ||
} | ||
|
||
func (r *SeedComponent) seed(ctx context.Context) error { | ||
r.writer.WriteString("starting redis seed") | ||
client, err := r.clientProvider() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = client.FlushAll(ctx).Err() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, hashData := range r.config.Data { | ||
var count int | ||
err = client.HSet(ctx, hashData.Key, hashData.Fields).Err() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
if hashData.TTL > 0 { | ||
err = client.Expire(ctx, hashData.Key, time.Duration(hashData.TTL)*time.Second).Err() | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
count = len(hashData.Fields) | ||
|
||
r.writer.WriteString(fmt.Sprintf( | ||
"inserted %s fields to %s", | ||
r.writer.Color.Green(strconv.Itoa(count)), | ||
r.writer.Color.Green(hashData.Key), | ||
)) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (r *SeedComponent) clientProvider() (*redis.Client, error) { | ||
if r.config.ClientProvider != nil { | ||
return r.config.ClientProvider() | ||
} | ||
|
||
options, err := redis.ParseURL(r.config.Address) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return redis.NewClient(options), nil | ||
} | ||
|
||
func (r *SeedComponent) Stop(context.Context) error { | ||
r.status.Store(envite.ComponentStatusStopped) | ||
return nil | ||
} | ||
|
||
func (r *SeedComponent) Cleanup(context.Context) error { | ||
return nil | ||
} | ||
|
||
func (r *SeedComponent) Status(context.Context) (envite.ComponentStatus, error) { | ||
return r.status.Load().(envite.ComponentStatus), nil | ||
} | ||
|
||
func (r *SeedComponent) Config() any { | ||
return r.config | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Copyright 2024 HUMAN Security. | ||
// Use of this source code is governed by a MIT style | ||
// license that can be found in the LICENSE file. | ||
|
||
package redis | ||
|
||
import "github.com/go-redis/redis/v8" | ||
|
||
// SeedConfig represents the configuration for the redis seed component. | ||
type SeedConfig struct { | ||
// Address - a valid redis server address to connect to | ||
Address string `json:"address,omitempty"` | ||
|
||
// ClientProvider - can be used as an alternative to Address, provides a redis client to use. | ||
// available only via code, not available in config files. | ||
// if both ClientProvider and Address are provided, ClientProvider is used. | ||
ClientProvider func() (*redis.Client, error) `json:"-"` | ||
|
||
// Data - a list of objects, each represents a redis key and its data | ||
Data []*SeedData `json:"data,omitempty"` | ||
} | ||
|
||
// SeedData represents data for a redis hash. | ||
type SeedData struct { | ||
// Key - the name of the redis key | ||
Key string `json:"key,omitempty"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. my only comment on the config is that this structure will only let us support HSet, or at least block the name // SeedConfig represents the configuration for the redis seed component.
type SeedConfig struct {
// Address - a valid redis server address to connect to
Address string `json:"address,omitempty"`
// ClientProvider - can be used as an alternative to Address, provides a redis client to use.
// available only via code, not available in config files.
// if both ClientProvider and Address are provided, ClientProvider is used.
ClientProvider func() (*redis.Client, error) `json:"-"`
SetKeys []*Set `json:"set_keys"`
HSetKeys []*HSet `json:"hset_keys"`
}
type Set struct {
Key string `json:"key"`
Value string `json:"value"`
TTL time.Duration `json:"ttl"`
}
type HSet struct {
Key string `json:"key"`
Values map[string]string `json:"values"`
TTL time.Duration `json:"ttl"`
} this will allow us to add future support for other data types as well without breaking anything There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks good |
||
|
||
// Fields - a map of field names and their values to insert using the redis HSet function: | ||
Fields []string `json:"fields,omitempty"` | ||
|
||
// TTL - the time to live for the key in seconds | ||
TTL int `json:"ttl,omitempty"` | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mongo.SeedConfig -> redis.SeedConfig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍