From 4e87a7a74e49539d5194b16bbff711a19e5659d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Sun, 26 Dec 2021 11:23:20 +0800 Subject: [PATCH 01/14] feat: support invoke cmd on kubernetes mode Signed-off-by: imneov --- cmd/invoke.go | 24 ++++-- pkg/kubernetes/invoke.go | 181 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+), 6 deletions(-) create mode 100644 pkg/kubernetes/invoke.go diff --git a/cmd/invoke.go b/cmd/invoke.go index 0a1c35d58..16b999d0c 100644 --- a/cmd/invoke.go +++ b/cmd/invoke.go @@ -22,6 +22,7 @@ import ( "github.com/spf13/cobra" + "github.com/dapr/cli/pkg/kubernetes" "github.com/dapr/cli/pkg/print" "github.com/dapr/cli/pkg/standalone" ) @@ -67,7 +68,6 @@ dapr invoke --unix-domain-socket --app-id target --method sample --verb GET } else if invokeData != "" { bytePayload = []byte(invokeData) } - client := standalone.NewClient() // TODO(@daixiang0): add Windows support if invokeSocket != "" { @@ -79,11 +79,22 @@ dapr invoke --unix-domain-socket --app-id target --method sample --verb GET } } - response, err := client.Invoke(invokeAppID, invokeAppMethod, bytePayload, invokeVerb, invokeSocket) - if err != nil { - err = fmt.Errorf("error invoking app %s: %s", invokeAppID, err) - print.FailureStatusEvent(os.Stderr, err.Error()) - return + var response string + if kubernetesMode { + response, err = kubernetes.Invoke(invokeAppID, invokeAppMethod, bytePayload, invokeVerb) + if err != nil { + err = fmt.Errorf("error invoking app %s: %s", invokeAppID, err) + print.FailureStatusEvent(os.Stderr, err.Error()) + return + } + } else { + client := standalone.NewClient() + response, err = client.Invoke(invokeAppID, invokeAppMethod, bytePayload, invokeVerb, invokeSocket) + if err != nil { + err = fmt.Errorf("error invoking app %s: %s", invokeAppID, err) + print.FailureStatusEvent(os.Stderr, err.Error()) + return + } } if response != "" { @@ -94,6 +105,7 @@ dapr invoke --unix-domain-socket --app-id target --method sample --verb GET } func init() { + InvokeCmd.Flags().BoolVarP(&kubernetesMode, "kubernetes", "k", false, "Invoke a method on a Dapr application in a Kubernetes cluster") InvokeCmd.Flags().StringVarP(&invokeAppID, "app-id", "a", "", "The application id to invoke") InvokeCmd.Flags().StringVarP(&invokeAppMethod, "method", "m", "", "The method to invoke") InvokeCmd.Flags().StringVarP(&invokeData, "data", "d", "", "The JSON serialized data string (optional)") diff --git a/pkg/kubernetes/invoke.go b/pkg/kubernetes/invoke.go new file mode 100644 index 000000000..07ac73642 --- /dev/null +++ b/pkg/kubernetes/invoke.go @@ -0,0 +1,181 @@ +/* +Copyright 2021 The Dapr Authors +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 kubernetes + +import ( + "context" + "fmt" + "github.com/dapr/cli/pkg/api" + "net/url" + "strings" + + core_v1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/net" + k8s "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +type AppInfo struct { + AppID string `csv:"APP ID" json:"appId" yaml:"appId"` + HTTPPort string `csv:"HTTP PORT" json:"httpPort" yaml:"httpPort"` + GRPCPort string `csv:"GRPC PORT" json:"grpcPort" yaml:"grpcPort"` + AppPort string `csv:"APP PORT" json:"appPort" yaml:"appPort"` + PodName string `csv:"POD NAME" json:"podName" yaml:"podName"` + Namespace string `csv:"NAMESPACE" json:"namespace" yaml:"namespace"` +} + +type ( + DaprPod core_v1.Pod + DaprAppList []*AppInfo +) + +// Invoke is a command to invoke a remote or local dapr instance. +func Invoke(appID, method string, data []byte, verb string) (string, error) { + client, err := Client() + if err != nil { + return "", err + } + + app, err := GetAppInfo(client, appID) + if err != nil { + return "", err + } + + return invoke(client.CoreV1().RESTClient(), app, method, data, verb) +} + +func invoke(client rest.Interface, app *AppInfo, method string, data []byte, verb string) (string, error) { + res, err := app.Request(client.Verb(verb), method, data, verb) + if err != nil { + return "", fmt.Errorf("error get request: %w", err) + } + + result := res.Do(context.TODO()) + rawbody, err := result.Raw() + if err != nil { + return "", fmt.Errorf("error get raw: %w", err) + } + + if len(rawbody) > 0 { + return string(rawbody), nil + } + + return "", nil +} + +func GetAppInfo(client k8s.Interface, appID string) (*AppInfo, error) { + list, err := ListAppInfos(client, appID) + if err != nil { + return nil, err + } + if len(list) == 0 { + return nil, fmt.Errorf("%s not found", appID) + } + app := list[0] + return app, nil +} + +// List outputs plugins. +func ListAppInfos(client k8s.Interface, appIDs ...string) (DaprAppList, error) { + opts := v1.ListOptions{} + podList, err := client.CoreV1().Pods(v1.NamespaceAll).List(context.TODO(), opts) + if err != nil { + return nil, fmt.Errorf("err get pods list:%w", err) + } + + fn := func(*AppInfo) bool { + return true + } + if len(appIDs) > 0 { + fn = func(a *AppInfo) bool { + for _, id := range appIDs { + if id != "" && a.AppID == id { + return true + } + } + return false + } + } + + l := make(DaprAppList, 0) + for _, p := range podList.Items { + p := DaprPod(p) + FindLoop: + for _, c := range p.Spec.Containers { + if c.Name == "daprd" { + app := getAppInfoFromPod(&p) + if fn(app) { + l = append(l, app) + } + break FindLoop + } + } + } + + return l, nil +} + +func getAppInfoFromPod(p *DaprPod) (a *AppInfo) { + for _, c := range p.Spec.Containers { + if c.Name == "daprd" { + a = &AppInfo{ + PodName: p.Name, + Namespace: p.Namespace, + } + for i, arg := range c.Args { + if arg == "--app-port" { + port := c.Args[i+1] + a.AppPort = port + } else if arg == "--dapr-http-port" { + port := c.Args[i+1] + a.HTTPPort = port + } else if arg == "--dapr-grpc-port" { + port := c.Args[i+1] + a.GRPCPort = port + } else if arg == "--app-id" { + id := c.Args[i+1] + a.AppID = id + } + } + } + } + + return +} + +func (a *AppInfo) Request(r *rest.Request, method string, data []byte, verb string) (*rest.Request, error) { + r = r.Namespace(a.Namespace). + Resource("pods"). + SubResource("proxy"). + SetHeader("Content-Type", "application/json"). + Name(net.JoinSchemeNamePort("", a.PodName, a.HTTPPort)) + if data != nil { + r = r.Body(data) + } + + u, err := url.Parse(method) + if err != nil { + return nil, fmt.Errorf("error parse method %s: %w", method, err) + } + + suffix := fmt.Sprintf("v%s/invoke/%s/method/%s", api.RuntimeAPIVersion, a.AppID, u.Path) + r = r.Suffix(suffix) + + for k, vs := range u.Query() { + r = r.Param(k, strings.Join(vs, ",")) + } + + return r, nil +} From bcf8f1a2fecc423216bb0de4df5d762e839c104d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Sun, 26 Dec 2021 11:36:17 +0800 Subject: [PATCH 02/14] feat: update cmd help Signed-off-by: imneov --- cmd/invoke.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/invoke.go b/cmd/invoke.go index 16b999d0c..63f9f807e 100644 --- a/cmd/invoke.go +++ b/cmd/invoke.go @@ -40,15 +40,18 @@ var ( var InvokeCmd = &cobra.Command{ Use: "invoke", - Short: "Invoke a method on a given Dapr application. Supported platforms: Self-hosted", + Short: "Invoke a method on a given Dapr application. Supported platforms: Kubernetes and self-hosted", Example: ` -# Invoke a sample method on target app with POST Verb +# Invoke a sample method on target app with POST Verb in self-hosted mode dapr invoke --app-id target --method sample --data '{"key":"value"} -# Invoke a sample method on target app with GET Verb +# Invoke a sample method on target app with in Kubernetes +dapr invoke -k --app-id target --method sample --data '{"key":"value"} + +# Invoke a sample method on target app with GET Verb in self-hosted mode dapr invoke --app-id target --method sample --verb GET -# Invoke a sample method on target app with GET Verb using Unix domain socket +# Invoke a sample method on target app with GET Verb using Unix domain socket in self-hosted mode dapr invoke --unix-domain-socket --app-id target --method sample --verb GET `, Run: func(cmd *cobra.Command, args []string) { From 2c3a2cd83165274ab97d86af101647ad1955004e Mon Sep 17 00:00:00 2001 From: Lirian Su Date: Thu, 23 Dec 2021 07:08:38 +0800 Subject: [PATCH 03/14] feat: support windows style delimiter (#834) - related to #779 Co-authored-by: Mukundan Sundararajan Co-authored-by: Yaron Schneider Signed-off-by: imneov --- pkg/kubernetes/client.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/kubernetes/client.go b/pkg/kubernetes/client.go index ff6d205a0..3883a2a9b 100644 --- a/pkg/kubernetes/client.go +++ b/pkg/kubernetes/client.go @@ -18,6 +18,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "strings" "sync" @@ -40,8 +41,6 @@ import ( "k8s.io/client-go/tools/clientcmd" ) -const kubeConfigDelimiter = ":" - var ( doOnce sync.Once kubeconfig *string @@ -60,6 +59,10 @@ func getConfig() (*rest.Config, error) { flag.Parse() }) kubeConfigEnv := os.Getenv("KUBECONFIG") + kubeConfigDelimiter := ":" + if runtime.GOOS == "windows" { + kubeConfigDelimiter = ";" + } delimiterBelongsToPath := strings.Count(*kubeconfig, kubeConfigDelimiter) == 1 && strings.EqualFold(*kubeconfig, kubeConfigEnv) if len(kubeConfigEnv) != 0 && !delimiterBelongsToPath { From 0a2e985578b5f0db6e5e2336c950a5502461d429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Sun, 26 Dec 2021 13:27:45 +0800 Subject: [PATCH 04/14] fix: only dapr appPort can be accessed in proxy mode Signed-off-by: imneov --- pkg/kubernetes/invoke.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/kubernetes/invoke.go b/pkg/kubernetes/invoke.go index 07ac73642..c81f4e6db 100644 --- a/pkg/kubernetes/invoke.go +++ b/pkg/kubernetes/invoke.go @@ -16,7 +16,6 @@ package kubernetes import ( "context" "fmt" - "github.com/dapr/cli/pkg/api" "net/url" "strings" @@ -160,7 +159,7 @@ func (a *AppInfo) Request(r *rest.Request, method string, data []byte, verb stri Resource("pods"). SubResource("proxy"). SetHeader("Content-Type", "application/json"). - Name(net.JoinSchemeNamePort("", a.PodName, a.HTTPPort)) + Name(net.JoinSchemeNamePort("", a.PodName, a.AppPort)) if data != nil { r = r.Body(data) } @@ -170,7 +169,7 @@ func (a *AppInfo) Request(r *rest.Request, method string, data []byte, verb stri return nil, fmt.Errorf("error parse method %s: %w", method, err) } - suffix := fmt.Sprintf("v%s/invoke/%s/method/%s", api.RuntimeAPIVersion, a.AppID, u.Path) + suffix := fmt.Sprintf("%s", u.Path) r = r.Suffix(suffix) for k, vs := range u.Query() { From 4bb0f15ab1a9af11ae66b910320caab145efa7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Thu, 30 Dec 2021 09:10:11 +0800 Subject: [PATCH 05/14] feat: add test Signed-off-by: imneov --- pkg/kubernetes/invoke_test.go | 242 ++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 pkg/kubernetes/invoke_test.go diff --git a/pkg/kubernetes/invoke_test.go b/pkg/kubernetes/invoke_test.go new file mode 100644 index 000000000..5a2cfb784 --- /dev/null +++ b/pkg/kubernetes/invoke_test.go @@ -0,0 +1,242 @@ +/* +Copyright 2021 The Dapr Authors +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 kubernetes + +import ( + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utiltesting "k8s.io/client-go/util/testing" +) + +func newDaprAppPod(name string, namespace string, appName string, creationTime time.Time, httpPort string, grpcPort string) *v1.Pod { + return &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Annotations: map[string]string{}, + Labels: map[string]string{ + "app": appName, + }, + CreationTimestamp: metav1.Time{ + Time: creationTime, + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + {}, + { + Name: "daprd", + Args: []string{ + "--mode", + "kubernetes", + "--dapr-http-port", + httpPort, + "--dapr-grpc-port", + grpcPort, + "--dapr-internal-grpc-port", + "50002", + "--dapr-listen-addresses", + "[::1],127.0.0.1", + "--dapr-public-port", + "3501", + "--app-port", + "8080", + "--app-id", + "testAppID", + "--control-plane-address", + "dapr-api.keel-system.svc.cluster.local:80", + "--app-protocol", + "http", + "--placement-host-address", + "dapr-placement-server.keel-system.svc.cluster.local:50005", + "--config", + "testAppID-Config", + "--log-level", + "info", + "--app-max-concurrency", + "-1", + "--sentry-address", + "dapr-sentry.keel-system.svc.cluster.local:80", + "--enable-metrics=true", + "--metrics-port", + "9090", + "--dapr-http-max-request-size", + "-1", + "--enable-mtls", + }, + }, + }, + }, + } +} + +func Test_getAppInfo(t *testing.T) { + client := fake.NewSimpleClientset(newDaprAppPod( + "testAppPod", "testAppNameSpace", + "testAppID", time.Now(), + "80801", "80802")) + + testCases := []struct { + name string + errorExpected bool + errString string + appID string + want *AppInfo + }{ + { + name: "get test Pod", + appID: "testAppID", + errorExpected: false, + errString: "", + want: &AppInfo{ + AppID: "testAppID", AppPort: "80801", PodName: "testAppPod", Namespace: "testAppNameSpace", + }, + }, + { + name: "get error Pod", + appID: "errorAppID", + errorExpected: true, + errString: "errorAppID not found", + want: nil, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + appInfo, err := GetAppInfo(client, tc.appID) + if tc.errorExpected { + assert.Error(t, err, "expected an error") + assert.Equal(t, tc.errString, err.Error(), "expected error strings to match") + } else { + assert.NoError(t, err, "expected no error") + assert.Equal(t, tc.want, appInfo, "expected appInfo to match") + } + }) + } +} + +func Test_invoke(t *testing.T) { + app := &AppInfo{ + AppID: "testAppID", AppPort: "8080", HTTPPort: "3500", GRPCPort: "50001", PodName: "testAppPod", Namespace: "testAppNameSpace", + } + + testCases := []struct { + name string + errorExpected bool + errString string + appID string + method string + verb string + data []byte + URLExpected string + }{ + { + name: "get request", + errorExpected: false, + errString: "", + method: "hello", + verb: "GET", + data: nil, + URLExpected: "https://localhost/api/v1/" + + "namespaces/testAppNameSpace/pods/testAppPod:8080/proxy/" + + "hello", + }, + { + name: "get request", + errorExpected: false, + errString: "", + method: "hello?abc=123&cdr=345#abb=aaa", + verb: "GET", + data: nil, + URLExpected: "https://localhost/api/v1/" + + "namespaces/testAppNameSpace/pods/testAppPod:8080/proxy/" + + "hello?abc=123&cdr=345#abb=aaa", + }, + { + name: "post request", + errorExpected: false, + errString: "", + method: "hello?abc=123&cdr=345#abb=aaa", + verb: "POST", + data: []byte("hello"), + URLExpected: "https://localhost/api/v1/" + + "namespaces/testAppNameSpace/pods/testAppPod:8080/proxy/" + + "hello?abc=123&cdr=345#abb=aaa", + }, + { + name: "post request", + errorExpected: false, + errString: "errorAppID not found", + method: "hello", + verb: "POST", + data: []byte("hello"), + URLExpected: "https://localhost/api/v1/" + + "namespaces/testAppNameSpace/pods/testAppPod:8080/proxy/" + + "hello", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + testServer, fakeHandler := testServerEnv(t, 200) + defer testServer.Close() + client, err := restClient(testServer) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + _, err = invoke(client, app, tc.method, tc.data, tc.verb) + if tc.errorExpected { + assert.Error(t, err, "expected an error") + assert.Equal(t, tc.errString, err.Error(), "expected error strings to match") + } else { + assert.NoError(t, err, "expected no error") + data := string(tc.data) + fakeHandler.ValidateRequest(t, tc.URLExpected, tc.verb, &data) + } + }) + } +} + +func testServerEnv(t *testing.T, statusCode int) (*httptest.Server, *utiltesting.FakeHandler) { + t.Helper() + fakeHandler := utiltesting.FakeHandler{ + StatusCode: statusCode, + ResponseBody: "", + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + return testServer, &fakeHandler +} + +func restClient(testServer *httptest.Server) (*rest.RESTClient, error) { + c, err := rest.RESTClientFor(&rest.Config{ + Host: testServer.URL, + ContentConfig: rest.ContentConfig{ + GroupVersion: &v1.SchemeGroupVersion, + NegotiatedSerializer: scheme.Codecs.WithoutConversion(), + }, + APIPath: "api", + Username: "user", + Password: "pass", + }) + return c, err +} From f75e0cf0438b2046e0eecae03529da065ff3888a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Thu, 30 Dec 2021 09:46:31 +0800 Subject: [PATCH 06/14] feat: update test Signed-off-by: imneov --- pkg/kubernetes/invoke_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/kubernetes/invoke_test.go b/pkg/kubernetes/invoke_test.go index 5a2cfb784..a39d9bd6d 100644 --- a/pkg/kubernetes/invoke_test.go +++ b/pkg/kubernetes/invoke_test.go @@ -28,7 +28,7 @@ import ( utiltesting "k8s.io/client-go/util/testing" ) -func newDaprAppPod(name string, namespace string, appName string, creationTime time.Time, httpPort string, grpcPort string) *v1.Pod { +func newDaprAppPod(name string, namespace string, appName string, creationTime time.Time, appPort string, httpPort string, grpcPort string) *v1.Pod { return &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -60,9 +60,9 @@ func newDaprAppPod(name string, namespace string, appName string, creationTime t "--dapr-public-port", "3501", "--app-port", - "8080", + appPort, "--app-id", - "testAppID", + appName, "--control-plane-address", "dapr-api.keel-system.svc.cluster.local:80", "--app-protocol", @@ -94,7 +94,7 @@ func Test_getAppInfo(t *testing.T) { client := fake.NewSimpleClientset(newDaprAppPod( "testAppPod", "testAppNameSpace", "testAppID", time.Now(), - "80801", "80802")) + "8080", "80801", "80802")) testCases := []struct { name string @@ -109,7 +109,7 @@ func Test_getAppInfo(t *testing.T) { errorExpected: false, errString: "", want: &AppInfo{ - AppID: "testAppID", AppPort: "80801", PodName: "testAppPod", Namespace: "testAppNameSpace", + AppID: "testAppID", HTTPPort: "80801", GRPCPort: "80802", AppPort: "8080", PodName: "testAppPod", Namespace: "testAppNameSpace", }, }, { @@ -156,7 +156,7 @@ func Test_invoke(t *testing.T) { method: "hello", verb: "GET", data: nil, - URLExpected: "https://localhost/api/v1/" + + URLExpected: "https://localhost/api/v1/" + "namespaces/testAppNameSpace/pods/testAppPod:8080/proxy/" + "hello", }, @@ -189,7 +189,7 @@ func Test_invoke(t *testing.T) { method: "hello", verb: "POST", data: []byte("hello"), - URLExpected: "https://localhost/api/v1/" + + URLExpected: "https://localhost/api/v1/" + "namespaces/testAppNameSpace/pods/testAppPod:8080/proxy/" + "hello", }, From 8df3681f94c11a1921493be37ed02c2c83289e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Thu, 30 Dec 2021 09:54:44 +0800 Subject: [PATCH 07/14] fix: collect all matching pods Signed-off-by: imneov --- pkg/kubernetes/invoke.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/kubernetes/invoke.go b/pkg/kubernetes/invoke.go index c81f4e6db..70aed5fbc 100644 --- a/pkg/kubernetes/invoke.go +++ b/pkg/kubernetes/invoke.go @@ -111,14 +111,12 @@ func ListAppInfos(client k8s.Interface, appIDs ...string) (DaprAppList, error) { l := make(DaprAppList, 0) for _, p := range podList.Items { p := DaprPod(p) - FindLoop: for _, c := range p.Spec.Containers { if c.Name == "daprd" { app := getAppInfoFromPod(&p) if fn(app) { l = append(l, app) } - break FindLoop } } } From 525921caf341a06c83acb2cd9f09896db0c43e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Sun, 10 Apr 2022 11:19:44 +0800 Subject: [PATCH 08/14] fix: --data has an unclosed single quote MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 柳丰 --- cmd/invoke.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/invoke.go b/cmd/invoke.go index 63f9f807e..072237bf0 100644 --- a/cmd/invoke.go +++ b/cmd/invoke.go @@ -43,10 +43,11 @@ var InvokeCmd = &cobra.Command{ Short: "Invoke a method on a given Dapr application. Supported platforms: Kubernetes and self-hosted", Example: ` # Invoke a sample method on target app with POST Verb in self-hosted mode -dapr invoke --app-id target --method sample --data '{"key":"value"} +dapr invoke --app-id target --method sample --data '{"key":"value"}' # Invoke a sample method on target app with in Kubernetes -dapr invoke -k --app-id target --method sample --data '{"key":"value"} +dapr invoke -k --app-id target --method sample --data '{"key":"value"}' + # Invoke a sample method on target app with GET Verb in self-hosted mode dapr invoke --app-id target --method sample --verb GET From 9dad732d8034506ca9d320de6e4eaf5ffa785750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Sun, 10 Apr 2022 11:37:53 +0800 Subject: [PATCH 09/14] fix: optimize error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 柳丰 --- cmd/invoke.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/cmd/invoke.go b/cmd/invoke.go index 072237bf0..18ca00a74 100644 --- a/cmd/invoke.go +++ b/cmd/invoke.go @@ -86,19 +86,14 @@ dapr invoke --unix-domain-socket --app-id target --method sample --verb GET var response string if kubernetesMode { response, err = kubernetes.Invoke(invokeAppID, invokeAppMethod, bytePayload, invokeVerb) - if err != nil { - err = fmt.Errorf("error invoking app %s: %s", invokeAppID, err) - print.FailureStatusEvent(os.Stderr, err.Error()) - return - } } else { client := standalone.NewClient() response, err = client.Invoke(invokeAppID, invokeAppMethod, bytePayload, invokeVerb, invokeSocket) - if err != nil { - err = fmt.Errorf("error invoking app %s: %s", invokeAppID, err) - print.FailureStatusEvent(os.Stderr, err.Error()) - return - } + } + if err != nil { + err = fmt.Errorf("error invoking app %s: %s", invokeAppID, err) + print.FailureStatusEvent(os.Stderr, err.Error()) + return } if response != "" { From c2740ad57d811d1f9bae92fb60530beec73b4d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Tue, 12 Apr 2022 08:46:05 +0800 Subject: [PATCH 10/14] fix: line break MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 柳丰 --- cmd/invoke.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/invoke.go b/cmd/invoke.go index 18ca00a74..0a28657be 100644 --- a/cmd/invoke.go +++ b/cmd/invoke.go @@ -90,6 +90,7 @@ dapr invoke --unix-domain-socket --app-id target --method sample --verb GET client := standalone.NewClient() response, err = client.Invoke(invokeAppID, invokeAppMethod, bytePayload, invokeVerb, invokeSocket) } + if err != nil { err = fmt.Errorf("error invoking app %s: %s", invokeAppID, err) print.FailureStatusEvent(os.Stderr, err.Error()) From 284b79fd7349bce4d0e7b0e3f8eee5bfbf221517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Mon, 2 May 2022 21:57:51 +0800 Subject: [PATCH 11/14] fix: remove extra line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 柳丰 --- cmd/invoke.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/invoke.go b/cmd/invoke.go index 0a28657be..266f50032 100644 --- a/cmd/invoke.go +++ b/cmd/invoke.go @@ -48,7 +48,6 @@ dapr invoke --app-id target --method sample --data '{"key":"value"}' # Invoke a sample method on target app with in Kubernetes dapr invoke -k --app-id target --method sample --data '{"key":"value"}' - # Invoke a sample method on target app with GET Verb in self-hosted mode dapr invoke --app-id target --method sample --verb GET From 8ce99eae56a86f84e09b76e629c7fbccd87befd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Thu, 2 Jun 2022 10:32:14 +0800 Subject: [PATCH 12/14] feat: remove no need to use fmt.Sprintf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 柳丰 --- pkg/kubernetes/invoke.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/kubernetes/invoke.go b/pkg/kubernetes/invoke.go index 70aed5fbc..cb0408954 100644 --- a/pkg/kubernetes/invoke.go +++ b/pkg/kubernetes/invoke.go @@ -167,8 +167,7 @@ func (a *AppInfo) Request(r *rest.Request, method string, data []byte, verb stri return nil, fmt.Errorf("error parse method %s: %w", method, err) } - suffix := fmt.Sprintf("%s", u.Path) - r = r.Suffix(suffix) + r = r.Suffix(u.Path) for k, vs := range u.Query() { r = r.Param(k, strings.Join(vs, ",")) From fd352d703c3cf5b28bffb028e2e1f5daf8ce8a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E4=B8=B0?= Date: Thu, 2 Jun 2022 16:28:37 +0800 Subject: [PATCH 13/14] feat: add usage instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 柳丰 --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index a28371179..e5d9bbd8d 100644 --- a/README.md +++ b/README.md @@ -363,6 +363,14 @@ By default, Dapr will use the `POST` verb. If your app uses Dapr for gRPC, you s $ dapr invoke --app-id nodeapp --method mymethod --verb GET ``` +Invoke your app in Kubernetes mode: + +If your app running in a Kubernetes cluster, use the `invoke` command with `--kubernetes` flag or the `-k` shorthand. + +``` +$ dapr invoke --kubernetes --app-id nodeapp --method mymethod +``` + ### List To list all Dapr instances running on your machine: From a2e55e82016a11ad8c961ba676a8a2d3f76517ed Mon Sep 17 00:00:00 2001 From: liufeng Date: Sun, 11 Sep 2022 10:27:42 +0800 Subject: [PATCH 14/14] fix lint Signed-off-by: liufeng --- pkg/kubernetes/invoke.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pkg/kubernetes/invoke.go b/pkg/kubernetes/invoke.go index cb0408954..2438a856d 100644 --- a/pkg/kubernetes/invoke.go +++ b/pkg/kubernetes/invoke.go @@ -124,32 +124,33 @@ func ListAppInfos(client k8s.Interface, appIDs ...string) (DaprAppList, error) { return l, nil } -func getAppInfoFromPod(p *DaprPod) (a *AppInfo) { +func getAppInfoFromPod(p *DaprPod) *AppInfo { + var appInfo *AppInfo for _, c := range p.Spec.Containers { if c.Name == "daprd" { - a = &AppInfo{ + appInfo = &AppInfo{ PodName: p.Name, Namespace: p.Namespace, } for i, arg := range c.Args { if arg == "--app-port" { port := c.Args[i+1] - a.AppPort = port + appInfo.AppPort = port } else if arg == "--dapr-http-port" { port := c.Args[i+1] - a.HTTPPort = port + appInfo.HTTPPort = port } else if arg == "--dapr-grpc-port" { port := c.Args[i+1] - a.GRPCPort = port + appInfo.GRPCPort = port } else if arg == "--app-id" { id := c.Args[i+1] - a.AppID = id + appInfo.AppID = id } } } } - return + return appInfo } func (a *AppInfo) Request(r *rest.Request, method string, data []byte, verb string) (*rest.Request, error) {