fix: quit minikube service when there is no available pods
parent
7489d959a8
commit
55868b1736
cmd/minikube/cmd
pkg/minikube
reason
service
site/content/en/docs/contrib
test/integration
|
@ -148,6 +148,10 @@ You may select another namespace by using 'minikube service {{.service}} -n <nam
|
|||
out.String(fmt.Sprintf("%s\n", serviceURLs))
|
||||
}
|
||||
}
|
||||
// check whether all pods of this service is crashed
|
||||
if err := service.CheckServicePods(cname, svc.Name, namespace); err != nil {
|
||||
exit.Error(reason.SvcUnreachable, "service not available", err)
|
||||
}
|
||||
}
|
||||
|
||||
if driver.NeedsPortForward(co.Config.Driver) && services != nil {
|
||||
|
|
|
@ -423,6 +423,8 @@ var (
|
|||
SvcCheckTimeout = Kind{ID: "SVC_CHECK_TIMEOUT", ExitCode: ExSvcTimeout}
|
||||
// minikube was unable to access a service
|
||||
SvcTimeout = Kind{ID: "SVC_TIMEOUT", ExitCode: ExSvcTimeout}
|
||||
// minikube finds that the service has not available pods
|
||||
SvcUnreachable = Kind{ID: "SVC_UNREACHABLE", ExitCode: ExSvcNotFound}
|
||||
// minikube failed to list services for the specified namespace
|
||||
SvcList = Kind{ID: "SVC_LIST", ExitCode: ExSvcError}
|
||||
// minikube failed to start a tunnel
|
||||
|
|
|
@ -373,3 +373,36 @@ func DeleteSecret(cname string, namespace, name string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// check whether there are running pods for a service
|
||||
func CheckServicePods(cname, svcName, namespace string) error {
|
||||
clientset, err := K8s.GetCoreClient(cname)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get k8s client")
|
||||
}
|
||||
|
||||
svc, err := clientset.Services(namespace).Get(context.Background(), svcName, meta.GetOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Get service")
|
||||
}
|
||||
// There are four types of service in k8s: NodePort, ClusterIp, LoadBalancer and ExternalName
|
||||
// However, NodePort means that this service will not be exposed outside the cluster
|
||||
// while ExternalName means that this service is not provided by this k8s cluster
|
||||
// So we only check when service type is NodePort or LoadBalancer
|
||||
if svc.Spec.Type != core.ServiceTypeNodePort && svc.Spec.Type != core.ServiceTypeLoadBalancer {
|
||||
return nil
|
||||
}
|
||||
pods, err := clientset.Pods(namespace).List(context.Background(), meta.ListOptions{
|
||||
LabelSelector: labels.Set(svc.Spec.Selector).AsSelector().String(),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "List Pods")
|
||||
}
|
||||
|
||||
for _, pod := range pods.Items {
|
||||
if pod.Status.Phase == core.PodRunning {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("no running pod for service %s found", svcName)
|
||||
}
|
||||
|
|
|
@ -697,6 +697,9 @@ verifies that minikube pause works
|
|||
## TestInsufficientStorage
|
||||
makes sure minikube status displays the correct info if there is insufficient disk space on the machine
|
||||
|
||||
## TestInvalidService
|
||||
makes sure minikube will not start a tunnel for a unavailable service who has no running pods
|
||||
|
||||
## TestRunningBinaryUpgrade
|
||||
upgrades a running legacy cluster to minikube at HEAD
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ func TestFunctional(t *testing.T) {
|
|||
{"ComponentHealth", validateComponentHealth},
|
||||
{"LogsCmd", validateLogsCmd},
|
||||
{"LogsFileCmd", validateLogsFileCmd},
|
||||
{"InvalidService", validateInvalidService},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
|
@ -2308,3 +2309,27 @@ func validateLicenseCmd(ctx context.Context, t *testing.T, _ string) {
|
|||
t.Errorf("expected license file to contain %q, but was not found", expectedString)
|
||||
}
|
||||
}
|
||||
|
||||
// validateInvalidService makes sure minikube will not start a tunnel for an unavailable service that has no running pods
|
||||
func validateInvalidService(ctx context.Context, t *testing.T, profile string) {
|
||||
|
||||
// try to start an invalid service. This service is linked to a pod whose image name is invalid, so this pod will never become running
|
||||
rrApply, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "apply", "-f", filepath.Join(*testdataDir, "invalidsvc.yaml")))
|
||||
defer func() {
|
||||
// Cleanup test configurations in advance of future tests
|
||||
rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "delete", "-f", filepath.Join(*testdataDir, "invalidsvc.yaml")))
|
||||
if err != nil {
|
||||
t.Fatalf("clean up %s failed: %v", rr.Command(), err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
t.Fatalf("%s failed: %v", rrApply.Command(), err)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// try to expose a service, this action is supposed to fail
|
||||
rrService, err := Run(t, exec.CommandContext(context.TODO(), Target(), "service", "invalid-svc", "-p", profile))
|
||||
if err == nil || rrService.ExitCode == 0 {
|
||||
t.Fatalf("%s should have failed: ", rrService.Command())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
run: invalid-svc
|
||||
name: invalid-svc
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nonexistingimage:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
run: invalid-svc
|
||||
name: invalid-svc
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
targetPort: 80
|
||||
selector:
|
||||
run: invalid-svc
|
||||
sessionAffinity: None
|
||||
type: NodePort
|
|
@ -953,6 +953,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "dry-run Modus. Validiert die Konfiguration, aber ändert den System Zustand nicht",
|
||||
"dry-run validation complete!": "dry-run Validierung komplett!",
|
||||
"enable failed": "aktivieren fehlgeschlagen",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "Fehler beim Anlegen des Clientsets",
|
||||
"error creating urls": "",
|
||||
"error getting defaults: {{.error}}": "",
|
||||
|
|
|
@ -951,6 +951,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "",
|
||||
"dry-run validation complete!": "",
|
||||
"enable failed": "",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "",
|
||||
"error creating urls": "",
|
||||
"error getting defaults: {{.error}}": "",
|
||||
|
|
|
@ -934,6 +934,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "mode simulation. Valide la configuration, mais ne modifie pas l'état du système",
|
||||
"dry-run validation complete!": "validation de la simulation terminée !",
|
||||
"enable failed": "échec de l'activation",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "erreur lors de la création de l'ensemble de clients",
|
||||
"error creating urls": "erreur lors de la création d'urls",
|
||||
"error getting defaults: {{.error}}": "erreur lors de l'obtention des valeurs par défaut : {{.error}}",
|
||||
|
|
|
@ -893,6 +893,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "dry-run モード。設定は検証しますが、システムの状態は変更しません",
|
||||
"dry-run validation complete!": "dry-run の検証が終了しました!",
|
||||
"enable failed": "有効化に失敗しました",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "clientset 作成中にエラー",
|
||||
"error creating urls": "URL 作成でエラー",
|
||||
"error getting defaults: {{.error}}": "デフォルト取得中にエラー: {{.error}}",
|
||||
|
|
|
@ -953,6 +953,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "",
|
||||
"dry-run validation complete!": "dry-run 검증 완료!",
|
||||
"enable failed": "활성화가 실패하였습니다",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "clientset 생성 오류",
|
||||
"error creating machine client": "머신 client 생성 오류",
|
||||
"error creating urls": "",
|
||||
|
|
|
@ -963,6 +963,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "",
|
||||
"dry-run validation complete!": "",
|
||||
"enable failed": "",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "",
|
||||
"error creating urls": "",
|
||||
"error getting defaults: {{.error}}": "",
|
||||
|
|
|
@ -883,6 +883,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "",
|
||||
"dry-run validation complete!": "",
|
||||
"enable failed": "",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "",
|
||||
"error creating urls": "",
|
||||
"error getting defaults: {{.error}}": "",
|
||||
|
|
|
@ -883,6 +883,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "",
|
||||
"dry-run validation complete!": "",
|
||||
"enable failed": "",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "",
|
||||
"error creating urls": "",
|
||||
"error getting defaults: {{.error}}": "",
|
||||
|
|
|
@ -1071,6 +1071,7 @@
|
|||
"dry-run mode. Validates configuration, but does not mutate system state": "",
|
||||
"dry-run validation complete!": "",
|
||||
"enable failed": "开启失败",
|
||||
"error checking service": "",
|
||||
"error creating clientset": "",
|
||||
"error creating urls": "",
|
||||
"error getting defaults: {{.error}}": "",
|
||||
|
|
Loading…
Reference in New Issue