Skip to content

Commit

Permalink
Default namespace for resource templates if not provided. Also fixes …
Browse files Browse the repository at this point in the history
…creation of Cluster scoped resources.
  • Loading branch information
Vincent-DeSousa-Tereso authored and tekton-robot committed Sep 10, 2019
1 parent cfa2d4c commit 2f2c625
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 73 deletions.
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Tekton Triggers
Triggers enables users to map fields from an event payload into resource templates. Put another way, this allows events to both model and instantiate themselves as Kubernetes resources. In the case of `tektoncd/pipeline`, this makes it easy to encapsulate configuration into `PipelineRuns` and `PipelineResources`.
Triggers enables users to map fields from an event payload into resource templates. Put another way, this allows events to both model and instantiate themselves as Kubernetes resources. In the case of `tektoncd/pipeline`, this makes it easy to encapsulate configuration into `PipelineRun`s and `PipelineResource`s.

![TriggerFlow](../images/TriggerFlow.png)
# Learn more
Expand Down
4 changes: 2 additions & 2 deletions docs/eventlisteners.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# EventListener
`EventListeners` connect `TriggerBindings` to `TriggerTemplates` and provide an addressable endpoint, which is where webhooks/events are directed.
`EventListener`s connect `TriggerBinding`s to `TriggerTemplate`s and provide an addressable endpoint, which is where webhooks/events are directed.
Further, it is as this level that the service account is connected, which specifies what permissions the resources will be created (or at least attempted) with.
When an `EventListener` is successfully created, a service is created that references a listener pod. This listener pod accepts the incoming events and does what has been specified in the corresponding `TriggerBindings`/`TriggerTemplates`.
When an `EventListener` is successfully created, a service is created that references a listener pod. This listener pod accepts the incoming events and does what has been specified in the corresponding `TriggerBinding`s/`TriggerTemplate`s.

<!-- FILE: examples/eventlisteners/eventlistener.yaml -->
```YAML
Expand Down
8 changes: 4 additions & 4 deletions docs/triggerbindings.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# TriggerBindings
As per the name, `TriggerBindings` bind against events/triggers.
`TriggerBindings` enable you to capture fields within an event payload and store them as parameters.
The separation of `TriggerBindings` from `TriggerTemplates` was deliberate to encourage reuse between them.
As per the name, `TriggerBinding`s bind against events/triggers.
`TriggerBinding`s enable you to capture fields within an event payload and store them as parameters.
The separation of `TriggerBinding`s from `TriggerTemplate`s was deliberate to encourage reuse between them.

<!-- FILE: examples/triggerbindings/triggerbinding.yaml -->
```YAML
Expand All @@ -20,4 +20,4 @@ spec:
value: tekton-pipelines
```
`TriggerBindings` are connected to `TriggerTemplates` within an [`EventListener`](eventlisteners.md), which is where the pod is actually instantiated that "listens" for the respective events.
`TriggerBinding`s are connected to `TriggerTemplate`s within an [`EventListener`](eventlisteners.md), which is where the pod is actually instantiated that "listens" for the respective events.
8 changes: 5 additions & 3 deletions docs/triggertemplates.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# TriggerTemplates
A `TriggerTemplate` is a resource that can template resources.
`TriggerTemplates` have optional parameters that can be substituted **anywhere** within the resource template.
`TriggerTemplate`s have optional parameters that can be substituted **anywhere** within the resource template.

<!-- FILE: examples/triggertemplates/triggertemplate.yaml -->
```YAML
Expand Down Expand Up @@ -49,9 +49,11 @@ spec:
name: git-source-$(uid)
```
Similar to [Pipelines](https://github.com/tektoncd/pipeline/blob/master/docs/pipelines.md),`TriggerTemplates` do not do any actual work, but instead act as the blueprint for what resources should be created.
Similar to [Pipelines](https://github.com/tektoncd/pipeline/blob/master/docs/pipelines.md),`TriggerTemplate`s do not do any actual work, but instead act as the blueprint for what resources should be created.
Any parameters defined in the [`TriggerBinding`](triggerbindings.md) are passed into to the `TriggerTemplate` before resource creation.
The `$(uid)` variable is implicitly available throughout a `TriggerTemplate's` resource templates.
If the namespace is omitted, it will be resolved to the `EventListener`'s namespace.

The `$(uid)` variable is implicitly available throughout a `TriggerTemplate`'s resource templates.
A random string value is assigned to `$(uid)` like the postfix generated by the Kubernetes `generateName` metadata field.
One instance where there is useful is when resources in a `TriggerTemplate` have internal references.

Expand Down
35 changes: 19 additions & 16 deletions pkg/sink/sink.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ func (r Resource) HandleEvent(response http.ResponseWriter, request *http.Reques
log.Print(err)
continue
}
err = createResources(resources, r.RESTClient, r.DiscoveryClient)
err = createResources(resources, r.RESTClient, r.DiscoveryClient, r.EventListenerNamespace)
if err != nil {
log.Print(err)
}
}
}

func createResources(resources []json.RawMessage, restClient restclient.Interface, discoveryClient discoveryclient.DiscoveryInterface) error {
func createResources(resources []json.RawMessage, restClient restclient.Interface, discoveryClient discoveryclient.DiscoveryInterface, eventListenerNamespace string) error {
for _, resource := range resources {
if err := createResource(resource, restClient, discoveryClient); err != nil {
if err := createResource(resource, restClient, discoveryClient, eventListenerNamespace); err != nil {
return err
}
}
Expand All @@ -85,16 +85,20 @@ func createResources(resources []json.RawMessage, restClient restclient.Interfac

// createResource uses the kubeClient to create the resource defined in the
// TriggerResourceTemplate and returns any errors with this process
func createResource(rt json.RawMessage, restClient restclient.Interface, discoveryClient discoveryclient.DiscoveryInterface) error {
func createResource(rt json.RawMessage, restClient restclient.Interface, discoveryClient discoveryclient.DiscoveryInterface, eventListenerNamespace string) error {
// Assume the TriggerResourceTemplate is valid (it has an apiVersion and Kind)
apiVersion := gjson.GetBytes(rt, "apiVersion").String()
kind := gjson.GetBytes(rt, "kind").String()
namespace := gjson.GetBytes(rt, "metadata.namespace").String()
namePlural, err := findAPIResourceNamePlural(discoveryClient, apiVersion, kind)
// Default the resource creation to the EventListenerNamespace if not found in the resource template
if namespace == "" {
namespace = eventListenerNamespace
}
apiResource, err := findAPIResource(discoveryClient, apiVersion, kind)
if err != nil {
return err
}
uri := createRequestURI(apiVersion, namePlural, namespace)
uri := createRequestURI(apiVersion, apiResource.Name, namespace, apiResource.Namespaced)
result := restClient.Post().
RequestURI(uri).
Body([]byte(rt)).
Expand All @@ -106,31 +110,30 @@ func createResource(rt json.RawMessage, restClient restclient.Interface, discove
return nil
}

// apiResourceName returns the plural resource name for the apiVersion and kind
func findAPIResourceNamePlural(discoveryClient discoveryclient.DiscoveryInterface, apiVersion, kind string) (string, error) {
// findAPIResource returns the APIResource defintion using the discovery client.
func findAPIResource(discoveryClient discoveryclient.DiscoveryInterface, apiVersion, kind string) (*metav1.APIResource, error) {
resourceList, err := discoveryClient.ServerResourcesForGroupVersion(apiVersion)
if err != nil {
return "", xerrors.Errorf("Error getting kubernetes server resources for apiVersion %s: %s", apiVersion, err)
return nil, xerrors.Errorf("Error getting kubernetes server resources for apiVersion %s: %s", apiVersion, err)
}
for _, apiResource := range resourceList.APIResources {
if apiResource.Kind == kind {
return apiResource.Name, nil
return &apiResource, nil
}
}
return "", xerrors.Errorf("Error could not find resource with apiVersion %s and kind %s", apiVersion, kind)
return nil, xerrors.Errorf("Error could not find resource with apiVersion %s and kind %s", apiVersion, kind)
}

// createRequestURI returns the URI for a request to the kubernetes API REST endpoint
// given apiVersion, namePlural, and namespace. If namespace is an empty string,
// then namespace will be excluded from the URI
func createRequestURI(apiVersion, namePlural, namespace string) string {
// createRequestURI returns the URI for a request to the kubernetes API REST endpoint.
// If namespaced is false, then namespace will be excluded from the URI.
func createRequestURI(apiVersion, namePlural, namespace string, namespaced bool) string {
var uri string
if apiVersion == "v1" {
uri = "api/v1"
} else {
uri = path.Join(uri, "apis", apiVersion)
}
if namespace != "" {
if namespaced {
uri = path.Join(uri, "namespaces", namespace)
}
uri = path.Join(uri, namePlural)
Expand Down
Loading

0 comments on commit 2f2c625

Please sign in to comment.