Skip to content
This repository was archived by the owner on Sep 14, 2022. It is now read-only.

Commit 4a86f81

Browse files
committed
add timeout if pvc not available or pod can't become ready from any reason
1 parent 8575716 commit 4a86f81

File tree

5 files changed

+37
-25
lines changed

5 files changed

+37
-25
lines changed

local.makefile

Lines changed: 0 additions & 5 deletions
This file was deleted.

local.mk

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
buildlocal:
2+
GOOS=darwin GOARCH=amd64 go build -o /usr/local/bin/kubectl-pvcexec ./main.go
3+
4+
run: buildlocal
5+
kubectl pvcexec mc -p testpvc1 -p testpvc2 -n default

pkg/cmd/mc.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,24 @@ func NewMcCommand(pvcexecOptions *k8s.PvcExecOptions) *cobra.Command {
4040
}
4141
cmd.Flags().StringArrayP("pvc", "p", nil, "-pvc pvc1 -pvc pvc2 ...")
4242
cmd.MarkFlagRequired("pvc")
43+
cmd.Flags().StringP("namespace", "n", "", "use this flag to override kubernetes namespace from current kubectl context")
4344
return cmd
4445
}
4546

4647
// Complete completes the setup of the command.
4748
func (mcOptions *McOptions) Complete(cmd *cobra.Command, args []string) error {
48-
// Prepare namespace
4949
var err error
5050
options := mcOptions.pvcExecOptions
51+
// Prepare namespace
5152
options.Namespace, _, err = options.ConfigFlags.ToRawKubeConfigLoader().Namespace()
5253
if err != nil {
5354
return err
5455
}
56+
57+
var overrideNamespace, _ = cmd.Flags().GetString("namespace")
58+
if len(overrideNamespace) > 0 {
59+
options.Namespace = overrideNamespace
60+
}
5561
// Prepare client
5662
options.RestConfig, err = options.ConfigFlags.ToRESTConfig()
5763
if err != nil {
@@ -75,6 +81,7 @@ func (mcOptions *McOptions) Run() error {
7581
options := mcOptions.pvcExecOptions
7682
restConfig, _ := options.ConfigFlags.ToRESTConfig()
7783
podClient, _ := corev1client.NewForConfig(restConfig)
84+
7885
defer podClient.Pods(options.Namespace).Delete(options.PodName, metav1.NewDeleteOptions(0))
7986
pod, err := k8s.CreateRunnerPod(podClient, options)
8087
if err != nil {

pkg/cmd/pvcexec.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import (
77
)
88

99
func NewPvcExecOptions(streams genericclioptions.IOStreams) *k8s.PvcExecOptions {
10-
return &k8s.PvcExecOptions{
10+
options := &k8s.PvcExecOptions{
1111
ConfigFlags: genericclioptions.NewConfigFlags(true),
1212
IOStreams: streams,
1313
}
14+
return options
1415
}
1516

1617
func NewPvcExecCmd(streams genericclioptions.IOStreams) *cobra.Command {

pkg/k8s/pod.go

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import (
55
"golang.org/x/crypto/ssh/terminal"
66
apiv1 "k8s.io/api/core/v1"
77
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8-
"k8s.io/apimachinery/pkg/watch"
98
"k8s.io/client-go/kubernetes/scheme"
109
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
1110
"k8s.io/client-go/tools/remotecommand"
11+
"time"
12+
1213
"os"
1314
)
1415

@@ -87,31 +88,34 @@ func CreateRunnerPod(pods *corev1client.CoreV1Client, options *PvcExecOptions) (
8788
if err != nil {
8889
return nil, err
8990
}
90-
// Wait for the Pod to indicate Ready == True.
91-
watcher, err := podsClient.Watch(
91+
status := pod.Status
92+
w, err := podsClient.Watch(
9293
metav1.SingleObject(pod.ObjectMeta),
9394
)
9495
if err != nil {
9596
return nil, err
9697
}
97-
for event := range watcher.ResultChan() {
98-
switch event.Type {
99-
case watch.Modified:
100-
pod = event.Object.(*apiv1.Pod)
101-
// If the Pod contains a status condition Ready == True, stop
102-
// watching.
103-
for _, cond := range pod.Status.Conditions {
104-
if cond.Type == apiv1.PodReady &&
105-
cond.Status == apiv1.ConditionTrue {
106-
watcher.Stop()
107-
} else if cond.Status == apiv1.ConditionFalse && cond.Reason == apiv1.PodReasonUnschedulable {
108-
watcher.Stop()
109-
return nil, fmt.Errorf("Error %v", cond.Message)
98+
func() {
99+
for {
100+
select {
101+
case events, ok := <-w.ResultChan():
102+
if !ok {
103+
return
104+
}
105+
pod = events.Object.(*apiv1.Pod)
106+
fmt.Println("Pod status:", pod.Status.Phase)
107+
status = pod.Status
108+
if pod.Status.Phase != apiv1.PodPending {
109+
w.Stop()
110110
}
111+
case <-time.After(20 * time.Second):
112+
fmt.Println("timeout to wait for pod active")
113+
w.Stop()
111114
}
112-
default:
113-
panic("unexpected event type " + event.Type)
114115
}
116+
}()
117+
if status.Phase != apiv1.PodRunning {
118+
return nil, fmt.Errorf("Pod is unavailable: %v, %v", status.Phase, status.Reason)
115119
}
116120
return pod, nil
117121
}

0 commit comments

Comments
 (0)