Using the Knative sample repository

The Knative project provides a sample repository that contains a template for a basic event source controller and a receive adapter.

Prerequisites

  • You are familiar with Kubernetes and Go development.
  • You have installed Git.
  • You have installed Go.
  • You have cloned the sample-source repository.

Optional:

Sample files overview

Receiver adapter files

  • cmd/receive_adapter/main.go - Translates resource variables to the underlying adapter structure, so that they can be passed into the Knative system.

  • pkg/adapter/adapter.go - The functions that support receiver adapter translation of events to CloudEvents.

Controller files

  • cmd/controller/main.go - Passes the event source’s NewController implementation to the shared main method.

  • pkg/reconciler/sample/controller.go - The NewController implementation that is passed to the shared main method.

CRD files

  • pkg/apis/samples/VERSION/samplesource_types.go - The schema for the underlying API types, which provide the variables to be defined in the resource YAML file.

Reconciler files

  • pkg/reconciler/sample/samplesource.go - The reconciliation functions for the receive adapter.

  • pkg/apis/samples/VERSION/samplesource_lifecycle.go - Contains status information for the event source’s reconciliation details:

    • Source ready
    • Sink provided
    • Deployed
    • EventType provided
    • Kubernetes resources correct

Procedure

  1. Define the types required in the resource’s schema in pkg/apis/samples/v1alpha1/samplesource_types.go.

    This includes the fields that are required in the resource YAML, as well as those referenced in the controller using the source’s clientset and API:

    1. // +genclient
    2. // +genreconciler
    3. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
    4. // +k8s:openapi-gen=true
    5. type SampleSource struct {
    6. metav1.TypeMeta `json:",inline"`
    7. // +optional
    8. metav1.ObjectMeta `json:"metadata,omitempty"`
    9. // Spec holds the desired state of the SampleSource (from the client).
    10. Spec SampleSourceSpec `json:"spec"`
    11. // Status communicates the observed state of the SampleSource (from the controller).
    12. // +optional
    13. Status SampleSourceStatus `json:"status,omitempty"`
    14. }
    15. // SampleSourceSpec holds the desired state of the SampleSource (from the client).
    16. type SampleSourceSpec struct {
    17. // inherits duck/v1 SourceSpec, which currently provides:
    18. // * Sink - a reference to an object that will resolve to a domain name or
    19. // a URI directly to use as the sink.
    20. // * CloudEventOverrides - defines overrides to control the output format
    21. // and modifications of the event sent to the sink.
    22. duckv1.SourceSpec `json:",inline"`
    23. // ServiceAccountName holds the name of the Kubernetes service account
    24. // as which the underlying K8s resources should be run. If unspecified
    25. // this will default to the "default" service account for the namespace
    26. // in which the SampleSource exists.
    27. // +optional
    28. ServiceAccountName string `json:"serviceAccountName,omitempty"`
    29. // Interval is the time interval between events.
    30. //
    31. // The string format is a sequence of decimal numbers, each with optional
    32. // fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time
    33. // units are "ns", "us" (or "µs"), "ms", "s", "m", "h". If unspecified
    34. // this will default to "10s".
    35. Interval string `json:"interval"`
    36. }
    37. // SampleSourceStatus communicates the observed state of the SampleSource (from the controller).
    38. type SampleSourceStatus struct {
    39. duckv1.Status `json:",inline"`
    40. // SinkURI is the current active sink URI that has been configured
    41. // for the SampleSource.
    42. // +optional
    43. SinkURI *apis.URL `json:"sinkUri,omitempty"`
    44. }
  2. Define the lifecycle to be reflected in the status and SinkURI fields:

    1. const (
    2. // SampleConditionReady has status True when the SampleSource is ready to send events.
    3. SampleConditionReady = apis.ConditionReady
    4. // ...
    5. )
  3. Set the lifecycle conditions by defining the functions to be called from the reconciler functions. This is typically done in pkg/apis/samples/VERSION/samplesource_lifecycle.go:

    1. // InitializeConditions sets relevant unset conditions to Unknown state.
    2. func (s *SampleSourceStatus) InitializeConditions() {
    3. SampleCondSet.Manage(s).InitializeConditions()
    4. }
    5. ...
    6. // MarkSink sets the condition that the source has a sink configured.
    7. func (s *SampleSourceStatus) MarkSink(uri *apis.URL) {
    8. s.SinkURI = uri
    9. if len(uri.String()) > 0 {
    10. SampleCondSet.Manage(s).MarkTrue(SampleConditionSinkProvided)
    11. } else {
    12. SampleCondSet.Manage(s).MarkUnknown(SampleConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "")
    13. }
    14. }
    15. // MarkNoSink sets the condition that the source does not have a sink configured.
    16. func (s *SampleSourceStatus) MarkNoSink(reason, messageFormat string, messageA ...interface{}) {
    17. SampleCondSet.Manage(s).MarkFalse(SampleConditionSinkProvided, reason, messageFormat, messageA...)
    18. }