Skip to content

Commit dad50ff

Browse files
authored
feat(firehose): enable resource to use same defaults as when created and provide upgrade action (#107)
* feat(firehose): extract default configs into module initialization * feat(firehose): use defaults from firehose output * feat(firehose): add upgrade action
1 parent 43e888f commit dad50ff

File tree

10 files changed

+144
-68
lines changed

10 files changed

+144
-68
lines changed

Diff for: cli/utils.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package cli
33
import (
44
"errors"
55
"fmt"
6-
"io/ioutil"
76
"os"
87
"path/filepath"
98

@@ -22,7 +21,7 @@ const (
2221
type RunEFunc func(cmd *cobra.Command, args []string) error
2322

2423
func parseFile(filePath string, v protoreflect.ProtoMessage) error {
25-
b, err := ioutil.ReadFile(filePath)
24+
b, err := os.ReadFile(filePath)
2625
if err != nil {
2726
return err
2827
}

Diff for: docs/modules/firehose.md

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ The configuration struct for Firehose module looks like:
1818
```
1919
type moduleConfig struct {
2020
State string `json:"state"`
21-
ChartVersion string `json:"chart_version"`
2221
Firehose struct {
2322
Replicas int `json:"replicas"`
2423
KafkaBrokerAddress string `json:"kafka_broker_address"`

Diff for: modules/firehose/config.go

+21-28
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,6 @@ import (
1111
"github.com/odpf/entropy/pkg/helm"
1212
)
1313

14-
const (
15-
defaultNamespace = "firehose"
16-
defaultChartString = "firehose"
17-
defaultVersionString = "0.1.1"
18-
defaultRepositoryString = "https://odpf.github.io/charts/"
19-
defaultImagePullPolicy = "IfNotPresent"
20-
defaultImageRepository = "odpf/firehose"
21-
defaultImageTag = "latest"
22-
)
23-
2414
var (
2515
//go:embed schema/config.json
2616
completeConfigSchema string
@@ -33,11 +23,10 @@ var (
3323
)
3424

3525
type moduleConfig struct {
36-
State string `json:"state"`
37-
ChartVersion string `json:"chart_version"`
38-
StopTime *time.Time `json:"stop_time"`
39-
Telegraf map[string]interface{} `json:"telegraf"`
40-
Firehose struct {
26+
State string `json:"state"`
27+
StopTime *time.Time `json:"stop_time"`
28+
Telegraf map[string]interface{} `json:"telegraf"`
29+
Firehose struct {
4130
Replicas int `json:"replicas"`
4231
KafkaBrokerAddress string `json:"kafka_broker_address"`
4332
KafkaTopic string `json:"kafka_topic"`
@@ -46,25 +35,29 @@ type moduleConfig struct {
4635
} `json:"firehose"`
4736
}
4837

49-
func (mc *moduleConfig) sanitiseAndValidate() error {
38+
func (mc *moduleConfig) validate() error {
5039
if mc.StopTime != nil && mc.StopTime.Before(time.Now()) {
5140
return errors.ErrInvalid.
5241
WithMsgf("value for stop_time must be greater than current time")
5342
}
54-
if mc.ChartVersion == "" {
55-
mc.ChartVersion = defaultVersionString
56-
}
5743
return nil
5844
}
5945

60-
func (mc moduleConfig) GetHelmReleaseConfig(r resource.Resource) *helm.ReleaseConfig {
46+
func (mc moduleConfig) GetHelmReleaseConfig(r resource.Resource) (*helm.ReleaseConfig, error) {
47+
var output Output
48+
err := json.Unmarshal(r.State.Output, &output)
49+
if err != nil {
50+
return nil, errors.ErrInvalid.WithMsgf("invalid output json: %v", err)
51+
}
52+
defaults := output.Defaults
53+
6154
rc := helm.DefaultReleaseConfig()
6255
rc.Name = fmt.Sprintf("%s-%s-firehose", r.Project, r.Name)
63-
rc.Repository = defaultRepositoryString
64-
rc.Chart = defaultChartString
65-
rc.Namespace = defaultNamespace
56+
rc.Repository = defaults.ChartRepository
57+
rc.Chart = defaults.ChartName
58+
rc.Namespace = defaults.Namespace
6659
rc.ForceUpdate = true
67-
rc.Version = mc.ChartVersion
60+
rc.Version = defaults.ChartVersion
6861

6962
fc := mc.Firehose
7063
fc.EnvVariables["SOURCE_KAFKA_BROKERS"] = fc.KafkaBrokerAddress
@@ -75,9 +68,9 @@ func (mc moduleConfig) GetHelmReleaseConfig(r resource.Resource) *helm.ReleaseCo
7568
"replicaCount": mc.Firehose.Replicas,
7669
"firehose": map[string]interface{}{
7770
"image": map[string]interface{}{
78-
"repository": defaultImageRepository,
79-
"pullPolicy": defaultImagePullPolicy,
80-
"tag": defaultImageTag,
71+
"repository": defaults.ImageRepository,
72+
"pullPolicy": defaults.ImagePullPolicy,
73+
"tag": defaults.ImageTag,
8174
},
8275
"config": fc.EnvVariables,
8376
},
@@ -87,7 +80,7 @@ func (mc moduleConfig) GetHelmReleaseConfig(r resource.Resource) *helm.ReleaseCo
8780
}
8881
rc.Values = hv
8982

90-
return rc
83+
return rc, nil
9184
}
9285

9386
func (mc moduleConfig) JSON() []byte {

Diff for: modules/firehose/log.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ func (*firehoseModule) Log(ctx context.Context, res module.ExpandedResource, fil
2626
if filter == nil {
2727
filter = make(map[string]string)
2828
}
29-
filter["app"] = conf.GetHelmReleaseConfig(r).Name
29+
30+
hc, err := conf.GetHelmReleaseConfig(r)
31+
if err != nil {
32+
return nil, err
33+
}
34+
35+
filter["app"] = hc.Name
3036

3137
kubeCl := kube.NewClient(kubeOut.Configs)
32-
logs, err := kubeCl.StreamLogs(ctx, defaultNamespace, filter)
38+
logs, err := kubeCl.StreamLogs(ctx, hc.Namespace, filter)
3339
if err != nil {
3440
return nil, err
3541
}

Diff for: modules/firehose/module.go

+44-6
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import (
99
)
1010

1111
const (
12-
StopAction = "stop"
13-
StartAction = "start"
14-
ScaleAction = "scale"
15-
ResetAction = "reset"
12+
StopAction = "stop"
13+
StartAction = "start"
14+
ScaleAction = "scale"
15+
ResetAction = "reset"
16+
UpgradeAction = "upgrade"
1617
)
1718

1819
const (
@@ -68,10 +69,47 @@ var Module = module.Descriptor{
6869
Description: "Reset firehose kafka consumer group to given timestamp",
6970
ParamSchema: resetActionSchema,
7071
},
72+
{
73+
Name: UpgradeAction,
74+
Description: "Upgrade firehose to current stable version",
75+
},
7176
},
7277
DriverFactory: func(conf json.RawMessage) (module.Driver, error) {
73-
return &firehoseModule{}, nil
78+
fm := firehoseModuleWithDefaultConfigs()
79+
err := json.Unmarshal(conf, fm)
80+
if err != nil {
81+
return nil, err
82+
}
83+
return fm, nil
7484
},
7585
}
7686

77-
type firehoseModule struct{}
87+
type firehoseModule struct {
88+
Config config `json:"config"`
89+
}
90+
91+
type config struct {
92+
ChartRepository string `json:"chart_repository,omitempty"`
93+
ChartName string `json:"chart_name,omitempty"`
94+
ChartVersion string `json:"chart_version,omitempty"`
95+
ImageRepository string `json:"image_repository,omitempty"`
96+
ImageName string `json:"image_name,omitempty"`
97+
ImageTag string `json:"image_tag,omitempty"`
98+
Namespace string `json:"namespace,omitempty"`
99+
ImagePullPolicy string `json:"image_pull_policy,omitempty"`
100+
}
101+
102+
func firehoseModuleWithDefaultConfigs() *firehoseModule {
103+
return &firehoseModule{
104+
config{
105+
ChartRepository: "https://odpf.github.io/charts/",
106+
ChartName: "firehose",
107+
ChartVersion: "0.1.3",
108+
ImageRepository: "odpf/firehose",
109+
ImageName: "firehose",
110+
ImageTag: "latest",
111+
Namespace: "firehose",
112+
ImagePullPolicy: "IfNotPresent",
113+
},
114+
}
115+
}

Diff for: modules/firehose/output.go

+23-6
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import (
1111
)
1212

1313
type Output struct {
14-
Namespace string `json:"namespace"`
15-
ReleaseName string `json:"release_name"`
16-
Pods []kube.Pod `json:"pods"`
14+
Namespace string `json:"namespace,omitempty"`
15+
ReleaseName string `json:"release_name,omitempty"`
16+
Pods []kube.Pod `json:"pods,omitempty"`
17+
Defaults config `json:"defaults,omitempty"`
1718
}
1819

1920
func (out Output) JSON() []byte {
@@ -30,15 +31,26 @@ func (m *firehoseModule) Output(ctx context.Context, res module.ExpandedResource
3031
return nil, errors.ErrInvalid.WithMsgf("invalid config json: %v", err)
3132
}
3233

34+
var output Output
35+
if err := json.Unmarshal(res.Resource.State.Output, &output); err != nil {
36+
return nil, errors.ErrInvalid.WithMsgf("invalid output json: %v", err)
37+
}
38+
3339
pods, err := m.podDetails(ctx, res)
3440
if err != nil {
3541
return nil, err
3642
}
3743

44+
hc, err := conf.GetHelmReleaseConfig(res.Resource)
45+
if err != nil {
46+
return nil, err
47+
}
48+
3849
return Output{
39-
Namespace: conf.GetHelmReleaseConfig(res.Resource).Namespace,
40-
ReleaseName: conf.GetHelmReleaseConfig(res.Resource).Name,
50+
Namespace: hc.Namespace,
51+
ReleaseName: hc.Name,
4152
Pods: pods,
53+
Defaults: output.Defaults,
4254
}.JSON(), nil
4355
}
4456

@@ -55,6 +67,11 @@ func (*firehoseModule) podDetails(ctx context.Context, res module.ExpandedResour
5567
return nil, err
5668
}
5769

70+
hc, err := conf.GetHelmReleaseConfig(r)
71+
if err != nil {
72+
return nil, err
73+
}
74+
5875
kubeCl := kube.NewClient(kubeOut.Configs)
59-
return kubeCl.GetPodDetails(ctx, defaultNamespace, map[string]string{"app": conf.GetHelmReleaseConfig(r).Name})
76+
return kubeCl.GetPodDetails(ctx, hc.Namespace, map[string]string{"app": hc.Name})
6077
}

Diff for: modules/firehose/plan.go

+21-4
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,29 @@ func (m *firehoseModule) Plan(_ context.Context, res module.ExpandedResource, ac
2020
}
2121
}
2222

23-
func (*firehoseModule) planCreate(res module.ExpandedResource, act module.ActionRequest) (*module.Plan, error) {
23+
func (m *firehoseModule) planCreate(res module.ExpandedResource, act module.ActionRequest) (*module.Plan, error) {
2424
var plan module.Plan
2525
r := res.Resource
2626

2727
var reqConf moduleConfig
2828
if err := json.Unmarshal(act.Params, &reqConf); err != nil {
2929
return nil, errors.ErrInvalid.WithMsgf("invalid config json: %v", err)
3030
}
31-
if err := reqConf.sanitiseAndValidate(); err != nil {
31+
if err := reqConf.validate(); err != nil {
3232
return nil, err
3333
}
3434

35+
output := Output{
36+
Defaults: m.Config,
37+
}.JSON()
38+
3539
r.Spec.Configs = reqConf.JSON()
3640
r.State = resource.State{
3741
Status: resource.StatusPending,
3842
ModuleData: moduleData{
3943
PendingSteps: []string{releaseCreate},
4044
}.JSON(),
45+
Output: output,
4146
}
4247

4348
plan.Resource = r
@@ -48,7 +53,7 @@ func (*firehoseModule) planCreate(res module.ExpandedResource, act module.Action
4853
return &plan, nil
4954
}
5055

51-
func (*firehoseModule) planChange(res module.ExpandedResource, act module.ActionRequest) (*module.Plan, error) {
56+
func (m *firehoseModule) planChange(res module.ExpandedResource, act module.ActionRequest) (*module.Plan, error) {
5257
var plan module.Plan
5358
r := res.Resource
5459

@@ -63,7 +68,7 @@ func (*firehoseModule) planChange(res module.ExpandedResource, act module.Action
6368
if err := json.Unmarshal(act.Params, &reqConf); err != nil {
6469
return nil, errors.ErrInvalid.WithMsgf("invalid config json: %v", err)
6570
}
66-
if err := reqConf.sanitiseAndValidate(); err != nil {
71+
if err := reqConf.validate(); err != nil {
6772
return nil, err
6873
}
6974
conf = reqConf
@@ -90,6 +95,18 @@ func (*firehoseModule) planChange(res module.ExpandedResource, act module.Action
9095
case StopAction:
9196
conf.State = stateStopped
9297
plan.Reason = "firehose stopped"
98+
99+
case UpgradeAction:
100+
var output Output
101+
err := json.Unmarshal(res.State.Output, &output)
102+
if err != nil {
103+
return nil, errors.ErrInvalid.WithMsgf("invalid output json: %v", err)
104+
}
105+
106+
output.Defaults = m.Config
107+
res.State.Output = output.JSON()
108+
109+
plan.Reason = "firehose upgraded"
93110
}
94111

95112
r.Spec.Configs = conf.JSON()

Diff for: modules/firehose/plan_test.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func TestFirehoseModule_Plan(t *testing.T) {
2222
Name: "test",
2323
Project: "demo",
2424
Spec: resource.Spec{
25-
Configs: []byte(`{"state":"RUNNING","chart_version":"0.1.1","firehose":{"replicas":1,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
25+
Configs: []byte(`{"state":"RUNNING","firehose":{"replicas":1,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
2626
},
2727
State: resource.State{},
2828
}
@@ -57,11 +57,12 @@ func TestFirehoseModule_Plan(t *testing.T) {
5757
Name: "test",
5858
Project: "demo",
5959
Spec: resource.Spec{
60-
Configs: []byte(`{"state":"RUNNING","chart_version":"0.1.1","stop_time":null,"telegraf":null,"firehose":{"replicas":1,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
60+
Configs: []byte(`{"state":"RUNNING","stop_time":null,"telegraf":null,"firehose":{"replicas":1,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
6161
},
6262
State: resource.State{
6363
Status: resource.StatusPending,
6464
ModuleData: []byte(`{"pending_steps":["release_create"]}`),
65+
Output: []byte(`{"defaults":{}}`),
6566
},
6667
},
6768
Reason: "firehose created",
@@ -90,7 +91,7 @@ func TestFirehoseModule_Plan(t *testing.T) {
9091
Name: "test",
9192
Project: "demo",
9293
Spec: resource.Spec{
93-
Configs: []byte(`{"state":"RUNNING","chart_version":"0.1.1","stop_time":null,"telegraf":null,"firehose":{"replicas":5,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
94+
Configs: []byte(`{"state":"RUNNING","stop_time":null,"telegraf":null,"firehose":{"replicas":5,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
9495
},
9596
State: resource.State{
9697
Status: resource.StatusPending,
@@ -114,7 +115,7 @@ func TestFirehoseModule_Plan(t *testing.T) {
114115
Name: "test",
115116
Project: "demo",
116117
Spec: resource.Spec{
117-
Configs: []byte(`{"state":"RUNNING","chart_version":"0.1.1","stop_time":null,"telegraf":null,"firehose":{"replicas":1,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
118+
Configs: []byte(`{"state":"RUNNING","stop_time":null,"telegraf":null,"firehose":{"replicas":1,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
118119
},
119120
State: resource.State{
120121
Status: resource.StatusPending,
@@ -138,11 +139,12 @@ func TestFirehoseModule_Plan(t *testing.T) {
138139
Name: "test",
139140
Project: "demo",
140141
Spec: resource.Spec{
141-
Configs: []byte(`{"state":"RUNNING","chart_version":"0.1.1","stop_time":"3022-07-13T00:40:14.028016Z","telegraf":null,"firehose":{"replicas":1,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
142+
Configs: []byte(`{"state":"RUNNING","stop_time":"3022-07-13T00:40:14.028016Z","telegraf":null,"firehose":{"replicas":1,"kafka_broker_address":"localhost:9092","kafka_topic":"test-topic","kafka_consumer_id":"test-consumer-id","env_variables":{}}}`),
142143
},
143144
State: resource.State{
144145
Status: resource.StatusPending,
145146
ModuleData: []byte(`{"pending_steps":["release_create"]}`),
147+
Output: []byte(`{"defaults":{}}`),
146148
},
147149
},
148150
ScheduleRunAt: parseTime("3022-07-13T00:40:14.028016Z"),

Diff for: modules/firehose/schema/config.json

-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
],
1212
"default": "RUNNING"
1313
},
14-
"chart_version": {
15-
"type": "string"
16-
},
1714
"stop_time": {
1815
"type": "string",
1916
"format": "date-time"

0 commit comments

Comments
 (0)