mirror of https://github.com/knative/func.git
143 lines
4.6 KiB
Go
143 lines
4.6 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
|
|
fn "github.com/boson-project/func"
|
|
"github.com/boson-project/func/cloudevents"
|
|
"github.com/boson-project/func/knative"
|
|
"github.com/google/uuid"
|
|
"github.com/ory/viper"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func init() {
|
|
e := cloudevents.NewEmitter()
|
|
root.AddCommand(emitCmd)
|
|
// TODO: do these env vars make sense?
|
|
emitCmd.Flags().StringP("sink", "k", "", "Send the CloudEvent to the function running at [sink]. The special value \"local\" can be used to send the event to a function running on the local host. When provided, the --path flag is ignored (Env: $FUNC_SINK)")
|
|
emitCmd.Flags().StringP("source", "s", e.Source, "CloudEvent source (Env: $FUNC_SOURCE)")
|
|
emitCmd.Flags().StringP("type", "t", e.Type, "CloudEvent type (Env: $FUNC_TYPE)")
|
|
emitCmd.Flags().StringP("id", "i", uuid.NewString(), "CloudEvent ID (Env: $FUNC_ID)")
|
|
emitCmd.Flags().StringP("data", "d", "", "Any arbitrary string to be sent as the CloudEvent data. Ignored if --file is provided (Env: $FUNC_DATA)")
|
|
emitCmd.Flags().StringP("file", "f", "", "Path to a local file containing CloudEvent data to be sent (Env: $FUNC_FILE)")
|
|
emitCmd.Flags().StringP("content-type", "c", "application/json", "The MIME Content-Type for the CloudEvent data (Env: $FUNC_CONTENT_TYPE)")
|
|
emitCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory. Ignored when --sink is provided (Env: $FUNC_PATH)")
|
|
}
|
|
|
|
var emitCmd = &cobra.Command{
|
|
Use: "emit",
|
|
Short: "Emit a CloudEvent to a function endpoint",
|
|
Long: `Emit event
|
|
|
|
Emits a CloudEvent, sending it to the deployed function.
|
|
`,
|
|
Example: `
|
|
# Send a CloudEvent to the deployed function with no data and default values
|
|
# for source, type and ID
|
|
kn func emit
|
|
|
|
# Send a CloudEvent to the deployed function with the data found in ./test.json
|
|
kn func emit --file ./test.json
|
|
|
|
# Send a CloudEvent to the function running locally with a CloudEvent containing
|
|
# "Hello World!" as the data field, with a content type of "text/plain"
|
|
kn func emit --data "Hello World!" --content-type "text/plain" -s local
|
|
|
|
# Send a CloudEvent to the function running locally with an event type of "my.event"
|
|
kn func emit --type my.event --sink local
|
|
|
|
# Send a CloudEvent to the deployed function found at /path/to/fn with an id of "fn.test"
|
|
kn func emit --path /path/to/fn -i fn.test
|
|
|
|
# Send a CloudEvent to an arbitrary endpoint
|
|
kn func emit --sink "http://my.event.broker.com"
|
|
`,
|
|
SuggestFor: []string{"meit", "emti", "send"},
|
|
PreRunE: bindEnv("source", "type", "id", "data", "file", "path", "sink", "content-type"),
|
|
RunE: runEmit,
|
|
}
|
|
|
|
func runEmit(cmd *cobra.Command, args []string) (err error) {
|
|
config := newEmitConfig()
|
|
var endpoint string
|
|
if config.Sink != "" {
|
|
if config.Sink == "local" {
|
|
endpoint = "http://localhost:8080"
|
|
} else {
|
|
endpoint = config.Sink
|
|
}
|
|
} else {
|
|
var f fn.Function
|
|
f, err = fn.NewFunction(config.Path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
// What happens if the function hasn't been deployed but they don't run with --local=true
|
|
// Maybe we should be thinking about saving the endpoint URL in func.yaml after each deploy
|
|
var d *knative.Describer
|
|
d, err = knative.NewDescriber("")
|
|
if err != nil {
|
|
return
|
|
}
|
|
var desc fn.Description
|
|
desc, err = d.Describe(f.Name)
|
|
if err != nil {
|
|
return
|
|
}
|
|
// Use the first available route
|
|
endpoint = desc.Routes[0]
|
|
}
|
|
|
|
emitter := cloudevents.NewEmitter()
|
|
emitter.Source = config.Source
|
|
emitter.Type = config.Type
|
|
emitter.Id = config.Id
|
|
emitter.ContentType = config.ContentType
|
|
emitter.Data = config.Data
|
|
if config.File != "" {
|
|
var buf []byte
|
|
if emitter.Data != "" && config.Verbose {
|
|
// TODO: This made me wonder whether we should switch to a real logging library
|
|
fmt.Printf("WARN: Found both --data and --file. Using file: %v\n", config.File)
|
|
}
|
|
buf, err = ioutil.ReadFile(config.File)
|
|
if err != nil {
|
|
return
|
|
}
|
|
emitter.Data = string(buf)
|
|
}
|
|
|
|
client := fn.New(
|
|
fn.WithEmitter(emitter),
|
|
)
|
|
return client.Emit(cmd.Context(), endpoint)
|
|
}
|
|
|
|
type emitConfig struct {
|
|
Path string
|
|
Source string
|
|
Type string
|
|
Id string
|
|
Data string
|
|
File string
|
|
ContentType string
|
|
Sink string
|
|
Verbose bool
|
|
}
|
|
|
|
func newEmitConfig() emitConfig {
|
|
return emitConfig{
|
|
Path: viper.GetString("path"),
|
|
Source: viper.GetString("source"),
|
|
Type: viper.GetString("type"),
|
|
Id: viper.GetString("id"),
|
|
Data: viper.GetString("data"),
|
|
File: viper.GetString("file"),
|
|
ContentType: viper.GetString("content-type"),
|
|
Sink: viper.GetString("sink"),
|
|
Verbose: viper.GetBool("verbose"),
|
|
}
|
|
}
|