Added functionality to read/open multiple ports via service cmd. Also

updated tests and help text for multiple ports.  Also updated docs.
pull/729/head
Aaron Prindle 2016-10-20 11:35:37 -07:00
parent 55fd539300
commit bc1f5db71a
6 changed files with 79 additions and 64 deletions

View File

@ -22,6 +22,7 @@ import (
"time"
"github.com/docker/machine/libmachine"
"github.com/golang/glog"
"github.com/pkg/browser"
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/cluster"
@ -52,19 +53,23 @@ var dashboardCmd = &cobra.Command{
os.Exit(1)
}
url, err := cluster.GetServiceURL(api, namespace, service, nil)
urls, err := cluster.GetServiceURLs(api, namespace, service, nil)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, "Check that minikube is running.")
os.Exit(1)
}
if len(urls) == 0 {
errMsg := "There appears to be no url associated with dashboard, this is not expected, exiting"
glog.Infoln(errMsg)
os.Exit(1)
}
if dashboardURLMode {
fmt.Fprintln(os.Stdout, url)
fmt.Fprintln(os.Stdout, urls[0])
} else {
fmt.Fprintln(os.Stdout, "Opening kubernetes dashboard in default browser...")
browser.OpenURL(url)
browser.OpenURL(urls[0])
}
},
}

View File

@ -44,8 +44,8 @@ var (
// serviceCmd represents the service command
var serviceCmd = &cobra.Command{
Use: "service [flags] SERVICE",
Short: "Gets the kubernetes URL for the specified service in your local cluster",
Long: `Gets the kubernetes URL for the specified service in your local cluster`,
Short: "Gets the kubernetes URL(s) for the specified service in your local cluster",
Long: `Gets the kubernetes URL(s) for the specified service in your local cluster. In the case of multiple URLs they will be printed one at a time`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
t, err := template.New("serviceURL").Parse(serviceURLFormat)
if err != nil {
@ -76,20 +76,22 @@ var serviceCmd = &cobra.Command{
os.Exit(1)
}
url, err := cluster.GetServiceURL(api, namespace, service, serviceURLTemplate)
urls, err := cluster.GetServiceURLs(api, namespace, service, serviceURLTemplate)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, "Check that minikube is running and that you have specified the correct namespace (-n flag).")
os.Exit(1)
}
if https {
url = strings.Replace(url, "http", "https", 1)
}
if serviceURLMode {
fmt.Fprintln(os.Stdout, url)
} else {
fmt.Fprintln(os.Stdout, "Opening kubernetes service "+namespace+"/"+service+" in default browser...")
browser.OpenURL(url)
for _, url := range urls {
if https {
url = strings.Replace(url, "http", "https", 1)
}
if serviceURLMode || !strings.HasPrefix(url, "http") {
fmt.Fprintln(os.Stdout, url)
} else {
fmt.Fprintln(os.Stdout, "Opening kubernetes service "+namespace+"/"+service+" in default browser...")
browser.OpenURL(url)
}
}
},
}
@ -99,7 +101,7 @@ func init() {
serviceCmd.Flags().BoolVar(&serviceURLMode, "url", false, "Display the kubernetes service URL in the CLI instead of opening it in the default browser")
serviceCmd.Flags().BoolVar(&https, "https", false, "Open the service URL with https instead of http")
serviceCmd.PersistentFlags().StringVar(&serviceURLFormat, "format", "http://{{.IP}}:{{.Port}}", "Format to output service URL in")
serviceCmd.PersistentFlags().StringVar(&serviceURLFormat, "format", "http://{{.IP}}:{{.Port}}", "Format to output service URL in. This format will be applied to each url individually and they will be printed one at a time.")
RootCmd.AddCommand(serviceCmd)
}

View File

@ -30,7 +30,7 @@ Minikube is a CLI tool that provisions and manages single-node Kubernetes cluste
* [minikube get-k8s-versions](minikube_get-k8s-versions.md) - Gets the list of available kubernetes versions available for minikube.
* [minikube ip](minikube_ip.md) - Retrieve the IP address of the running cluster.
* [minikube logs](minikube_logs.md) - Gets the logs of the running localkube instance, used for debugging minikube, not user code.
* [minikube service](minikube_service.md) - Gets the kubernetes URL for the specified service in your local cluster
* [minikube service](minikube_service.md) - Gets the kubernetes URL(s) for the specified service in your local cluster
* [minikube ssh](minikube_ssh.md) - Log into or run a command on a machine with SSH; similar to 'docker-machine ssh'
* [minikube start](minikube_start.md) - Starts a local kubernetes cluster.
* [minikube status](minikube_status.md) - Gets the status of a local kubernetes cluster.

View File

@ -1,11 +1,11 @@
## minikube service
Gets the kubernetes URL for the specified service in your local cluster
Gets the kubernetes URL(s) for the specified service in your local cluster
### Synopsis
Gets the kubernetes URL for the specified service in your local cluster
Gets the kubernetes URL(s) for the specified service in your local cluster. In the case of multiple URLs they will be printed one at a time
```
minikube service [flags] SERVICE
@ -14,7 +14,7 @@ minikube service [flags] SERVICE
### Options
```
--format string Format to output service URL in (default "http://{{.IP}}:{{.Port}}")
--format string Format to output service URL in. This format will be applied to each url individually and they will be printed one at a time. (default "http://{{.IP}}:{{.Port}}")
--https Open the service URL with https instead of http
-n, --namespace string The service namespace (default "default")
--url Display the kubernetes service URL in the CLI instead of opening it in the default browser

View File

@ -27,7 +27,6 @@ import (
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"text/template"
"time"
@ -513,50 +512,54 @@ func CreateSSHShell(api libmachine.API, args []string) error {
type ipPort struct {
IP string
Port int
Port int32
}
func GetServiceURL(api libmachine.API, namespace, service string, t *template.Template) (string, error) {
func GetServiceURLs(api libmachine.API, namespace, service string, t *template.Template) ([]string, error) {
host, err := CheckIfApiExistsAndLoad(api)
if err != nil {
return "", errors.Wrap(err, "Error checking if api exist and loading it")
return nil, errors.Wrap(err, "Error checking if api exist and loading it")
}
ip, err := host.Driver.GetIP()
if err != nil {
return "", errors.Wrap(err, "Error getting ip from host")
return nil, errors.Wrap(err, "Error getting ip from host")
}
client, err := GetKubernetesClient()
if err != nil {
return "", err
return nil, err
}
return getServiceURLWithClient(client, ip, namespace, service, t)
return getServiceURLsWithClient(client, ip, namespace, service, t)
}
func getServiceURLWithClient(client *unversioned.Client, ip, namespace, service string, t *template.Template) (string, error) {
port, err := getServicePort(client, namespace, service)
if err != nil {
return "", err
}
func getServiceURLsWithClient(client *unversioned.Client, ip, namespace, service string, t *template.Template) ([]string, error) {
if t == nil {
return fmt.Sprintf("http://%s", net.JoinHostPort(ip, strconv.Itoa(port))), nil
return nil, errors.New("Error, attempted to generate service url with nil --format template")
}
var doc bytes.Buffer
err = t.Execute(&doc, ipPort{ip, port})
ports, err := getServicePorts(client, namespace, service)
if err != nil {
return "", err
return nil, err
}
urls := []string{}
for _, port := range ports {
u, err := url.Parse(doc.String())
if err != nil {
return "", err
var doc bytes.Buffer
err = t.Execute(&doc, ipPort{ip, port})
if err != nil {
return nil, err
}
u, err := url.Parse(doc.String())
if err != nil {
return nil, err
}
urls = append(urls, u.String())
}
return u.String(), nil
return urls, nil
}
type serviceGetter interface {
@ -568,9 +571,9 @@ type endpointGetter interface {
Get(name string) (*kubeapi.Endpoints, error)
}
func getServicePort(client *unversioned.Client, namespace, service string) (int, error) {
func getServicePorts(client *unversioned.Client, namespace, service string) ([]int32, error) {
services := client.Services(namespace)
return getServicePortFromServiceGetter(services, service)
return getServicePortsFromServiceGetter(services, service)
}
type MissingNodePortError struct {
@ -589,19 +592,21 @@ func getServiceFromServiceGetter(services serviceGetter, service string) (*kubea
return svc, nil
}
func getServicePortFromServiceGetter(services serviceGetter, service string) (int, error) {
func getServicePortsFromServiceGetter(services serviceGetter, service string) ([]int32, error) {
svc, err := getServiceFromServiceGetter(services, service)
if err != nil {
return 0, err
return nil, err
}
nodePort := 0
var nodePorts []int32
if len(svc.Spec.Ports) > 0 {
nodePort = int(svc.Spec.Ports[0].NodePort)
for _, port := range svc.Spec.Ports {
nodePorts = append(nodePorts, port.NodePort)
}
}
if nodePort == 0 {
return 0, MissingNodePortError{svc}
if len(nodePorts) == 0 {
return nil, MissingNodePortError{svc}
}
return nodePort, nil
return nodePorts, nil
}
func GetKubernetesClient() (*unversioned.Client, error) {

View File

@ -551,27 +551,30 @@ func (mockServiceGetter *MockServiceGetter) List(options api.ListOptions) (*api.
return &services, nil
}
func TestGetDashboardURL(t *testing.T) {
func TestGetServiceURLs(t *testing.T) {
mockServiceGetter := NewMockServiceGetter()
nodeport := api.ServicePort{
NodePort: 1234,
}
expected := []int32{1111, 2222}
mockDashboardService := api.Service{
Spec: api.ServiceSpec{
Ports: []api.ServicePort{nodeport},
Ports: []api.ServicePort{
{
NodePort: expected[0],
}, {
NodePort: expected[1],
}},
},
}
mockServiceGetter.services["kubernetes-dashboard"] = mockDashboardService
mockServiceGetter.services["mock-service"] = mockDashboardService
port, err := getServicePortFromServiceGetter(mockServiceGetter, "kubernetes-dashboard")
ports, err := getServicePortsFromServiceGetter(mockServiceGetter, "mock-service")
if err != nil {
t.Fatalf("Error getting dashboard port from api: Error: %s", err)
t.Fatalf("Error getting mock-service ports from api: Error: %s", err)
}
expected := 1234
if port != expected {
t.Fatalf("Error getting dashboard port from api: Expected: %d, Got: %d", port, expected)
for i := range ports {
if ports[i] != expected[i] {
t.Fatalf("Error getting mock-service port from api: Expected: %d, Got: %d", ports[0], expected)
}
}
}
func TestGetServiceURLWithoutNodePort(t *testing.T) {
@ -579,7 +582,7 @@ func TestGetServiceURLWithoutNodePort(t *testing.T) {
mockDashboardService := api.Service{}
mockServiceGetter.services["mock-service"] = mockDashboardService
_, err := getServicePortFromServiceGetter(mockServiceGetter, "mock-service")
_, err := getServicePortsFromServiceGetter(mockServiceGetter, "mock-service")
if err == nil {
t.Fatalf("Expected error getting service with no node port")
}