Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to get json for "minikube service list" #15831

Merged
merged 5 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 36 additions & 14 deletions cmd/minikube/cmd/service_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ limitations under the License.
package cmd

import (
"encoding/json"
"fmt"
"os"
"runtime"
"strings"

"github.com/spf13/cobra"
core "k8s.io/api/core/v1"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/mustload"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/reason"
Expand All @@ -32,6 +35,7 @@ import (
)

var serviceListNamespace string
var profileOutput string

// serviceListCmd represents the service list command
var serviceListCmd = &cobra.Command{
Expand All @@ -40,6 +44,7 @@ var serviceListCmd = &cobra.Command{
Long: `Lists the URLs for the services in your local cluster`,
Run: func(cmd *cobra.Command, args []string) {
co := mustload.Healthy(ClusterFlagValue())
output := strings.ToLower(profileOutput)

serviceURLs, err := service.GetServiceURLs(co.API, co.Config.Name, serviceListNamespace, serviceURLTemplate)
if err != nil {
Expand All @@ -48,28 +53,45 @@ var serviceListCmd = &cobra.Command{
os.Exit(reason.ExSvcUnavailable)
}

var data [][]string
for _, serviceURL := range serviceURLs {
if len(serviceURL.URLs) == 0 {
data = append(data, []string{serviceURL.Namespace, serviceURL.Name, "No node port"})
} else {
servicePortNames := strings.Join(serviceURL.PortNames, "\n")
serviceURLs := strings.Join(serviceURL.URLs, "\n")
switch output {
case "table":
printServicesTable(serviceURLs, co)
case "json":
printServicesJSON(serviceURLs)
default:
exit.Message(reason.Usage, fmt.Sprintf("invalid output format: %s. Valid values: 'table', 'json'", output))
}
},
}

// if we are running Docker on OSX we empty the internal service URLs
if runtime.GOOS == "darwin" && co.Config.Driver == oci.Docker {
serviceURLs = ""
}
func printServicesTable(serviceURLs service.URLs, co mustload.ClusterController) {
var data [][]string
for _, serviceURL := range serviceURLs {
if len(serviceURL.URLs) == 0 {
data = append(data, []string{serviceURL.Namespace, serviceURL.Name, "No node port"})
} else {
servicePortNames := strings.Join(serviceURL.PortNames, "\n")
serviceURLs := strings.Join(serviceURL.URLs, "\n")

data = append(data, []string{serviceURL.Namespace, serviceURL.Name, servicePortNames, serviceURLs})
// if we are running Docker on OSX we empty the internal service URLs
if runtime.GOOS == "darwin" && co.Config.Driver == oci.Docker {
serviceURLs = ""
}

data = append(data, []string{serviceURL.Namespace, serviceURL.Name, servicePortNames, serviceURLs})
}
}

service.PrintServiceList(os.Stdout, data)
},
service.PrintServiceList(os.Stdout, data)
}

func printServicesJSON(serviceURLs service.URLs) {
jsonString, _ := json.Marshal(serviceURLs)
os.Stdout.Write(jsonString)
}

func init() {
serviceListCmd.Flags().StringVarP(&profileOutput, "output", "o", "table", "The output format. One of 'json', 'table'")
serviceListCmd.Flags().StringVarP(&serviceListNamespace, "namespace", "n", core.NamespaceAll, "The services namespace")
serviceCmd.AddCommand(serviceListCmd)
}
39 changes: 39 additions & 0 deletions test/integration/functional_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"k8s.io/minikube/pkg/minikube/detect"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/reason"
"k8s.io/minikube/pkg/minikube/service"
"k8s.io/minikube/pkg/util/retry"

"github.com/blang/semver/v4"
Expand Down Expand Up @@ -1454,6 +1455,8 @@ func validateServiceCmd(ctx context.Context, t *testing.T, profile string) {
t.Errorf("expected 'service list' to contain *hello-node* but got -%q-", rr.Stdout.String())
}

validateServiceCmdJSON(ctx, t, profile)

// docs: Run `minikube service` with `--https --url` to make sure the HTTPS endpoint URL of the service is printed
cmdContext := exec.CommandContext(ctx, Target(), "-p", profile, "service", "--namespace=default", "--https", "--url", "hello-node")
if NeedsPortForward() {
Expand Down Expand Up @@ -1520,6 +1523,42 @@ func validateServiceCmd(ctx context.Context, t *testing.T, profile string) {
}
}

func validateServiceCmdJSON(ctx context.Context, t *testing.T, profile string) {
// docs: Run `minikube service list -o JSON` and make sure the services are correctly listed as JSON output
t.Run("service_json_output", func(t *testing.T) {
spowelljr marked this conversation as resolved.
Show resolved Hide resolved
targetSvcName := "hello-node"
// helper function to run command then, return target service object from json output.
extractServiceObjFunc := func(rr *RunResult) *service.SvcURL {
var jsonObjects service.URLs
err := json.Unmarshal(rr.Stdout.Bytes(), &jsonObjects)
if err != nil {
t.Errorf("failed to decode json from profile list: args %q: %v", rr.Command(), err)
return nil
spowelljr marked this conversation as resolved.
Show resolved Hide resolved
}

for _, svc := range jsonObjects {
if svc.Name == targetSvcName {
return &svc
}
}
return nil
}

start := time.Now()
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "service", "list", "-o", "json"))
elapsed := time.Since(start)
if err != nil {
t.Errorf("failed to list services with json format. args %q: %v", rr.Command(), err)
spowelljr marked this conversation as resolved.
Show resolved Hide resolved
}
t.Logf("Took %q to run %q", elapsed, rr.Command())

pr := extractServiceObjFunc(rr)
if pr == nil {
t.Errorf("expected the json of 'service list' to include %q but got *%q*. args: %q", targetSvcName, rr.Stdout.String(), rr.Command())
}
})
}

func validateServiceCmdConnect(ctx context.Context, t *testing.T, profile string) {
defer PostMortemLogs(t, profile)

Expand Down