Merge pull request #122994 from ardaguclu/wait-non-existed-resources
kubectl wait: Introduce --wait-for-creation flag Kubernetes-commit: b95fce1732016c06501ca5a1aa5452b55149a2d5
This commit is contained in:
commit
f508e12184
4
go.mod
4
go.mod
|
|
@ -29,8 +29,8 @@ require (
|
|||
golang.org/x/sys v0.20.0
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.0.0-20240620180645-9f6f03ff043b
|
||||
k8s.io/apimachinery v0.0.0-20240620180412-04fe5186a7b1
|
||||
k8s.io/api v0.0.0-20240620180646-e09016fffd8e
|
||||
k8s.io/apimachinery v0.0.0-20240620220412-eb26334eeb0f
|
||||
k8s.io/cli-runtime v0.0.0-20240620184121-8e480ebaa098
|
||||
k8s.io/client-go v0.0.0-20240620181025-b9309ac26b16
|
||||
k8s.io/component-base v0.0.0-20240620181933-0407e51f2497
|
||||
|
|
|
|||
8
go.sum
8
go.sum
|
|
@ -277,10 +277,10 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.0.0-20240620180645-9f6f03ff043b h1:MlO1MxAa8kX7fiaDMVyFJYqqancoCHGggG9UurjrKNc=
|
||||
k8s.io/api v0.0.0-20240620180645-9f6f03ff043b/go.mod h1:1MT1m3FZiytU3Iz+RVL9/0UV96hiPGA1mPCSCgP0QTk=
|
||||
k8s.io/apimachinery v0.0.0-20240620180412-04fe5186a7b1 h1:avzIPRkvVSlb207+JV7eZv498CJ0EBDMKvwmcTS3m2k=
|
||||
k8s.io/apimachinery v0.0.0-20240620180412-04fe5186a7b1/go.mod h1:wKr/cy6yAwcKdBBcxyg2m/xTdMwHdCRNo7Wt2GxZEP8=
|
||||
k8s.io/api v0.0.0-20240620180646-e09016fffd8e h1:sikgfs6oUZr6NPm/El/AQPSUb8OFsnI4Vkwch/o4l1g=
|
||||
k8s.io/api v0.0.0-20240620180646-e09016fffd8e/go.mod h1:1MT1m3FZiytU3Iz+RVL9/0UV96hiPGA1mPCSCgP0QTk=
|
||||
k8s.io/apimachinery v0.0.0-20240620220412-eb26334eeb0f h1:JnekvpSdfvWpcvCIbuU0rMFutVA4W9KosWY8HYLcjMw=
|
||||
k8s.io/apimachinery v0.0.0-20240620220412-eb26334eeb0f/go.mod h1:wKr/cy6yAwcKdBBcxyg2m/xTdMwHdCRNo7Wt2GxZEP8=
|
||||
k8s.io/cli-runtime v0.0.0-20240620184121-8e480ebaa098 h1:KxwXNJlEbq8gzldnFPCMpSRb1r2t3mVsssC/+YxQqOU=
|
||||
k8s.io/cli-runtime v0.0.0-20240620184121-8e480ebaa098/go.mod h1:CZrbWDD+2kp0D0v1mc9T3h2g/73NqyzO42y6FX838hE=
|
||||
k8s.io/client-go v0.0.0-20240620181025-b9309ac26b16 h1:ws4qTqL+vL0yr8xFKOlcRFO926YHDvwJnjgVAHQJdTs=
|
||||
|
|
|
|||
|
|
@ -82,7 +82,10 @@ var (
|
|||
|
||||
# Wait for the pod "busybox1" to be deleted, with a timeout of 60s, after having issued the "delete" command
|
||||
kubectl delete pod/busybox1
|
||||
kubectl wait --for=delete pod/busybox1 --timeout=60s`))
|
||||
kubectl wait --for=delete pod/busybox1 --timeout=60s
|
||||
|
||||
# Wait for the creation of the service "loadbalancer" in addition to wait to have ingress
|
||||
kubectl wait --for=jsonpath='{.status.loadBalancer.ingress}' service/loadbalancer --wait-for-creation`))
|
||||
)
|
||||
|
||||
// errNoMatchingResources is returned when there is no resources matching a query.
|
||||
|
|
@ -96,8 +99,9 @@ type WaitFlags struct {
|
|||
PrintFlags *genericclioptions.PrintFlags
|
||||
ResourceBuilderFlags *genericclioptions.ResourceBuilderFlags
|
||||
|
||||
Timeout time.Duration
|
||||
ForCondition string
|
||||
Timeout time.Duration
|
||||
ForCondition string
|
||||
WaitForCreation bool
|
||||
|
||||
genericiooptions.IOStreams
|
||||
}
|
||||
|
|
@ -115,7 +119,8 @@ func NewWaitFlags(restClientGetter genericclioptions.RESTClientGetter, streams g
|
|||
WithLocal(false).
|
||||
WithLatest(),
|
||||
|
||||
Timeout: 30 * time.Second,
|
||||
Timeout: 30 * time.Second,
|
||||
WaitForCreation: true,
|
||||
|
||||
IOStreams: streams,
|
||||
}
|
||||
|
|
@ -152,6 +157,7 @@ func (flags *WaitFlags) AddFlags(cmd *cobra.Command) {
|
|||
|
||||
cmd.Flags().DurationVar(&flags.Timeout, "timeout", flags.Timeout, "The length of time to wait before giving up. Zero means check once and don't wait, negative means wait for a week.")
|
||||
cmd.Flags().StringVar(&flags.ForCondition, "for", flags.ForCondition, "The condition to wait on: [delete|condition=condition-name[=condition-value]|jsonpath='{JSONPath expression}'=[JSONPath value]]. The default condition-value is true. Condition values are compared after Unicode simple case folding, which is a more general form of case-insensitivity.")
|
||||
cmd.Flags().BoolVar(&flags.WaitForCreation, "wait-for-creation", flags.WaitForCreation, "The default value is true. If set to true, also wait for creation of objects if they do not already exist. This flag is ignored in --for=delete")
|
||||
}
|
||||
|
||||
// ToOptions converts from CLI inputs to runtime inputs
|
||||
|
|
@ -180,10 +186,11 @@ func (flags *WaitFlags) ToOptions(args []string) (*WaitOptions, error) {
|
|||
}
|
||||
|
||||
o := &WaitOptions{
|
||||
ResourceFinder: builder,
|
||||
DynamicClient: dynamicClient,
|
||||
Timeout: effectiveTimeout,
|
||||
ForCondition: flags.ForCondition,
|
||||
ResourceFinder: builder,
|
||||
DynamicClient: dynamicClient,
|
||||
Timeout: effectiveTimeout,
|
||||
ForCondition: flags.ForCondition,
|
||||
WaitForCreation: flags.WaitForCreation,
|
||||
|
||||
Printer: printer,
|
||||
ConditionFn: conditionFn,
|
||||
|
|
@ -302,10 +309,11 @@ type WaitOptions struct {
|
|||
ResourceFinder genericclioptions.ResourceFinder
|
||||
// UIDMap maps a resource location to a UID. It is optional, but ConditionFuncs may choose to use it to make the result
|
||||
// more reliable. For instance, delete can look for UID consistency during delegated calls.
|
||||
UIDMap UIDMap
|
||||
DynamicClient dynamic.Interface
|
||||
Timeout time.Duration
|
||||
ForCondition string
|
||||
UIDMap UIDMap
|
||||
DynamicClient dynamic.Interface
|
||||
Timeout time.Duration
|
||||
ForCondition string
|
||||
WaitForCreation bool
|
||||
|
||||
Printer printers.ResourcePrinter
|
||||
ConditionFn ConditionFunc
|
||||
|
|
@ -320,6 +328,40 @@ func (o *WaitOptions) RunWait() error {
|
|||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), o.Timeout)
|
||||
defer cancel()
|
||||
|
||||
isForDelete := strings.ToLower(o.ForCondition) == "delete"
|
||||
if o.WaitForCreation && o.Timeout == 0 {
|
||||
return fmt.Errorf("--wait-for-creation requires a timeout value greater than 0")
|
||||
}
|
||||
|
||||
if o.WaitForCreation && !isForDelete {
|
||||
err := func() error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return fmt.Errorf("context deadline is exceeded while waiting for the creation of the resources")
|
||||
default:
|
||||
err := o.ResourceFinder.Do().Visit(func(info *resource.Info, err error) error {
|
||||
// We don't need to do anything after we assure that the resources exist. Because
|
||||
// actual logic will be incorporated after we wait all the resources' existence.
|
||||
return nil
|
||||
})
|
||||
// It is verified that all the resources exist.
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// We specifically wait for the creation of resources and all the errors
|
||||
// other than not found means that this is something we cannot handle.
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
visitCount := 0
|
||||
visitFunc := func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
|
|
@ -338,7 +380,6 @@ func (o *WaitOptions) RunWait() error {
|
|||
return err
|
||||
}
|
||||
visitor := o.ResourceFinder.Do()
|
||||
isForDelete := strings.ToLower(o.ForCondition) == "delete"
|
||||
if visitor, ok := visitor.(*resource.Result); ok && isForDelete {
|
||||
visitor.IgnoreErrors(apierrors.IsNotFound)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue