Merge pull request #428 from aaron-prindle/dashboard-wait
Have working minikube service & minikube dashboard wait until ready functionality.pull/375/merge
commit
d799222e35
|
@ -19,13 +19,15 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/browser"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/minikube/pkg/minikube/cluster"
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
|
||||
commonutil "k8s.io/minikube/pkg/util"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -40,9 +42,20 @@ var dashboardCmd = &cobra.Command{
|
|||
Run: func(cmd *cobra.Command, args []string) {
|
||||
api := libmachine.NewClient(constants.Minipath, constants.MakeMiniPath("certs"))
|
||||
defer api.Close()
|
||||
url, err := cluster.GetServiceURL(api, "kube-system", "kubernetes-dashboard")
|
||||
|
||||
cluster.EnsureMinikubeRunningOrExit(api)
|
||||
namespace := "kube-system"
|
||||
service := "kubernetes-dashboard"
|
||||
|
||||
if err := commonutil.RetryAfter(20, func() error { return CheckService(namespace, service) }, 6*time.Second); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Could not find finalized endpoint being pointed to by %s: %s", service, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
url, err := cluster.GetServiceURL(api, namespace, service)
|
||||
if err != nil {
|
||||
glog.Errorln("Error accessing the kubernetes dashboard (is minikube running?): Error: ", err)
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
fmt.Fprintln(os.Stderr, "Check that minikube is running.")
|
||||
os.Exit(1)
|
||||
}
|
||||
if dashboardURLMode {
|
||||
|
@ -51,6 +64,7 @@ var dashboardCmd = &cobra.Command{
|
|||
fmt.Fprintln(os.Stdout, "Opening kubernetes dashboard in default browser...")
|
||||
browser.OpenURL(url)
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -19,12 +19,16 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/pkg/browser"
|
||||
"github.com/spf13/cobra"
|
||||
kubeApi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/minikube/pkg/minikube/cluster"
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
|
||||
commonutil "k8s.io/minikube/pkg/util"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -44,9 +48,15 @@ var serviceCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
service := args[0]
|
||||
|
||||
api := libmachine.NewClient(constants.Minipath, constants.MakeMiniPath("certs"))
|
||||
defer api.Close()
|
||||
|
||||
cluster.EnsureMinikubeRunningOrExit(api)
|
||||
if err := commonutil.RetryAfter(20, func() error { return CheckService(namespace, service) }, 6*time.Second); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Could not find finalized endpoint being pointed to by %s: %s", service, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
url, err := cluster.GetServiceURL(api, namespace, service)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
@ -67,3 +77,31 @@ func init() {
|
|||
serviceCmd.Flags().BoolVar(&serviceURLMode, "url", false, "Display the kubernetes service URL in the CLI instead of opening it in the default browser")
|
||||
RootCmd.AddCommand(serviceCmd)
|
||||
}
|
||||
|
||||
// CheckService waits for the specified service to be ready by returning an error until the service is up
|
||||
// The check is done by polling the endpoint associated with the service and when the endpoint exists, returning no error->service-online
|
||||
func CheckService(namespace string, service string) error {
|
||||
endpoints, err := cluster.GetKubernetesEndpointsWithNamespace(namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
endpoint, err := endpoints.Get(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return CheckEndpointReady(endpoint)
|
||||
}
|
||||
|
||||
func CheckEndpointReady(endpoint *kubeApi.Endpoints) error {
|
||||
if len(endpoint.Subsets) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "Waiting, endpoint for service is not ready yet...\n")
|
||||
return fmt.Errorf("Endpoint for service is not ready yet\n")
|
||||
}
|
||||
for _, subset := range endpoint.Subsets {
|
||||
if len(subset.NotReadyAddresses) != 0 {
|
||||
fmt.Fprintf(os.Stderr, "Waiting, endpoint for service is not ready yet...\n")
|
||||
return fmt.Errorf("Endpoint for service is not ready yet\n")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
kubeApi "k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
func TestCheckEndpointReady(t *testing.T) {
|
||||
endpointNoSubsets := &kubeApi.Endpoints{}
|
||||
if err := CheckEndpointReady(endpointNoSubsets); err == nil {
|
||||
t.Fatalf("Endpoint had no subsets but CheckEndpointReady did not return an error")
|
||||
}
|
||||
|
||||
endpointNotReady := &kubeApi.Endpoints{
|
||||
Subsets: []kubeApi.EndpointSubset{
|
||||
{Addresses: []kubeApi.EndpointAddress{
|
||||
{IP: "1.1.1.1"},
|
||||
{IP: "2.2.2.2"}},
|
||||
NotReadyAddresses: []kubeApi.EndpointAddress{
|
||||
{IP: "3.3.3.3"},
|
||||
}}}}
|
||||
if err := CheckEndpointReady(endpointNotReady); err == nil {
|
||||
t.Fatalf("Endpoint had NotReadyAddresses but CheckEndpointReady did not return an error")
|
||||
}
|
||||
|
||||
endpointReady := &kubeApi.Endpoints{
|
||||
Subsets: []kubeApi.EndpointSubset{
|
||||
{Addresses: []kubeApi.EndpointAddress{
|
||||
{IP: "1.1.1.1"},
|
||||
{IP: "2.2.2.2"},
|
||||
},
|
||||
NotReadyAddresses: []kubeApi.EndpointAddress{},
|
||||
}},
|
||||
}
|
||||
if err := CheckEndpointReady(endpointReady); err != nil {
|
||||
t.Fatalf("Endpoint was ready with no NotReadyAddresses but CheckEndpointReady returned an error")
|
||||
}
|
||||
}
|
|
@ -507,8 +507,12 @@ type serviceGetter interface {
|
|||
Get(name string) (*kubeApi.Service, error)
|
||||
}
|
||||
|
||||
type endpointGetter interface {
|
||||
Get(name string) (*kubeApi.Endpoints, error)
|
||||
}
|
||||
|
||||
func getServicePort(namespace, service string) (int, error) {
|
||||
services, err := getKubernetesServicesWithNamespace(namespace)
|
||||
services, err := GetKubernetesServicesWithNamespace(namespace)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -530,7 +534,7 @@ func getServicePortFromServiceGetter(services serviceGetter, service string) (in
|
|||
return nodePort, nil
|
||||
}
|
||||
|
||||
func getKubernetesServicesWithNamespace(namespace string) (serviceGetter, error) {
|
||||
func GetKubernetesClient() (*unversioned.Client, error) {
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
configOverrides := &clientcmd.ConfigOverrides{}
|
||||
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
|
||||
|
@ -542,6 +546,37 @@ func getKubernetesServicesWithNamespace(namespace string) (serviceGetter, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func GetKubernetesServicesWithNamespace(namespace string) (serviceGetter, error) {
|
||||
client, err := GetKubernetesClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
services := client.Services(namespace)
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func GetKubernetesEndpointsWithNamespace(namespace string) (endpointGetter, error) {
|
||||
client, err := GetKubernetesClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endpoints := client.Endpoints(namespace)
|
||||
return endpoints, nil
|
||||
}
|
||||
|
||||
// EnsureMinikubeRunningOrExit checks that minikube has a status available and that
|
||||
// that the status is `Running`, otherwise it will exit
|
||||
func EnsureMinikubeRunningOrExit(api libmachine.API) {
|
||||
s, err := GetHostStatus(api)
|
||||
if err != nil {
|
||||
glog.Errorln("Error getting machine status:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if s != state.Running.String() {
|
||||
fmt.Fprintln(os.Stdout, "minikube is not currently running so the service cannot be accessed")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue