Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions eventing/samples/github-events/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2018 The Knative 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
#
# https://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.

FROM golang AS builder

WORKDIR /go/src/github.com/knative/docs/
ADD . /go/src/github.com/knative/docs/
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you don't need to use dep, so this is much cleaner than what I had to do in the k8sevents commit (see f00e99d and d1b685a for the dep changes). Prior to needing dep, I used the following, which is even simpler than what you have here, and works from the sample directory:

FROM golang AS builder

ADD . /go/src/k8s-events
# Build the event processing function command inside the container.
# (You may fetch or manage dependencies here,
# either manually or with a tool like "godep".)
RUN go get k8s.io/api/core/v1 github.com/knative/eventing/pkg/event
RUN go install k8s-events

FROM gcr.io/distroless/base
COPY --from=builder /go/src/github.com/knative/docs/k8s-events /sample
...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the k8s event docker file and changed the path of the runable. I was able to get this to work testing the README script just fine.


RUN CGO_ENABLED=0 go build ./eventing/samples/github-events

FROM gcr.io/distroless/base

COPY --from=builder /go/src/github.com/knative/docs/github-events /sample

ENTRYPOINT ["/sample"]
EXPOSE 8080
174 changes: 174 additions & 0 deletions eventing/samples/github-events/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Reacting to GitHub Events

In response to a pull request event, the sample app _legit_ Service will add
`(looks pretty legit)` to the PR title.

A GitHub webhook will be created on a repository and a Knative `Service` will be
deployed to receive the webhook's event deliveries and forward them into a
`Channel`, through a `Bus`, and out to the consumer via a `Subscription`. The
`Flow` resource takes care of provisioning the webhook, the `Service`, the
`Channel`, and the `Subscription`.

## Prerequisites

You will need:

- A Kubernetes cluster with Knative serving installed. Follow the
[installation instructions](https://github.com/knative/docs/blob/master/install/README.md)
if you need to create one.
- [Docker](https://www.docker.com/) installed and running on your local machine,
and a Docker Hub account configured (you'll use it for a container registry).
- Knative eventing core installed on your Kubernetes cluster. You can install
with:
```shell
kubectl apply -f https://storage.googleapis.com/knative-releases/eventing/latest/release.yaml
```
- A domain name that allows GitHub to call into the cluster: Follow the
[assign a static IP address](https://github.com/knative/docs/blob/master/serving/gke-assigning-static-ip-address.md)
and
[configure a custom domain](https://github.com/knative/docs/blob/master/serving/using-a-custom-domain.md)
instructions.

## Configuring Knative

To use this sample, you'll need to install the `stub` ClusterBus and the
`github` EventSource:

```shell
# Installs ClusterBus
kubectl apply -f https://storage.googleapis.com/knative-releases/eventing/latest/release-clusterbus-stub.yaml
# Installs EventSource
kubectl apply -f https://storage.googleapis.com/knative-releases/eventing/latest/release-source-github.yaml
```

## Granting permissions

Because the `github` EventSource needs to create a Knative Service, you'll need
to provision a special ServiceAccount with the necessary permissions.

The `eventing/samples/github-events/auth.yaml` file provisions a service
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to do this from this directory, rather than rooted at docs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This matches how k8s events is asked to run. if we want to change that, then perhaps both need to be updated. It will mean that the Docker file interactions will be from a different directory than the kubectl commands.

account, and creates a role which can create a Knative Service in the `default`
namespace. In a production environment, you might want to limit the access of
this service account to only specific namespaces.

```shell
kubectl apply -f eventing/samples/github-events/auth.yaml
```

## Building and deploying the sample

1. Use Docker to build the sample code into a container. To build and push with
Docker Hub, run the following commands, replacing `{username}` with your
Docker Hub username. Run these commands, r following from the _root_ of the
`knative/docs` repo:

```shell
# Build the container on your local machine
docker build -t {username}/github-events --file=eventing/samples/github-events/Dockerfile .

# Push the container to docker registry
docker push {username}/github-events
```

1. After the build has completed and the container is pushed to Docker Hub, you
can deploy the function into your cluster. **Ensure that the container image
value in `function.yaml` matches the container you built in the previous
step.** Apply the configuration using `kubectl`:

```shell
kubectl apply -f eventing/samples/github-events/function.yaml
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again (and below), it would be nice if these could be relative to the current directory.

I'll see if I can do this for the k8sevents sample once I get my laptop back this afternoon.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an issue to fix this for all eventing samples: #351

```

1. Check that your service is running using:

```shell
kubectl get services.serving.knative.dev -o "custom-columns=NAME:.metadata.name,READY:.status.conditions[2].status,REASON:.status.conditions[2].message"
NAME READY REASON
legit True <none>
```

1. Create a [personal access token](https://github.com/settings/tokens) to
GitHub repo that the GitHub source can use to register webhooks with the
GitHub API. Also decide on a token that your code will use to authenticate
the incoming webhooks from GitHub (*accessToken*).

The token can be named anything you find convenient. This sample requires
full `repo` control to be able update the title of the _Pull Request_.
The Source requires `admin:repo_hook`, this allows it to create webhooks
into repos that your account is allowed to do so. Copy and save this token;
GitHub will force you to generate it again if misplaced.

Here I named my token "EventingSample" and have selected the recommended
scopes:

![GitHub UI](personal_access_token.png "GitHub personal access token screenshot")

Update `eventing/samples/github-events/githubsecret.yaml` with those
values. If your generated access token is `'asdfasfdsaf'` and you choose
your *secretToken* as `'personal_access_token_value'`, you'd modify
`eventing/samples/github-events/githubsecret.yaml` like so:

```yaml
apiVersion: v1
kind: Secret
metadata:
name: githubsecret
type: Opaque
stringData:
githubCredentials: >
{
"accessToken": "asdfasfdsaf",
"secretToken": "personal_access_token_value"
}
```

Hint: you can makeup a random *accessToken* with:

```shell
head -c 8 /dev/urandom | base64
```

Then, apply the githubsecret using `kubectl`:

```shell
kubectl apply -f eventing/samples/github-events/githubsecret.yaml
```

1. Update the resource inside `eventing/samples/github-events/flow.yaml` to the
org/repo of your choosing. Note that the personal access token must be valid
for the chosen org/repo.

Then create the flow sending GitHub Events to the service:

```shell
kubectl apply -f eventing/samples/github-events/flow.yaml
```

1. Create a PR for the repo you configured the webhook for, and you'll see that
the Title will be modified with the suffix `(looks pretty legit)`


## Understanding what happened

`TODO: similar to k8s-events.`

<!--TODO:
explain the resources and communication channels, as well as where the secret
is used. In particular include a note to look at
https://github.com/<owner>/<repo>/settings/hooks to see the webhook registered
and then deleted.
-->

## Cleaning up

To clean up the function, `Flow`, auth, and secret:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to clean up auth.yaml? I think it's needed to make the github source able to operate at all.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but I need help because I have not looked into what rbac arguments should look like


```shell
kubectl delete -f eventing/samples/github-events/function.yaml
kubectl delete -f eventing/samples/github-events/flow.yaml
kubectl delete -f eventing/samples/github-events/auth.yaml
kubectl delete -f eventing/samples/github-events/githubsecret.yaml
```

And then delete the [personal access token](https://github.com/settings/tokens)
created from GitHub.
43 changes: 43 additions & 0 deletions eventing/samples/github-events/auth.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright 2018 The Knative 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.
apiVersion: v1
kind: ServiceAccount
metadata:
name: feed-sa
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: create-knative-service
namespace: default
rules:
- apiGroups: ["serving.knative.dev"]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "delete", "patch"]
---
# This enables the feed-sa to deploy the receive adapter.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: feed-sa-deploy
namespace: default
subjects:
- kind: ServiceAccount
name: feed-sa
namespace: default
roleRef:
kind: Role
name: create-knative-service
apiGroup: rbac.authorization.k8s.io
37 changes: 37 additions & 0 deletions eventing/samples/github-events/flow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright 2018 The Knative 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
#
# https://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.

apiVersion: flows.knative.dev/v1alpha1
kind: Flow
metadata:
name: github-flow
namespace: default
spec:
serviceAccountName: feed-sa
trigger:
eventType: dev.knative.github.pullrequest
resource: <org>/<repo> # TODO: update this
service: github
parameters:
secretName: githubsecret
secretKey: githubCredentials
parametersFrom:
- secretKeyRef:
name: githubsecret
key: githubCredentials
action:
target:
kind: Service
apiVersion: serving.knative.dev/v1alpha1
name: legit
106 changes: 106 additions & 0 deletions eventing/samples/github-events/function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
Copyright 2018 The Knative 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

https://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 main

import (
"context"
"encoding/json"
"flag"
"fmt"
ghclient "github.com/google/go-github/github"
"github.com/knative/eventing/pkg/event"
"golang.org/x/oauth2"
"gopkg.in/go-playground/webhooks.v3/github"
"log"
"net/http"
"os"
"strings"
)

const (
// Environment variable containing json credentials
envSecret = "GITHUB_SECRET"
// this is what we tack onto each PR title if not there already
titleSuffix = "looks pretty legit"
)

// GithubHandler holds necessary objects for communicating with the Github.
type GithubHandler struct {
client *ghclient.Client
ctx context.Context
}

type GithubSecrets struct {
AccessToken string `json:"accessToken"`
SecretToken string `json:"secretToken"`
}

func (h *GithubHandler) newPullRequestPayload(ctx context.Context, pl *github.PullRequestPayload) {

title := pl.PullRequest.Title
log.Printf("GOT PR with Title: %q", title)

// Check the title and if it contains 'looks pretty legit' leave it alone
if strings.Contains(title, titleSuffix) {
// already modified, leave it alone.
return
}

newTitle := fmt.Sprintf("%s (%s)", title, titleSuffix)
updatedPR := ghclient.PullRequest{
Title: &newTitle,
}
newPR, response, err := h.client.PullRequests.Edit(h.ctx,
pl.Repository.Owner.Login, pl.Repository.Name, int(pl.Number), &updatedPR)
if err != nil {
log.Printf("Failed to update PR: %s\n%s", err, response)
return
}
if newPR.Title != nil {
log.Printf("New PR Title: %q", *newPR.Title)
} else {
log.Printf("New PR title is nil")
}
}

func main() {
flag.Parse()
githubSecrets := os.Getenv(envSecret)

var credentials GithubSecrets
err := json.Unmarshal([]byte(githubSecrets), &credentials)
if err != nil {
log.Fatalf("Failed to unmarshal credentials: %s", err)
return
}

// Set up the auth for being able to talk to Github.
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: credentials.AccessToken},
)
tc := oauth2.NewClient(ctx, ts)

client := ghclient.NewClient(tc)

h := &GithubHandler{
client: client,
ctx: ctx,
}

log.Fatal(http.ListenAndServe(":8080", event.Handler(h.newPullRequestPayload)))
}
Loading