Skip to content

Commit 0f9fe49

Browse files
author
Amit Kumar Das
authored
feat(job): add eligible tunable (#65)
This commit has following features: - eligible check to enable or disable a job - thinkTimeInSeconds to delay start of a Job - failFast to stop retrying in case of specific errors - ignoreError to mark a task as warning & job to completed Signed-off-by: AmitKumarDas <[email protected]>
1 parent bd652f3 commit 0f9fe49

29 files changed

+1153
-356
lines changed

cmd/main.go

+19
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ limitations under the License.
1717
package main
1818

1919
import (
20+
"flag"
21+
22+
"k8s.io/klog/v2"
2023
"openebs.io/metac/controller/generic"
2124
"openebs.io/metac/start"
2225

@@ -41,6 +44,22 @@ import (
4144
// One can consider each registered function as an independent
4245
// kubernetes controller & this project as the operator.
4346
func main() {
47+
flag.Set("alsologtostderr", "true")
48+
flag.Parse()
49+
50+
klogFlags := flag.NewFlagSet("klog", flag.ExitOnError)
51+
klog.InitFlags(klogFlags)
52+
53+
// Sync the glog and klog flags.
54+
flag.CommandLine.VisitAll(func(f1 *flag.Flag) {
55+
f2 := klogFlags.Lookup(f1.Name)
56+
if f2 != nil {
57+
value := f1.Value.String()
58+
f2.Value.Set(value)
59+
}
60+
})
61+
defer klog.Flush()
62+
4463
// controller name & corresponding controller reconcile function
4564
var controllers = map[string]generic.InlineInvokeFn{
4665
"sync/job": job.Sync,

controller/job/reconciler.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,20 @@ func (r *Reconciler) setWatchStatusFromJobStatus() {
9696
r.HookResponse.Labels = map[string]*string{
9797
"job.dope.metacontroller.io/phase": pointer.StringPtr(string(r.JobStatus.Phase)),
9898
}
99+
if r.ObservedJob != nil &&
100+
r.ObservedJob.Spec.Refresh.ResyncAfterSeconds != nil {
101+
r.HookResponse.ResyncAfterSeconds = *r.ObservedJob.Spec.Refresh.ResyncAfterSeconds
102+
}
99103
}
100104

101105
func (r *Reconciler) setWatchStatus() {
102106
if r.Err != nil {
103-
// resync since this might be a temporary error
104-
//
105-
// TODO:
106-
// Might be better to expose this from job.spec
107-
r.HookResponse.ResyncAfterSeconds = 5.0
107+
if r.ObservedJob != nil &&
108+
r.ObservedJob.Spec.Refresh.OnErrorResyncAfterSeconds != nil {
109+
// resync based on configuration
110+
r.HookResponse.ResyncAfterSeconds =
111+
*r.ObservedJob.Spec.Refresh.OnErrorResyncAfterSeconds
112+
}
108113
r.setWatchStatusAsError()
109114
return
110115
}

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module mayadata.io/d-operators
33
go 1.13
44

55
require (
6+
9fans.net/go v0.0.2
67
github.com/go-resty/resty/v2 v2.2.0
78
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
89
github.com/google/go-cmp v0.4.0
@@ -12,6 +13,7 @@ require (
1213
k8s.io/apiextensions-apiserver v0.17.3
1314
k8s.io/apimachinery v0.17.3
1415
k8s.io/client-go v0.17.3
16+
k8s.io/klog v1.0.0
1517
k8s.io/klog/v2 v2.0.0
1618
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f
1719
openebs.io/metac v0.3.0

go.sum

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
9fans.net/go v0.0.2 h1:RYM6lWITV8oADrwLfdzxmt8ucfW6UtP9v1jg4qAbqts=
2+
9fans.net/go v0.0.2/go.mod h1:lfPdxjq9v8pVQXUMBCx5EO5oLXWQFlKRQgs1kEkjoIM=
13
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
24
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
35
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -477,6 +479,7 @@ k8s.io/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok=
477479
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
478480
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
479481
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
482+
k8s.io/kubernetes v1.18.3 h1:6qtm8v3z+OwYm2SnsTxYUtGCsIbGBZ/Dh9yER+aNIoI=
480483
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
481484
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
482485
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=

pkg/job/apply.go

+35-42
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ import (
3030

3131
// Applyable helps applying desired state(s) against the cluster
3232
type Applyable struct {
33-
*Fixture
34-
Retry *Retryable
33+
BaseRunner
3534
Apply *types.Apply
3635

3736
result *types.ApplyResult
@@ -40,18 +39,16 @@ type Applyable struct {
4039

4140
// ApplyableConfig helps in creating new instance of Applyable
4241
type ApplyableConfig struct {
43-
Fixture *Fixture
44-
Retry *Retryable
45-
Apply *types.Apply
42+
BaseRunner
43+
Apply *types.Apply
4644
}
4745

4846
// NewApplier returns a new instance of Applyable
4947
func NewApplier(config ApplyableConfig) *Applyable {
5048
return &Applyable{
51-
Apply: config.Apply,
52-
Fixture: config.Fixture,
53-
Retry: config.Retry,
54-
result: &types.ApplyResult{},
49+
BaseRunner: config.BaseRunner,
50+
Apply: config.Apply,
51+
result: &types.ApplyResult{},
5552
}
5653
}
5754

@@ -66,27 +63,26 @@ func (a *Applyable) postCreateCRD(
6663
// discover custom resource API
6764
err := a.Retry.Waitf(
6865
func() (bool, error) {
69-
got := a.apiDiscovery.
70-
GetAPIForAPIVersionAndResource(
71-
crd.Spec.Group+"/"+crd.Spec.Version,
72-
crd.Spec.Names.Plural,
73-
)
66+
got := a.GetAPIForAPIVersionAndResource(
67+
crd.Spec.Group+"/"+crd.Spec.Version,
68+
crd.Spec.Names.Plural,
69+
)
7470
if got == nil {
75-
return false, errors.Errorf(
76-
"Failed to discover: Kind %s: APIVersion %s",
77-
crd.Spec.Names.Singular,
78-
crd.Spec.Group+"/"+crd.Spec.Version,
79-
)
71+
return a.IsFailFastOnDiscoveryError(),
72+
errors.Errorf(
73+
"Failed to discover: Kind %s: APIVersion %s",
74+
crd.Spec.Names.Singular,
75+
crd.Spec.Group+"/"+crd.Spec.Version,
76+
)
8077
}
8178
// fetch dynamic client for the custom resource
8279
// corresponding to this CRD
83-
customResourceClient, err := a.dynamicClientset.
84-
GetClientForAPIVersionAndResource(
85-
crd.Spec.Group+"/"+crd.Spec.Version,
86-
crd.Spec.Names.Plural,
87-
)
80+
customResourceClient, err := a.GetClientForAPIVersionAndResource(
81+
crd.Spec.Group+"/"+crd.Spec.Version,
82+
crd.Spec.Names.Plural,
83+
)
8884
if err != nil {
89-
return false, err
85+
return a.IsFailFastOnDiscoveryError(), err
9086
}
9187
_, err = customResourceClient.List(metav1.ListOptions{})
9288
if err != nil {
@@ -256,11 +252,10 @@ func (a *Applyable) createResource() (*types.ApplyResult, error) {
256252
a.Apply.State.GetName(),
257253
a.Apply.State.GroupVersionKind(),
258254
)
259-
client, err := a.dynamicClientset.
260-
GetClientForAPIVersionAndKind(
261-
a.Apply.State.GetAPIVersion(),
262-
a.Apply.State.GetKind(),
263-
)
255+
client, err := a.GetClientForAPIVersionAndKind(
256+
a.Apply.State.GetAPIVersion(),
257+
a.Apply.State.GetKind(),
258+
)
264259
if err != nil {
265260
return nil, err
266261
}
@@ -307,13 +302,12 @@ func (a *Applyable) updateResource() (*types.ApplyResult, error) {
307302
err := a.Retry.Waitf(
308303
func() (bool, error) {
309304
// get appropriate dynamic client
310-
client, err := a.dynamicClientset.
311-
GetClientForAPIVersionAndKind(
312-
a.Apply.State.GetAPIVersion(),
313-
a.Apply.State.GetKind(),
314-
)
305+
client, err := a.GetClientForAPIVersionAndKind(
306+
a.Apply.State.GetAPIVersion(),
307+
a.Apply.State.GetKind(),
308+
)
315309
if err != nil {
316-
return false, err
310+
return a.IsFailFastOnDiscoveryError(), err
317311
}
318312
// get the resource from cluster to update
319313
target, err := client.
@@ -372,13 +366,12 @@ func (a *Applyable) applyResource() (*types.ApplyResult, error) {
372366
err := a.Retry.Waitf(
373367
func() (bool, error) {
374368
var err error
375-
client, err := a.dynamicClientset.
376-
GetClientForAPIVersionAndKind(
377-
a.Apply.State.GetAPIVersion(),
378-
a.Apply.State.GetKind(),
379-
)
369+
client, err := a.GetClientForAPIVersionAndKind(
370+
a.Apply.State.GetAPIVersion(),
371+
a.Apply.State.GetKind(),
372+
)
380373
if err != nil {
381-
return false, err
374+
return a.IsFailFastOnDiscoveryError(), err
382375
}
383376
_, err = client.
384377
Namespace(a.Apply.State.GetNamespace()).

pkg/job/assert.go

+11-21
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@ import (
2424
// Assertable is used to perform matches of desired state(s)
2525
// against observed state(s)
2626
type Assertable struct {
27-
*Fixture
28-
Retry *Retryable
29-
TaskName string
30-
Assert *types.Assert
27+
BaseRunner
28+
Assert *types.Assert
3129

3230
assertCheckType types.AssertCheckType
3331
retryOnDiff bool
@@ -40,20 +38,16 @@ type Assertable struct {
4038

4139
// AssertableConfig is used to create an instance of Assertable
4240
type AssertableConfig struct {
43-
Fixture *Fixture
44-
Retry *Retryable
45-
TaskName string
46-
Assert *types.Assert
41+
BaseRunner
42+
Assert *types.Assert
4743
}
4844

4945
// NewAsserter returns a new instance of Assertion
5046
func NewAsserter(config AssertableConfig) *Assertable {
5147
return &Assertable{
52-
Assert: config.Assert,
53-
Retry: config.Retry,
54-
Fixture: config.Fixture,
55-
TaskName: config.TaskName,
56-
status: &types.AssertStatus{},
48+
BaseRunner: config.BaseRunner,
49+
Assert: config.Assert,
50+
status: &types.AssertStatus{},
5751
}
5852
}
5953

@@ -85,11 +79,9 @@ func (a *Assertable) init() {
8579
func (a *Assertable) runAssertByPath() {
8680
chk := NewPathChecker(
8781
PathCheckingConfig{
88-
TaskName: a.TaskName,
89-
Fixture: a.Fixture,
90-
State: a.Assert.State,
91-
PathCheck: *a.Assert.PathCheck,
92-
Retry: a.Retry,
82+
BaseRunner: a.BaseRunner,
83+
State: a.Assert.State,
84+
PathCheck: *a.Assert.PathCheck,
9385
},
9486
)
9587
got, err := chk.Run()
@@ -109,11 +101,9 @@ func (a *Assertable) runAssertByPath() {
109101
func (a *Assertable) runAssertByState() {
110102
chk := NewStateChecker(
111103
StateCheckingConfig{
112-
TaskName: a.TaskName,
113-
Fixture: a.Fixture,
104+
BaseRunner: a.BaseRunner,
114105
State: a.Assert.State,
115106
StateCheck: *a.Assert.StateCheck,
116-
Retry: a.Retry,
117107
},
118108
)
119109
got, err := chk.Run()

pkg/job/base.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Copyright 2020 The MayaData Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package job
18+
19+
import types "mayadata.io/d-operators/types/job"
20+
21+
// BaseRunner is the common runner used by all action runners
22+
type BaseRunner struct {
23+
*Fixture
24+
TaskIndex int
25+
TaskName string
26+
Retry *Retryable
27+
FailFastRule types.FailFastRule
28+
}
29+
30+
// IsFailFastOnDiscoveryError returns true if logic that leads to
31+
// discovery error should not be re-tried
32+
func (r *BaseRunner) IsFailFastOnDiscoveryError() bool {
33+
return r.FailFastRule == types.FailFastOnDiscoveryError
34+
}
35+
36+
// IsFailFastOnError returns true if logic that lead to given error
37+
// should not be re-tried
38+
func (r *BaseRunner) IsFailFastOnError(err error) bool {
39+
if _, discoveryErr := err.(*DiscoveryError); discoveryErr {
40+
return r.IsFailFastOnDiscoveryError()
41+
}
42+
return false
43+
}

0 commit comments

Comments
 (0)