Skip to content

Commit c588a3f

Browse files
committed
Added missing /cmd directory
1 parent 3076c55 commit c588a3f

File tree

6 files changed

+571
-1
lines changed

6 files changed

+571
-1
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@
22
vendor/
33
_output/
44
pod-reaper.iml
5-
pod-reaper

cmd/pod-reaper/app/options.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package app
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
"time"
8+
9+
"k8s.io/apimachinery/pkg/labels"
10+
"k8s.io/apimachinery/pkg/selection"
11+
12+
"github.com/target/pod-reaper/internal/pkg/rules"
13+
)
14+
15+
// environment variable names
16+
const envNamespace = "NAMESPACE"
17+
const envGracePeriod = "GRACE_PERIOD"
18+
const envScheduleCron = "SCHEDULE"
19+
const envRunDuration = "RUN_DURATION"
20+
const envExcludeLabelKey = "EXCLUDE_LABEL_KEY"
21+
const envExcludeLabelValues = "EXCLUDE_LABEL_VALUES"
22+
const envRequireLabelKey = "REQUIRE_LABEL_KEY"
23+
const envRequireLabelValues = "REQUIRE_LABEL_VALUES"
24+
25+
type options struct {
26+
namespace string
27+
gracePeriod *int64
28+
schedule string
29+
runDuration time.Duration
30+
labelExclusion *labels.Requirement
31+
labelRequirement *labels.Requirement
32+
rules rules.Rules
33+
}
34+
35+
func namespace() string {
36+
return os.Getenv(envNamespace)
37+
}
38+
39+
func gracePeriod() (*int64, error) {
40+
envGraceDuration, exists := os.LookupEnv(envGracePeriod)
41+
if !exists {
42+
return nil, nil
43+
}
44+
duration, err := time.ParseDuration(envGraceDuration)
45+
if err != nil {
46+
return nil, fmt.Errorf("invalid %s: %s", envGracePeriod, err)
47+
}
48+
seconds := int64(duration.Seconds())
49+
return &seconds, nil
50+
}
51+
52+
func envDuration(key string, defValue string) (time.Duration, error) {
53+
envDuration, exists := os.LookupEnv(key)
54+
if !exists {
55+
envDuration = defValue
56+
}
57+
duration, err := time.ParseDuration(envDuration)
58+
if err != nil {
59+
return duration, fmt.Errorf("invalid %s: %s", key, err)
60+
}
61+
return duration, nil
62+
}
63+
64+
func schedule() string {
65+
schedule, exists := os.LookupEnv(envScheduleCron)
66+
if !exists {
67+
schedule = "@every 1m"
68+
}
69+
return schedule
70+
}
71+
72+
func runDuration() (time.Duration, error) {
73+
return envDuration(envRunDuration, "0s")
74+
}
75+
76+
func labelExclusion() (*labels.Requirement, error) {
77+
labelKey, labelKeyExists := os.LookupEnv(envExcludeLabelKey)
78+
labelValue, labelValuesExist := os.LookupEnv(envExcludeLabelValues)
79+
if labelKeyExists && !labelValuesExist {
80+
return nil, fmt.Errorf("specified %s but not %s", envExcludeLabelKey, envExcludeLabelValues)
81+
} else if !labelKeyExists && labelValuesExist {
82+
return nil, fmt.Errorf("did not specify %s but did specify %s", envExcludeLabelKey, envExcludeLabelValues)
83+
} else if !labelKeyExists && !labelValuesExist {
84+
return nil, nil
85+
}
86+
labelValues := strings.Split(labelValue, ",")
87+
labelExclusion, err := labels.NewRequirement(labelKey, selection.NotIn, labelValues)
88+
if err != nil {
89+
return nil, fmt.Errorf("could not create exclusion label: %s", err)
90+
}
91+
return labelExclusion, nil
92+
}
93+
94+
func labelRequirement() (*labels.Requirement, error) {
95+
labelKey, labelKeyExists := os.LookupEnv(envRequireLabelKey)
96+
labelValue, labelValuesExist := os.LookupEnv(envRequireLabelValues)
97+
if labelKeyExists && !labelValuesExist {
98+
return nil, fmt.Errorf("specified %s but not %s", envRequireLabelKey, envRequireLabelValues)
99+
} else if !labelKeyExists && labelValuesExist {
100+
return nil, fmt.Errorf("did not specify %s but did specify %s", envRequireLabelKey, envRequireLabelValues)
101+
} else if !labelKeyExists && !labelValuesExist {
102+
return nil, nil
103+
}
104+
labelValues := strings.Split(labelValue, ",")
105+
labelRequirement, err := labels.NewRequirement(labelKey, selection.In, labelValues)
106+
if err != nil {
107+
return nil, fmt.Errorf("could not create requirement label: %s", err)
108+
}
109+
return labelRequirement, nil
110+
}
111+
112+
func loadOptions() (options options, err error) {
113+
options.namespace = namespace()
114+
options.gracePeriod, err = gracePeriod()
115+
if err != nil {
116+
return options, err
117+
}
118+
options.schedule = schedule()
119+
options.runDuration, err = runDuration()
120+
if err != nil {
121+
return options, err
122+
}
123+
options.labelExclusion, err = labelExclusion()
124+
if err != nil {
125+
return options, err
126+
}
127+
options.labelRequirement, err = labelRequirement()
128+
if err != nil {
129+
return options, err
130+
}
131+
132+
// rules
133+
options.rules, err = rules.LoadRules()
134+
if err != nil {
135+
return options, err
136+
}
137+
return options, err
138+
}

cmd/pod-reaper/app/options_test.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package app
2+
3+
import (
4+
"os"
5+
"testing"
6+
"time"
7+
8+
"io/ioutil"
9+
10+
"github.com/sirupsen/logrus"
11+
"github.com/stretchr/testify/assert"
12+
"k8s.io/apimachinery/pkg/labels"
13+
)
14+
15+
func init() {
16+
logrus.SetOutput(ioutil.Discard)
17+
}
18+
19+
func TestOptions(t *testing.T) {
20+
t.Run("namespace", func(t *testing.T) {
21+
t.Run("default", func(t *testing.T) {
22+
os.Clearenv()
23+
namespace := namespace()
24+
assert.Equal(t, "", namespace)
25+
})
26+
t.Run("valid", func(t *testing.T) {
27+
os.Clearenv()
28+
os.Setenv(envNamespace, "test-namespace")
29+
namespace := namespace()
30+
assert.Equal(t, "test-namespace", namespace)
31+
})
32+
})
33+
t.Run("grace period", func(t *testing.T) {
34+
t.Run("default", func(t *testing.T) {
35+
os.Clearenv()
36+
gracePeriod, err := gracePeriod()
37+
assert.NoError(t, err)
38+
assert.Nil(t, gracePeriod)
39+
})
40+
t.Run("valid", func(t *testing.T) {
41+
os.Clearenv()
42+
os.Setenv(envGracePeriod, "1m53s999ms")
43+
gracePeriod, err := gracePeriod()
44+
assert.NoError(t, err)
45+
assert.Equal(t, int64(113), *gracePeriod)
46+
})
47+
t.Run("invalid", func(t *testing.T) {
48+
os.Clearenv()
49+
os.Setenv(envGracePeriod, "invalid")
50+
_, err := gracePeriod()
51+
assert.Error(t, err)
52+
})
53+
})
54+
t.Run("schedule", func(t *testing.T) {
55+
t.Run("default", func(t *testing.T) {
56+
os.Clearenv()
57+
schedule := schedule()
58+
assert.Equal(t, "@every 1m", schedule)
59+
})
60+
})
61+
t.Run("run duration", func(t *testing.T) {
62+
t.Run("default", func(t *testing.T) {
63+
os.Clearenv()
64+
duration, err := runDuration()
65+
assert.NoError(t, err)
66+
assert.Equal(t, 0*time.Second, duration)
67+
})
68+
t.Run("invalid", func(t *testing.T) {
69+
os.Clearenv()
70+
os.Setenv(envRunDuration, "not-a-duration")
71+
_, err := runDuration()
72+
assert.Error(t, err)
73+
})
74+
t.Run("valid", func(t *testing.T) {
75+
os.Clearenv()
76+
os.Setenv(envRunDuration, "1m58s")
77+
duration, err := runDuration()
78+
assert.NoError(t, err)
79+
assert.Equal(t, 2*time.Minute-2*time.Second, duration)
80+
})
81+
})
82+
t.Run("label exclusion", func(t *testing.T) {
83+
t.Run("default", func(t *testing.T) {
84+
os.Clearenv()
85+
exclusion, err := labelExclusion()
86+
assert.NoError(t, err)
87+
assert.Nil(t, exclusion)
88+
})
89+
t.Run("only key", func(t *testing.T) {
90+
os.Clearenv()
91+
os.Setenv(envExcludeLabelKey, "test-key")
92+
_, err := labelExclusion()
93+
assert.Error(t, err)
94+
})
95+
t.Run("only values", func(t *testing.T) {
96+
os.Clearenv()
97+
os.Setenv(envExcludeLabelValues, "test-value1,test-value2")
98+
_, err := labelExclusion()
99+
assert.Error(t, err)
100+
})
101+
t.Run("invalid key", func(t *testing.T) {
102+
os.Clearenv()
103+
os.Setenv(envExcludeLabelKey, "keys cannot have spaces")
104+
os.Setenv(envExcludeLabelValues, "test-value1,test-value2")
105+
_, err := labelExclusion()
106+
assert.Error(t, err)
107+
})
108+
t.Run("valid", func(t *testing.T) {
109+
os.Clearenv()
110+
os.Setenv(envExcludeLabelKey, "test-key")
111+
os.Setenv(envExcludeLabelValues, "test-value1,test-value2")
112+
exclusion, err := labelExclusion()
113+
assert.NoError(t, err)
114+
assert.NotNil(t, exclusion)
115+
assert.Equal(t, "test-key notin (test-value1,test-value2)", labels.NewSelector().Add(*exclusion).String())
116+
})
117+
})
118+
t.Run("label requirement", func(t *testing.T) {
119+
t.Run("default", func(t *testing.T) {
120+
os.Clearenv()
121+
requirement, err := labelRequirement()
122+
assert.NoError(t, err)
123+
assert.Nil(t, requirement)
124+
})
125+
t.Run("only key", func(t *testing.T) {
126+
os.Clearenv()
127+
os.Setenv(envRequireLabelKey, "test-key")
128+
_, err := labelRequirement()
129+
assert.Error(t, err)
130+
})
131+
t.Run("only values", func(t *testing.T) {
132+
os.Clearenv()
133+
os.Setenv(envRequireLabelValues, "test-value1,test-value2")
134+
_, err := labelRequirement()
135+
assert.Error(t, err)
136+
})
137+
t.Run("invalid key", func(t *testing.T) {
138+
os.Clearenv()
139+
os.Setenv(envRequireLabelKey, "keys cannot have spaces")
140+
os.Setenv(envRequireLabelValues, "test-value1,test-value2")
141+
_, err := labelRequirement()
142+
assert.Error(t, err)
143+
})
144+
t.Run("valid", func(t *testing.T) {
145+
os.Clearenv()
146+
os.Setenv(envRequireLabelKey, "test-key")
147+
os.Setenv(envRequireLabelValues, "test-value1,test-value2")
148+
requirement, err := labelRequirement()
149+
assert.NoError(t, err)
150+
assert.NotNil(t, requirement)
151+
assert.Equal(t, "test-key in (test-value1,test-value2)", labels.NewSelector().Add(*requirement).String())
152+
})
153+
})
154+
}
155+
156+
func TestOptionsLoad(t *testing.T) {
157+
t.Run("invalid options", func(t *testing.T) {
158+
os.Clearenv()
159+
os.Setenv(envRunDuration, "invalid")
160+
_, err := loadOptions()
161+
assert.Error(t, err)
162+
})
163+
t.Run("no rules", func(t *testing.T) {
164+
os.Clearenv()
165+
_, err := loadOptions()
166+
assert.Error(t, err)
167+
})
168+
t.Run("valid", func(t *testing.T) {
169+
os.Clearenv()
170+
// ensure at least one rule loads
171+
os.Setenv("CHAOS_CHANCE", "1.0")
172+
options, err := loadOptions()
173+
assert.NoError(t, err)
174+
assert.Equal(t, "@every 1m", options.schedule)
175+
assert.Equal(t, 0*time.Second, options.runDuration)
176+
assert.Nil(t, options.labelExclusion)
177+
assert.Nil(t, options.labelRequirement)
178+
})
179+
}

0 commit comments

Comments
 (0)