first commit
This commit is contained in:
commit
be3c522f14
11 changed files with 635 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
env.txt
|
||||
secret.yaml
|
||||
1
.ko.yaml
Normal file
1
.ko.yaml
Normal file
|
|
@ -0,0 +1 @@
|
|||
defaultBaseImage: gcr.io/distroless/static:nonroot
|
||||
12
Dockerfile
Normal file
12
Dockerfile
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
FROM golang:alpine as builder
|
||||
RUN adduser -D -g '' appuser
|
||||
RUN mkdir /build
|
||||
ADD . /build/
|
||||
WORKDIR /build
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -gcflags 'all=-e' -ldflags "-s -w" -o main .
|
||||
FROM scratch
|
||||
COPY --from=builder /etc/passwd /etc/passwd
|
||||
COPY --from=builder /build/main /main
|
||||
USER appuser
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/main"]
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (C) 2019 Marius Schellenberger
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* The names of the authors and/or contributors may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ston1th BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
51
README.md
Normal file
51
README.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# status-reporter
|
||||
|
||||
The status reporter is a controller that watches pipelineruns for status cahnges.
|
||||
These are synced to the associated git commit hashes.
|
||||
|
||||
For successful runs a preview environment comment will be added to the pull request.
|
||||
|
||||
`PipelineRun` requirements:
|
||||
|
||||
Params:
|
||||
|
||||
* gitapi - `github`, `ghe` or `gitea`
|
||||
* issue - pull request issue id
|
||||
* scheme - `http://` or `https://`
|
||||
* tektonurl - `http://tekton-dashboard.example.com`
|
||||
* previewurl - url to your deployed preview environment
|
||||
|
||||
Resources:
|
||||
|
||||
* git - revision: githash, url: clone_url
|
||||
|
||||
# Requirements
|
||||
|
||||
* Kubernetes Cluster
|
||||
* go
|
||||
* ko
|
||||
|
||||
# Build and run
|
||||
|
||||
Create git authentication secret:
|
||||
|
||||
**NOTE:** the name must be `git-auth`.
|
||||
|
||||
```
|
||||
cat <<EOF>secret.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: git-auth
|
||||
namespace: status-reporter
|
||||
type: Opaque
|
||||
stringData:
|
||||
github.com: "<username>:<password>"
|
||||
EOF
|
||||
```
|
||||
|
||||
```
|
||||
echo KO_DOCKER_REPO='gcr.io/my-gcloud-project-name' >env.txt
|
||||
|
||||
./build.sh
|
||||
```
|
||||
8
build.sh
Executable file
8
build.sh
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
source env.txt
|
||||
kubectl -n status-reporter delete deploy status-reporter
|
||||
GO111MODULE=off ko apply -f config/
|
||||
kubectl apply -f secret.yaml
|
||||
sleep 10
|
||||
kubectl -n status-reporter logs -f $(kubectl -n status-reporter get pod -ojsonpath='{.items[0].metadata.name}')
|
||||
5
config/100-namespace.yaml
Normal file
5
config/100-namespace.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: status-reporter
|
||||
28
config/200-podsecuritypolicy.yaml
Normal file
28
config/200-podsecuritypolicy.yaml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
apiVersion: policy/v1beta1
|
||||
kind: PodSecurityPolicy
|
||||
metadata:
|
||||
name: status-reporter
|
||||
spec:
|
||||
privileged: false
|
||||
allowPrivilegeEscalation: false
|
||||
requiredDropCapabilities:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
hostNetwork: false
|
||||
hostIPC: false
|
||||
hostPID: false
|
||||
runAsUser:
|
||||
rule: 'RunAsAny'
|
||||
seLinux:
|
||||
rule: 'RunAsAny'
|
||||
supplementalGroups:
|
||||
rule: 'MustRunAs'
|
||||
ranges:
|
||||
- min: 1
|
||||
max: 65535
|
||||
fsGroup:
|
||||
rule: 'MustRunAs'
|
||||
ranges:
|
||||
- min: 1
|
||||
max: 65535
|
||||
55
config/300-rbac.yaml
Normal file
55
config/300-rbac.yaml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: status-reporter
|
||||
namespace: status-reporter
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: status-reporter
|
||||
rules:
|
||||
- apiGroups: ["tekton.dev"]
|
||||
resources: ["pipelineruns"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["policy"]
|
||||
resources: ["podsecuritypolicies"]
|
||||
resourceNames: ["status-reporter"]
|
||||
verbs: ["use"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: status-reporter
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: status-reporter
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: status-reporter
|
||||
namespace: status-reporter
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: status-reporter
|
||||
namespace: status-reporter
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: status-reporter
|
||||
namespace: status-reporter
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: status-reporter
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: status-reporter
|
||||
27
config/deployment.yaml
Normal file
27
config/deployment.yaml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: status-reporter
|
||||
namespace: status-reporter
|
||||
labels:
|
||||
app: status-reporter
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: status-reporter
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: status-reporter
|
||||
spec:
|
||||
serviceAccountName: status-reporter
|
||||
containers:
|
||||
- name: status-reporter
|
||||
image: git.giftfish.de/ston1th/status-reporter
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
imagePullPolicy: Always
|
||||
422
main.go
Normal file
422
main.go
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
// Copyright (C) 2019 Marius Schellenberger
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
|
||||
"github.com/tektoncd/pipeline/pkg/client/clientset/versioned"
|
||||
extinf "github.com/tektoncd/pipeline/pkg/client/informers/externalversions"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
//"k8s.io/apimachinery/pkg/types"
|
||||
//"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
type PipelineRun = pipelinev1alpha1.PipelineRun
|
||||
|
||||
func init() {
|
||||
log.SetFlags(log.Flags() | log.Lshortfile)
|
||||
}
|
||||
|
||||
func getNS() (string, error) {
|
||||
if ns := os.Getenv("POD_NAMESPACE"); ns != "" {
|
||||
return ns, nil
|
||||
}
|
||||
if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil {
|
||||
if ns := strings.TrimSpace(string(data)); len(ns) > 0 {
|
||||
return ns, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "default", nil
|
||||
}
|
||||
|
||||
func mapGitAPI(s string) string {
|
||||
switch s {
|
||||
case "ghe", "github":
|
||||
return "api/v3"
|
||||
case "gitea":
|
||||
return "api/v1"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func mapState(s string) string {
|
||||
switch s {
|
||||
case "Running":
|
||||
return "pending"
|
||||
case "PipelineRunCancelled":
|
||||
return "error"
|
||||
case "Failed":
|
||||
return "failure"
|
||||
case "Succeeded":
|
||||
return "success"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Type string
|
||||
Date time.Time
|
||||
}
|
||||
|
||||
type StatusCache struct {
|
||||
sync.Mutex
|
||||
cache map[string]Status
|
||||
}
|
||||
|
||||
func NewStatusCache() *StatusCache {
|
||||
return &StatusCache{cache: make(map[string]Status)}
|
||||
}
|
||||
|
||||
func (sc *StatusCache) Set(sha, status string, st, fin time.Time) bool {
|
||||
sc.Lock()
|
||||
defer sc.Unlock()
|
||||
s, ok := sc.cache[sha]
|
||||
if !ok {
|
||||
log.Printf("adding status to cache: %s %s", sha, status)
|
||||
if fin.After(st) {
|
||||
sc.cache[sha] = Status{status, fin}
|
||||
return true
|
||||
}
|
||||
sc.cache[sha] = Status{status, st}
|
||||
return true
|
||||
}
|
||||
if fin.After(s.Date) {
|
||||
log.Printf("updating status in cache: %s %s", sha, status)
|
||||
sc.cache[sha] = Status{status, fin}
|
||||
return true
|
||||
}
|
||||
if st.After(s.Date) {
|
||||
log.Printf("updating status in cache: %s %s", sha, status)
|
||||
sc.cache[sha] = Status{status, st}
|
||||
return true
|
||||
}
|
||||
if fin.Equal(s.Date) && s.Type != status {
|
||||
log.Printf("updating status in cache: %s %s", sha, status)
|
||||
sc.cache[sha] = Status{status, fin}
|
||||
return true
|
||||
}
|
||||
if st.Equal(s.Date) && s.Type != status {
|
||||
log.Printf("updating status in cache: %s %s", sha, status)
|
||||
sc.cache[sha] = Status{status, st}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (sc *StatusCache) Remove(sha string) {
|
||||
log.Printf("removing status from cache: %s", sha)
|
||||
sc.Lock()
|
||||
delete(sc.cache, sha)
|
||||
sc.Unlock()
|
||||
}
|
||||
|
||||
func getGit(pr *PipelineRun) (rev, url string) {
|
||||
for _, v := range pr.Spec.Resources {
|
||||
rs := v.ResourceSpec
|
||||
if rs == nil {
|
||||
continue
|
||||
}
|
||||
if rs.Type != "git" {
|
||||
continue
|
||||
}
|
||||
for _, rp := range rs.Params {
|
||||
if rp.Name == "revision" {
|
||||
rev = rp.Value
|
||||
}
|
||||
if rp.Name == "url" {
|
||||
url = rp.Value
|
||||
}
|
||||
if rev != "" && url != "" {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getParam(pr *PipelineRun, name string) string {
|
||||
for _, p := range pr.Spec.Params {
|
||||
if p.Name == name {
|
||||
return p.Value.StringVal
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func statusUpdate(obj interface{}, s *StatusCache, sec typedcorev1.SecretInterface) {
|
||||
pr, ok := obj.(*PipelineRun)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if len(pr.Status.Conditions) < 1 {
|
||||
return
|
||||
}
|
||||
status := pr.Status.Conditions[0].Reason
|
||||
var (
|
||||
start time.Time
|
||||
fin time.Time
|
||||
)
|
||||
st := pr.Status.StartTime
|
||||
f := pr.Status.CompletionTime
|
||||
if st != nil {
|
||||
start = (*st).Time
|
||||
}
|
||||
if f != nil {
|
||||
fin = (*f).Time
|
||||
}
|
||||
sha, url := getGit(pr)
|
||||
if sha == "" {
|
||||
return
|
||||
}
|
||||
if !s.Set(sha, status, start, fin) {
|
||||
return
|
||||
}
|
||||
secret, err := sec.Get("git-auth", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Printf("error getting secret for %s:%s: %v", sha, status, err)
|
||||
s.Remove(sha)
|
||||
return
|
||||
}
|
||||
err = postStatus(pr, url, sha, status, secret)
|
||||
if err != nil {
|
||||
log.Printf("error posting status for %s:%s: %v", sha, status, err)
|
||||
s.Remove(sha)
|
||||
return
|
||||
}
|
||||
|
||||
if status != "Succeeded" {
|
||||
return
|
||||
}
|
||||
issue := getParam(pr, "issue")
|
||||
if issue == "" || issue == "master" {
|
||||
log.Printf("skipped comment on issue %s for %s/%s", issue, pr.Namespace, pr.Name)
|
||||
return
|
||||
}
|
||||
err = postComment(pr, url, issue, secret)
|
||||
if err != nil {
|
||||
log.Printf("error posting comment for %s:%s: %v", sha, status, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
contentType = "Content-Type"
|
||||
jsonType = "application/json"
|
||||
)
|
||||
|
||||
type GitStatus struct {
|
||||
Context string `json:"context"`
|
||||
Description string `json:"description"`
|
||||
State string `json:"state"`
|
||||
TargetURL string `json:"target_url"`
|
||||
}
|
||||
|
||||
func getSecret(sec *corev1.Secret, host string) (username, password string, err error) {
|
||||
s, ok := sec.Data[host]
|
||||
if !ok {
|
||||
err = fmt.Errorf("no key found for host %s in secret %s/%s", host, sec.Namespace, sec.Name)
|
||||
return
|
||||
}
|
||||
a := strings.SplitN(string(s), ":", 2)
|
||||
if len(a) < 2 {
|
||||
err = fmt.Errorf("missing credentials for host %s in secret %s/%s", host, sec.Namespace, sec.Name)
|
||||
return
|
||||
}
|
||||
username = a[0]
|
||||
password = a[1]
|
||||
return
|
||||
}
|
||||
|
||||
func postStatus(pr *PipelineRun, gitUrl, sha, status string, sec *corev1.Secret) error {
|
||||
u, err := url.Parse(gitUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uri := strings.TrimPrefix(strings.TrimSuffix(u.RequestURI(), ".git"), "/")
|
||||
t := getParam(pr, "gitapi")
|
||||
api := mapGitAPI(t)
|
||||
if api == "" {
|
||||
return fmt.Errorf("error parsing gittype: %s", t)
|
||||
}
|
||||
u.Path = strings.Join([]string{api, "repos",
|
||||
uri, "statuses", sha}, "/")
|
||||
tektonurl := getParam(pr, "tektonurl")
|
||||
if tektonurl == "" {
|
||||
log.Printf("missing tektonurl parameter for %s/%s", pr.Namespace, pr.Name)
|
||||
}
|
||||
s := &GitStatus{
|
||||
Context: "tekton",
|
||||
Description: pr.Name,
|
||||
State: mapState(status),
|
||||
TargetURL: tektonurl,
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
err = json.NewEncoder(buf).Encode(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest("POST", u.String(), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set(contentType, jsonType)
|
||||
user, pass, err := getSecret(sec, u.Host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.SetBasicAuth(user, pass)
|
||||
c := &http.Client{Transport: &http.Transport{
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
}).DialContext,
|
||||
}}
|
||||
_, err = c.Do(req)
|
||||
return err
|
||||
}
|
||||
|
||||
type Comment struct {
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
func postComment(pr *PipelineRun, gitUrl, issue string, sec *corev1.Secret) error {
|
||||
u, err := url.Parse(gitUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uri := strings.TrimPrefix(strings.TrimSuffix(u.RequestURI(), ".git"), "/")
|
||||
t := getParam(pr, "gitapi")
|
||||
api := mapGitAPI(t)
|
||||
if api == "" {
|
||||
return fmt.Errorf("error parsing gittype: %s", t)
|
||||
}
|
||||
u.Path = strings.Join([]string{api, "repos",
|
||||
uri, "issues", issue, "comments"}, "/")
|
||||
previewurl := getParam(pr, "previewurl")
|
||||
if previewurl == "" {
|
||||
return fmt.Errorf("missing previewurl parameter for %s/%s", pr.Namespace, pr.Name)
|
||||
}
|
||||
scheme := getParam(pr, "scheme")
|
||||
preview := fmt.Sprintf("Preview Environment: [Link](%s%s)", scheme, previewurl)
|
||||
user, pass, err := getSecret(sec, u.Host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest("GET", u.String(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set(contentType, jsonType)
|
||||
req.SetBasicAuth(user, pass)
|
||||
c := &http.Client{Transport: &http.Transport{
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
}).DialContext,
|
||||
}}
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bytes.Contains(body, []byte(preview)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
comment := &Comment{preview}
|
||||
buf := new(bytes.Buffer)
|
||||
err = json.NewEncoder(buf).Encode(comment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err = http.NewRequest("POST", u.String(), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set(contentType, jsonType)
|
||||
req.SetBasicAuth(user, pass)
|
||||
_, err = c.Do(req)
|
||||
if err == nil {
|
||||
log.Printf("set git comment: %s %s", u.String(), previewurl)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
log.Fatalf("error configuring kube client: %s\n", err)
|
||||
}
|
||||
|
||||
cl, err := versioned.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("error creating new versioned kube client: %s\n", err)
|
||||
}
|
||||
kcl, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("error creating new kube client: %s\n", err)
|
||||
}
|
||||
ns, err := getNS()
|
||||
if err != nil {
|
||||
log.Fatalf("error getting current namespace %s\n", err)
|
||||
}
|
||||
sec := kcl.CoreV1().Secrets(ns)
|
||||
|
||||
extFactory := extinf.NewSharedInformerFactory(cl, time.Second*30)
|
||||
prInformer := extFactory.Tekton().V1alpha1().PipelineRuns().Informer()
|
||||
|
||||
s := NewStatusCache()
|
||||
|
||||
prInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
statusUpdate(obj, s, sec)
|
||||
},
|
||||
UpdateFunc: func(_, obj interface{}) {
|
||||
statusUpdate(obj, s, sec)
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
pr, ok := obj.(*PipelineRun)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
sha, _ := getGit(pr)
|
||||
if sha != "" {
|
||||
s.Remove(sha)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
stop := make(chan struct{})
|
||||
extFactory.Start(stop)
|
||||
log.Println("started pipelinerun watcher")
|
||||
|
||||
sigs := make(chan os.Signal)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
log.Println("started signal handler")
|
||||
sig := <-sigs
|
||||
close(stop)
|
||||
log.Printf("signal: %s\n", sig.String())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue