diff --git a/.gitignore b/.gitignore index ff3a5323..d6da41d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ out/ run.sh .vscode +manifests/config.yaml \ No newline at end of file diff --git a/README.md b/README.md index 3421807c..70395da0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,22 @@ # qe-eventmanager Sample app for handling qe events +[![Container Repository on Quay](https://quay.io/repository/ariobolo/qe-eventmanager/status "Container Repository on Quay")](https://quay.io/repository/ariobolo/qe-eventmanager) + # overview UMB integration with qe platform ![Overview](docs/diagrams/overview.jpg?raw=true) + +# Deploy + +```bash +# Create config +manifest/create-config.sh $CA_FILE_PATH $CERTIFICATE_FILE_PATH $KEY_FILE_PATH $BROKERS + +# Deploy resources +oc apply -f manifest/config.yaml +oc apply -f manifest/rbac.yaml +oc apply -f manifest/deployment.yaml +``` diff --git a/docs/diagrams/next.drawio b/docs/diagrams/next.drawio new file mode 100644 index 00000000..1b6ba8e0 --- /dev/null +++ b/docs/diagrams/next.drawio @@ -0,0 +1 @@ +7VzdcqM2GH2azLQXmwEkQFxusrvdXmQm022n2asOBtnWLAaPkDd2n77CFhgkOZYdAYndK1tCYDjf0fl+JHwD7hfr32i8nD8UKc5uPCdd34BPN57nIhDyj6pns+tByNl1zChJxaB9xzfyLxad9bAVSXHZGciKImNk2e1MijzHCev0xZQWz91h0yLr/uoynmGl41sSZ2rv3yRlc/EUvrPv/4rJbF7/suuII4u4Hiw6ynmcFs+tLvD5BtzTomC7b4v1Pc4q8Gpcdud9OXC0uTGKc2ZyAvvjMYfw6WHzz8Pmy1c826Dl5IMb7S7zM85W4onF3bJNDQEtVnmKq6u4N+DueU4Y/raMk+roMzc675uzRSYOxxmZ5fx7hqf8ru6mJMvui6yg20uBNMZomvD+ktHiB24dCRKEJ1N+RNwPpgyvDz6p2+DHiYeLBWZ0w4eIEwKBuKAcAKL9vDcgqGk4bxmvOTEWpJk1l97jyr8IaE+B2TLKEqzYTX0c6mCNghDEgR1YYRdWpKLqehpUewPVU0D96+FOwZU/L+uC1wUpL3IsISq6aionHB/M++8q9AiXho/iwIKkafUzWmvt7enYgR914W+EpoU/1JG6L/iBHn7nd47WjMaMQ2mT45zhKIU6jiNvAgJLHPd8CWUNyz1HA3PYF8z+cengnmVZfU1imr5RXCNJkgONePgaWJtO67gGCq48hChXC7yNMJYk6UFJhFMcV0dcV7JFqNpC6x37skSoWILiGX+8bQyVzK/GDtHIdkCKHXCeLgvCH8dzfmGUzGaYlr9eiz2gq9Eod0iDqLH5khbpKrk6iYJw5KlR30/bFDEtST6rckpaLKrHI0uckRzTVc5bFJerjJVXYyGNE3F1cVJ/JlJzLCFZduOlKUpwok1hJ8iHviV8lRzWNGDqLV5yVTct8J2QPN3OhPcPM/T8sWFWvXAtLBcBsCbIGRZgT5VyBVge93ysaocVtllcliTpQonXhD1VYnoLARDt79u244Si/Wkt1Hbb2NSNnD/DU7uxOy/06/b+vG1r07rKI6aEg1DVIrZ952ZyOFVqnpI9ORrFiib4BRzFRGExnWH2wjig50fL/i+Zn+IsZuRn93Z1nBC/8CjC1Zp+Us1KodXuMcVZXqt4Kl9ISmCbGkB9oR0OyoU4jeJNa9g2nC4P37Dr+93fAUBi/O6Ke/43mL5iSqiu80/8gxW5MjHOKgU39bNRFAhJkcr4ZUvPggA1MnLrt4XENVCRp5aIfd9f4rBkHVceY0taUZ460jsqPYeYMY72AFvaAwy1x5o8qJXe/wl7EmHDd0FY6Ek8i/zzCBtKkqsUcfsmLLQZ4kVRN8QL4ADsO3e+2GQtepeshbLjNmatI7EWDsxadaVHrEioFQyrcdgwK0CBLArjB2LqEtCrZAJ1ZAK6L8vEgUTwWB54uu10gmRRJoCpSvhXHYwdTgSt64haqHsFrf02qc0Y7d46DuqyGgThsUCvar2pAodnWuG47izj1ApHILtZx5NmQR8VjsNV1e1yzfsvc0ShBKtuwWBY92qwtdBUh05K/w6Ezs5pnnXYFNEzrmmgMdUGyWoji4Sp2iC5nmqYIp5cT3WANC/czi7ZfuSm/s32lpbtqvDBpZwLCOg93RLwoIoDDLbZnhf5mMbyr1Ic483Rw4Y3wNHTYBjF8aVtr82LAacqTiALgUzDntN7oFZRxfr5h/02q/cfhyDngL3GU4XTqoFit42+dh2EoJvYRFFkIbGxGmu88Xodilw7ExqhoDuhIRh2QhvszB4yvj1WGh41ma7F97i3GXW/QChlUWcXk5FclZZZbim+RfI+MWeI8FYtnO7CW5JPC3qh9WrtDrxhHZnFwt7lC05g6g1HTahDKaGG55bvkKRczT6XvhPq+rWFfhVHrd+dTf1TMrtRMzRznxmMSeFAztDOpbByIUMK2yJZPRWlTf6VOxPb+at7ydPKdrj6COJF5brySblsLH9ZTk/34sWwTg+OVNMZd+abOi84am1GnrBA3jFx7swH8tu0fc98722QzGAxv7XI6nrdWkQQHt1Np6tFWOQtNPVYo1YgZLb5MttMaQulRYxGGW0vmUqxnS//04c83jttvO+/brzbHd9PCAjV+mnJuDeu3n3xnBRPSU4YqfasOwuczOOclAtlEl/Mn0HI7wn4usWXSDOHznj/jjf3/1KzM+f+v37A5/8A \ No newline at end of file diff --git a/docs/diagrams/next.jpg b/docs/diagrams/next.jpg new file mode 100644 index 00000000..3514d3dd Binary files /dev/null and b/docs/diagrams/next.jpg differ diff --git a/images/builder/Dockerfile b/images/builder/Dockerfile index 3d49dee1..1761187b 100644 --- a/images/builder/Dockerfile +++ b/images/builder/Dockerfile @@ -1,6 +1,7 @@ # Build the manager binary FROM registry.access.redhat.com/ubi8/go-toolset:1.14.12 as builder +USER root WORKDIR /workspace COPY . . RUN make build @@ -12,12 +13,3 @@ LABEL MAINTAINER "Adrian Riobo" "" COPY --from=builder /workspace/out/qe-eventmanager /workspace/images/builder/entrypoint.sh /usr/local/bin/ ENTRYPOINT entrypoint.sh - - - -# "start", -# "-b", "messaging-devops-broker02.web.stage.ext.phx2.redhat.com:61612", -# "--ca-certs", "/etc/pki/ca-trust/source/anchors/2015-RH-IT-Root-CA.pem", -# "--certificate-file", "/home/ariobolo/02OFFTOPIC/umb-certificates/psi-crcqe-openstack.crt", -# "--private-key-file", "/home/ariobolo/02OFFTOPIC/umb-certificates/psi-crcqe-openstack.key", -# "-k", "/home/ariobolo/02OFFTOPIC/umb-certificates/config"] \ No newline at end of file diff --git a/images/builder/entrypoint.sh b/images/builder/entrypoint.sh index 5bd8565a..a5b7e3fb 100755 --- a/images/builder/entrypoint.sh +++ b/images/builder/entrypoint.sh @@ -29,18 +29,16 @@ fi # Run qe-eventmanager if [ -z "${KUBECONFIG}" ]; then - # Inside the cluster por running as SA with permissions - qe-eventmanager start \ - --brokers "${BROKERS}" \ - --ca-certs "${CA}" \ - --certificate-file "${CERTIFICATE}" \ - --private-key-file "${KEY}" \ + exec qe-eventmanager start \ + --brokers "${BROKERS}" \ + --ca-certs "${CA}" \ + --certificate-file "${CERTIFICATE}" \ + --private-key-file "${KEY}" else - # OCP Cluster access based on kubeconfig file - qe-eventmanager start \ - --brokers "${BROKERS}" \ - --ca-certs "${CA}" \ - --certificate-file "${CERTIFICATE}" \ - --private-key-file "${KEY}" \ - --kubeconfig "${KUBECONFIG}" + exec qe-eventmanager start \ + --brokers "${BROKERS}" \ + --ca-certs "${CA}" \ + --certificate-file "${CERTIFICATE}" \ + --private-key-file "${KEY}" \ + --kubeconfig "${KUBECONFIG}" fi diff --git a/manifests/create-config.sh b/manifests/create-config.sh new file mode 100755 index 00000000..66e3864b --- /dev/null +++ b/manifests/create-config.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Usage create-config.sh $CA_FILE_PATH $CERTIFICATE_FILE_PATH $KEY_FILE_PATH $BROKERS + +ca=$(cat $1 | base64 -w0) +certificate=$(cat $2 | base64 -w0) +key=$(cat $3 | base64 -w0) +brokers=$(echo -n $4 | base64 -w0) + + +if [ "${DEBUG:-}" = "true" ]; then + set -xuo +fi + +set -e pipefail + +# Create file +cat < config.yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: qe-eventmanager-config +type: Opaque +data: + ca: ${ca} + certificate: ${certificate} + key: ${key} + brokers: ${brokers} +EOF \ No newline at end of file diff --git a/manifests/create-secret.sh b/manifests/create-secret.sh deleted file mode 100644 index ae7ae8a6..00000000 --- a/manifests/create-secret.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -oc create secret generic qe-eventmanager-config \ - --from-file=ca=ca.crt \ - --from-file=certificate=user.crt \ - --from-file=key=user.key \ No newline at end of file diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml index c0e82421..b51c9acd 100644 --- a/manifests/deployment.yaml +++ b/manifests/deployment.yaml @@ -18,16 +18,30 @@ spec: containers: - name: qe-eventmanager image: quay.io/ariobolo/qe-eventmanager:0.0.1 + env: + - name: BROKERS + valueFrom: + secretKeyRef: + name: qe-eventmanager-config + key: brokers + - name: CA + value: /etc/qe-eventmanager/ca.crt + - name: CERTIFICATE + value: /etc/qe-eventmanager/sa.crt + - name: KEY + value: /etc/qe-eventmanager/sa.key volumeMounts: - - mountPath: /var/run/secrets/tokens - name: vault-token - serviceAccountName: pipeline-runner + - mountPath: /etc/qe-eventmanager/ + name: qe-eventmanager-config + serviceAccountName: qe-eventmanager volumes: - - name: vault-token - projected: - sources: - - serviceAccountToken: - path: vault-token - expirationSeconds: 7200 - audience: vault - \ No newline at end of file + - name: qe-eventmanager-config + secret: + secretName: qe-eventmanager-config + items: + - key: ca + path: ca.crt + - key: certificate + path: sa.crt + - key: key + path: sa.key diff --git a/manifests/rbac.yaml b/manifests/rbac.yaml index dfef4e29..c13f2ec1 100644 --- a/manifests/rbac.yaml +++ b/manifests/rbac.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: pipeline-runner + name: qe-eventmanager labels: app.kubernetes.io/component: rbac app.kubernetes.io/part-of: qe-eventmanager @@ -10,7 +10,7 @@ metadata: kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: pipeline-runner + name: qe-eventmanager labels: app.kubernetes.io/component: rbac app.kubernetes.io/part-of: qe-eventmanager @@ -22,14 +22,14 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: pipeline-runner + name: qe-eventmanager labels: app.kubernetes.io/component: rbac app.kubernetes.io/part-of: qe-eventmanager subjects: - kind: ServiceAccount - name: pipeline-runner + name: qe-eventmanager roleRef: kind: Role - name: pipeline-runner + name: qe-eventmanager apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/pkg/crc/pipelines/contants.go b/pkg/crc/pipelines/contants.go index 4270f2c0..c7dc410b 100644 --- a/pkg/crc/pipelines/contants.go +++ b/pkg/crc/pipelines/contants.go @@ -22,6 +22,6 @@ var ( } defaultTimeout v1.Duration = v1.Duration{ - Duration: 5 * time.Hour, + Duration: 8 * time.Hour, } ) diff --git a/pkg/crc/pipelines/pipelines.go b/pkg/crc/pipelines/pipelines.go index a6046036..aef830ed 100644 --- a/pkg/crc/pipelines/pipelines.go +++ b/pkg/crc/pipelines/pipelines.go @@ -15,10 +15,12 @@ const ( ocpVersionParamName string = "ocp-version" correlationParamName string = "correlation" + serversidsParamName string = "servers-ids" + platformsParamName string = "platforms" ) -func RunInteropOCP(ocpVersion, correlation string) (string, string, *v1beta1.PipelineRunStatus, error) { - pipelinerun, err := pipelines.CreatePipelinerun(crcNamespace, getSpecInteropOCP(ocpVersion, correlation)) +func RunInteropOCP(ocpVersion, correlation, serversids, platforms string) (string, string, *v1beta1.PipelineRunStatus, error) { + pipelinerun, err := pipelines.CreatePipelinerun(crcNamespace, getSpecInteropOCP(ocpVersion, correlation, serversids, platforms)) if err != nil { return "", "", nil, err } @@ -30,7 +32,7 @@ func RunInteropOCP(ocpVersion, correlation string) (string, string, *v1beta1.Pip return pipelinerun.GetName(), correlation, <-status, nil } -func getSpecInteropOCP(ocpVersion, correlation string) *v1beta1.PipelineRun { +func getSpecInteropOCP(ocpVersion, correlation, serversids, platforms string) *v1beta1.PipelineRun { return &v1beta1.PipelineRun{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{GenerateName: pipelineRunName, Namespace: crcNamespace}, @@ -38,7 +40,9 @@ func getSpecInteropOCP(ocpVersion, correlation string) *v1beta1.PipelineRun { PipelineRef: &v1beta1.PipelineRef{Name: pipelineRefName}, Params: []v1beta1.Param{ {Name: ocpVersionParamName, Value: *v1beta1.NewArrayOrString(ocpVersion)}, - {Name: correlationParamName, Value: *v1beta1.NewArrayOrString(correlation)}}, + {Name: correlationParamName, Value: *v1beta1.NewArrayOrString(correlation)}, + {Name: serversidsParamName, Value: *v1beta1.NewArrayOrString(serversids)}, + {Name: platformsParamName, Value: *v1beta1.NewArrayOrString(platforms)}}, Timeout: &defaultTimeout, Workspaces: []v1beta1.WorkspaceBinding{crcWorkspace}}, } diff --git a/pkg/event/interop/ocp/event.go b/pkg/event/interop/ocp/event.go index 09a0bd05..56f5b6be 100644 --- a/pkg/event/interop/ocp/event.go +++ b/pkg/event/interop/ocp/event.go @@ -2,6 +2,7 @@ package ocp import ( "fmt" + "strings" "time" "github.com/mitchellh/mapstructure" @@ -13,11 +14,19 @@ import ( ) const ( - topicBuildComplete string = "VirtualTopic.qe.ci.product-scenario.ascerra.build.complete" - topicTestComplete string = "VirtualTopic.qe.ci.product-scenario.ascerra.test.complete" + topicBuildComplete string = "VirtualTopic.qe.ci.product-scenario.build.complete" + topicTestComplete string = "VirtualTopic.qe.ci.product-scenario.test.complete" // testError string = "VirtualTopic.qe.ci.product-scenario.ascerra.test.error" ) +var ( + serversids []string = []string{"macos14-brno", "macos15-brno", "windows10-brno", "rhel8-brno"} + platforms []string = []string{"fedora33", "rhel79", "rhel83"} + files []string = []string{"basic.xml", "config.xml", "story_health.xml", + "story_marketplace.xml", "story_registry.xml", "cert_rotation.xml", + "proxy.xml", "integration.xml"} +) + type ProductScenarioBuild struct { } @@ -35,17 +44,29 @@ func (p ProductScenarioBuild) Handler(event interface{}) error { return err } // Business Logic + var openshiftVersion string = "" + var codereadyContainersMessage bool = false for _, product := range data.Artifact.Products { if product.Name == "openshift" { - name, correlation, _, err := pipelines.RunInteropOCP(product.Id, util.GenerateCorrelation()) - if err != nil { - logging.Error(err) - } - // We will take info from status to send back the results - response := buildResponse(name, correlation, &data) - return umb.Send(topicTestComplete, response) + openshiftVersion = product.Id + } + if product.Name == "codeready_containers" { + codereadyContainersMessage = true } } + // Filtering this will be improved in future versions + if len(openshiftVersion) > 0 && codereadyContainersMessage { + name, correlation, _, err := + pipelines.RunInteropOCP(openshiftVersion, util.GenerateCorrelation(), + strings.Join(serversids[:], ","), + strings.Join(platforms[:], ",")) + if err != nil { + logging.Error(err) + } + // We will take info from status to send back the results + response := buildResponse(name, correlation, &data) + return umb.Send(topicTestComplete, response) + } return nil } @@ -67,14 +88,10 @@ func buildResponse(name, correlation string, source *BuildComplete) *TestComplet func xunitFilesUrls(correlation string) []string { var xunitUrls []string - servers := []string{"fedora33", "macos14-brno", "macos15-brno", - "rhel79", "rhel8-brno", "rhel83", "windows10-brno"} - files := []string{"basic.xml", "config.xml", "story_health.xml", - "story_marketplace.xml", "story_registry.xml", "cert_rotation.xml", - "proxy.xml", "integration.xml"} datalakeUrl := "http://10.0.110.220:9000/logs" t := time.Now().Local() logsDate := fmt.Sprint(t.Format("20060102")) + servers := append(serversids, platforms...) for _, server := range servers { for _, file := range files { url := fmt.Sprintf("%s/%s/%s/%s/%s", diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 0af17375..f7da4cbb 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -3,6 +3,7 @@ package manager import ( "os" "os/signal" + "syscall" eventInteropOCP "github.com/adrianriobo/qe-eventmanager/pkg/event/interop/ocp" "github.com/adrianriobo/qe-eventmanager/pkg/services/ci/pipelines" @@ -46,7 +47,10 @@ func handleEvents() error { func waitForStop() { s := make(chan os.Signal, 1) - signal.Notify(s, os.Interrupt) + signal.Notify(s, + os.Interrupt, + syscall.SIGTERM, + syscall.SIGQUIT) <-s } diff --git a/pkg/services/messaging/umb/client.go b/pkg/services/messaging/umb/client.go index 287e4758..f7cdc027 100644 --- a/pkg/services/messaging/umb/client.go +++ b/pkg/services/messaging/umb/client.go @@ -57,7 +57,7 @@ func Subscribe(virtualTopic string, handler func(event interface{}) error) error } client.subscriptions = append(client.subscriptions, subscription) client.consumers.Add(1) - go consume(subscription, handler) + go consume(&client, subscription, handler) return nil } @@ -67,27 +67,28 @@ func Send(destination string, message interface{}) error { return client.connection.FailoverSend("/topic/"+destination, message) } -func consume(subscription *stomp.Subscription, handler func(event interface{}) error) { +func consume(client *Client, subscription *stomp.Subscription, handler func(event interface{}) error) { defer client.consumers.Done() for subscription.Active() { msg, err := subscription.Read() if err != nil { if !subscription.Active() { + logging.Debugf("Read message from inactive subscription %s", subscription.Destination()) break } logging.Errorf("Error reading from topic: %s. %s", subscription.Destination(), err) break } - logging.Debugf("New message from %s", subscription.Destination()) + logging.Infof("New message from %s, adding new handler for it", subscription.Destination()) client.handlers.Add(1) - go handle(msg, handler) + go handle(client, msg, handler) } + logging.Debugf("Finalize consumer for subscription %s", subscription.Destination()) } -func handle(msg *stomp.Message, handler func(event interface{}) error) { - // when finish remove from group +func handle(client *Client, msg *stomp.Message, handler func(event interface{}) error) { defer client.handlers.Done() - // heavy consuming may regex over string + // heavy consuming may regex over string, jsonpath var event map[string]interface{} logging.Debugf("Print message %+v", string(msg.Body[:])) if err := json.Unmarshal(msg.Body, &event); err != nil { @@ -104,8 +105,10 @@ func GracefullShutdown() { logging.Error(err) // Force consume as finished ? } - client.consumers.Done() + logging.Infof("Unsubscribing %s", subscription.Destination()) } + client.consumers.Wait() client.handlers.Wait() client.connection.Disconnect() + logging.Infof("Client disconnected from UMB") } diff --git a/pkg/util/logging/logging.go b/pkg/util/logging/logging.go index cd5e4a1a..de5a5f43 100644 --- a/pkg/util/logging/logging.go +++ b/pkg/util/logging/logging.go @@ -43,13 +43,14 @@ func BackupLogFile() { } func InitLogrus(logLevel, basePath string, fileName string) { - var err error - logfile, err = OpenLogFile(basePath, fileName) - if err != nil { - logrus.Fatal("Unable to open log file: ", err) - } + // var err error + // logfile, err = OpenLogFile(basePath, fileName) + // if err != nil { + // logrus.Fatal("Unable to open log file: ", err) + // } // send logs to file and console - logrus.SetOutput(io.MultiWriter(logfile, os.Stdout)) + // logrus.SetOutput(io.MultiWriter(logfile, os.Stdout)) + logrus.SetOutput(io.MultiWriter(os.Stdout)) logrus.SetLevel(logrus.DebugLevel) logrus.SetFormatter(&logrus.JSONFormatter{})