diff --git a/_topic_map.yml b/_topic_map.yml index 587f0ef3ed..70f17db01b 100644 --- a/_topic_map.yml +++ b/_topic_map.yml @@ -3159,5 +3159,7 @@ Topics: File: kn-flags-reference - Name: Knative Serving CLI commands File: kn-serving-ref + - Name: Knative Eventing CLI commands + File: kn-eventing-ref - Name: kn func File: kn-func-ref diff --git a/modules/apiserversource-kn.adoc b/modules/apiserversource-kn.adoc index 3bd7b6d25e..ed2b7727a6 100644 --- a/modules/apiserversource-kn.adoc +++ b/modules/apiserversource-kn.adoc @@ -1,4 +1,4 @@ -[id="apiserversource-kn_context"] +[id="apiserversource-kn_{context}"] = Creating an API server source by using the Knative CLI This section describes the steps required to create an API server source using `kn` commands. diff --git a/modules/serverless-containersource-custom-sources.adoc b/modules/serverless-containersource-custom-sources.adoc new file mode 100644 index 0000000000..dedec6e30c --- /dev/null +++ b/modules/serverless-containersource-custom-sources.adoc @@ -0,0 +1,197 @@ +[id="serverless-containersource-custom-sources_{context}"] += Creating custom event sources by using a container source + +You can use a container source to create and manage a container for your custom event source image. + +To implement a custom event source by using a container source, you must first create a container image of your event source, and then create a container source that specifies the correct configuration, including the container image URI. + +== Guidelines for creating a container image + +* A container image can be developed using any language, and can be built and published with any tool that you prefer. + +* The main process of the container image must accept parameters from arguments and environment variables. + +* Two environment variables are injected by the container source controller: `K_SINK` and `K_CE_OVERRIDES`. These variables are resolved from the `sink` and `ceOverrides` spec, respectively. + +* Event messages are sent to the sink URI specified in the `K_SINK` environment variable. The event message can be in any format; however, using the link:https://cloudevents.io/[`CloudEvent`] spec is recommended. + +== Example container images + +The following is an example of a heartbeats container image: + +[source,go] +---- +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "log" + "os" + "strconv" + "time" + + duckv1 "knative.dev/pkg/apis/duck/v1" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/kelseyhightower/envconfig" +) + +type Heartbeat struct { + Sequence int `json:"id"` + Label string `json:"label"` +} + +var ( + eventSource string + eventType string + sink string + label string + periodStr string +) + +func init() { + flag.StringVar(&eventSource, "eventSource", "", "the event-source (CloudEvents)") + flag.StringVar(&eventType, "eventType", "dev.knative.eventing.samples.heartbeat", "the event-type (CloudEvents)") + flag.StringVar(&sink, "sink", "", "the host url to heartbeat to") + flag.StringVar(&label, "label", "", "a special label") + flag.StringVar(&periodStr, "period", "5", "the number of seconds between heartbeats") +} + +type envConfig struct { + // Sink URL where to send heartbeat cloud events + Sink string `envconfig:"K_SINK"` + + // CEOverrides are the CloudEvents overrides to be applied to the outbound event. + CEOverrides string `envconfig:"K_CE_OVERRIDES"` + + // Name of this pod. + Name string `envconfig:"POD_NAME" required:"true"` + + // Namespace this pod exists in. + Namespace string `envconfig:"POD_NAMESPACE" required:"true"` + + // Whether to run continuously or exit. + OneShot bool `envconfig:"ONE_SHOT" default:"false"` +} + +func main() { + flag.Parse() + + var env envConfig + if err := envconfig.Process("", &env); err != nil { + log.Printf("[ERROR] Failed to process env var: %s", err) + os.Exit(1) + } + + if env.Sink != "" { + sink = env.Sink + } + + var ceOverrides *duckv1.CloudEventOverrides + if len(env.CEOverrides) > 0 { + overrides := duckv1.CloudEventOverrides{} + err := json.Unmarshal([]byte(env.CEOverrides), &overrides) + if err != nil { + log.Printf("[ERROR] Unparseable CloudEvents overrides %s: %v", env.CEOverrides, err) + os.Exit(1) + } + ceOverrides = &overrides + } + + p, err := cloudevents.NewHTTP(cloudevents.WithTarget(sink)) + if err != nil { + log.Fatalf("failed to create http protocol: %s", err.Error()) + } + + c, err := cloudevents.NewClient(p, cloudevents.WithUUIDs(), cloudevents.WithTimeNow()) + if err != nil { + log.Fatalf("failed to create client: %s", err.Error()) + } + + var period time.Duration + if p, err := strconv.Atoi(periodStr); err != nil { + period = time.Duration(5) * time.Second + } else { + period = time.Duration(p) * time.Second + } + + if eventSource == "" { + eventSource = fmt.Sprintf("https://knative.dev/eventing-contrib/cmd/heartbeats/#%s/%s", env.Namespace, env.Name) + log.Printf("Heartbeats Source: %s", eventSource) + } + + if len(label) > 0 && label[0] == '"' { + label, _ = strconv.Unquote(label) + } + hb := &Heartbeat{ + Sequence: 0, + Label: label, + } + ticker := time.NewTicker(period) + for { + hb.Sequence++ + + event := cloudevents.NewEvent("1.0") + event.SetType(eventType) + event.SetSource(eventSource) + event.SetExtension("the", 42) + event.SetExtension("heart", "yes") + event.SetExtension("beats", true) + + if ceOverrides != nil && ceOverrides.Extensions != nil { + for n, v := range ceOverrides.Extensions { + event.SetExtension(n, v) + } + } + + if err := event.SetData(cloudevents.ApplicationJSON, hb); err != nil { + log.Printf("failed to set cloudevents data: %s", err.Error()) + } + + log.Printf("sending cloudevent to %s", sink) + if res := c.Send(context.Background(), event); !cloudevents.IsACK(res) { + log.Printf("failed to send cloudevent: %v", res) + } + + if env.OneShot { + return + } + + // Wait for next tick + <-ticker.C + } +} +---- + +The following is an example of a container source that references the previous heartbeats container image: + +[source,yaml] +---- +apiVersion: sources.knative.dev/v1 +kind: ContainerSource +metadata: + name: test-heartbeats +spec: + template: + spec: + containers: + # This corresponds to a heartbeats image URI that you have built and published + - image: gcr.io/knative-releases/knative.dev/eventing/cmd/heartbeats + name: heartbeats + args: + - --period=1 + env: + - name: POD_NAME + value: "example-pod" + - name: POD_NAMESPACE + value: "event-test" + sink: + ref: + apiVersion: serving.knative.dev/v1 + kind: Service + name: example-service +... +---- diff --git a/modules/serverless-kn-containersource.adoc b/modules/serverless-kn-containersource.adoc new file mode 100644 index 0000000000..361a017baa --- /dev/null +++ b/modules/serverless-kn-containersource.adoc @@ -0,0 +1,43 @@ +[id="serverless-kn-containersource_{context}"] += Creating and managing container sources by using the Knative CLI + +You can use the following `kn` commands to create and manage container sources: + +.Create a container source +[source,terminal] +---- +$ kn source container create --image --sink +---- + +.Delete a container source +[source,terminal] +---- +$ kn source container delete +---- + +.Describe a container source +[source,terminal] +---- +$ kn source container describe +---- + +.List existing container sources +[source,terminal] +---- +$ kn source container list +---- + +.List existing container sources in YAML format +[source,terminal] +---- +$ kn source container list -o yaml +---- + +.Update a container source + +This command updates the image URI for an existing container source: + +[source,terminal] +---- +$ kn source container update --image +---- diff --git a/serverless/cli_tools/kn-eventing-ref.adoc b/serverless/cli_tools/kn-eventing-ref.adoc new file mode 100644 index 0000000000..b22a36c496 --- /dev/null +++ b/serverless/cli_tools/kn-eventing-ref.adoc @@ -0,0 +1,22 @@ +include::modules/serverless-document-attributes.adoc[] +[id="kn-eventing-ref"] += Knative Eventing CLI commands +:context: kn-eventing-ref +include::modules/common-attributes.adoc[] + +toc::[] + +You can use the following `kn` CLI commands to complete Knative Eventing tasks on the cluster. + +[id="kn-eventing-ref-kn-sources"] +== kn source commands + +You can use the following commands to list, create, and manage Knative event sources. + +include::modules/serverless-list-source-types-kn.adoc[leveloffset=+2] +include::modules/serverless-kn-containersource.adoc[leveloffset=+2] +include::modules/apiserversource-kn.adoc[leveloffset=+2] +include::modules/apiserversource-kn-delete.adoc[leveloffset=+2] +include::modules/serverless-pingsource-kn.adoc[leveloffset=+2] +include::modules/deleting-pingsource-kn.adoc[leveloffset=+2] +include::modules/serverless-kafka-source-kn.adoc[leveloffset=+2] diff --git a/serverless/event_sources/serverless-containersource.adoc b/serverless/event_sources/serverless-containersource.adoc index fc213c04d2..9d9fe6235b 100644 --- a/serverless/event_sources/serverless-containersource.adoc +++ b/serverless/event_sources/serverless-containersource.adoc @@ -8,4 +8,6 @@ toc::[] Container sources create a container image that generates events and sends events to a sink. You can use a container source to create a custom event source. +include::modules/serverless-containersource-custom-sources.adoc[leveloffset=+1] +include::modules/serverless-kn-containersource.adoc[leveloffset=+1] include::modules/serverless-odc-create-containersource.adoc[leveloffset=+1]