-
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.
Merge pull request #313 from werf/feat-new-dynamic-tracker
feat: new high-level concurrent dynamic tracker
- Loading branch information
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.