-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new high-level concurrent dynamic tracker
Signed-off-by: Ilya Lesikov <ilya@lesikov.com>
- Loading branch information
1 parent
6f6030f
commit 5721c3e
Showing
22 changed files
with
2,135 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package dyntracker | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"time" | ||
|
||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/apimachinery/pkg/util/wait" | ||
"k8s.io/client-go/dynamic" | ||
|
||
"github.com/werf/kubedog/pkg/trackers/dyntracker/statestore" | ||
"github.com/werf/kubedog/pkg/trackers/dyntracker/util" | ||
) | ||
|
||
type DynamicAbsenceTracker struct { | ||
taskState *util.Concurrent[*statestore.AbsenceTaskState] | ||
dynamicClient dynamic.Interface | ||
mapper meta.ResettableRESTMapper | ||
|
||
timeout time.Duration | ||
pollPeriod time.Duration | ||
} | ||
|
||
func NewDynamicAbsenceTracker( | ||
taskState *util.Concurrent[*statestore.AbsenceTaskState], | ||
dynamicClient dynamic.Interface, | ||
mapper meta.ResettableRESTMapper, | ||
opts DynamicAbsenceTrackerOptions, | ||
) *DynamicAbsenceTracker { | ||
timeout := opts.Timeout | ||
var pollPeriod time.Duration | ||
if opts.PollPeriod != 0 { | ||
pollPeriod = opts.PollPeriod | ||
} else { | ||
pollPeriod = 1 * time.Second | ||
} | ||
|
||
return &DynamicAbsenceTracker{ | ||
taskState: taskState, | ||
dynamicClient: dynamicClient, | ||
mapper: mapper, | ||
timeout: timeout, | ||
pollPeriod: pollPeriod, | ||
} | ||
} | ||
|
||
type DynamicAbsenceTrackerOptions struct { | ||
Timeout time.Duration | ||
PollPeriod time.Duration | ||
} | ||
|
||
func (t *DynamicAbsenceTracker) Track(ctx context.Context) error { | ||
var ( | ||
name string | ||
namespace string | ||
groupVersionKind schema.GroupVersionKind | ||
) | ||
t.taskState.RTransaction(func(ts *statestore.AbsenceTaskState) { | ||
name = ts.Name() | ||
namespace = ts.Namespace() | ||
groupVersionKind = ts.GroupVersionKind() | ||
}) | ||
|
||
namespaced, err := util.IsNamespaced(groupVersionKind, t.mapper) | ||
if err != nil { | ||
return fmt.Errorf("check if namespaced: %w", err) | ||
} | ||
|
||
gvr, err := util.GVRFromGVK(groupVersionKind, t.mapper) | ||
if err != nil { | ||
return fmt.Errorf("get GroupVersionResource: %w", err) | ||
} | ||
|
||
var resourceClient dynamic.ResourceInterface | ||
if namespaced { | ||
resourceClient = t.dynamicClient.Resource(gvr).Namespace(namespace) | ||
} else { | ||
resourceClient = t.dynamicClient.Resource(gvr) | ||
} | ||
|
||
resourceHumanID, err := util.ResourceHumanID(name, namespace, groupVersionKind, t.mapper) | ||
if err != nil { | ||
return fmt.Errorf("get resource human ID: %w", err) | ||
} | ||
|
||
if err := wait.PollImmediate(t.pollPeriod, t.timeout, func() (bool, error) { | ||
if _, err := resourceClient.Get(ctx, name, metav1.GetOptions{}); err != nil { | ||
if apierrors.IsResourceExpired(err) || apierrors.IsGone(err) || err == io.EOF || err == io.ErrUnexpectedEOF { | ||
return false, nil | ||
} | ||
|
||
if apierrors.IsNotFound(err) { | ||
return true, nil | ||
} | ||
|
||
return false, fmt.Errorf("get resource %q: %w", resourceHumanID, err) | ||
} | ||
|
||
return false, nil | ||
}); err != nil { | ||
return fmt.Errorf("poll resource %q: %w", resourceHumanID, err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package dyntracker | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"time" | ||
|
||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/apimachinery/pkg/util/wait" | ||
"k8s.io/client-go/dynamic" | ||
|
||
"github.com/werf/kubedog/pkg/trackers/dyntracker/statestore" | ||
"github.com/werf/kubedog/pkg/trackers/dyntracker/util" | ||
) | ||
|
||
type DynamicPresenceTracker struct { | ||
taskState *util.Concurrent[*statestore.PresenceTaskState] | ||
dynamicClient dynamic.Interface | ||
mapper meta.ResettableRESTMapper | ||
|
||
timeout time.Duration | ||
pollPeriod time.Duration | ||
} | ||
|
||
func NewDynamicPresenceTracker( | ||
taskState *util.Concurrent[*statestore.PresenceTaskState], | ||
dynamicClient dynamic.Interface, | ||
mapper meta.ResettableRESTMapper, | ||
opts DynamicPresenceTrackerOptions, | ||
) *DynamicPresenceTracker { | ||
var timeout time.Duration | ||
if opts.Timeout != 0 { | ||
timeout = opts.Timeout | ||
} else { | ||
timeout = 5 * time.Minute | ||
} | ||
|
||
var pollPeriod time.Duration | ||
if opts.PollPeriod != 0 { | ||
pollPeriod = opts.PollPeriod | ||
} else { | ||
pollPeriod = 1 * time.Second | ||
} | ||
|
||
return &DynamicPresenceTracker{ | ||
taskState: taskState, | ||
dynamicClient: dynamicClient, | ||
mapper: mapper, | ||
timeout: timeout, | ||
pollPeriod: pollPeriod, | ||
} | ||
} | ||
|
||
type DynamicPresenceTrackerOptions struct { | ||
Timeout time.Duration | ||
PollPeriod time.Duration | ||
} | ||
|
||
func (t *DynamicPresenceTracker) Track(ctx context.Context) error { | ||
var ( | ||
name string | ||
namespace string | ||
groupVersionKind schema.GroupVersionKind | ||
) | ||
t.taskState.RTransaction(func(ts *statestore.PresenceTaskState) { | ||
name = ts.Name() | ||
namespace = ts.Namespace() | ||
groupVersionKind = ts.GroupVersionKind() | ||
}) | ||
|
||
namespaced, err := util.IsNamespaced(groupVersionKind, t.mapper) | ||
if err != nil { | ||
return fmt.Errorf("check if namespaced: %w", err) | ||
} | ||
|
||
gvr, err := util.GVRFromGVK(groupVersionKind, t.mapper) | ||
if err != nil { | ||
return fmt.Errorf("get GroupVersionResource: %w", err) | ||
} | ||
|
||
var resourceClient dynamic.ResourceInterface | ||
if namespaced { | ||
resourceClient = t.dynamicClient.Resource(gvr).Namespace(namespace) | ||
} else { | ||
resourceClient = t.dynamicClient.Resource(gvr) | ||
} | ||
|
||
resourceHumanID, err := util.ResourceHumanID(name, namespace, groupVersionKind, t.mapper) | ||
if err != nil { | ||
return fmt.Errorf("get resource human ID: %w", err) | ||
} | ||
|
||
if err := wait.PollImmediate(t.pollPeriod, t.timeout, func() (bool, error) { | ||
if _, err := resourceClient.Get(ctx, name, metav1.GetOptions{}); err != nil { | ||
if apierrors.IsResourceExpired(err) || apierrors.IsGone(err) || err == io.EOF || err == io.ErrUnexpectedEOF || apierrors.IsNotFound(err) { | ||
return false, nil | ||
} | ||
|
||
return false, fmt.Errorf("get resource %q: %w", resourceHumanID, err) | ||
} | ||
|
||
return true, nil | ||
}); err != nil { | ||
return fmt.Errorf("poll resource %q: %w", resourceHumanID, err) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.