├── .dockerignore ├── .gitignore ├── .travis.yml ├── Dockerfile.gatekeeper ├── Dockerfile.operator ├── LICENSE ├── Makefile ├── README.md ├── charts └── gravity-operator │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── admin.yaml │ ├── cluster-co.yaml │ ├── crd.yaml │ ├── gatekeeper.yaml │ ├── operator.yaml │ └── rbac.yaml │ └── values.yaml ├── cmd ├── gatekeeper │ └── main.go └── operator │ └── main.go ├── docs ├── README-cn.md ├── arch.png └── k8s-160.png ├── go.mod ├── go.sum ├── grafana ├── gravity-gatekeeper.json └── gravity-operator.json ├── hack ├── boilerplate.go.txt ├── generate-groups.sh ├── update-codegen.sh └── verify-codegen.sh ├── hooks └── pre-commit └── pkg ├── apis ├── cluster │ └── v1alpha1 │ │ ├── doc.go │ │ ├── register.go │ │ ├── types.go │ │ └── zz_generated.deepcopy.go └── pipeline │ └── v1alpha1 │ ├── doc.go │ ├── register.go │ ├── types.go │ └── zz_generated.deepcopy.go ├── apiserver ├── api_server.go ├── cronjob.go └── pipeline.go ├── client ├── cluster │ ├── clientset │ │ └── versioned │ │ │ ├── clientset.go │ │ │ ├── doc.go │ │ │ ├── fake │ │ │ ├── clientset_generated.go │ │ │ ├── doc.go │ │ │ └── register.go │ │ │ ├── scheme │ │ │ ├── doc.go │ │ │ └── register.go │ │ │ └── typed │ │ │ └── cluster │ │ │ └── v1alpha1 │ │ │ ├── cluster.go │ │ │ ├── cluster_client.go │ │ │ ├── doc.go │ │ │ ├── fake │ │ │ ├── doc.go │ │ │ ├── fake_cluster.go │ │ │ └── fake_cluster_client.go │ │ │ └── generated_expansion.go │ ├── informers │ │ └── externalversions │ │ │ ├── cluster │ │ │ ├── interface.go │ │ │ └── v1alpha1 │ │ │ │ ├── cluster.go │ │ │ │ └── interface.go │ │ │ ├── factory.go │ │ │ ├── generic.go │ │ │ └── internalinterfaces │ │ │ └── factory_interfaces.go │ └── listers │ │ └── cluster │ │ └── v1alpha1 │ │ ├── cluster.go │ │ └── expansion_generated.go └── pipeline │ ├── clientset │ └── versioned │ │ ├── clientset.go │ │ ├── doc.go │ │ ├── fake │ │ ├── clientset_generated.go │ │ ├── doc.go │ │ └── register.go │ │ ├── scheme │ │ ├── doc.go │ │ └── register.go │ │ └── typed │ │ └── pipeline │ │ └── v1alpha1 │ │ ├── doc.go │ │ ├── fake │ │ ├── doc.go │ │ ├── fake_pipeline.go │ │ └── fake_pipeline_client.go │ │ ├── generated_expansion.go │ │ ├── pipeline.go │ │ └── pipeline_client.go │ ├── informers │ └── externalversions │ │ ├── factory.go │ │ ├── generic.go │ │ ├── internalinterfaces │ │ └── factory_interfaces.go │ │ └── pipeline │ │ ├── interface.go │ │ └── v1alpha1 │ │ ├── interface.go │ │ └── pipeline.go │ └── listers │ └── pipeline │ └── v1alpha1 │ ├── expansion_generated.go │ └── pipeline.go ├── controller ├── cluster_controller.go ├── metrics.go └── pipeline_manager.go ├── gatekeeper ├── api_server.go ├── chaos.go ├── domain.go └── repository.go ├── signals ├── signal.go ├── signal_posix.go └── signal_windows.go └── utils ├── def.go ├── glob.go └── glob_test.go /.dockerignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .git 3 | .idea -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff 7 | .idea 8 | 9 | # CMake 10 | cmake-build-debug/ 11 | cmake-build-release/ 12 | 13 | # Mongo Explorer plugin 14 | .idea/**/mongoSettings.xml 15 | 16 | # File-based project format 17 | *.iws 18 | 19 | # IntelliJ 20 | out/ 21 | 22 | # mpeltonen/sbt-idea plugin 23 | .idea_modules/ 24 | 25 | # JIRA plugin 26 | atlassian-ide-plugin.xml 27 | 28 | # Cursive Clojure plugin 29 | .idea/replstate.xml 30 | 31 | # Crashlytics plugin (for Android Studio and IntelliJ) 32 | com_crashlytics_export_strings.xml 33 | crashlytics.properties 34 | crashlytics-build.properties 35 | fabric.properties 36 | 37 | # Editor-based Rest Client 38 | .idea/httpRequests 39 | ### Go template 40 | # Binaries for programs and plugins 41 | *.exe 42 | *.exe~ 43 | *.dll 44 | *.so 45 | *.dylib 46 | 47 | # Test binary, build with `go test -c` 48 | *.test 49 | 50 | # Output of the go coverage tool, specifically when used with LiteIDE 51 | *.out 52 | 53 | bin/ 54 | 55 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.11.4" 5 | 6 | env: 7 | - GO111MODULE=on 8 | 9 | jobs: 10 | include: 11 | - stage: "test" 12 | name: "build" 13 | script: 14 | - make build-linux 15 | - make test 16 | - docker build -t moiot/gravity-operator:${TRAVIS_COMMIT::8} -f Dockerfile.operator . 17 | - docker build -t moiot/gravity-gatekeeper:${TRAVIS_COMMIT::8} -f Dockerfile.gatekeeper . 18 | - stage: "publish" 19 | if: tag IS present 20 | script: 21 | - make build-linux 22 | - docker build -t moiot/gravity-operator:${TRAVIS_TAG} -f Dockerfile.operator . 23 | - docker build -t moiot/gravity-gatekeeper:${TRAVIS_TAG} -f Dockerfile.gatekeeper . 24 | - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin 25 | - docker push moiot/gravity-operator:${TRAVIS_TAG} 26 | - docker push moiot/gravity-gatekeeper:${TRAVIS_TAG} -------------------------------------------------------------------------------- /Dockerfile.gatekeeper: -------------------------------------------------------------------------------- 1 | FROM frolvlad/alpine-glibc 2 | 3 | RUN apk update && apk upgrade && apk add bash && apk add tzdata 4 | 5 | RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone 6 | 7 | COPY bin/gravity-gatekeeper-amd64 /gravity-gatekeeper -------------------------------------------------------------------------------- /Dockerfile.operator: -------------------------------------------------------------------------------- 1 | FROM frolvlad/alpine-glibc 2 | 3 | RUN apk update && apk upgrade && apk add bash && apk add tzdata 4 | 5 | RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone 6 | 7 | COPY bin/gravity-operator-amd64 /gravity-operator -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PACKAGES := $$(go list ./...| grep -vE 'vendor' | grep -vE 'nuclear') 2 | TEST_DIRS := $(shell find . -iname "*_test.go" -exec dirname {} \; | uniq | grep -vE 'vendor') 3 | 4 | default: build 5 | 6 | test: 7 | go test -race $(TEST_DIRS) 8 | 9 | build: 10 | go build -o bin/gravity-operator cmd/operator/main.go 11 | go build -o bin/gravity-gatekeeper cmd/gatekeeper/main.go 12 | 13 | build-linux: 14 | GOARCH=amd64 GOOS=linux go build -o bin/gravity-operator-amd64 cmd/operator/main.go 15 | GOARCH=amd64 GOOS=linux go build -o bin/gravity-gatekeeper-amd64 cmd/gatekeeper/main.go 16 | 17 | image: build-linux 18 | docker build -t moiot/gravity-operator -f Dockerfile.operator . 19 | docker build -t moiot/gravity-gatekeeper -f Dockerfile.gatekeeper . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gravity Operator 2 | [![Build Status](https://travis-ci.com/moiot/gravity-operator.svg?branch=master)](https://travis-ci.com/moiot/gravity-operator) 3 | 4 | Gravity Operator manages Gravity processes on Kubernetes. 5 | 6 | ## Getting Started 7 | 8 | This document introduces how to deploy, configure and upgrade a Gravity Operator. 9 | 10 | ### Prerequisites 11 | 12 | - Kubernetes 1.11+ with CRD status subroutine 13 | - [helm](https://helm.sh/) 14 | 15 | ### Installing 16 | 17 | ```bash 18 | $ cd charts/gravity-operator 19 | $ helm install --name gravity-operator ./ 20 | ``` 21 | 22 | This chart bootstraps a gravity-operator deployment on a Kubernetes cluster using the Helm package manager. 23 | 24 | ## Gravity Cluster Configuration 25 | 26 | The following table shows the configurable parameters of the gravity-operator chart and their default values. See `deploy/k8s/gravity-operator/values.yaml`. 27 | 28 | Parameter | Description | Default Value 29 | --- | --- | --- 30 | `deploymentRules`| Array of deployment rules which control Gravity deployment versions | See [`DeploymentRules`](#DeploymentRules) 31 | `operator.image.repository`| Image of the operator | `moiot/gravity-operator` 32 | `operator.image.tag`| Image tag of the operator | `v0.1.0` 33 | `operator.rolling`| The maximum number of pipelines that can be upgraded in parallel. Value can be an absolute number (ex: 5) or a percentage (ex: 10%). | `25%` 34 | `admin.image.repository`| Image of admin | `moiot/gravity-admin` 35 | `admin.image.tag`| Image tag of admin | `v0.2.0` 36 | `admin.service.nodePort`| Node port of the admin service | `30066` 37 | 38 | 39 | By defining `DeploymentRule`, a Gravity cluster is divided into multiple groups based on the pipeline name and these groups can use different Gravity versions. 40 | 41 | The default rule is as follows: 42 | 43 | ```yaml 44 | - group: "default" 45 | pipelines: ["*"] 46 | image: "moiot/gravity:v0.9.15" 47 | command: ["/gravity", "-config=/etc/gravity/config.json"] 48 | ``` 49 | 50 | Parameter | Type | Description 51 | --- | --- | --- 52 | `group`| String | Name of the rule 53 | `pipelines`| String array | Global expression of the matched pipeline name 54 | `image` | String | Image (including tag) of matched pipeline deployment. It will be written to pod template's container image field 55 | `command` | String array | Command of running matched pipeline. It will be written to pod template's container command field 56 | 57 | ## Gravity Cluster Upgrade 58 | 59 | To upgrade a Gravity cluster, perform the following steps: 60 | 61 | 1. Modify the `values.yaml` file in the chart. 62 | 2. Use [helm](https://helm.sh/) to upgrade the cluster. 63 | 64 | ## Architecture 65 | ![Architecture](docs/arch.png) 66 | 67 | ## License 68 | 69 | This project is licensed under the Apache License 2.0 License - see the [LICENSE](LICENSE) file for details -------------------------------------------------------------------------------- /charts/gravity-operator/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | -------------------------------------------------------------------------------- /charts/gravity-operator/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: Data Replication Center 4 | name: gravity-operator 5 | version: 0.3.0 6 | -------------------------------------------------------------------------------- /charts/gravity-operator/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Get the application URL by running these commands: 2 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 3 | echo http://$NODE_IP:{{ .Values.admin.service.nodePort }} 4 | -------------------------------------------------------------------------------- /charts/gravity-operator/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "gravity-operator.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "gravity-operator.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "gravity-operator.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /charts/gravity-operator/templates/admin.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "gravity-operator.fullname" . }}-admin 5 | labels: 6 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-admin 7 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 8 | app.kubernetes.io/instance: {{ .Release.Name }} 9 | app.kubernetes.io/managed-by: {{ .Release.Service }} 10 | spec: 11 | type: NodePort 12 | ports: 13 | - name: http 14 | port: {{ .Values.admin.service.port }} 15 | targetPort: http 16 | nodePort: {{ .Values.admin.service.nodePort }} 17 | selector: 18 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-admin 19 | app.kubernetes.io/instance: {{ .Release.Name }} 20 | --- 21 | apiVersion: v1 22 | kind: ConfigMap 23 | metadata: 24 | name: {{ include "gravity-operator.fullname" . }}-admin 25 | labels: 26 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-admin 27 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 28 | app.kubernetes.io/instance: {{ .Release.Name }} 29 | app.kubernetes.io/managed-by: {{ .Release.Service }} 30 | data: 31 | gravity.conf: | 32 | tcp_nopush on; 33 | tcp_nodelay on; 34 | types_hash_max_size 2048; 35 | 36 | gzip on; 37 | gzip_min_length 1024; 38 | gzip_buffers 4 8k; 39 | gzip_types text/plain application/x-javascript text/css application/xml application/json; 40 | 41 | server { 42 | listen 80; 43 | server_name localhost; 44 | 45 | location / { 46 | root /usr/share/nginx/html; 47 | index index.html; 48 | try_files $uri $uri/ /index.html; 49 | } 50 | 51 | location /api/ { 52 | proxy_pass http://{{ include "gravity-operator.fullname" . }}:{{ .Values.operator.service.port }}/; 53 | } 54 | 55 | location /health { 56 | access_log off; 57 | return 200 "healthy"; 58 | } 59 | } 60 | --- 61 | apiVersion: apps/v1 62 | kind: Deployment 63 | metadata: 64 | name: {{ include "gravity-operator.fullname" . }}-admin 65 | labels: 66 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-admin 67 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 68 | app.kubernetes.io/instance: {{ .Release.Name }} 69 | app.kubernetes.io/managed-by: {{ .Release.Service }} 70 | spec: 71 | selector: 72 | matchLabels: 73 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-admin 74 | app.kubernetes.io/instance: {{ .Release.Name }} 75 | strategy: 76 | rollingUpdate: 77 | maxUnavailable: 0 78 | template: 79 | metadata: 80 | labels: 81 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-admin 82 | app.kubernetes.io/instance: {{ .Release.Name }} 83 | spec: 84 | restartPolicy: Always 85 | volumes: 86 | - name: ng-conf 87 | configMap: 88 | name: {{ include "gravity-operator.fullname" . }}-admin 89 | containers: 90 | - name: admin 91 | image: "{{ .Values.admin.image.repository }}:{{ .Values.admin.image.tag }}" 92 | imagePullPolicy: {{ .Values.admin.image.pullPolicy }} 93 | volumeMounts: 94 | - name: ng-conf 95 | mountPath: /etc/nginx/conf.d 96 | ports: 97 | - name: http 98 | containerPort: 80 99 | protocol: TCP 100 | readinessProbe: 101 | httpGet: 102 | path: /health 103 | port: http 104 | {{- if .Values.admin.resources }} 105 | resources: 106 | {{ toYaml .Values.admin.resources | indent 10 }} 107 | {{- end }} -------------------------------------------------------------------------------- /charts/gravity-operator/templates/cluster-co.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: gravity.mobike.io/v1alpha1 2 | kind: Cluster 3 | metadata: 4 | name: {{ include "gravity-operator.fullname" . }}-cluster 5 | labels: 6 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-cluster 7 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 8 | app.kubernetes.io/instance: {{ .Release.Name }} 9 | app.kubernetes.io/managed-by: {{ .Release.Service }} 10 | spec: 11 | rolling: {{ .Values.operator.rolling }} 12 | deploymentRules: 13 | {{ toYaml .Values.deploymentRules | indent 4}} -------------------------------------------------------------------------------- /charts/gravity-operator/templates/crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: clusters.gravity.mobike.io 5 | annotations: 6 | "helm.sh/hook": crd-install 7 | spec: 8 | scope: Namespaced 9 | group: gravity.mobike.io 10 | version: v1alpha1 11 | names: 12 | kind: Cluster 13 | plural: clusters 14 | singular: cluster 15 | subresources: 16 | status: {} 17 | additionalPrinterColumns: 18 | - name: Total 19 | type: integer 20 | description: Total number of pipelines. 21 | JSONPath: .status.pipelines 22 | - name: Updated 23 | type: integer 24 | description: Total number of pipelines which version match current deployment rule. 25 | JSONPath: .status.updatedPipelines 26 | - name: Available 27 | type: integer 28 | description: Total number of available pipelines (ready for at least minReadySeconds). 29 | JSONPath: .status.availablePipelines 30 | - name: Unavailable 31 | type: integer 32 | description: Total number of unavailable pipelines. 33 | JSONPath: .status.unavailablePipelines 34 | 35 | --- 36 | apiVersion: apiextensions.k8s.io/v1beta1 37 | kind: CustomResourceDefinition 38 | metadata: 39 | name: pipelines.gravity.mobike.io 40 | annotations: 41 | "helm.sh/hook": crd-install 42 | spec: 43 | scope: Namespaced 44 | group: gravity.mobike.io 45 | version: v1alpha1 46 | names: 47 | kind: Pipeline 48 | plural: pipelines 49 | singular: pipeline 50 | subresources: 51 | status: {} 52 | additionalPrinterColumns: 53 | - name: Position 54 | type: string 55 | description: Position of the pipeline. 56 | JSONPath: .status.position -------------------------------------------------------------------------------- /charts/gravity-operator/templates/gatekeeper.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.tags.gatekeeper }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: {{ include "gravity-operator.fullname" . }}-gatekeeper 6 | labels: 7 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-gatekeeper 8 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 9 | app.kubernetes.io/instance: {{ .Release.Name }} 10 | app.kubernetes.io/managed-by: {{ .Release.Service }} 11 | data: 12 | cases.yaml: | 13 | {{ toYaml .Values.gatekeeper.cases | indent 4 }} 14 | --- 15 | apiVersion: v1 16 | kind: Service 17 | metadata: 18 | name: {{ include "gravity-operator.fullname" . }}-gatekeeper 19 | labels: 20 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-gatekeeper 21 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 22 | app.kubernetes.io/instance: {{ .Release.Name }} 23 | app.kubernetes.io/managed-by: {{ .Release.Service }} 24 | spec: 25 | type: NodePort 26 | ports: 27 | - name: http 28 | port: 80 29 | targetPort: http 30 | nodePort: {{ .Values.gatekeeper.service.nodePort }} 31 | selector: 32 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-gatekeeper 33 | app.kubernetes.io/instance: {{ .Release.Name }} 34 | --- 35 | apiVersion: apps/v1 36 | kind: Deployment 37 | metadata: 38 | name: {{ include "gravity-operator.fullname" . }}-gatekeeper 39 | labels: 40 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-gatekeeper 41 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 42 | app.kubernetes.io/instance: {{ .Release.Name }} 43 | app.kubernetes.io/managed-by: {{ .Release.Service }} 44 | annotations: 45 | checksum/cases: {{ toYaml .Values.gatekeeper.cases | sha256sum }} 46 | spec: 47 | minReadySeconds: 5 48 | selector: 49 | matchLabels: 50 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-gatekeeper 51 | app.kubernetes.io/instance: {{ .Release.Name }} 52 | strategy: 53 | type: Recreate 54 | template: 55 | metadata: 56 | labels: 57 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }}-gatekeeper 58 | app.kubernetes.io/instance: {{ .Release.Name }} 59 | spec: 60 | serviceAccountName: {{ include "gravity-operator.fullname" . }} 61 | restartPolicy: Always 62 | volumes: 63 | - name: config 64 | configMap: 65 | name: '{{ include "gravity-operator.fullname" . }}-gatekeeper' 66 | containers: 67 | - name: gatekeeper 68 | env: 69 | - name: MY_POD_NAMESPACE 70 | valueFrom: 71 | fieldRef: 72 | fieldPath: metadata.namespace 73 | image: "{{ .Values.gatekeeper.image.repository }}:{{ .Values.gatekeeper.image.tag }}" 74 | command: 75 | - "/gravity-gatekeeper" 76 | - "--api" 77 | - 'http://{{ include "gravity-operator.fullname" . }}:{{ .Values.operator.service.port }}' 78 | - "--srcMySQL" 79 | - "{{ .Values.gatekeeper.mysql.source }}" 80 | - "--tarMySQL" 81 | - "{{ .Values.gatekeeper.mysql.target }}" 82 | - "--chaosInterval" 83 | - "1m" 84 | imagePullPolicy: {{ .Values.gatekeeper.image.pullPolicy }} 85 | volumeMounts: 86 | - name: config 87 | mountPath: /etc/gravity 88 | ports: 89 | - name: http 90 | containerPort: 8080 91 | protocol: TCP 92 | readinessProbe: 93 | httpGet: 94 | path: /healthz 95 | port: http 96 | {{- if .Values.gatekeeper.resources }} 97 | resources: 98 | {{ toYaml .Values.gatekeeper.resources | indent 10 }} 99 | {{- end }} 100 | {{- end }} -------------------------------------------------------------------------------- /charts/gravity-operator/templates/operator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "gravity-operator.fullname" . }} 6 | labels: 7 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }} 8 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 9 | app.kubernetes.io/instance: {{ .Release.Name }} 10 | app.kubernetes.io/managed-by: {{ .Release.Service }} 11 | spec: 12 | type: {{ .Values.operator.service.type }} 13 | ports: 14 | - name: http 15 | port: {{ .Values.operator.service.port }} 16 | targetPort: http 17 | selector: 18 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }} 19 | app.kubernetes.io/instance: {{ .Release.Name }} 20 | --- 21 | apiVersion: apps/v1 22 | kind: Deployment 23 | metadata: 24 | name: {{ include "gravity-operator.fullname" . }} 25 | labels: 26 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }} 27 | helm.sh/chart: {{ include "gravity-operator.chart" . }} 28 | app.kubernetes.io/instance: {{ .Release.Name }} 29 | app.kubernetes.io/managed-by: {{ .Release.Service }} 30 | spec: 31 | minReadySeconds: 5 32 | selector: 33 | matchLabels: 34 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }} 35 | app.kubernetes.io/instance: {{ .Release.Name }} 36 | strategy: 37 | type: Recreate 38 | template: 39 | metadata: 40 | labels: 41 | app.kubernetes.io/name: {{ include "gravity-operator.name" . }} 42 | app.kubernetes.io/instance: {{ .Release.Name }} 43 | spec: 44 | serviceAccountName: {{ include "gravity-operator.fullname" . }} 45 | restartPolicy: Always 46 | containers: 47 | - name: operator 48 | env: 49 | - name: MY_POD_NAMESPACE 50 | valueFrom: 51 | fieldRef: 52 | fieldPath: metadata.namespace 53 | - name: MY_SERVICE_URI 54 | value: http://{{ include "gravity-operator.fullname" . }}:{{ .Values.operator.service.port }} 55 | 56 | image: "{{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag }}" 57 | command: ["/gravity-operator"] 58 | imagePullPolicy: {{ .Values.operator.image.pullPolicy }} 59 | ports: 60 | - name: http 61 | containerPort: 8080 62 | protocol: TCP 63 | readinessProbe: 64 | httpGet: 65 | path: /metrics 66 | port: http 67 | {{- if .Values.operator.resources }} 68 | resources: 69 | {{ toYaml .Values.operator.resources | indent 10 }} 70 | {{- end }} -------------------------------------------------------------------------------- /charts/gravity-operator/templates/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: {{ include "gravity-operator.fullname" . }}-role 6 | rules: 7 | - apiGroups: [""] 8 | resources: ["configmaps", "pods", "services", "endpoints", "events"] 9 | verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] 10 | 11 | - apiGroups: ["apps"] 12 | resources: ["statefulsets"] 13 | verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] 14 | 15 | - apiGroups: ["batch"] 16 | resources: ["cronjobs", "jobs"] 17 | verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] 18 | 19 | - apiGroups: ["gravity.mobike.io"] 20 | resources: ["*"] 21 | verbs: ["*"] 22 | 23 | 24 | --- 25 | apiVersion: rbac.authorization.k8s.io/v1 26 | kind: RoleBinding 27 | metadata: 28 | name: gravity-operator-rolebinding 29 | subjects: 30 | - kind: ServiceAccount 31 | name: {{ include "gravity-operator.fullname" . }} 32 | 33 | roleRef: 34 | kind: Role 35 | name: {{ include "gravity-operator.fullname" . }}-role 36 | apiGroup: rbac.authorization.k8s.io 37 | 38 | --- 39 | apiVersion: v1 40 | kind: ServiceAccount 41 | metadata: 42 | name: {{ include "gravity-operator.fullname" . }} -------------------------------------------------------------------------------- /charts/gravity-operator/values.yaml: -------------------------------------------------------------------------------- 1 | nameOverride: "" 2 | fullnameOverride: "" 3 | 4 | deploymentRules: 5 | - group: "default" 6 | pipelines: ["*"] 7 | image: "moiot/gravity:v0.9.21" 8 | command: ["/gravity", "-config=/etc/gravity/config.json"] 9 | 10 | operator: 11 | image: 12 | repository: moiot/gravity-operator 13 | tag: v0.3.0 14 | pullPolicy: IfNotPresent 15 | rolling: "25%" 16 | service: 17 | type: ClusterIP 18 | port: 80 19 | resources: {} 20 | # limits: 21 | # cpu: 2 22 | # memory: 500M 23 | # requests: 24 | # cpu: 0.5 25 | # memory: 100M 26 | 27 | tags: 28 | gatekeeper: false 29 | 30 | admin: 31 | image: 32 | repository: moiot/gravity-admin 33 | tag: v0.2.0 34 | pullPolicy: IfNotPresent 35 | service: 36 | port: 80 37 | nodePort: 30066 38 | resources: {} 39 | # limits: 40 | # cpu: 100m 41 | # memory: 100M 42 | # requests: 43 | # cpu: 100m 44 | # memory: 100M 45 | 46 | gatekeeper: 47 | image: 48 | repository: moiot/gravity-gatekeeper 49 | tag: v0.2.0 50 | pullPolicy: IfNotPresent 51 | resources: {} 52 | # requests: 53 | # cpu: 100m 54 | # memory: 100M 55 | service: 56 | port: 80 57 | nodePort: 30067 58 | mysql: 59 | source: root@tcp(source-mysql:3306)/?interpolateParams=true&parseTime=true&collation=utf8mb4_general_ci&loc=Local 60 | target: root@tcp(target-mysql:3306)/?interpolateParams=true&parseTime=true&collation=utf8mb4_general_ci&loc=Local 61 | cases: 62 | - name: simple 63 | nrTables: 10 64 | nrSeedRows: 10000 65 | deleteRatio: 0.2 66 | insertRatio: 0.5 67 | concurrency: 20 68 | transactionLength: 5 -------------------------------------------------------------------------------- /cmd/gatekeeper/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "flag" 6 | _ "net/http/pprof" 7 | "os" 8 | 9 | _ "github.com/go-sql-driver/mysql" 10 | log "github.com/sirupsen/logrus" 11 | 12 | "k8s.io/client-go/dynamic" 13 | "k8s.io/client-go/rest" 14 | 15 | clusterclient "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned" 16 | "github.com/moiot/gravity-operator/pkg/gatekeeper" 17 | "github.com/moiot/gravity-operator/pkg/signals" 18 | ) 19 | 20 | func main() { 21 | var casePath, operatorAddr, sourceMysql, targetMysql, chaosInterval string 22 | flag.StringVar(&casePath, "f", "/etc/gravity/cases.yaml", "path of case config") 23 | flag.StringVar(&operatorAddr, "api", "http://gravity-operator", "url of operator") 24 | flag.StringVar(&sourceMysql, "srcMySQL", "root@tcp(source-mysql:3306)/?interpolateParams=true&readTimeout=%s&parseTime=true&collation=utf8mb4_general_ci", "source mysql url") 25 | flag.StringVar(&targetMysql, "tarMySQL", "root@tcp(target-mysql:3306)/?interpolateParams=true&readTimeout=%s&parseTime=true&collation=utf8mb4_general_ci", "target mysql url") 26 | flag.StringVar(&chaosInterval, "chaosInterval", "45s", "tick interval of chaos monkey") 27 | flag.Parse() 28 | 29 | namespace := os.Getenv("MY_POD_NAMESPACE") 30 | if namespace == "" { 31 | namespace = "default" 32 | } 33 | 34 | stopCh := signals.SetupSignalHandler() 35 | 36 | cfg, err := rest.InClusterConfig() 37 | if err != nil { 38 | log.Fatalf("Error building kubeconfig: %s", err.Error()) 39 | } 40 | 41 | kubeDynamic, err := dynamic.NewForConfig(cfg) 42 | if err != nil { 43 | log.Fatalf("Error building kubernetes dynamic: %s", err.Error()) 44 | } 45 | 46 | clusterClient, err := clusterclient.NewForConfig(cfg) 47 | if err != nil { 48 | log.Fatalf("Error building cluster client: %s", err.Error()) 49 | } 50 | 51 | chaosMonkey := gatekeeper.NewChaosMonkey(namespace, kubeDynamic, chaosInterval, stopCh) 52 | if err = chaosMonkey.Start(); err != nil { 53 | log.Fatalf("fail to start chaos monkey. %s", err.Error()) 54 | } 55 | 56 | sourceDB, err := sql.Open("mysql", sourceMysql) 57 | if err != nil { 58 | log.Panic(err) 59 | } 60 | defer sourceDB.Close() 61 | 62 | targetDB, err := sql.Open("mysql", targetMysql) 63 | if err != nil { 64 | log.Panic(err) 65 | } 66 | defer targetDB.Close() 67 | 68 | repo := gatekeeper.NewRepository(casePath, operatorAddr, sourceDB, targetDB, clusterClient.GravityV1alpha1().Clusters(namespace)) 69 | api := gatekeeper.NewApiServer(repo) 70 | api.Start() 71 | 72 | <-stopCh 73 | 74 | log.Info("Shutting down operator") 75 | 76 | chaosMonkey.Close() 77 | api.Stop() 78 | } 79 | -------------------------------------------------------------------------------- /cmd/operator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "os" 6 | "time" 7 | 8 | log "github.com/sirupsen/logrus" 9 | 10 | kubeinformers "k8s.io/client-go/informers" 11 | "k8s.io/client-go/kubernetes" 12 | "k8s.io/client-go/tools/clientcmd" 13 | 14 | "github.com/moiot/gravity-operator/pkg/apiserver" 15 | clusterclient "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned" 16 | clusterinformer "github.com/moiot/gravity-operator/pkg/client/cluster/informers/externalversions" 17 | pipeclient "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned" 18 | pipeinformer "github.com/moiot/gravity-operator/pkg/client/pipeline/informers/externalversions" 19 | "github.com/moiot/gravity-operator/pkg/controller" 20 | "github.com/moiot/gravity-operator/pkg/signals" 21 | ) 22 | 23 | var ( 24 | masterURL string 25 | kubeconfig string 26 | port int 27 | ) 28 | 29 | func main() { 30 | flag.Parse() 31 | 32 | namespace := os.Getenv("MY_POD_NAMESPACE") 33 | if namespace == "" { 34 | namespace = "default" 35 | } 36 | 37 | stopCh := signals.SetupSignalHandler() 38 | 39 | cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig) 40 | if err != nil { 41 | log.Fatalf("Error building kubeconfig: %s", err.Error()) 42 | } 43 | 44 | kubeClient, err := kubernetes.NewForConfig(cfg) 45 | if err != nil { 46 | log.Fatalf("Error building kubernetes clientset: %s", err.Error()) 47 | } 48 | 49 | clusterClient, err := clusterclient.NewForConfig(cfg) 50 | if err != nil { 51 | log.Fatalf("Error building cluster client: %s", err.Error()) 52 | } 53 | 54 | pipelineClient, err := pipeclient.NewForConfig(cfg) 55 | if err != nil { 56 | log.Fatalf("Error building pipeline client: %s", err.Error()) 57 | } 58 | 59 | clusterInformerFactory := clusterinformer.NewSharedInformerFactoryWithOptions(clusterClient, time.Second*30, clusterinformer.WithNamespace(namespace)) 60 | pipelinesInformerFactory := pipeinformer.NewSharedInformerFactoryWithOptions(pipelineClient, time.Second*30, pipeinformer.WithNamespace(namespace)) 61 | kubeInformerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, time.Second*30, kubeinformers.WithNamespace(namespace)) 62 | 63 | clusterController := controller.NewClusterController( 64 | namespace, 65 | kubeInformerFactory, 66 | kubeClient, 67 | clusterClient, 68 | clusterInformerFactory.Gravity().V1alpha1().Clusters(), 69 | pipelineClient, 70 | pipelinesInformerFactory.Gravity().V1alpha1().Pipelines(), 71 | ) 72 | 73 | go kubeInformerFactory.Start(stopCh) 74 | go clusterInformerFactory.Start(stopCh) 75 | go pipelinesInformerFactory.Start(stopCh) 76 | 77 | log.Infof("running controllers") 78 | 79 | if err := clusterController.Run(5, stopCh); err != nil { 80 | log.Fatalf("Error running clusterController: %v", err.Error()) 81 | } 82 | 83 | apiServer := apiserver.NewApiServer(namespace, kubeClient, pipelineClient, clusterController, port) 84 | apiServer.Start() 85 | 86 | <-stopCh 87 | log.Info("Shutting down operator") 88 | } 89 | 90 | func init() { 91 | flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.") 92 | flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.") 93 | flag.IntVar(&port, "p", 8080, "port number") 94 | } 95 | -------------------------------------------------------------------------------- /docs/README-cn.md: -------------------------------------------------------------------------------- 1 | Gravity 集群使用 [helm](https://helm.sh/) 来安装和升级 2 | 3 | ### 环境要求 4 | - Kubernetes 1.11+ with CRD status subroutine 5 | 6 | ### 安装 Gravity Cluster (TODO 开源后直接放到公共 repo) 7 | ```bash 8 | $ cd deploy/k8s/gravity-operator 9 | $ helm install --name gravity-operator ./ 10 | ``` 11 | 12 | 这个 chart 会使用 helm 在 Kubernetes 集群里面启动 gravity-operator 以及 gravity-admin 管理界面 13 | 14 | 15 | ### 配置 16 | 17 | Gravity 集群的配置选项如下 18 | 19 | 请参考 `deploy/k8s/gravity-operator/values.yaml` 20 | 21 | Parameter | Description | Default 22 | --- | --- | --- 23 | `deploymentRules`| array of DeploymentRules which control gravity deployment versions | see [DeploymentRules](#DeploymentRules) 24 | `operator.image.repository`| image of operator | `docker.mobike.io/database/gravity/operator` 25 | `operator.image.tag`| image tag of operator | `156a28a4` 26 | `admin.image.repository`| image of admin | `docker.mobike.io/database/gravity-admin` 27 | `admin.image.tag`| image tag of admin | `59d44f7c` 28 | `admin.service.nodePort`| node port of admin service | `30066` 29 | 30 | ### DeploymentRules 31 | 32 | DeploymentRule 定义了把集群按照 pipeline 的名字分为多组,每一个组可以使用不同的 Gravity 版本。 33 | 34 | 系统定义了一个默认的组。 35 | 36 | ```yaml 37 | - group: "default" 38 | pipelines: ["*"] 39 | image: "docker.mobike.io/database/gravity/gravity:156a28a4" 40 | command: ["/gravity", "-config=/etc/gravity/config.json"] 41 | ``` 42 | 43 | 44 | Parameter | Type | Description 45 | --- | --- | --- 46 | `group`| string | name of the rule 47 | `pipelines`| string array | glob expression of pipeline name to match 48 | `image` | string | image(including tag) to deploy of matched pipeline. will be write to pod template's container image field 49 | `command` | string array| command to run of matched pipeline. will be write to pod template's container command field 50 | 51 | 52 | ## 集群升级 53 | 54 | 修改 chart 内定义的 values.yaml 文件,并使用 helm 升级集群。 -------------------------------------------------------------------------------- /docs/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moiot/gravity-operator/625441be12f8caa823bd9495b8fa9bb34e2c6cd4/docs/arch.png -------------------------------------------------------------------------------- /docs/k8s-160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moiot/gravity-operator/625441be12f8caa823bd9495b8fa9bb34e2c6cd4/docs/k8s-160.png -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/moiot/gravity-operator 2 | 3 | require ( 4 | github.com/DataDog/zstd v1.3.5 // indirect 5 | github.com/Shopify/sarama v1.20.1 // indirect 6 | github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect 7 | github.com/gin-gonic/gin v1.3.0 8 | github.com/go-sql-driver/mysql v1.4.1 9 | github.com/gofrs/uuid v3.2.0+incompatible // indirect 10 | github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect 11 | github.com/googleapis/gnostic v0.2.0 // indirect 12 | github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f // indirect 13 | github.com/grpc-ecosystem/grpc-gateway v1.6.3 // indirect 14 | github.com/hashicorp/go-getter v0.0.0-20190112230949-c68364a1fae1 // indirect 15 | github.com/hashicorp/go-plugin v1.0.0 // indirect 16 | github.com/imdario/mergo v0.3.6 // indirect 17 | github.com/jinzhu/gorm v1.9.2 // indirect 18 | github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect 19 | github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 20 | github.com/modern-go/reflect2 v1.0.1 // indirect 21 | github.com/moiot/gravity v0.9.62 22 | github.com/peterbourgon/diskv v2.0.1+incompatible // indirect 23 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 24 | github.com/serialx/hashring v0.0.0-20180504054112-49a4782e9908 // indirect 25 | github.com/sirupsen/logrus v1.2.0 26 | github.com/spf13/pflag v1.0.3 // indirect 27 | github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 // indirect 28 | gopkg.in/go-playground/assert.v1 v1.2.1 // indirect 29 | gopkg.in/go-playground/validator.v8 v8.18.2 // indirect 30 | gopkg.in/inf.v0 v0.9.1 // indirect 31 | gopkg.in/yaml.v2 v2.2.2 32 | k8s.io/api v0.0.0-20181216230433-16e3e9a3868f 33 | k8s.io/apimachinery v0.0.0-20181203235515-3d8ee2261517 34 | k8s.io/client-go v8.0.0+incompatible 35 | k8s.io/kube-openapi v0.0.0-20181114233023-0317810137be // indirect 36 | ) 37 | -------------------------------------------------------------------------------- /grafana/gravity-gatekeeper.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_PROMETHEUS", 5 | "label": "prometheus", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "5.0.0" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "5.0.0" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "prometheus", 28 | "name": "Prometheus", 29 | "version": "5.0.0" 30 | } 31 | ], 32 | "annotations": { 33 | "list": [ 34 | { 35 | "builtIn": 1, 36 | "datasource": "-- Grafana --", 37 | "enable": true, 38 | "hide": true, 39 | "iconColor": "rgba(0, 211, 255, 1)", 40 | "name": "Annotations & Alerts", 41 | "type": "dashboard" 42 | } 43 | ] 44 | }, 45 | "editable": true, 46 | "gnetId": null, 47 | "graphTooltip": 1, 48 | "id": null, 49 | "links": [], 50 | "panels": [ 51 | { 52 | "aliasColors": {}, 53 | "bars": false, 54 | "dashLength": 10, 55 | "dashes": false, 56 | "datasource": "${DS_PROMETHEUS}", 57 | "fill": 1, 58 | "gridPos": { 59 | "h": 9, 60 | "w": 12, 61 | "x": 0, 62 | "y": 0 63 | }, 64 | "id": 2, 65 | "legend": { 66 | "alignAsTable": true, 67 | "avg": false, 68 | "current": true, 69 | "hideEmpty": true, 70 | "hideZero": true, 71 | "max": false, 72 | "min": false, 73 | "rightSide": true, 74 | "show": true, 75 | "total": false, 76 | "values": true 77 | }, 78 | "lines": true, 79 | "linewidth": 1, 80 | "links": [], 81 | "nullPointMode": "null", 82 | "percentage": false, 83 | "pointradius": 5, 84 | "points": false, 85 | "renderer": "flot", 86 | "seriesOverrides": [], 87 | "spaceLength": 10, 88 | "stack": false, 89 | "steppedLine": false, 90 | "targets": [ 91 | { 92 | "expr": "sum(gravity_gatekeeper_inconsistent) by (case)", 93 | "format": "time_series", 94 | "intervalFactor": 1, 95 | "legendFormat": "{{ case }}", 96 | "refId": "A" 97 | } 98 | ], 99 | "thresholds": [], 100 | "timeFrom": null, 101 | "timeShift": null, 102 | "title": "Inconsistent Count", 103 | "tooltip": { 104 | "shared": true, 105 | "sort": 0, 106 | "value_type": "individual" 107 | }, 108 | "type": "graph", 109 | "xaxis": { 110 | "buckets": null, 111 | "mode": "time", 112 | "name": null, 113 | "show": true, 114 | "values": [] 115 | }, 116 | "yaxes": [ 117 | { 118 | "format": "short", 119 | "label": null, 120 | "logBase": 1, 121 | "max": null, 122 | "min": null, 123 | "show": true 124 | }, 125 | { 126 | "format": "short", 127 | "label": null, 128 | "logBase": 1, 129 | "max": null, 130 | "min": null, 131 | "show": true 132 | } 133 | ] 134 | }, 135 | { 136 | "aliasColors": {}, 137 | "bars": false, 138 | "dashLength": 10, 139 | "dashes": false, 140 | "datasource": "${DS_PROMETHEUS}", 141 | "fill": 1, 142 | "gridPos": { 143 | "h": 9, 144 | "w": 12, 145 | "x": 12, 146 | "y": 0 147 | }, 148 | "id": 4, 149 | "legend": { 150 | "alignAsTable": true, 151 | "avg": false, 152 | "current": true, 153 | "hideEmpty": true, 154 | "hideZero": true, 155 | "max": false, 156 | "min": false, 157 | "rightSide": true, 158 | "show": true, 159 | "sort": "current", 160 | "sortDesc": true, 161 | "total": false, 162 | "values": true 163 | }, 164 | "lines": true, 165 | "linewidth": 1, 166 | "links": [], 167 | "nullPointMode": "null", 168 | "percentage": false, 169 | "pointradius": 5, 170 | "points": false, 171 | "renderer": "flot", 172 | "seriesOverrides": [], 173 | "spaceLength": 10, 174 | "stack": false, 175 | "steppedLine": false, 176 | "targets": [ 177 | { 178 | "expr": "increase(gravity_gatekeeper_chaos[1m])", 179 | "format": "time_series", 180 | "intervalFactor": 1, 181 | "legendFormat": "{{name}} - {{ kind }}", 182 | "refId": "A" 183 | } 184 | ], 185 | "thresholds": [], 186 | "timeFrom": null, 187 | "timeShift": null, 188 | "title": "chaos", 189 | "tooltip": { 190 | "shared": true, 191 | "sort": 2, 192 | "value_type": "individual" 193 | }, 194 | "type": "graph", 195 | "xaxis": { 196 | "buckets": null, 197 | "mode": "time", 198 | "name": null, 199 | "show": true, 200 | "values": [] 201 | }, 202 | "yaxes": [ 203 | { 204 | "format": "none", 205 | "label": null, 206 | "logBase": 1, 207 | "max": null, 208 | "min": null, 209 | "show": true 210 | }, 211 | { 212 | "format": "short", 213 | "label": null, 214 | "logBase": 1, 215 | "max": null, 216 | "min": null, 217 | "show": true 218 | } 219 | ] 220 | } 221 | ], 222 | "refresh": "10s", 223 | "schemaVersion": 16, 224 | "style": "dark", 225 | "tags": [], 226 | "templating": { 227 | "list": [] 228 | }, 229 | "time": { 230 | "from": "now-1h", 231 | "to": "now" 232 | }, 233 | "timepicker": { 234 | "refresh_intervals": [ 235 | "5s", 236 | "10s", 237 | "30s", 238 | "1m", 239 | "5m", 240 | "15m", 241 | "30m", 242 | "1h", 243 | "2h", 244 | "1d" 245 | ], 246 | "time_options": [ 247 | "5m", 248 | "15m", 249 | "1h", 250 | "6h", 251 | "12h", 252 | "24h", 253 | "2d", 254 | "7d", 255 | "30d" 256 | ] 257 | }, 258 | "timezone": "", 259 | "title": "Gravity Gatekeeper", 260 | "uid": "Pc-QJhPik", 261 | "version": 10 262 | } -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /hack/generate-groups.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2017 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | # generate-groups generates everything for a project with external types only, e.g. a project based 22 | # on CustomResourceDefinitions. 23 | 24 | if [ "$#" -lt 4 ] || [ "${1}" == "--help" ]; then 25 | cat < ... 27 | 28 | the generators comma separated to run (deepcopy,defaulter,client,lister,informer) or "all". 29 | the output package name (e.g. github.com/example/project/pkg/generated). 30 | the external types dir (e.g. github.com/example/api or github.com/example/project/pkg/apis). 31 | the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative 32 | to . 33 | ... arbitrary flags passed to all generator binaries. 34 | 35 | 36 | Examples: 37 | $(basename $0) all github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" 38 | $(basename $0) deepcopy,client github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" 39 | EOF 40 | exit 0 41 | fi 42 | 43 | GENS="$1" 44 | OUTPUT_PKG="$2" 45 | APIS_PKG="$3" 46 | GROUPS_WITH_VERSIONS="$4" 47 | shift 4 48 | 49 | GO111MODULE=on go get k8s.io/code-generator/cmd/defaulter-gen@kubernetes-1.11.4 50 | GO111MODULE=on go get k8s.io/code-generator/cmd/client-gen@kubernetes-1.11.4 51 | GO111MODULE=on go get k8s.io/code-generator/cmd/lister-gen@kubernetes-1.11.4 52 | GO111MODULE=on go get k8s.io/code-generator/cmd/informer-gen@kubernetes-1.11.4 53 | GO111MODULE=on go get k8s.io/code-generator/cmd/deepcopy-gen@kubernetes-1.11.4 54 | 55 | # ( 56 | # # To support running this script from anywhere, we have to first cd into this directory 57 | # # so we can install the tools. 58 | # cd $(dirname "${0}") 59 | # go install ./cmd/{defaulter-gen,client-gen,lister-gen,informer-gen,deepcopy-gen} 60 | # ) 61 | 62 | function codegen::join() { local IFS="$1"; shift; echo "$*"; } 63 | 64 | # enumerate group versions 65 | FQ_APIS=() # e.g. k8s.io/api/apps/v1 66 | for GVs in ${GROUPS_WITH_VERSIONS}; do 67 | IFS=: read G Vs <<<"${GVs}" 68 | 69 | # enumerate versions 70 | for V in ${Vs//,/ }; do 71 | FQ_APIS+=(${APIS_PKG}/${G}/${V}) 72 | done 73 | done 74 | 75 | scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 76 | 77 | if [ "${GENS}" = "all" ] || grep -qw "deepcopy" <<<"${GENS}"; then 78 | echo "Generating deepcopy funcs" 79 | ${GOPATH}/bin/deepcopy-gen --go-header-file=${scriptdir}/boilerplate.go.txt --input-dirs $(codegen::join , "${FQ_APIS[@]}") -O zz_generated.deepcopy --bounding-dirs ${APIS_PKG} "$@" 80 | fi 81 | 82 | if [ "${GENS}" = "all" ] || grep -qw "client" <<<"${GENS}"; then 83 | echo "Generating clientset for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/clientset" 84 | ${GOPATH}/bin/client-gen --go-header-file=${scriptdir}/boilerplate.go.txt --clientset-name ${CLIENTSET_NAME_VERSIONED:-versioned} --input-base "" --input $(codegen::join , "${FQ_APIS[@]}") --output-package ${OUTPUT_PKG}/clientset "$@" 85 | fi 86 | 87 | if [ "${GENS}" = "all" ] || grep -qw "lister" <<<"${GENS}"; then 88 | echo "Generating listers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/listers" 89 | ${GOPATH}/bin/lister-gen --go-header-file=${scriptdir}/boilerplate.go.txt --input-dirs $(codegen::join , "${FQ_APIS[@]}") --output-package ${OUTPUT_PKG}/listers "$@" 90 | fi 91 | 92 | if [ "${GENS}" = "all" ] || grep -qw "informer" <<<"${GENS}"; then 93 | echo "Generating informers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/informers" 94 | ${GOPATH}/bin/informer-gen --go-header-file=${scriptdir}/boilerplate.go.txt \ 95 | --input-dirs $(codegen::join , "${FQ_APIS[@]}") \ 96 | --versioned-clientset-package ${OUTPUT_PKG}/clientset/${CLIENTSET_NAME_VERSIONED:-versioned} \ 97 | --listers-package ${OUTPUT_PKG}/listers \ 98 | --output-package ${OUTPUT_PKG}/informers \ 99 | "$@" 100 | fi -------------------------------------------------------------------------------- /hack/update-codegen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2017 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | # SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/.. 22 | # CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} 23 | # echo $CODEGEN_PKG 24 | 25 | hack/generate-groups.sh "all" \ 26 | github.com/moiot/gravity-operator/pkg/client/pipeline \ 27 | github.com/moiot/gravity-operator/pkg/apis \ 28 | pipeline:v1alpha1 && hack/generate-groups.sh "all" \ 29 | github.com/moiot/gravity-operator/pkg/client/cluster \ 30 | github.com/moiot/gravity-operator/pkg/apis \ 31 | cluster:v1alpha1 32 | 33 | # To use your own boilerplate text use: 34 | # --go-header-file ${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt 35 | -------------------------------------------------------------------------------- /hack/verify-codegen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2017 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/.. 22 | 23 | DIFFROOT="${SCRIPT_ROOT}/pkg" 24 | TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg" 25 | _tmp="${SCRIPT_ROOT}/_tmp" 26 | 27 | cleanup() { 28 | rm -rf "${_tmp}" 29 | } 30 | trap "cleanup" EXIT SIGINT 31 | 32 | cleanup 33 | 34 | mkdir -p "${TMP_DIFFROOT}" 35 | cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" 36 | 37 | "${SCRIPT_ROOT}/hack/update-codegen.sh" 38 | echo "diffing ${DIFFROOT} against freshly generated codegen" 39 | ret=0 40 | diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? 41 | cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}" 42 | if [[ $ret -eq 0 ]] 43 | then 44 | echo "${DIFFROOT} up to date." 45 | else 46 | echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh" 47 | exit 1 48 | fi 49 | -------------------------------------------------------------------------------- /hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This file modified from k8s 3 | # https://github.com/kubernetes/kubernetes/blob/master/hooks/pre-commit 4 | 5 | # How to use this hook? 6 | # ln -s hooks/pre-commit .git/hooks/ 7 | # In case hook is not executable 8 | # chmod +x .git/hooks/pre-commit 9 | 10 | readonly reset=$(tput sgr0) 11 | readonly red=$(tput bold; tput setaf 1) 12 | readonly green=$(tput bold; tput setaf 2) 13 | 14 | exit_code=0 15 | 16 | # comment it by default. You can uncomment it. 17 | # echo -ne "Checking that it builds..." 18 | # if ! OUT=$(make 2>&1); then 19 | # echo 20 | # echo "${red}${OUT}" 21 | # exit_code=1 22 | # else 23 | # echo "${green}OK" 24 | # fi 25 | # echo "${reset}" 26 | 27 | echo -ne "Checking for files that need goimport... " 28 | files_need_gofmt=() 29 | files=($(git diff --cached --name-only --diff-filter ACM | grep "\.go" | grep -v -e "^vendor" | grep -v "pb.go")) 30 | for file in "${files[@]}"; do 31 | # Check for files that fail gofmt. 32 | diff="$(cat "${file}" | goimports -local github.com/moiot -d 2>&1)" 33 | if [[ -n "$diff" ]]; then 34 | echo ${diff} 35 | files_need_gofmt+=("${file}") 36 | fi 37 | done 38 | 39 | if [[ "${#files_need_gofmt[@]}" -ne 0 ]]; then 40 | echo "${red}ERROR!" 41 | echo "Some files have not been gofmt'd. To fix these errors, " 42 | echo "copy and paste the following:" 43 | echo " goimports -local github.com/moiot -w ${files_need_gofmt[@]}" 44 | exit_code=1 45 | else 46 | echo "${green}OK" 47 | fi 48 | echo "${reset}" 49 | 50 | if [[ "${exit_code}" != 0 ]]; then 51 | echo "${red}Aborting commit${reset}" 52 | fi 53 | exit ${exit_code} 54 | -------------------------------------------------------------------------------- /pkg/apis/cluster/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // +k8s:deepcopy-gen=package 2 | 3 | // Package v1alpha1 is the v1alpha1 version of the API. 4 | // +groupName=gravity.mobike.io 5 | package v1alpha1 6 | -------------------------------------------------------------------------------- /pkg/apis/cluster/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | "k8s.io/apimachinery/pkg/runtime" 6 | "k8s.io/apimachinery/pkg/runtime/schema" 7 | ) 8 | 9 | const ( 10 | GroupName = "gravity.mobike.io" 11 | ClusterResourceKind = "Cluster" 12 | ) 13 | 14 | var ( 15 | SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} 16 | ) 17 | 18 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind 19 | func Kind(kind string) schema.GroupKind { 20 | return SchemeGroupVersion.WithKind(kind).GroupKind() 21 | } 22 | 23 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 24 | func Resource(resource string) schema.GroupResource { 25 | return SchemeGroupVersion.WithResource(resource).GroupResource() 26 | } 27 | 28 | var ( 29 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 30 | AddToScheme = SchemeBuilder.AddToScheme 31 | ) 32 | 33 | func addKnownTypes(scheme *runtime.Scheme) error { 34 | scheme.AddKnownTypes(SchemeGroupVersion, 35 | &Cluster{}, 36 | &ClusterList{}, 37 | ) 38 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /pkg/apis/cluster/v1alpha1/types.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | "k8s.io/apimachinery/pkg/util/intstr" 7 | 8 | "github.com/moiot/gravity-operator/pkg/utils" 9 | ) 10 | 11 | // +genclient 12 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 13 | 14 | // Cluster is a specification for a Cluster resource 15 | type Cluster struct { 16 | metav1.TypeMeta `json:",inline"` 17 | metav1.ObjectMeta `json:"metadata,omitempty"` 18 | 19 | Spec ClusterSpec `json:"spec"` 20 | Status ClusterStatus `json:"status"` 21 | } 22 | 23 | // ClusterSpec is the spec for a cluster resource 24 | type ClusterSpec struct { 25 | // The maximum number of pipelines that can be upgraded. 26 | // Value can be an absolute number (ex: 5) or a percentage of pipelines (ex: 10%). 27 | // Absolute number is calculated from percentage by rounding up. 28 | // Defaults to 25%. 29 | Rolling *intstr.IntOrString `json:"rolling"` 30 | 31 | DeploymentRules []DeploymentRule `json:"deploymentRules"` 32 | } 33 | 34 | type DeploymentRule struct { 35 | Group string `json:"group" yaml:"group"` 36 | Pipelines []string `json:"pipelines" yaml:"pipelines"` 37 | Image string `json:"image" yaml:"image"` 38 | Command []string `json:"command" yaml:"command"` 39 | } 40 | 41 | func (dc *Cluster) FindDeploymentRule(pipelineName string) *DeploymentRule { 42 | for _, rule := range dc.Spec.DeploymentRules { 43 | for _, pipelineNameExpr := range rule.Pipelines { 44 | if utils.Glob(pipelineNameExpr, pipelineName) { 45 | return &rule 46 | } 47 | } 48 | } 49 | return nil 50 | } 51 | 52 | // ClusterStatus is the status for a cluster resource 53 | type ClusterStatus struct { 54 | ObservedGeneration int64 `json:"observedGeneration"` 55 | 56 | // Total number of pipelines. 57 | // +optional 58 | Pipelines int32 `json:"pipelines"` 59 | 60 | // Total number of pipelines which version match current deployment rule. 61 | // +optional 62 | UpdatedPipelines int32 `json:"updatedPipelines"` 63 | 64 | // Total number of available pipelines (ready for at least minReadySeconds). 65 | // +optional 66 | AvailablePipelines int32 `json:"availablePipelines"` 67 | 68 | // Total number of unavailable pipelines. They may 69 | // either be pipelines that are running but not yet available or pipelines that still have not been created. 70 | // +optional 71 | UnavailablePipelines int32 `json:"unavailablePipelines"` 72 | 73 | Conditions []ClusterCondition `json:"conditions,omitempty"` 74 | } 75 | 76 | func (t ClusterStatus) Condition(condType ClusterConditionType) *ClusterCondition { 77 | for _, cond := range t.Conditions { 78 | if cond.Type == condType { 79 | return &cond 80 | } 81 | } 82 | 83 | return nil 84 | } 85 | 86 | type ClusterConditionType string 87 | 88 | const ( 89 | // Available means the deployment is available, ie. at least the minimum available 90 | // replicas required are up and running for at least minReadySeconds. 91 | ClusterAvailable ClusterConditionType = "Available" 92 | 93 | // UpToDate means every pipeline in cluster has been updated. 94 | ClusterUpToDate ClusterConditionType = "UpToDate" 95 | ) 96 | 97 | type ClusterCondition struct { 98 | // Type of Cluster condition. 99 | Type ClusterConditionType `json:"type"` 100 | // Status of the condition, one of True, False, Unknown. 101 | Status corev1.ConditionStatus `json:"status"` 102 | // LastUpdateTime is the last time this condition was updated. 103 | LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` 104 | // LastTransitionTime is the last time the condition transitioned from one status to another. 105 | LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` 106 | // Reason for the condition's last transition. 107 | Reason string `json:"reason,omitempty"` 108 | // Message which is human readable indicating details about the transition. 109 | Message string `json:"message,omitempty"` 110 | } 111 | 112 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 113 | 114 | // PipelineList is a list of Pipeline resources 115 | type ClusterList struct { 116 | metav1.TypeMeta `json:",inline"` 117 | metav1.ListMeta `json:"metadata"` 118 | 119 | Items []Cluster `json:"items"` 120 | } 121 | -------------------------------------------------------------------------------- /pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | // +build !ignore_autogenerated 2 | 3 | /* 4 | Copyright The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | // Code generated by deepcopy-gen. DO NOT EDIT. 20 | 21 | package v1alpha1 22 | 23 | import ( 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | intstr "k8s.io/apimachinery/pkg/util/intstr" 26 | ) 27 | 28 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 29 | func (in *Cluster) DeepCopyInto(out *Cluster) { 30 | *out = *in 31 | out.TypeMeta = in.TypeMeta 32 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 33 | in.Spec.DeepCopyInto(&out.Spec) 34 | in.Status.DeepCopyInto(&out.Status) 35 | return 36 | } 37 | 38 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. 39 | func (in *Cluster) DeepCopy() *Cluster { 40 | if in == nil { 41 | return nil 42 | } 43 | out := new(Cluster) 44 | in.DeepCopyInto(out) 45 | return out 46 | } 47 | 48 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 49 | func (in *Cluster) DeepCopyObject() runtime.Object { 50 | if c := in.DeepCopy(); c != nil { 51 | return c 52 | } 53 | return nil 54 | } 55 | 56 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 57 | func (in *ClusterCondition) DeepCopyInto(out *ClusterCondition) { 58 | *out = *in 59 | in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) 60 | in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) 61 | return 62 | } 63 | 64 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterCondition. 65 | func (in *ClusterCondition) DeepCopy() *ClusterCondition { 66 | if in == nil { 67 | return nil 68 | } 69 | out := new(ClusterCondition) 70 | in.DeepCopyInto(out) 71 | return out 72 | } 73 | 74 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 75 | func (in *ClusterList) DeepCopyInto(out *ClusterList) { 76 | *out = *in 77 | out.TypeMeta = in.TypeMeta 78 | out.ListMeta = in.ListMeta 79 | if in.Items != nil { 80 | in, out := &in.Items, &out.Items 81 | *out = make([]Cluster, len(*in)) 82 | for i := range *in { 83 | (*in)[i].DeepCopyInto(&(*out)[i]) 84 | } 85 | } 86 | return 87 | } 88 | 89 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterList. 90 | func (in *ClusterList) DeepCopy() *ClusterList { 91 | if in == nil { 92 | return nil 93 | } 94 | out := new(ClusterList) 95 | in.DeepCopyInto(out) 96 | return out 97 | } 98 | 99 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 100 | func (in *ClusterList) DeepCopyObject() runtime.Object { 101 | if c := in.DeepCopy(); c != nil { 102 | return c 103 | } 104 | return nil 105 | } 106 | 107 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 108 | func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { 109 | *out = *in 110 | if in.Rolling != nil { 111 | in, out := &in.Rolling, &out.Rolling 112 | *out = new(intstr.IntOrString) 113 | **out = **in 114 | } 115 | if in.DeploymentRules != nil { 116 | in, out := &in.DeploymentRules, &out.DeploymentRules 117 | *out = make([]DeploymentRule, len(*in)) 118 | for i := range *in { 119 | (*in)[i].DeepCopyInto(&(*out)[i]) 120 | } 121 | } 122 | return 123 | } 124 | 125 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec. 126 | func (in *ClusterSpec) DeepCopy() *ClusterSpec { 127 | if in == nil { 128 | return nil 129 | } 130 | out := new(ClusterSpec) 131 | in.DeepCopyInto(out) 132 | return out 133 | } 134 | 135 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 136 | func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { 137 | *out = *in 138 | if in.Conditions != nil { 139 | in, out := &in.Conditions, &out.Conditions 140 | *out = make([]ClusterCondition, len(*in)) 141 | for i := range *in { 142 | (*in)[i].DeepCopyInto(&(*out)[i]) 143 | } 144 | } 145 | return 146 | } 147 | 148 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus. 149 | func (in *ClusterStatus) DeepCopy() *ClusterStatus { 150 | if in == nil { 151 | return nil 152 | } 153 | out := new(ClusterStatus) 154 | in.DeepCopyInto(out) 155 | return out 156 | } 157 | 158 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 159 | func (in *DeploymentRule) DeepCopyInto(out *DeploymentRule) { 160 | *out = *in 161 | if in.Pipelines != nil { 162 | in, out := &in.Pipelines, &out.Pipelines 163 | *out = make([]string, len(*in)) 164 | copy(*out, *in) 165 | } 166 | if in.Command != nil { 167 | in, out := &in.Command, &out.Command 168 | *out = make([]string, len(*in)) 169 | copy(*out, *in) 170 | } 171 | return 172 | } 173 | 174 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentRule. 175 | func (in *DeploymentRule) DeepCopy() *DeploymentRule { 176 | if in == nil { 177 | return nil 178 | } 179 | out := new(DeploymentRule) 180 | in.DeepCopyInto(out) 181 | return out 182 | } 183 | -------------------------------------------------------------------------------- /pkg/apis/pipeline/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // +k8s:deepcopy-gen=package 2 | 3 | // Package v1alpha1 is the v1alpha1 version of the API. 4 | // +groupName=gravity.mobike.io 5 | package v1alpha1 6 | -------------------------------------------------------------------------------- /pkg/apis/pipeline/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | "k8s.io/apimachinery/pkg/runtime" 6 | "k8s.io/apimachinery/pkg/runtime/schema" 7 | ) 8 | 9 | const ( 10 | GroupName = "gravity.mobike.io" 11 | PipelineResourceKind = "Pipeline" 12 | ) 13 | 14 | var ( 15 | SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} 16 | ) 17 | 18 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind 19 | func Kind(kind string) schema.GroupKind { 20 | return SchemeGroupVersion.WithKind(kind).GroupKind() 21 | } 22 | 23 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 24 | func Resource(resource string) schema.GroupResource { 25 | return SchemeGroupVersion.WithResource(resource).GroupResource() 26 | } 27 | 28 | var ( 29 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 30 | AddToScheme = SchemeBuilder.AddToScheme 31 | ) 32 | 33 | func addKnownTypes(scheme *runtime.Scheme) error { 34 | scheme.AddKnownTypes(SchemeGroupVersion, 35 | &Pipeline{}, 36 | &PipelineList{}, 37 | ) 38 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /pkg/apis/pipeline/v1alpha1/types.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | const ( 9 | ConfigFileKey = "config.json" 10 | ) 11 | 12 | // +genclient 13 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 14 | 15 | // Pipeline is a specification for a Pipeline resource 16 | type Pipeline struct { 17 | metav1.TypeMeta `json:",inline"` 18 | metav1.ObjectMeta `json:"metadata,omitempty"` 19 | 20 | Spec PipelineSpec `json:"spec"` 21 | Status PipelineStatus `json:"status"` 22 | } 23 | 24 | // PipelineSpec is the spec for a Pipeline resource 25 | type PipelineSpec struct { 26 | Task `json:",inline"` 27 | Paused bool `json:"paused"` 28 | LastUpdate metav1.Time `json:"lastUpdate"` 29 | } 30 | 31 | // PipelineStatus is the status for a Pipeline resource 32 | type PipelineStatus struct { 33 | ObservedGeneration int64 `json:"observedGeneration"` 34 | Task `json:",inline"` 35 | Position string `json:"position"` 36 | PodName string `json:"podName"` 37 | Conditions []PipelineCondition `json:"conditions,omitempty"` 38 | } 39 | 40 | func (t PipelineStatus) Available() bool { 41 | c := t.Condition(PipelineConditionRunning) 42 | return c != nil && c.Status == corev1.ConditionTrue 43 | } 44 | 45 | func (t PipelineStatus) Condition(condType PipelineConditionType) *PipelineCondition { 46 | for _, cond := range t.Conditions { 47 | if cond.Type == condType { 48 | return &cond 49 | } 50 | } 51 | 52 | return nil 53 | } 54 | 55 | type Task struct { 56 | ConfigHash string `json:"configHash"` 57 | Image string `json:"image"` 58 | Command []string `json:"command"` 59 | } 60 | 61 | type PipelineConditionType string 62 | 63 | const ( 64 | PipelineConditionRunning PipelineConditionType = "Running" 65 | PipelineConditionStream PipelineConditionType = "Stream" 66 | ) 67 | 68 | type PipelineCondition struct { 69 | // Type of cluster condition. 70 | Type PipelineConditionType `json:"type"` 71 | // Status of the condition, one of True, False, Unknown. 72 | Status corev1.ConditionStatus `json:"status"` 73 | // LastUpdateTime is the last time this condition was updated. 74 | LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` 75 | // LastTransitionTime is the last time the condition transitioned from one status to another. 76 | LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` 77 | // Reason for the condition's last transition. 78 | Reason string `json:"reason,omitempty"` 79 | // Message which is human readable indicating details about the transition. 80 | Message string `json:"message,omitempty"` 81 | } 82 | 83 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 84 | 85 | // PipelineList is a list of Pipeline resources 86 | type PipelineList struct { 87 | metav1.TypeMeta `json:",inline"` 88 | metav1.ListMeta `json:"metadata"` 89 | 90 | Items []Pipeline `json:"items"` 91 | } 92 | -------------------------------------------------------------------------------- /pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | // +build !ignore_autogenerated 2 | 3 | /* 4 | Copyright The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | // Code generated by deepcopy-gen. DO NOT EDIT. 20 | 21 | package v1alpha1 22 | 23 | import ( 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | ) 26 | 27 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 28 | func (in *Pipeline) DeepCopyInto(out *Pipeline) { 29 | *out = *in 30 | out.TypeMeta = in.TypeMeta 31 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 32 | in.Spec.DeepCopyInto(&out.Spec) 33 | in.Status.DeepCopyInto(&out.Status) 34 | return 35 | } 36 | 37 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Pipeline. 38 | func (in *Pipeline) DeepCopy() *Pipeline { 39 | if in == nil { 40 | return nil 41 | } 42 | out := new(Pipeline) 43 | in.DeepCopyInto(out) 44 | return out 45 | } 46 | 47 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 48 | func (in *Pipeline) DeepCopyObject() runtime.Object { 49 | if c := in.DeepCopy(); c != nil { 50 | return c 51 | } 52 | return nil 53 | } 54 | 55 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 56 | func (in *PipelineCondition) DeepCopyInto(out *PipelineCondition) { 57 | *out = *in 58 | in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) 59 | in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) 60 | return 61 | } 62 | 63 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineCondition. 64 | func (in *PipelineCondition) DeepCopy() *PipelineCondition { 65 | if in == nil { 66 | return nil 67 | } 68 | out := new(PipelineCondition) 69 | in.DeepCopyInto(out) 70 | return out 71 | } 72 | 73 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 74 | func (in *PipelineList) DeepCopyInto(out *PipelineList) { 75 | *out = *in 76 | out.TypeMeta = in.TypeMeta 77 | out.ListMeta = in.ListMeta 78 | if in.Items != nil { 79 | in, out := &in.Items, &out.Items 80 | *out = make([]Pipeline, len(*in)) 81 | for i := range *in { 82 | (*in)[i].DeepCopyInto(&(*out)[i]) 83 | } 84 | } 85 | return 86 | } 87 | 88 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineList. 89 | func (in *PipelineList) DeepCopy() *PipelineList { 90 | if in == nil { 91 | return nil 92 | } 93 | out := new(PipelineList) 94 | in.DeepCopyInto(out) 95 | return out 96 | } 97 | 98 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 99 | func (in *PipelineList) DeepCopyObject() runtime.Object { 100 | if c := in.DeepCopy(); c != nil { 101 | return c 102 | } 103 | return nil 104 | } 105 | 106 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 107 | func (in *PipelineSpec) DeepCopyInto(out *PipelineSpec) { 108 | *out = *in 109 | in.Task.DeepCopyInto(&out.Task) 110 | in.LastUpdate.DeepCopyInto(&out.LastUpdate) 111 | return 112 | } 113 | 114 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineSpec. 115 | func (in *PipelineSpec) DeepCopy() *PipelineSpec { 116 | if in == nil { 117 | return nil 118 | } 119 | out := new(PipelineSpec) 120 | in.DeepCopyInto(out) 121 | return out 122 | } 123 | 124 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 125 | func (in *PipelineStatus) DeepCopyInto(out *PipelineStatus) { 126 | *out = *in 127 | in.Task.DeepCopyInto(&out.Task) 128 | if in.Conditions != nil { 129 | in, out := &in.Conditions, &out.Conditions 130 | *out = make([]PipelineCondition, len(*in)) 131 | for i := range *in { 132 | (*in)[i].DeepCopyInto(&(*out)[i]) 133 | } 134 | } 135 | return 136 | } 137 | 138 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineStatus. 139 | func (in *PipelineStatus) DeepCopy() *PipelineStatus { 140 | if in == nil { 141 | return nil 142 | } 143 | out := new(PipelineStatus) 144 | in.DeepCopyInto(out) 145 | return out 146 | } 147 | 148 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 149 | func (in *Task) DeepCopyInto(out *Task) { 150 | *out = *in 151 | if in.Command != nil { 152 | in, out := &in.Command, &out.Command 153 | *out = make([]string, len(*in)) 154 | copy(*out, *in) 155 | } 156 | return 157 | } 158 | 159 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Task. 160 | func (in *Task) DeepCopy() *Task { 161 | if in == nil { 162 | return nil 163 | } 164 | out := new(Task) 165 | in.DeepCopyInto(out) 166 | return out 167 | } 168 | -------------------------------------------------------------------------------- /pkg/apiserver/cronjob.go: -------------------------------------------------------------------------------- 1 | package apiserver 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/juju/errors" 7 | "k8s.io/api/batch/v1" 8 | "k8s.io/api/batch/v1beta1" 9 | corev1 "k8s.io/api/core/v1" 10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 | 12 | pipeapi "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 13 | ) 14 | 15 | const ( 16 | ActionPause = "pause" 17 | ActionResume = "resume" 18 | ) 19 | 20 | type ApiCronJob struct { 21 | PipelineName string `json:"pipeline"` 22 | CronJobName string `json:"name"` 23 | 24 | // Schedule takes a Cron format 25 | // https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#schedule 26 | // THE TIMEZONE used by Schedule are based the timezone of the kubernetes master 27 | Schedule string `json:"schedule"` 28 | 29 | // Action is used to Pause and Resume a pipeline 30 | Action string `json:action` 31 | } 32 | 33 | func (apiCronJob *ApiCronJob) Validate() error { 34 | if apiCronJob.PipelineName == "" { 35 | return errors.Errorf("pipeline name is empty") 36 | } 37 | 38 | if apiCronJob.CronJobName == "" { 39 | return errors.Errorf("cronjob name is empty") 40 | } 41 | 42 | if apiCronJob.Schedule == "" { 43 | return errors.Errorf("schedule config is empty") 44 | } 45 | 46 | if apiCronJob.Action != ActionPause && apiCronJob.Action != ActionResume { 47 | return errors.Errorf("action config is not valid") 48 | } 49 | 50 | return nil 51 | } 52 | 53 | func pauseCommand(apiUrl string, pipelineName string) []string { 54 | return []string{"curl", "-X", "POST", fmt.Sprintf("%s/pipeline/%s/pause", apiUrl, pipelineName)} 55 | } 56 | 57 | func resumeCommand(apiUrl string, pipelineName string) []string { 58 | return []string{"curl", "-X", "POST", fmt.Sprintf("%s/pipeline/%s/resume", apiUrl, pipelineName)} 59 | } 60 | 61 | func containerCommand(action, apiUrl, pipelineName string) []string { 62 | if action == ActionPause { 63 | return pauseCommand(apiUrl, pipelineName) 64 | } else { 65 | return resumeCommand(apiUrl, pipelineName) 66 | } 67 | } 68 | 69 | func (apiCronJob *ApiCronJob) tok8(apiUrl string, pipeline *pipeapi.Pipeline, action string) *v1beta1.CronJob { 70 | command := containerCommand(action, apiUrl, pipeline.Name) 71 | 72 | jobMeta := metav1.ObjectMeta{ 73 | Name: apiCronJob.CronJobName, 74 | Namespace: pipeline.Namespace, 75 | Labels: map[string]string{ 76 | "app.kubernetes.io/name": "gravity-cronjob", 77 | "pipeline": pipeline.Name, 78 | "action": action, 79 | }, 80 | Annotations: map[string]string{ 81 | "action": apiCronJob.Action, 82 | "schedule": apiCronJob.Schedule, 83 | }, 84 | OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(pipeline, pipeapi.SchemeGroupVersion.WithKind(pipeapi.PipelineResourceKind))}, 85 | } 86 | 87 | return &v1beta1.CronJob{ 88 | ObjectMeta: jobMeta, 89 | Spec: v1beta1.CronJobSpec{ 90 | Schedule: apiCronJob.Schedule, 91 | JobTemplate: v1beta1.JobTemplateSpec{ 92 | Spec: v1.JobSpec{ 93 | Template: corev1.PodTemplateSpec{ 94 | Spec: corev1.PodSpec{ 95 | Containers: []corev1.Container{ 96 | { 97 | Name: apiCronJob.CronJobName, 98 | Command: command, 99 | Image: "byrnedo/alpine-curl", 100 | }, 101 | }, 102 | RestartPolicy: corev1.RestartPolicyOnFailure, 103 | }, 104 | }, 105 | }, 106 | }, 107 | }, 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /pkg/apiserver/pipeline.go: -------------------------------------------------------------------------------- 1 | package apiserver 2 | 3 | import ( 4 | "encoding/json" 5 | "regexp" 6 | 7 | "github.com/juju/errors" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | 11 | api "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 12 | "github.com/moiot/gravity/pkg/app" 13 | "github.com/moiot/gravity/pkg/config" 14 | "github.com/moiot/gravity/pkg/core" 15 | ) 16 | 17 | type ApiPipeline struct { 18 | metav1.TypeMeta `json:",inline"` 19 | metav1.ObjectMeta `json:"metadata,omitempty"` 20 | 21 | Spec ApiPipelineSpec `json:"spec"` 22 | Status api.PipelineStatus `json:"status"` 23 | } 24 | 25 | type ApiPipelineSpec struct { 26 | api.PipelineSpec 27 | Config *json.RawMessage `json:"config,omitempty"` 28 | } 29 | 30 | func (apiPipeline *ApiPipeline) toK8() *api.Pipeline { 31 | apiPipeline.Spec.LastUpdate = metav1.Now() 32 | return &api.Pipeline{ 33 | TypeMeta: apiPipeline.TypeMeta, 34 | ObjectMeta: apiPipeline.ObjectMeta, 35 | Spec: apiPipeline.Spec.PipelineSpec, 36 | Status: apiPipeline.Status, 37 | } 38 | } 39 | 40 | func (apiPipeline *ApiPipeline) fromK8(pipeline *api.Pipeline) { 41 | apiPipeline.TypeMeta = pipeline.TypeMeta 42 | apiPipeline.ObjectMeta = pipeline.ObjectMeta 43 | apiPipeline.Spec = ApiPipelineSpec{PipelineSpec: pipeline.Spec} 44 | apiPipeline.Status = pipeline.Status 45 | } 46 | 47 | func (apiPipeline *ApiPipeline) newConfigMap(pipeline *api.Pipeline) *corev1.ConfigMap { 48 | return &corev1.ConfigMap{ 49 | ObjectMeta: metav1.ObjectMeta{ 50 | Name: apiPipeline.Name, 51 | Namespace: pipeline.Namespace, 52 | Labels: map[string]string{ 53 | "app.kubernetes.io/name": "gravity", 54 | "app.kubernetes.io/instance": apiPipeline.Name, 55 | }, 56 | Annotations: map[string]string{ 57 | api.GroupName + "/hash": apiPipeline.Spec.ConfigHash, 58 | }, 59 | OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(pipeline, api.SchemeGroupVersion.WithKind(api.PipelineResourceKind))}, 60 | }, 61 | Data: map[string]string{ 62 | api.ConfigFileKey: string(*apiPipeline.Spec.Config), 63 | }, 64 | } 65 | } 66 | 67 | var nameReg = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`) 68 | 69 | func (apiPipeline *ApiPipeline) validate() error { 70 | if !nameReg.Match([]byte(apiPipeline.Name)) { 71 | return errors.Errorf("name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc')") 72 | } 73 | cfgV3 := &config.PipelineConfigV3{} 74 | err := json.Unmarshal(*apiPipeline.Spec.Config, cfgV3) 75 | if err != nil { 76 | return errors.Annotatef(err, "error unmarshal gravity config v3: %s", string(*apiPipeline.Spec.Config)) 77 | } 78 | 79 | if cfgV3.Version != config.PipelineConfigV3Version { 80 | return errors.Errorf("ONLY support 1.0 configuration version") 81 | } 82 | 83 | cfgV3.PipelineName = apiPipeline.Name 84 | _, err = app.ParsePlugins(*cfgV3) 85 | if err != nil { 86 | return errors.Annotatef(err, "error parse gravity cfg: %s. %#v.", err, cfgV3) 87 | } 88 | updated, err := json.Marshal(cfgV3) 89 | if err != nil { 90 | return errors.Annotatef(err, "error marshal cfg: %#v. err: %s", cfgV3, err) 91 | } 92 | updatedRaw := json.RawMessage(updated) 93 | apiPipeline.Spec.Config = &updatedRaw 94 | 95 | apiPipeline.Spec.ConfigHash = core.HashConfig(string(*apiPipeline.Spec.Config)) 96 | return nil 97 | } 98 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/clientset.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package versioned 20 | 21 | import ( 22 | gravityv1alpha1 "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1" 23 | discovery "k8s.io/client-go/discovery" 24 | rest "k8s.io/client-go/rest" 25 | flowcontrol "k8s.io/client-go/util/flowcontrol" 26 | ) 27 | 28 | type Interface interface { 29 | Discovery() discovery.DiscoveryInterface 30 | GravityV1alpha1() gravityv1alpha1.GravityV1alpha1Interface 31 | // Deprecated: please explicitly pick a version if possible. 32 | Gravity() gravityv1alpha1.GravityV1alpha1Interface 33 | } 34 | 35 | // Clientset contains the clients for groups. Each group has exactly one 36 | // version included in a Clientset. 37 | type Clientset struct { 38 | *discovery.DiscoveryClient 39 | gravityV1alpha1 *gravityv1alpha1.GravityV1alpha1Client 40 | } 41 | 42 | // GravityV1alpha1 retrieves the GravityV1alpha1Client 43 | func (c *Clientset) GravityV1alpha1() gravityv1alpha1.GravityV1alpha1Interface { 44 | return c.gravityV1alpha1 45 | } 46 | 47 | // Deprecated: Gravity retrieves the default version of GravityClient. 48 | // Please explicitly pick a version. 49 | func (c *Clientset) Gravity() gravityv1alpha1.GravityV1alpha1Interface { 50 | return c.gravityV1alpha1 51 | } 52 | 53 | // Discovery retrieves the DiscoveryClient 54 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 55 | if c == nil { 56 | return nil 57 | } 58 | return c.DiscoveryClient 59 | } 60 | 61 | // NewForConfig creates a new Clientset for the given config. 62 | func NewForConfig(c *rest.Config) (*Clientset, error) { 63 | configShallowCopy := *c 64 | if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { 65 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) 66 | } 67 | var cs Clientset 68 | var err error 69 | cs.gravityV1alpha1, err = gravityv1alpha1.NewForConfig(&configShallowCopy) 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return &cs, nil 79 | } 80 | 81 | // NewForConfigOrDie creates a new Clientset for the given config and 82 | // panics if there is an error in the config. 83 | func NewForConfigOrDie(c *rest.Config) *Clientset { 84 | var cs Clientset 85 | cs.gravityV1alpha1 = gravityv1alpha1.NewForConfigOrDie(c) 86 | 87 | cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) 88 | return &cs 89 | } 90 | 91 | // New creates a new Clientset for the given RESTClient. 92 | func New(c rest.Interface) *Clientset { 93 | var cs Clientset 94 | cs.gravityV1alpha1 = gravityv1alpha1.New(c) 95 | 96 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c) 97 | return &cs 98 | } 99 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated clientset. 20 | package versioned 21 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/fake/clientset_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | clientset "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned" 23 | gravityv1alpha1 "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1" 24 | fakegravityv1alpha1 "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1/fake" 25 | "k8s.io/apimachinery/pkg/runtime" 26 | "k8s.io/apimachinery/pkg/watch" 27 | "k8s.io/client-go/discovery" 28 | fakediscovery "k8s.io/client-go/discovery/fake" 29 | "k8s.io/client-go/testing" 30 | ) 31 | 32 | // NewSimpleClientset returns a clientset that will respond with the provided objects. 33 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, 34 | // without applying any validations and/or defaults. It shouldn't be considered a replacement 35 | // for a real clientset and is mostly useful in simple unit tests. 36 | func NewSimpleClientset(objects ...runtime.Object) *Clientset { 37 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) 38 | for _, obj := range objects { 39 | if err := o.Add(obj); err != nil { 40 | panic(err) 41 | } 42 | } 43 | 44 | cs := &Clientset{} 45 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} 46 | cs.AddReactor("*", "*", testing.ObjectReaction(o)) 47 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { 48 | gvr := action.GetResource() 49 | ns := action.GetNamespace() 50 | watch, err := o.Watch(gvr, ns) 51 | if err != nil { 52 | return false, nil, err 53 | } 54 | return true, watch, nil 55 | }) 56 | 57 | return cs 58 | } 59 | 60 | // Clientset implements clientset.Interface. Meant to be embedded into a 61 | // struct to get a default implementation. This makes faking out just the method 62 | // you want to test easier. 63 | type Clientset struct { 64 | testing.Fake 65 | discovery *fakediscovery.FakeDiscovery 66 | } 67 | 68 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 69 | return c.discovery 70 | } 71 | 72 | var _ clientset.Interface = &Clientset{} 73 | 74 | // GravityV1alpha1 retrieves the GravityV1alpha1Client 75 | func (c *Clientset) GravityV1alpha1() gravityv1alpha1.GravityV1alpha1Interface { 76 | return &fakegravityv1alpha1.FakeGravityV1alpha1{Fake: &c.Fake} 77 | } 78 | 79 | // Gravity retrieves the GravityV1alpha1Client 80 | func (c *Clientset) Gravity() gravityv1alpha1.GravityV1alpha1Interface { 81 | return &fakegravityv1alpha1.FakeGravityV1alpha1{Fake: &c.Fake} 82 | } 83 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated fake clientset. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/fake/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | gravityv1alpha1 "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 27 | ) 28 | 29 | var scheme = runtime.NewScheme() 30 | var codecs = serializer.NewCodecFactory(scheme) 31 | var parameterCodec = runtime.NewParameterCodec(scheme) 32 | 33 | func init() { 34 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) 35 | AddToScheme(scheme) 36 | } 37 | 38 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 39 | // of clientsets, like in: 40 | // 41 | // import ( 42 | // "k8s.io/client-go/kubernetes" 43 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 44 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 45 | // ) 46 | // 47 | // kclientset, _ := kubernetes.NewForConfig(c) 48 | // aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 49 | // 50 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 51 | // correctly. 52 | func AddToScheme(scheme *runtime.Scheme) { 53 | gravityv1alpha1.AddToScheme(scheme) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package contains the scheme of the automatically generated clientset. 20 | package scheme 21 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/scheme/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package scheme 20 | 21 | import ( 22 | gravityv1alpha1 "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 27 | ) 28 | 29 | var Scheme = runtime.NewScheme() 30 | var Codecs = serializer.NewCodecFactory(Scheme) 31 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 32 | 33 | func init() { 34 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 35 | AddToScheme(Scheme) 36 | } 37 | 38 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 39 | // of clientsets, like in: 40 | // 41 | // import ( 42 | // "k8s.io/client-go/kubernetes" 43 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 44 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 45 | // ) 46 | // 47 | // kclientset, _ := kubernetes.NewForConfig(c) 48 | // aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 49 | // 50 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 51 | // correctly. 52 | func AddToScheme(scheme *runtime.Scheme) { 53 | gravityv1alpha1.AddToScheme(scheme) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1/cluster.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 23 | scheme "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned/scheme" 24 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 | types "k8s.io/apimachinery/pkg/types" 26 | watch "k8s.io/apimachinery/pkg/watch" 27 | rest "k8s.io/client-go/rest" 28 | ) 29 | 30 | // ClustersGetter has a method to return a ClusterInterface. 31 | // A group's client should implement this interface. 32 | type ClustersGetter interface { 33 | Clusters(namespace string) ClusterInterface 34 | } 35 | 36 | // ClusterInterface has methods to work with Cluster resources. 37 | type ClusterInterface interface { 38 | Create(*v1alpha1.Cluster) (*v1alpha1.Cluster, error) 39 | Update(*v1alpha1.Cluster) (*v1alpha1.Cluster, error) 40 | UpdateStatus(*v1alpha1.Cluster) (*v1alpha1.Cluster, error) 41 | Delete(name string, options *v1.DeleteOptions) error 42 | DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error 43 | Get(name string, options v1.GetOptions) (*v1alpha1.Cluster, error) 44 | List(opts v1.ListOptions) (*v1alpha1.ClusterList, error) 45 | Watch(opts v1.ListOptions) (watch.Interface, error) 46 | Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Cluster, err error) 47 | ClusterExpansion 48 | } 49 | 50 | // clusters implements ClusterInterface 51 | type clusters struct { 52 | client rest.Interface 53 | ns string 54 | } 55 | 56 | // newClusters returns a Clusters 57 | func newClusters(c *GravityV1alpha1Client, namespace string) *clusters { 58 | return &clusters{ 59 | client: c.RESTClient(), 60 | ns: namespace, 61 | } 62 | } 63 | 64 | // Get takes name of the cluster, and returns the corresponding cluster object, and an error if there is any. 65 | func (c *clusters) Get(name string, options v1.GetOptions) (result *v1alpha1.Cluster, err error) { 66 | result = &v1alpha1.Cluster{} 67 | err = c.client.Get(). 68 | Namespace(c.ns). 69 | Resource("clusters"). 70 | Name(name). 71 | VersionedParams(&options, scheme.ParameterCodec). 72 | Do(). 73 | Into(result) 74 | return 75 | } 76 | 77 | // List takes label and field selectors, and returns the list of Clusters that match those selectors. 78 | func (c *clusters) List(opts v1.ListOptions) (result *v1alpha1.ClusterList, err error) { 79 | result = &v1alpha1.ClusterList{} 80 | err = c.client.Get(). 81 | Namespace(c.ns). 82 | Resource("clusters"). 83 | VersionedParams(&opts, scheme.ParameterCodec). 84 | Do(). 85 | Into(result) 86 | return 87 | } 88 | 89 | // Watch returns a watch.Interface that watches the requested clusters. 90 | func (c *clusters) Watch(opts v1.ListOptions) (watch.Interface, error) { 91 | opts.Watch = true 92 | return c.client.Get(). 93 | Namespace(c.ns). 94 | Resource("clusters"). 95 | VersionedParams(&opts, scheme.ParameterCodec). 96 | Watch() 97 | } 98 | 99 | // Create takes the representation of a cluster and creates it. Returns the server's representation of the cluster, and an error, if there is any. 100 | func (c *clusters) Create(cluster *v1alpha1.Cluster) (result *v1alpha1.Cluster, err error) { 101 | result = &v1alpha1.Cluster{} 102 | err = c.client.Post(). 103 | Namespace(c.ns). 104 | Resource("clusters"). 105 | Body(cluster). 106 | Do(). 107 | Into(result) 108 | return 109 | } 110 | 111 | // Update takes the representation of a cluster and updates it. Returns the server's representation of the cluster, and an error, if there is any. 112 | func (c *clusters) Update(cluster *v1alpha1.Cluster) (result *v1alpha1.Cluster, err error) { 113 | result = &v1alpha1.Cluster{} 114 | err = c.client.Put(). 115 | Namespace(c.ns). 116 | Resource("clusters"). 117 | Name(cluster.Name). 118 | Body(cluster). 119 | Do(). 120 | Into(result) 121 | return 122 | } 123 | 124 | // UpdateStatus was generated because the type contains a Status member. 125 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 126 | 127 | func (c *clusters) UpdateStatus(cluster *v1alpha1.Cluster) (result *v1alpha1.Cluster, err error) { 128 | result = &v1alpha1.Cluster{} 129 | err = c.client.Put(). 130 | Namespace(c.ns). 131 | Resource("clusters"). 132 | Name(cluster.Name). 133 | SubResource("status"). 134 | Body(cluster). 135 | Do(). 136 | Into(result) 137 | return 138 | } 139 | 140 | // Delete takes name of the cluster and deletes it. Returns an error if one occurs. 141 | func (c *clusters) Delete(name string, options *v1.DeleteOptions) error { 142 | return c.client.Delete(). 143 | Namespace(c.ns). 144 | Resource("clusters"). 145 | Name(name). 146 | Body(options). 147 | Do(). 148 | Error() 149 | } 150 | 151 | // DeleteCollection deletes a collection of objects. 152 | func (c *clusters) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { 153 | return c.client.Delete(). 154 | Namespace(c.ns). 155 | Resource("clusters"). 156 | VersionedParams(&listOptions, scheme.ParameterCodec). 157 | Body(options). 158 | Do(). 159 | Error() 160 | } 161 | 162 | // Patch applies the patch and returns the patched cluster. 163 | func (c *clusters) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Cluster, err error) { 164 | result = &v1alpha1.Cluster{} 165 | err = c.client.Patch(pt). 166 | Namespace(c.ns). 167 | Resource("clusters"). 168 | SubResource(subresources...). 169 | Name(name). 170 | Body(data). 171 | Do(). 172 | Into(result) 173 | return 174 | } 175 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1/cluster_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 23 | "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned/scheme" 24 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 25 | rest "k8s.io/client-go/rest" 26 | ) 27 | 28 | type GravityV1alpha1Interface interface { 29 | RESTClient() rest.Interface 30 | ClustersGetter 31 | } 32 | 33 | // GravityV1alpha1Client is used to interact with features provided by the gravity.mobike.io group. 34 | type GravityV1alpha1Client struct { 35 | restClient rest.Interface 36 | } 37 | 38 | func (c *GravityV1alpha1Client) Clusters(namespace string) ClusterInterface { 39 | return newClusters(c, namespace) 40 | } 41 | 42 | // NewForConfig creates a new GravityV1alpha1Client for the given config. 43 | func NewForConfig(c *rest.Config) (*GravityV1alpha1Client, error) { 44 | config := *c 45 | if err := setConfigDefaults(&config); err != nil { 46 | return nil, err 47 | } 48 | client, err := rest.RESTClientFor(&config) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return &GravityV1alpha1Client{client}, nil 53 | } 54 | 55 | // NewForConfigOrDie creates a new GravityV1alpha1Client for the given config and 56 | // panics if there is an error in the config. 57 | func NewForConfigOrDie(c *rest.Config) *GravityV1alpha1Client { 58 | client, err := NewForConfig(c) 59 | if err != nil { 60 | panic(err) 61 | } 62 | return client 63 | } 64 | 65 | // New creates a new GravityV1alpha1Client for the given RESTClient. 66 | func New(c rest.Interface) *GravityV1alpha1Client { 67 | return &GravityV1alpha1Client{c} 68 | } 69 | 70 | func setConfigDefaults(config *rest.Config) error { 71 | gv := v1alpha1.SchemeGroupVersion 72 | config.GroupVersion = &gv 73 | config.APIPath = "/apis" 74 | config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} 75 | 76 | if config.UserAgent == "" { 77 | config.UserAgent = rest.DefaultKubernetesUserAgent() 78 | } 79 | 80 | return nil 81 | } 82 | 83 | // RESTClient returns a RESTClient that is used to communicate 84 | // with API server by this client implementation. 85 | func (c *GravityV1alpha1Client) RESTClient() rest.Interface { 86 | if c == nil { 87 | return nil 88 | } 89 | return c.restClient 90 | } 91 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v1alpha1 21 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1/fake/fake_cluster.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | labels "k8s.io/apimachinery/pkg/labels" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | types "k8s.io/apimachinery/pkg/types" 27 | watch "k8s.io/apimachinery/pkg/watch" 28 | testing "k8s.io/client-go/testing" 29 | ) 30 | 31 | // FakeClusters implements ClusterInterface 32 | type FakeClusters struct { 33 | Fake *FakeGravityV1alpha1 34 | ns string 35 | } 36 | 37 | var clustersResource = schema.GroupVersionResource{Group: "gravity.mobike.io", Version: "v1alpha1", Resource: "clusters"} 38 | 39 | var clustersKind = schema.GroupVersionKind{Group: "gravity.mobike.io", Version: "v1alpha1", Kind: "Cluster"} 40 | 41 | // Get takes name of the cluster, and returns the corresponding cluster object, and an error if there is any. 42 | func (c *FakeClusters) Get(name string, options v1.GetOptions) (result *v1alpha1.Cluster, err error) { 43 | obj, err := c.Fake. 44 | Invokes(testing.NewGetAction(clustersResource, c.ns, name), &v1alpha1.Cluster{}) 45 | 46 | if obj == nil { 47 | return nil, err 48 | } 49 | return obj.(*v1alpha1.Cluster), err 50 | } 51 | 52 | // List takes label and field selectors, and returns the list of Clusters that match those selectors. 53 | func (c *FakeClusters) List(opts v1.ListOptions) (result *v1alpha1.ClusterList, err error) { 54 | obj, err := c.Fake. 55 | Invokes(testing.NewListAction(clustersResource, clustersKind, c.ns, opts), &v1alpha1.ClusterList{}) 56 | 57 | if obj == nil { 58 | return nil, err 59 | } 60 | 61 | label, _, _ := testing.ExtractFromListOptions(opts) 62 | if label == nil { 63 | label = labels.Everything() 64 | } 65 | list := &v1alpha1.ClusterList{ListMeta: obj.(*v1alpha1.ClusterList).ListMeta} 66 | for _, item := range obj.(*v1alpha1.ClusterList).Items { 67 | if label.Matches(labels.Set(item.Labels)) { 68 | list.Items = append(list.Items, item) 69 | } 70 | } 71 | return list, err 72 | } 73 | 74 | // Watch returns a watch.Interface that watches the requested clusters. 75 | func (c *FakeClusters) Watch(opts v1.ListOptions) (watch.Interface, error) { 76 | return c.Fake. 77 | InvokesWatch(testing.NewWatchAction(clustersResource, c.ns, opts)) 78 | 79 | } 80 | 81 | // Create takes the representation of a cluster and creates it. Returns the server's representation of the cluster, and an error, if there is any. 82 | func (c *FakeClusters) Create(cluster *v1alpha1.Cluster) (result *v1alpha1.Cluster, err error) { 83 | obj, err := c.Fake. 84 | Invokes(testing.NewCreateAction(clustersResource, c.ns, cluster), &v1alpha1.Cluster{}) 85 | 86 | if obj == nil { 87 | return nil, err 88 | } 89 | return obj.(*v1alpha1.Cluster), err 90 | } 91 | 92 | // Update takes the representation of a cluster and updates it. Returns the server's representation of the cluster, and an error, if there is any. 93 | func (c *FakeClusters) Update(cluster *v1alpha1.Cluster) (result *v1alpha1.Cluster, err error) { 94 | obj, err := c.Fake. 95 | Invokes(testing.NewUpdateAction(clustersResource, c.ns, cluster), &v1alpha1.Cluster{}) 96 | 97 | if obj == nil { 98 | return nil, err 99 | } 100 | return obj.(*v1alpha1.Cluster), err 101 | } 102 | 103 | // UpdateStatus was generated because the type contains a Status member. 104 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 105 | func (c *FakeClusters) UpdateStatus(cluster *v1alpha1.Cluster) (*v1alpha1.Cluster, error) { 106 | obj, err := c.Fake. 107 | Invokes(testing.NewUpdateSubresourceAction(clustersResource, "status", c.ns, cluster), &v1alpha1.Cluster{}) 108 | 109 | if obj == nil { 110 | return nil, err 111 | } 112 | return obj.(*v1alpha1.Cluster), err 113 | } 114 | 115 | // Delete takes name of the cluster and deletes it. Returns an error if one occurs. 116 | func (c *FakeClusters) Delete(name string, options *v1.DeleteOptions) error { 117 | _, err := c.Fake. 118 | Invokes(testing.NewDeleteAction(clustersResource, c.ns, name), &v1alpha1.Cluster{}) 119 | 120 | return err 121 | } 122 | 123 | // DeleteCollection deletes a collection of objects. 124 | func (c *FakeClusters) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { 125 | action := testing.NewDeleteCollectionAction(clustersResource, c.ns, listOptions) 126 | 127 | _, err := c.Fake.Invokes(action, &v1alpha1.ClusterList{}) 128 | return err 129 | } 130 | 131 | // Patch applies the patch and returns the patched cluster. 132 | func (c *FakeClusters) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Cluster, err error) { 133 | obj, err := c.Fake. 134 | Invokes(testing.NewPatchSubresourceAction(clustersResource, c.ns, name, data, subresources...), &v1alpha1.Cluster{}) 135 | 136 | if obj == nil { 137 | return nil, err 138 | } 139 | return obj.(*v1alpha1.Cluster), err 140 | } 141 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1/fake/fake_cluster_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1" 23 | rest "k8s.io/client-go/rest" 24 | testing "k8s.io/client-go/testing" 25 | ) 26 | 27 | type FakeGravityV1alpha1 struct { 28 | *testing.Fake 29 | } 30 | 31 | func (c *FakeGravityV1alpha1) Clusters(namespace string) v1alpha1.ClusterInterface { 32 | return &FakeClusters{c, namespace} 33 | } 34 | 35 | // RESTClient returns a RESTClient that is used to communicate 36 | // with API server by this client implementation. 37 | func (c *FakeGravityV1alpha1) RESTClient() rest.Interface { 38 | var ret *rest.RESTClient 39 | return ret 40 | } 41 | -------------------------------------------------------------------------------- /pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | type ClusterExpansion interface{} 22 | -------------------------------------------------------------------------------- /pkg/client/cluster/informers/externalversions/cluster/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package gravity 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/client/cluster/informers/externalversions/cluster/v1alpha1" 23 | internalinterfaces "github.com/moiot/gravity-operator/pkg/client/cluster/informers/externalversions/internalinterfaces" 24 | ) 25 | 26 | // Interface provides access to each of this group's versions. 27 | type Interface interface { 28 | // V1alpha1 provides access to shared informers for resources in V1alpha1. 29 | V1alpha1() v1alpha1.Interface 30 | } 31 | 32 | type group struct { 33 | factory internalinterfaces.SharedInformerFactory 34 | namespace string 35 | tweakListOptions internalinterfaces.TweakListOptionsFunc 36 | } 37 | 38 | // New returns a new Interface. 39 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 40 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 41 | } 42 | 43 | // V1alpha1 returns a new v1alpha1.Interface. 44 | func (g *group) V1alpha1() v1alpha1.Interface { 45 | return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) 46 | } 47 | -------------------------------------------------------------------------------- /pkg/client/cluster/informers/externalversions/cluster/v1alpha1/cluster.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | time "time" 23 | 24 | clusterv1alpha1 "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 25 | versioned "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned" 26 | internalinterfaces "github.com/moiot/gravity-operator/pkg/client/cluster/informers/externalversions/internalinterfaces" 27 | v1alpha1 "github.com/moiot/gravity-operator/pkg/client/cluster/listers/cluster/v1alpha1" 28 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 | runtime "k8s.io/apimachinery/pkg/runtime" 30 | watch "k8s.io/apimachinery/pkg/watch" 31 | cache "k8s.io/client-go/tools/cache" 32 | ) 33 | 34 | // ClusterInformer provides access to a shared informer and lister for 35 | // Clusters. 36 | type ClusterInformer interface { 37 | Informer() cache.SharedIndexInformer 38 | Lister() v1alpha1.ClusterLister 39 | } 40 | 41 | type clusterInformer struct { 42 | factory internalinterfaces.SharedInformerFactory 43 | tweakListOptions internalinterfaces.TweakListOptionsFunc 44 | namespace string 45 | } 46 | 47 | // NewClusterInformer constructs a new informer for Cluster type. 48 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 49 | // one. This reduces memory footprint and number of connections to the server. 50 | func NewClusterInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 51 | return NewFilteredClusterInformer(client, namespace, resyncPeriod, indexers, nil) 52 | } 53 | 54 | // NewFilteredClusterInformer constructs a new informer for Cluster type. 55 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 56 | // one. This reduces memory footprint and number of connections to the server. 57 | func NewFilteredClusterInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { 58 | return cache.NewSharedIndexInformer( 59 | &cache.ListWatch{ 60 | ListFunc: func(options v1.ListOptions) (runtime.Object, error) { 61 | if tweakListOptions != nil { 62 | tweakListOptions(&options) 63 | } 64 | return client.GravityV1alpha1().Clusters(namespace).List(options) 65 | }, 66 | WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { 67 | if tweakListOptions != nil { 68 | tweakListOptions(&options) 69 | } 70 | return client.GravityV1alpha1().Clusters(namespace).Watch(options) 71 | }, 72 | }, 73 | &clusterv1alpha1.Cluster{}, 74 | resyncPeriod, 75 | indexers, 76 | ) 77 | } 78 | 79 | func (f *clusterInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 80 | return NewFilteredClusterInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) 81 | } 82 | 83 | func (f *clusterInformer) Informer() cache.SharedIndexInformer { 84 | return f.factory.InformerFor(&clusterv1alpha1.Cluster{}, f.defaultInformer) 85 | } 86 | 87 | func (f *clusterInformer) Lister() v1alpha1.ClusterLister { 88 | return v1alpha1.NewClusterLister(f.Informer().GetIndexer()) 89 | } 90 | -------------------------------------------------------------------------------- /pkg/client/cluster/informers/externalversions/cluster/v1alpha1/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | internalinterfaces "github.com/moiot/gravity-operator/pkg/client/cluster/informers/externalversions/internalinterfaces" 23 | ) 24 | 25 | // Interface provides access to all the informers in this group version. 26 | type Interface interface { 27 | // Clusters returns a ClusterInformer. 28 | Clusters() ClusterInformer 29 | } 30 | 31 | type version struct { 32 | factory internalinterfaces.SharedInformerFactory 33 | namespace string 34 | tweakListOptions internalinterfaces.TweakListOptionsFunc 35 | } 36 | 37 | // New returns a new Interface. 38 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 39 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 40 | } 41 | 42 | // Clusters returns a ClusterInformer. 43 | func (v *version) Clusters() ClusterInformer { 44 | return &clusterInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 45 | } 46 | -------------------------------------------------------------------------------- /pkg/client/cluster/informers/externalversions/factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | reflect "reflect" 23 | sync "sync" 24 | time "time" 25 | 26 | versioned "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned" 27 | cluster "github.com/moiot/gravity-operator/pkg/client/cluster/informers/externalversions/cluster" 28 | internalinterfaces "github.com/moiot/gravity-operator/pkg/client/cluster/informers/externalversions/internalinterfaces" 29 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | runtime "k8s.io/apimachinery/pkg/runtime" 31 | schema "k8s.io/apimachinery/pkg/runtime/schema" 32 | cache "k8s.io/client-go/tools/cache" 33 | ) 34 | 35 | // SharedInformerOption defines the functional option type for SharedInformerFactory. 36 | type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory 37 | 38 | type sharedInformerFactory struct { 39 | client versioned.Interface 40 | namespace string 41 | tweakListOptions internalinterfaces.TweakListOptionsFunc 42 | lock sync.Mutex 43 | defaultResync time.Duration 44 | customResync map[reflect.Type]time.Duration 45 | 46 | informers map[reflect.Type]cache.SharedIndexInformer 47 | // startedInformers is used for tracking which informers have been started. 48 | // This allows Start() to be called multiple times safely. 49 | startedInformers map[reflect.Type]bool 50 | } 51 | 52 | // WithCustomResyncConfig sets a custom resync period for the specified informer types. 53 | func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { 54 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 55 | for k, v := range resyncConfig { 56 | factory.customResync[reflect.TypeOf(k)] = v 57 | } 58 | return factory 59 | } 60 | } 61 | 62 | // WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. 63 | func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { 64 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 65 | factory.tweakListOptions = tweakListOptions 66 | return factory 67 | } 68 | } 69 | 70 | // WithNamespace limits the SharedInformerFactory to the specified namespace. 71 | func WithNamespace(namespace string) SharedInformerOption { 72 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 73 | factory.namespace = namespace 74 | return factory 75 | } 76 | } 77 | 78 | // NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. 79 | func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { 80 | return NewSharedInformerFactoryWithOptions(client, defaultResync) 81 | } 82 | 83 | // NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. 84 | // Listers obtained via this SharedInformerFactory will be subject to the same filters 85 | // as specified here. 86 | // Deprecated: Please use NewSharedInformerFactoryWithOptions instead 87 | func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { 88 | return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) 89 | } 90 | 91 | // NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. 92 | func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { 93 | factory := &sharedInformerFactory{ 94 | client: client, 95 | namespace: v1.NamespaceAll, 96 | defaultResync: defaultResync, 97 | informers: make(map[reflect.Type]cache.SharedIndexInformer), 98 | startedInformers: make(map[reflect.Type]bool), 99 | customResync: make(map[reflect.Type]time.Duration), 100 | } 101 | 102 | // Apply all options 103 | for _, opt := range options { 104 | factory = opt(factory) 105 | } 106 | 107 | return factory 108 | } 109 | 110 | // Start initializes all requested informers. 111 | func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { 112 | f.lock.Lock() 113 | defer f.lock.Unlock() 114 | 115 | for informerType, informer := range f.informers { 116 | if !f.startedInformers[informerType] { 117 | go informer.Run(stopCh) 118 | f.startedInformers[informerType] = true 119 | } 120 | } 121 | } 122 | 123 | // WaitForCacheSync waits for all started informers' cache were synced. 124 | func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { 125 | informers := func() map[reflect.Type]cache.SharedIndexInformer { 126 | f.lock.Lock() 127 | defer f.lock.Unlock() 128 | 129 | informers := map[reflect.Type]cache.SharedIndexInformer{} 130 | for informerType, informer := range f.informers { 131 | if f.startedInformers[informerType] { 132 | informers[informerType] = informer 133 | } 134 | } 135 | return informers 136 | }() 137 | 138 | res := map[reflect.Type]bool{} 139 | for informType, informer := range informers { 140 | res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) 141 | } 142 | return res 143 | } 144 | 145 | // InternalInformerFor returns the SharedIndexInformer for obj using an internal 146 | // client. 147 | func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { 148 | f.lock.Lock() 149 | defer f.lock.Unlock() 150 | 151 | informerType := reflect.TypeOf(obj) 152 | informer, exists := f.informers[informerType] 153 | if exists { 154 | return informer 155 | } 156 | 157 | resyncPeriod, exists := f.customResync[informerType] 158 | if !exists { 159 | resyncPeriod = f.defaultResync 160 | } 161 | 162 | informer = newFunc(f.client, resyncPeriod) 163 | f.informers[informerType] = informer 164 | 165 | return informer 166 | } 167 | 168 | // SharedInformerFactory provides shared informers for resources in all known 169 | // API group versions. 170 | type SharedInformerFactory interface { 171 | internalinterfaces.SharedInformerFactory 172 | ForResource(resource schema.GroupVersionResource) (GenericInformer, error) 173 | WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool 174 | 175 | Gravity() cluster.Interface 176 | } 177 | 178 | func (f *sharedInformerFactory) Gravity() cluster.Interface { 179 | return cluster.New(f, f.namespace, f.tweakListOptions) 180 | } 181 | -------------------------------------------------------------------------------- /pkg/client/cluster/informers/externalversions/generic.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | "fmt" 23 | 24 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | cache "k8s.io/client-go/tools/cache" 27 | ) 28 | 29 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other 30 | // sharedInformers based on type 31 | type GenericInformer interface { 32 | Informer() cache.SharedIndexInformer 33 | Lister() cache.GenericLister 34 | } 35 | 36 | type genericInformer struct { 37 | informer cache.SharedIndexInformer 38 | resource schema.GroupResource 39 | } 40 | 41 | // Informer returns the SharedIndexInformer. 42 | func (f *genericInformer) Informer() cache.SharedIndexInformer { 43 | return f.informer 44 | } 45 | 46 | // Lister returns the GenericLister. 47 | func (f *genericInformer) Lister() cache.GenericLister { 48 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) 49 | } 50 | 51 | // ForResource gives generic access to a shared informer of the matching type 52 | // TODO extend this to unknown resources with a client pool 53 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { 54 | switch resource { 55 | // Group=gravity.mobike.io, Version=v1alpha1 56 | case v1alpha1.SchemeGroupVersion.WithResource("clusters"): 57 | return &genericInformer{resource: resource.GroupResource(), informer: f.Gravity().V1alpha1().Clusters().Informer()}, nil 58 | 59 | } 60 | 61 | return nil, fmt.Errorf("no informer found for %v", resource) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/client/cluster/informers/externalversions/internalinterfaces/factory_interfaces.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package internalinterfaces 20 | 21 | import ( 22 | time "time" 23 | 24 | versioned "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned" 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | runtime "k8s.io/apimachinery/pkg/runtime" 27 | cache "k8s.io/client-go/tools/cache" 28 | ) 29 | 30 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer 31 | 32 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle 33 | type SharedInformerFactory interface { 34 | Start(stopCh <-chan struct{}) 35 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer 36 | } 37 | 38 | type TweakListOptionsFunc func(*v1.ListOptions) 39 | -------------------------------------------------------------------------------- /pkg/client/cluster/listers/cluster/v1alpha1/cluster.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 23 | "k8s.io/apimachinery/pkg/api/errors" 24 | "k8s.io/apimachinery/pkg/labels" 25 | "k8s.io/client-go/tools/cache" 26 | ) 27 | 28 | // ClusterLister helps list Clusters. 29 | type ClusterLister interface { 30 | // List lists all Clusters in the indexer. 31 | List(selector labels.Selector) (ret []*v1alpha1.Cluster, err error) 32 | // Clusters returns an object that can list and get Clusters. 33 | Clusters(namespace string) ClusterNamespaceLister 34 | ClusterListerExpansion 35 | } 36 | 37 | // clusterLister implements the ClusterLister interface. 38 | type clusterLister struct { 39 | indexer cache.Indexer 40 | } 41 | 42 | // NewClusterLister returns a new ClusterLister. 43 | func NewClusterLister(indexer cache.Indexer) ClusterLister { 44 | return &clusterLister{indexer: indexer} 45 | } 46 | 47 | // List lists all Clusters in the indexer. 48 | func (s *clusterLister) List(selector labels.Selector) (ret []*v1alpha1.Cluster, err error) { 49 | err = cache.ListAll(s.indexer, selector, func(m interface{}) { 50 | ret = append(ret, m.(*v1alpha1.Cluster)) 51 | }) 52 | return ret, err 53 | } 54 | 55 | // Clusters returns an object that can list and get Clusters. 56 | func (s *clusterLister) Clusters(namespace string) ClusterNamespaceLister { 57 | return clusterNamespaceLister{indexer: s.indexer, namespace: namespace} 58 | } 59 | 60 | // ClusterNamespaceLister helps list and get Clusters. 61 | type ClusterNamespaceLister interface { 62 | // List lists all Clusters in the indexer for a given namespace. 63 | List(selector labels.Selector) (ret []*v1alpha1.Cluster, err error) 64 | // Get retrieves the Cluster from the indexer for a given namespace and name. 65 | Get(name string) (*v1alpha1.Cluster, error) 66 | ClusterNamespaceListerExpansion 67 | } 68 | 69 | // clusterNamespaceLister implements the ClusterNamespaceLister 70 | // interface. 71 | type clusterNamespaceLister struct { 72 | indexer cache.Indexer 73 | namespace string 74 | } 75 | 76 | // List lists all Clusters in the indexer for a given namespace. 77 | func (s clusterNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Cluster, err error) { 78 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { 79 | ret = append(ret, m.(*v1alpha1.Cluster)) 80 | }) 81 | return ret, err 82 | } 83 | 84 | // Get retrieves the Cluster from the indexer for a given namespace and name. 85 | func (s clusterNamespaceLister) Get(name string) (*v1alpha1.Cluster, error) { 86 | obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) 87 | if err != nil { 88 | return nil, err 89 | } 90 | if !exists { 91 | return nil, errors.NewNotFound(v1alpha1.Resource("cluster"), name) 92 | } 93 | return obj.(*v1alpha1.Cluster), nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/client/cluster/listers/cluster/v1alpha1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // ClusterListerExpansion allows custom methods to be added to 22 | // ClusterLister. 23 | type ClusterListerExpansion interface{} 24 | 25 | // ClusterNamespaceListerExpansion allows custom methods to be added to 26 | // ClusterNamespaceLister. 27 | type ClusterNamespaceListerExpansion interface{} 28 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/clientset.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package versioned 20 | 21 | import ( 22 | gravityv1alpha1 "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1" 23 | discovery "k8s.io/client-go/discovery" 24 | rest "k8s.io/client-go/rest" 25 | flowcontrol "k8s.io/client-go/util/flowcontrol" 26 | ) 27 | 28 | type Interface interface { 29 | Discovery() discovery.DiscoveryInterface 30 | GravityV1alpha1() gravityv1alpha1.GravityV1alpha1Interface 31 | // Deprecated: please explicitly pick a version if possible. 32 | Gravity() gravityv1alpha1.GravityV1alpha1Interface 33 | } 34 | 35 | // Clientset contains the clients for groups. Each group has exactly one 36 | // version included in a Clientset. 37 | type Clientset struct { 38 | *discovery.DiscoveryClient 39 | gravityV1alpha1 *gravityv1alpha1.GravityV1alpha1Client 40 | } 41 | 42 | // GravityV1alpha1 retrieves the GravityV1alpha1Client 43 | func (c *Clientset) GravityV1alpha1() gravityv1alpha1.GravityV1alpha1Interface { 44 | return c.gravityV1alpha1 45 | } 46 | 47 | // Deprecated: Gravity retrieves the default version of GravityClient. 48 | // Please explicitly pick a version. 49 | func (c *Clientset) Gravity() gravityv1alpha1.GravityV1alpha1Interface { 50 | return c.gravityV1alpha1 51 | } 52 | 53 | // Discovery retrieves the DiscoveryClient 54 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 55 | if c == nil { 56 | return nil 57 | } 58 | return c.DiscoveryClient 59 | } 60 | 61 | // NewForConfig creates a new Clientset for the given config. 62 | func NewForConfig(c *rest.Config) (*Clientset, error) { 63 | configShallowCopy := *c 64 | if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { 65 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) 66 | } 67 | var cs Clientset 68 | var err error 69 | cs.gravityV1alpha1, err = gravityv1alpha1.NewForConfig(&configShallowCopy) 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return &cs, nil 79 | } 80 | 81 | // NewForConfigOrDie creates a new Clientset for the given config and 82 | // panics if there is an error in the config. 83 | func NewForConfigOrDie(c *rest.Config) *Clientset { 84 | var cs Clientset 85 | cs.gravityV1alpha1 = gravityv1alpha1.NewForConfigOrDie(c) 86 | 87 | cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) 88 | return &cs 89 | } 90 | 91 | // New creates a new Clientset for the given RESTClient. 92 | func New(c rest.Interface) *Clientset { 93 | var cs Clientset 94 | cs.gravityV1alpha1 = gravityv1alpha1.New(c) 95 | 96 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c) 97 | return &cs 98 | } 99 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated clientset. 20 | package versioned 21 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/fake/clientset_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | clientset "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned" 23 | gravityv1alpha1 "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1" 24 | fakegravityv1alpha1 "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1/fake" 25 | "k8s.io/apimachinery/pkg/runtime" 26 | "k8s.io/apimachinery/pkg/watch" 27 | "k8s.io/client-go/discovery" 28 | fakediscovery "k8s.io/client-go/discovery/fake" 29 | "k8s.io/client-go/testing" 30 | ) 31 | 32 | // NewSimpleClientset returns a clientset that will respond with the provided objects. 33 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, 34 | // without applying any validations and/or defaults. It shouldn't be considered a replacement 35 | // for a real clientset and is mostly useful in simple unit tests. 36 | func NewSimpleClientset(objects ...runtime.Object) *Clientset { 37 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) 38 | for _, obj := range objects { 39 | if err := o.Add(obj); err != nil { 40 | panic(err) 41 | } 42 | } 43 | 44 | cs := &Clientset{} 45 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} 46 | cs.AddReactor("*", "*", testing.ObjectReaction(o)) 47 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { 48 | gvr := action.GetResource() 49 | ns := action.GetNamespace() 50 | watch, err := o.Watch(gvr, ns) 51 | if err != nil { 52 | return false, nil, err 53 | } 54 | return true, watch, nil 55 | }) 56 | 57 | return cs 58 | } 59 | 60 | // Clientset implements clientset.Interface. Meant to be embedded into a 61 | // struct to get a default implementation. This makes faking out just the method 62 | // you want to test easier. 63 | type Clientset struct { 64 | testing.Fake 65 | discovery *fakediscovery.FakeDiscovery 66 | } 67 | 68 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 69 | return c.discovery 70 | } 71 | 72 | var _ clientset.Interface = &Clientset{} 73 | 74 | // GravityV1alpha1 retrieves the GravityV1alpha1Client 75 | func (c *Clientset) GravityV1alpha1() gravityv1alpha1.GravityV1alpha1Interface { 76 | return &fakegravityv1alpha1.FakeGravityV1alpha1{Fake: &c.Fake} 77 | } 78 | 79 | // Gravity retrieves the GravityV1alpha1Client 80 | func (c *Clientset) Gravity() gravityv1alpha1.GravityV1alpha1Interface { 81 | return &fakegravityv1alpha1.FakeGravityV1alpha1{Fake: &c.Fake} 82 | } 83 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated fake clientset. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/fake/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | gravityv1alpha1 "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 27 | ) 28 | 29 | var scheme = runtime.NewScheme() 30 | var codecs = serializer.NewCodecFactory(scheme) 31 | var parameterCodec = runtime.NewParameterCodec(scheme) 32 | 33 | func init() { 34 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) 35 | AddToScheme(scheme) 36 | } 37 | 38 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 39 | // of clientsets, like in: 40 | // 41 | // import ( 42 | // "k8s.io/client-go/kubernetes" 43 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 44 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 45 | // ) 46 | // 47 | // kclientset, _ := kubernetes.NewForConfig(c) 48 | // aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 49 | // 50 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 51 | // correctly. 52 | func AddToScheme(scheme *runtime.Scheme) { 53 | gravityv1alpha1.AddToScheme(scheme) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package contains the scheme of the automatically generated clientset. 20 | package scheme 21 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/scheme/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package scheme 20 | 21 | import ( 22 | gravityv1alpha1 "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | runtime "k8s.io/apimachinery/pkg/runtime" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 27 | ) 28 | 29 | var Scheme = runtime.NewScheme() 30 | var Codecs = serializer.NewCodecFactory(Scheme) 31 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 32 | 33 | func init() { 34 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 35 | AddToScheme(Scheme) 36 | } 37 | 38 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 39 | // of clientsets, like in: 40 | // 41 | // import ( 42 | // "k8s.io/client-go/kubernetes" 43 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 44 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 45 | // ) 46 | // 47 | // kclientset, _ := kubernetes.NewForConfig(c) 48 | // aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 49 | // 50 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 51 | // correctly. 52 | func AddToScheme(scheme *runtime.Scheme) { 53 | gravityv1alpha1.AddToScheme(scheme) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v1alpha1 21 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_pipeline.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | labels "k8s.io/apimachinery/pkg/labels" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | types "k8s.io/apimachinery/pkg/types" 27 | watch "k8s.io/apimachinery/pkg/watch" 28 | testing "k8s.io/client-go/testing" 29 | ) 30 | 31 | // FakePipelines implements PipelineInterface 32 | type FakePipelines struct { 33 | Fake *FakeGravityV1alpha1 34 | ns string 35 | } 36 | 37 | var pipelinesResource = schema.GroupVersionResource{Group: "gravity.mobike.io", Version: "v1alpha1", Resource: "pipelines"} 38 | 39 | var pipelinesKind = schema.GroupVersionKind{Group: "gravity.mobike.io", Version: "v1alpha1", Kind: "Pipeline"} 40 | 41 | // Get takes name of the pipeline, and returns the corresponding pipeline object, and an error if there is any. 42 | func (c *FakePipelines) Get(name string, options v1.GetOptions) (result *v1alpha1.Pipeline, err error) { 43 | obj, err := c.Fake. 44 | Invokes(testing.NewGetAction(pipelinesResource, c.ns, name), &v1alpha1.Pipeline{}) 45 | 46 | if obj == nil { 47 | return nil, err 48 | } 49 | return obj.(*v1alpha1.Pipeline), err 50 | } 51 | 52 | // List takes label and field selectors, and returns the list of Pipelines that match those selectors. 53 | func (c *FakePipelines) List(opts v1.ListOptions) (result *v1alpha1.PipelineList, err error) { 54 | obj, err := c.Fake. 55 | Invokes(testing.NewListAction(pipelinesResource, pipelinesKind, c.ns, opts), &v1alpha1.PipelineList{}) 56 | 57 | if obj == nil { 58 | return nil, err 59 | } 60 | 61 | label, _, _ := testing.ExtractFromListOptions(opts) 62 | if label == nil { 63 | label = labels.Everything() 64 | } 65 | list := &v1alpha1.PipelineList{ListMeta: obj.(*v1alpha1.PipelineList).ListMeta} 66 | for _, item := range obj.(*v1alpha1.PipelineList).Items { 67 | if label.Matches(labels.Set(item.Labels)) { 68 | list.Items = append(list.Items, item) 69 | } 70 | } 71 | return list, err 72 | } 73 | 74 | // Watch returns a watch.Interface that watches the requested pipelines. 75 | func (c *FakePipelines) Watch(opts v1.ListOptions) (watch.Interface, error) { 76 | return c.Fake. 77 | InvokesWatch(testing.NewWatchAction(pipelinesResource, c.ns, opts)) 78 | 79 | } 80 | 81 | // Create takes the representation of a pipeline and creates it. Returns the server's representation of the pipeline, and an error, if there is any. 82 | func (c *FakePipelines) Create(pipeline *v1alpha1.Pipeline) (result *v1alpha1.Pipeline, err error) { 83 | obj, err := c.Fake. 84 | Invokes(testing.NewCreateAction(pipelinesResource, c.ns, pipeline), &v1alpha1.Pipeline{}) 85 | 86 | if obj == nil { 87 | return nil, err 88 | } 89 | return obj.(*v1alpha1.Pipeline), err 90 | } 91 | 92 | // Update takes the representation of a pipeline and updates it. Returns the server's representation of the pipeline, and an error, if there is any. 93 | func (c *FakePipelines) Update(pipeline *v1alpha1.Pipeline) (result *v1alpha1.Pipeline, err error) { 94 | obj, err := c.Fake. 95 | Invokes(testing.NewUpdateAction(pipelinesResource, c.ns, pipeline), &v1alpha1.Pipeline{}) 96 | 97 | if obj == nil { 98 | return nil, err 99 | } 100 | return obj.(*v1alpha1.Pipeline), err 101 | } 102 | 103 | // UpdateStatus was generated because the type contains a Status member. 104 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 105 | func (c *FakePipelines) UpdateStatus(pipeline *v1alpha1.Pipeline) (*v1alpha1.Pipeline, error) { 106 | obj, err := c.Fake. 107 | Invokes(testing.NewUpdateSubresourceAction(pipelinesResource, "status", c.ns, pipeline), &v1alpha1.Pipeline{}) 108 | 109 | if obj == nil { 110 | return nil, err 111 | } 112 | return obj.(*v1alpha1.Pipeline), err 113 | } 114 | 115 | // Delete takes name of the pipeline and deletes it. Returns an error if one occurs. 116 | func (c *FakePipelines) Delete(name string, options *v1.DeleteOptions) error { 117 | _, err := c.Fake. 118 | Invokes(testing.NewDeleteAction(pipelinesResource, c.ns, name), &v1alpha1.Pipeline{}) 119 | 120 | return err 121 | } 122 | 123 | // DeleteCollection deletes a collection of objects. 124 | func (c *FakePipelines) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { 125 | action := testing.NewDeleteCollectionAction(pipelinesResource, c.ns, listOptions) 126 | 127 | _, err := c.Fake.Invokes(action, &v1alpha1.PipelineList{}) 128 | return err 129 | } 130 | 131 | // Patch applies the patch and returns the patched pipeline. 132 | func (c *FakePipelines) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Pipeline, err error) { 133 | obj, err := c.Fake. 134 | Invokes(testing.NewPatchSubresourceAction(pipelinesResource, c.ns, name, data, subresources...), &v1alpha1.Pipeline{}) 135 | 136 | if obj == nil { 137 | return nil, err 138 | } 139 | return obj.(*v1alpha1.Pipeline), err 140 | } 141 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_pipeline_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1" 23 | rest "k8s.io/client-go/rest" 24 | testing "k8s.io/client-go/testing" 25 | ) 26 | 27 | type FakeGravityV1alpha1 struct { 28 | *testing.Fake 29 | } 30 | 31 | func (c *FakeGravityV1alpha1) Pipelines(namespace string) v1alpha1.PipelineInterface { 32 | return &FakePipelines{c, namespace} 33 | } 34 | 35 | // RESTClient returns a RESTClient that is used to communicate 36 | // with API server by this client implementation. 37 | func (c *FakeGravityV1alpha1) RESTClient() rest.Interface { 38 | var ret *rest.RESTClient 39 | return ret 40 | } 41 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | type PipelineExpansion interface{} 22 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1/pipeline.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 23 | scheme "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned/scheme" 24 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 | types "k8s.io/apimachinery/pkg/types" 26 | watch "k8s.io/apimachinery/pkg/watch" 27 | rest "k8s.io/client-go/rest" 28 | ) 29 | 30 | // PipelinesGetter has a method to return a PipelineInterface. 31 | // A group's client should implement this interface. 32 | type PipelinesGetter interface { 33 | Pipelines(namespace string) PipelineInterface 34 | } 35 | 36 | // PipelineInterface has methods to work with Pipeline resources. 37 | type PipelineInterface interface { 38 | Create(*v1alpha1.Pipeline) (*v1alpha1.Pipeline, error) 39 | Update(*v1alpha1.Pipeline) (*v1alpha1.Pipeline, error) 40 | UpdateStatus(*v1alpha1.Pipeline) (*v1alpha1.Pipeline, error) 41 | Delete(name string, options *v1.DeleteOptions) error 42 | DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error 43 | Get(name string, options v1.GetOptions) (*v1alpha1.Pipeline, error) 44 | List(opts v1.ListOptions) (*v1alpha1.PipelineList, error) 45 | Watch(opts v1.ListOptions) (watch.Interface, error) 46 | Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Pipeline, err error) 47 | PipelineExpansion 48 | } 49 | 50 | // pipelines implements PipelineInterface 51 | type pipelines struct { 52 | client rest.Interface 53 | ns string 54 | } 55 | 56 | // newPipelines returns a Pipelines 57 | func newPipelines(c *GravityV1alpha1Client, namespace string) *pipelines { 58 | return &pipelines{ 59 | client: c.RESTClient(), 60 | ns: namespace, 61 | } 62 | } 63 | 64 | // Get takes name of the pipeline, and returns the corresponding pipeline object, and an error if there is any. 65 | func (c *pipelines) Get(name string, options v1.GetOptions) (result *v1alpha1.Pipeline, err error) { 66 | result = &v1alpha1.Pipeline{} 67 | err = c.client.Get(). 68 | Namespace(c.ns). 69 | Resource("pipelines"). 70 | Name(name). 71 | VersionedParams(&options, scheme.ParameterCodec). 72 | Do(). 73 | Into(result) 74 | return 75 | } 76 | 77 | // List takes label and field selectors, and returns the list of Pipelines that match those selectors. 78 | func (c *pipelines) List(opts v1.ListOptions) (result *v1alpha1.PipelineList, err error) { 79 | result = &v1alpha1.PipelineList{} 80 | err = c.client.Get(). 81 | Namespace(c.ns). 82 | Resource("pipelines"). 83 | VersionedParams(&opts, scheme.ParameterCodec). 84 | Do(). 85 | Into(result) 86 | return 87 | } 88 | 89 | // Watch returns a watch.Interface that watches the requested pipelines. 90 | func (c *pipelines) Watch(opts v1.ListOptions) (watch.Interface, error) { 91 | opts.Watch = true 92 | return c.client.Get(). 93 | Namespace(c.ns). 94 | Resource("pipelines"). 95 | VersionedParams(&opts, scheme.ParameterCodec). 96 | Watch() 97 | } 98 | 99 | // Create takes the representation of a pipeline and creates it. Returns the server's representation of the pipeline, and an error, if there is any. 100 | func (c *pipelines) Create(pipeline *v1alpha1.Pipeline) (result *v1alpha1.Pipeline, err error) { 101 | result = &v1alpha1.Pipeline{} 102 | err = c.client.Post(). 103 | Namespace(c.ns). 104 | Resource("pipelines"). 105 | Body(pipeline). 106 | Do(). 107 | Into(result) 108 | return 109 | } 110 | 111 | // Update takes the representation of a pipeline and updates it. Returns the server's representation of the pipeline, and an error, if there is any. 112 | func (c *pipelines) Update(pipeline *v1alpha1.Pipeline) (result *v1alpha1.Pipeline, err error) { 113 | result = &v1alpha1.Pipeline{} 114 | err = c.client.Put(). 115 | Namespace(c.ns). 116 | Resource("pipelines"). 117 | Name(pipeline.Name). 118 | Body(pipeline). 119 | Do(). 120 | Into(result) 121 | return 122 | } 123 | 124 | // UpdateStatus was generated because the type contains a Status member. 125 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 126 | 127 | func (c *pipelines) UpdateStatus(pipeline *v1alpha1.Pipeline) (result *v1alpha1.Pipeline, err error) { 128 | result = &v1alpha1.Pipeline{} 129 | err = c.client.Put(). 130 | Namespace(c.ns). 131 | Resource("pipelines"). 132 | Name(pipeline.Name). 133 | SubResource("status"). 134 | Body(pipeline). 135 | Do(). 136 | Into(result) 137 | return 138 | } 139 | 140 | // Delete takes name of the pipeline and deletes it. Returns an error if one occurs. 141 | func (c *pipelines) Delete(name string, options *v1.DeleteOptions) error { 142 | return c.client.Delete(). 143 | Namespace(c.ns). 144 | Resource("pipelines"). 145 | Name(name). 146 | Body(options). 147 | Do(). 148 | Error() 149 | } 150 | 151 | // DeleteCollection deletes a collection of objects. 152 | func (c *pipelines) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { 153 | return c.client.Delete(). 154 | Namespace(c.ns). 155 | Resource("pipelines"). 156 | VersionedParams(&listOptions, scheme.ParameterCodec). 157 | Body(options). 158 | Do(). 159 | Error() 160 | } 161 | 162 | // Patch applies the patch and returns the patched pipeline. 163 | func (c *pipelines) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Pipeline, err error) { 164 | result = &v1alpha1.Pipeline{} 165 | err = c.client.Patch(pt). 166 | Namespace(c.ns). 167 | Resource("pipelines"). 168 | SubResource(subresources...). 169 | Name(name). 170 | Body(data). 171 | Do(). 172 | Into(result) 173 | return 174 | } 175 | -------------------------------------------------------------------------------- /pkg/client/pipeline/clientset/versioned/typed/pipeline/v1alpha1/pipeline_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 23 | "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned/scheme" 24 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 25 | rest "k8s.io/client-go/rest" 26 | ) 27 | 28 | type GravityV1alpha1Interface interface { 29 | RESTClient() rest.Interface 30 | PipelinesGetter 31 | } 32 | 33 | // GravityV1alpha1Client is used to interact with features provided by the gravity.mobike.io group. 34 | type GravityV1alpha1Client struct { 35 | restClient rest.Interface 36 | } 37 | 38 | func (c *GravityV1alpha1Client) Pipelines(namespace string) PipelineInterface { 39 | return newPipelines(c, namespace) 40 | } 41 | 42 | // NewForConfig creates a new GravityV1alpha1Client for the given config. 43 | func NewForConfig(c *rest.Config) (*GravityV1alpha1Client, error) { 44 | config := *c 45 | if err := setConfigDefaults(&config); err != nil { 46 | return nil, err 47 | } 48 | client, err := rest.RESTClientFor(&config) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return &GravityV1alpha1Client{client}, nil 53 | } 54 | 55 | // NewForConfigOrDie creates a new GravityV1alpha1Client for the given config and 56 | // panics if there is an error in the config. 57 | func NewForConfigOrDie(c *rest.Config) *GravityV1alpha1Client { 58 | client, err := NewForConfig(c) 59 | if err != nil { 60 | panic(err) 61 | } 62 | return client 63 | } 64 | 65 | // New creates a new GravityV1alpha1Client for the given RESTClient. 66 | func New(c rest.Interface) *GravityV1alpha1Client { 67 | return &GravityV1alpha1Client{c} 68 | } 69 | 70 | func setConfigDefaults(config *rest.Config) error { 71 | gv := v1alpha1.SchemeGroupVersion 72 | config.GroupVersion = &gv 73 | config.APIPath = "/apis" 74 | config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} 75 | 76 | if config.UserAgent == "" { 77 | config.UserAgent = rest.DefaultKubernetesUserAgent() 78 | } 79 | 80 | return nil 81 | } 82 | 83 | // RESTClient returns a RESTClient that is used to communicate 84 | // with API server by this client implementation. 85 | func (c *GravityV1alpha1Client) RESTClient() rest.Interface { 86 | if c == nil { 87 | return nil 88 | } 89 | return c.restClient 90 | } 91 | -------------------------------------------------------------------------------- /pkg/client/pipeline/informers/externalversions/factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | reflect "reflect" 23 | sync "sync" 24 | time "time" 25 | 26 | versioned "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned" 27 | internalinterfaces "github.com/moiot/gravity-operator/pkg/client/pipeline/informers/externalversions/internalinterfaces" 28 | pipeline "github.com/moiot/gravity-operator/pkg/client/pipeline/informers/externalversions/pipeline" 29 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | runtime "k8s.io/apimachinery/pkg/runtime" 31 | schema "k8s.io/apimachinery/pkg/runtime/schema" 32 | cache "k8s.io/client-go/tools/cache" 33 | ) 34 | 35 | // SharedInformerOption defines the functional option type for SharedInformerFactory. 36 | type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory 37 | 38 | type sharedInformerFactory struct { 39 | client versioned.Interface 40 | namespace string 41 | tweakListOptions internalinterfaces.TweakListOptionsFunc 42 | lock sync.Mutex 43 | defaultResync time.Duration 44 | customResync map[reflect.Type]time.Duration 45 | 46 | informers map[reflect.Type]cache.SharedIndexInformer 47 | // startedInformers is used for tracking which informers have been started. 48 | // This allows Start() to be called multiple times safely. 49 | startedInformers map[reflect.Type]bool 50 | } 51 | 52 | // WithCustomResyncConfig sets a custom resync period for the specified informer types. 53 | func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { 54 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 55 | for k, v := range resyncConfig { 56 | factory.customResync[reflect.TypeOf(k)] = v 57 | } 58 | return factory 59 | } 60 | } 61 | 62 | // WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. 63 | func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { 64 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 65 | factory.tweakListOptions = tweakListOptions 66 | return factory 67 | } 68 | } 69 | 70 | // WithNamespace limits the SharedInformerFactory to the specified namespace. 71 | func WithNamespace(namespace string) SharedInformerOption { 72 | return func(factory *sharedInformerFactory) *sharedInformerFactory { 73 | factory.namespace = namespace 74 | return factory 75 | } 76 | } 77 | 78 | // NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. 79 | func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { 80 | return NewSharedInformerFactoryWithOptions(client, defaultResync) 81 | } 82 | 83 | // NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. 84 | // Listers obtained via this SharedInformerFactory will be subject to the same filters 85 | // as specified here. 86 | // Deprecated: Please use NewSharedInformerFactoryWithOptions instead 87 | func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { 88 | return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) 89 | } 90 | 91 | // NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. 92 | func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { 93 | factory := &sharedInformerFactory{ 94 | client: client, 95 | namespace: v1.NamespaceAll, 96 | defaultResync: defaultResync, 97 | informers: make(map[reflect.Type]cache.SharedIndexInformer), 98 | startedInformers: make(map[reflect.Type]bool), 99 | customResync: make(map[reflect.Type]time.Duration), 100 | } 101 | 102 | // Apply all options 103 | for _, opt := range options { 104 | factory = opt(factory) 105 | } 106 | 107 | return factory 108 | } 109 | 110 | // Start initializes all requested informers. 111 | func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { 112 | f.lock.Lock() 113 | defer f.lock.Unlock() 114 | 115 | for informerType, informer := range f.informers { 116 | if !f.startedInformers[informerType] { 117 | go informer.Run(stopCh) 118 | f.startedInformers[informerType] = true 119 | } 120 | } 121 | } 122 | 123 | // WaitForCacheSync waits for all started informers' cache were synced. 124 | func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { 125 | informers := func() map[reflect.Type]cache.SharedIndexInformer { 126 | f.lock.Lock() 127 | defer f.lock.Unlock() 128 | 129 | informers := map[reflect.Type]cache.SharedIndexInformer{} 130 | for informerType, informer := range f.informers { 131 | if f.startedInformers[informerType] { 132 | informers[informerType] = informer 133 | } 134 | } 135 | return informers 136 | }() 137 | 138 | res := map[reflect.Type]bool{} 139 | for informType, informer := range informers { 140 | res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) 141 | } 142 | return res 143 | } 144 | 145 | // InternalInformerFor returns the SharedIndexInformer for obj using an internal 146 | // client. 147 | func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { 148 | f.lock.Lock() 149 | defer f.lock.Unlock() 150 | 151 | informerType := reflect.TypeOf(obj) 152 | informer, exists := f.informers[informerType] 153 | if exists { 154 | return informer 155 | } 156 | 157 | resyncPeriod, exists := f.customResync[informerType] 158 | if !exists { 159 | resyncPeriod = f.defaultResync 160 | } 161 | 162 | informer = newFunc(f.client, resyncPeriod) 163 | f.informers[informerType] = informer 164 | 165 | return informer 166 | } 167 | 168 | // SharedInformerFactory provides shared informers for resources in all known 169 | // API group versions. 170 | type SharedInformerFactory interface { 171 | internalinterfaces.SharedInformerFactory 172 | ForResource(resource schema.GroupVersionResource) (GenericInformer, error) 173 | WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool 174 | 175 | Gravity() pipeline.Interface 176 | } 177 | 178 | func (f *sharedInformerFactory) Gravity() pipeline.Interface { 179 | return pipeline.New(f, f.namespace, f.tweakListOptions) 180 | } 181 | -------------------------------------------------------------------------------- /pkg/client/pipeline/informers/externalversions/generic.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | "fmt" 23 | 24 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 25 | schema "k8s.io/apimachinery/pkg/runtime/schema" 26 | cache "k8s.io/client-go/tools/cache" 27 | ) 28 | 29 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other 30 | // sharedInformers based on type 31 | type GenericInformer interface { 32 | Informer() cache.SharedIndexInformer 33 | Lister() cache.GenericLister 34 | } 35 | 36 | type genericInformer struct { 37 | informer cache.SharedIndexInformer 38 | resource schema.GroupResource 39 | } 40 | 41 | // Informer returns the SharedIndexInformer. 42 | func (f *genericInformer) Informer() cache.SharedIndexInformer { 43 | return f.informer 44 | } 45 | 46 | // Lister returns the GenericLister. 47 | func (f *genericInformer) Lister() cache.GenericLister { 48 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) 49 | } 50 | 51 | // ForResource gives generic access to a shared informer of the matching type 52 | // TODO extend this to unknown resources with a client pool 53 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { 54 | switch resource { 55 | // Group=gravity.mobike.io, Version=v1alpha1 56 | case v1alpha1.SchemeGroupVersion.WithResource("pipelines"): 57 | return &genericInformer{resource: resource.GroupResource(), informer: f.Gravity().V1alpha1().Pipelines().Informer()}, nil 58 | 59 | } 60 | 61 | return nil, fmt.Errorf("no informer found for %v", resource) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/client/pipeline/informers/externalversions/internalinterfaces/factory_interfaces.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package internalinterfaces 20 | 21 | import ( 22 | time "time" 23 | 24 | versioned "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned" 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | runtime "k8s.io/apimachinery/pkg/runtime" 27 | cache "k8s.io/client-go/tools/cache" 28 | ) 29 | 30 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer 31 | 32 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle 33 | type SharedInformerFactory interface { 34 | Start(stopCh <-chan struct{}) 35 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer 36 | } 37 | 38 | type TweakListOptionsFunc func(*v1.ListOptions) 39 | -------------------------------------------------------------------------------- /pkg/client/pipeline/informers/externalversions/pipeline/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package gravity 20 | 21 | import ( 22 | internalinterfaces "github.com/moiot/gravity-operator/pkg/client/pipeline/informers/externalversions/internalinterfaces" 23 | v1alpha1 "github.com/moiot/gravity-operator/pkg/client/pipeline/informers/externalversions/pipeline/v1alpha1" 24 | ) 25 | 26 | // Interface provides access to each of this group's versions. 27 | type Interface interface { 28 | // V1alpha1 provides access to shared informers for resources in V1alpha1. 29 | V1alpha1() v1alpha1.Interface 30 | } 31 | 32 | type group struct { 33 | factory internalinterfaces.SharedInformerFactory 34 | namespace string 35 | tweakListOptions internalinterfaces.TweakListOptionsFunc 36 | } 37 | 38 | // New returns a new Interface. 39 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 40 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 41 | } 42 | 43 | // V1alpha1 returns a new v1alpha1.Interface. 44 | func (g *group) V1alpha1() v1alpha1.Interface { 45 | return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) 46 | } 47 | -------------------------------------------------------------------------------- /pkg/client/pipeline/informers/externalversions/pipeline/v1alpha1/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | internalinterfaces "github.com/moiot/gravity-operator/pkg/client/pipeline/informers/externalversions/internalinterfaces" 23 | ) 24 | 25 | // Interface provides access to all the informers in this group version. 26 | type Interface interface { 27 | // Pipelines returns a PipelineInformer. 28 | Pipelines() PipelineInformer 29 | } 30 | 31 | type version struct { 32 | factory internalinterfaces.SharedInformerFactory 33 | namespace string 34 | tweakListOptions internalinterfaces.TweakListOptionsFunc 35 | } 36 | 37 | // New returns a new Interface. 38 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 39 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 40 | } 41 | 42 | // Pipelines returns a PipelineInformer. 43 | func (v *version) Pipelines() PipelineInformer { 44 | return &pipelineInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 45 | } 46 | -------------------------------------------------------------------------------- /pkg/client/pipeline/informers/externalversions/pipeline/v1alpha1/pipeline.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by informer-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | time "time" 23 | 24 | pipelinev1alpha1 "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 25 | versioned "github.com/moiot/gravity-operator/pkg/client/pipeline/clientset/versioned" 26 | internalinterfaces "github.com/moiot/gravity-operator/pkg/client/pipeline/informers/externalversions/internalinterfaces" 27 | v1alpha1 "github.com/moiot/gravity-operator/pkg/client/pipeline/listers/pipeline/v1alpha1" 28 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 | runtime "k8s.io/apimachinery/pkg/runtime" 30 | watch "k8s.io/apimachinery/pkg/watch" 31 | cache "k8s.io/client-go/tools/cache" 32 | ) 33 | 34 | // PipelineInformer provides access to a shared informer and lister for 35 | // Pipelines. 36 | type PipelineInformer interface { 37 | Informer() cache.SharedIndexInformer 38 | Lister() v1alpha1.PipelineLister 39 | } 40 | 41 | type pipelineInformer struct { 42 | factory internalinterfaces.SharedInformerFactory 43 | tweakListOptions internalinterfaces.TweakListOptionsFunc 44 | namespace string 45 | } 46 | 47 | // NewPipelineInformer constructs a new informer for Pipeline type. 48 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 49 | // one. This reduces memory footprint and number of connections to the server. 50 | func NewPipelineInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 51 | return NewFilteredPipelineInformer(client, namespace, resyncPeriod, indexers, nil) 52 | } 53 | 54 | // NewFilteredPipelineInformer constructs a new informer for Pipeline type. 55 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 56 | // one. This reduces memory footprint and number of connections to the server. 57 | func NewFilteredPipelineInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { 58 | return cache.NewSharedIndexInformer( 59 | &cache.ListWatch{ 60 | ListFunc: func(options v1.ListOptions) (runtime.Object, error) { 61 | if tweakListOptions != nil { 62 | tweakListOptions(&options) 63 | } 64 | return client.GravityV1alpha1().Pipelines(namespace).List(options) 65 | }, 66 | WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { 67 | if tweakListOptions != nil { 68 | tweakListOptions(&options) 69 | } 70 | return client.GravityV1alpha1().Pipelines(namespace).Watch(options) 71 | }, 72 | }, 73 | &pipelinev1alpha1.Pipeline{}, 74 | resyncPeriod, 75 | indexers, 76 | ) 77 | } 78 | 79 | func (f *pipelineInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 80 | return NewFilteredPipelineInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) 81 | } 82 | 83 | func (f *pipelineInformer) Informer() cache.SharedIndexInformer { 84 | return f.factory.InformerFor(&pipelinev1alpha1.Pipeline{}, f.defaultInformer) 85 | } 86 | 87 | func (f *pipelineInformer) Lister() v1alpha1.PipelineLister { 88 | return v1alpha1.NewPipelineLister(f.Informer().GetIndexer()) 89 | } 90 | -------------------------------------------------------------------------------- /pkg/client/pipeline/listers/pipeline/v1alpha1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // PipelineListerExpansion allows custom methods to be added to 22 | // PipelineLister. 23 | type PipelineListerExpansion interface{} 24 | 25 | // PipelineNamespaceListerExpansion allows custom methods to be added to 26 | // PipelineNamespaceLister. 27 | type PipelineNamespaceListerExpansion interface{} 28 | -------------------------------------------------------------------------------- /pkg/client/pipeline/listers/pipeline/v1alpha1/pipeline.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by lister-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | v1alpha1 "github.com/moiot/gravity-operator/pkg/apis/pipeline/v1alpha1" 23 | "k8s.io/apimachinery/pkg/api/errors" 24 | "k8s.io/apimachinery/pkg/labels" 25 | "k8s.io/client-go/tools/cache" 26 | ) 27 | 28 | // PipelineLister helps list Pipelines. 29 | type PipelineLister interface { 30 | // List lists all Pipelines in the indexer. 31 | List(selector labels.Selector) (ret []*v1alpha1.Pipeline, err error) 32 | // Pipelines returns an object that can list and get Pipelines. 33 | Pipelines(namespace string) PipelineNamespaceLister 34 | PipelineListerExpansion 35 | } 36 | 37 | // pipelineLister implements the PipelineLister interface. 38 | type pipelineLister struct { 39 | indexer cache.Indexer 40 | } 41 | 42 | // NewPipelineLister returns a new PipelineLister. 43 | func NewPipelineLister(indexer cache.Indexer) PipelineLister { 44 | return &pipelineLister{indexer: indexer} 45 | } 46 | 47 | // List lists all Pipelines in the indexer. 48 | func (s *pipelineLister) List(selector labels.Selector) (ret []*v1alpha1.Pipeline, err error) { 49 | err = cache.ListAll(s.indexer, selector, func(m interface{}) { 50 | ret = append(ret, m.(*v1alpha1.Pipeline)) 51 | }) 52 | return ret, err 53 | } 54 | 55 | // Pipelines returns an object that can list and get Pipelines. 56 | func (s *pipelineLister) Pipelines(namespace string) PipelineNamespaceLister { 57 | return pipelineNamespaceLister{indexer: s.indexer, namespace: namespace} 58 | } 59 | 60 | // PipelineNamespaceLister helps list and get Pipelines. 61 | type PipelineNamespaceLister interface { 62 | // List lists all Pipelines in the indexer for a given namespace. 63 | List(selector labels.Selector) (ret []*v1alpha1.Pipeline, err error) 64 | // Get retrieves the Pipeline from the indexer for a given namespace and name. 65 | Get(name string) (*v1alpha1.Pipeline, error) 66 | PipelineNamespaceListerExpansion 67 | } 68 | 69 | // pipelineNamespaceLister implements the PipelineNamespaceLister 70 | // interface. 71 | type pipelineNamespaceLister struct { 72 | indexer cache.Indexer 73 | namespace string 74 | } 75 | 76 | // List lists all Pipelines in the indexer for a given namespace. 77 | func (s pipelineNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Pipeline, err error) { 78 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { 79 | ret = append(ret, m.(*v1alpha1.Pipeline)) 80 | }) 81 | return ret, err 82 | } 83 | 84 | // Get retrieves the Pipeline from the indexer for a given namespace and name. 85 | func (s pipelineNamespaceLister) Get(name string) (*v1alpha1.Pipeline, error) { 86 | obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) 87 | if err != nil { 88 | return nil, err 89 | } 90 | if !exists { 91 | return nil, errors.NewNotFound(v1alpha1.Resource("pipeline"), name) 92 | } 93 | return obj.(*v1alpha1.Pipeline), nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/controller/metrics.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import "github.com/prometheus/client_golang/prometheus" 4 | 5 | var syncCount = prometheus.NewCounterVec(prometheus.CounterOpts{ 6 | Namespace: "gravity", 7 | Subsystem: "operator", 8 | Name: "sync_counter", 9 | Help: "Number of sync", 10 | }, []string{"pipeline", "controller", "result"}) 11 | 12 | var scheduleHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{ 13 | Namespace: "gravity", 14 | Subsystem: "operator", 15 | Name: "schedule_duration_seconds", 16 | Help: "Bucketed histogram of processing time of schedule.", 17 | Buckets: prometheus.ExponentialBuckets(0.0005, 2, 22), 18 | }, []string{"pipeline", "controller"}) 19 | 20 | var pipelineUnavailable = prometheus.NewGaugeVec(prometheus.GaugeOpts{ 21 | Namespace: "gravity", 22 | Subsystem: "operator", 23 | Name: "pipeline_unavailable", 24 | Help: "Number of pipeline unavailable", 25 | }, []string{"pipeline"}) 26 | 27 | var clusterStatus = prometheus.NewGaugeVec(prometheus.GaugeOpts{ 28 | Namespace: "gravity", 29 | Subsystem: "operator", 30 | Name: "cluster_status", 31 | Help: "Number of pipelines in different status", 32 | }, []string{"status"}) 33 | 34 | func init() { 35 | prometheus.MustRegister(syncCount) 36 | prometheus.MustRegister(scheduleHistogram) 37 | prometheus.MustRegister(pipelineUnavailable) 38 | prometheus.MustRegister(clusterStatus) 39 | } 40 | -------------------------------------------------------------------------------- /pkg/gatekeeper/api_server.go: -------------------------------------------------------------------------------- 1 | package gatekeeper 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "net/http/pprof" 7 | "time" 8 | 9 | "github.com/gin-gonic/gin" 10 | "github.com/prometheus/client_golang/prometheus/promhttp" 11 | 12 | log "github.com/sirupsen/logrus" 13 | ) 14 | 15 | type ApiServer struct { 16 | srv *http.Server 17 | repository *Repository 18 | } 19 | 20 | func (s *ApiServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) { 21 | s.srv.Handler.ServeHTTP(resp, req) 22 | } 23 | 24 | func NewApiServer(repo *Repository) *ApiServer { 25 | gin.SetMode(gin.ReleaseMode) 26 | router := gin.Default() 27 | 28 | srv := &http.Server{ 29 | Addr: ":8080", 30 | Handler: router, 31 | } 32 | apiServer := &ApiServer{ 33 | srv: srv, 34 | repository: repo, 35 | } 36 | 37 | router.Any("/metrics", gin.WrapH(promhttp.Handler())) 38 | 39 | router.GET("/debug/pprof/", gin.WrapF(pprof.Index)) 40 | router.GET("/debug/pprof/cmdline", gin.WrapF(pprof.Cmdline)) 41 | router.GET("/debug/pprof/profile", gin.WrapF(pprof.Profile)) 42 | router.GET("/debug/pprof/symbol", gin.WrapF(pprof.Symbol)) 43 | router.GET("/debug/pprof/trace", gin.WrapF(pprof.Trace)) 44 | router.GET("/debug/pprof/block", gin.WrapH(pprof.Handler("block"))) 45 | router.GET("/debug/pprof/goroutine", gin.WrapH(pprof.Handler("goroutine"))) 46 | router.GET("/debug/pprof/heap", gin.WrapH(pprof.Handler("heap"))) 47 | router.GET("/debug/pprof/mutex", gin.WrapH(pprof.Handler("mutex"))) 48 | router.GET("/debug/pprof/threadcreate", gin.WrapH(pprof.Handler("threadcreate"))) 49 | 50 | router.GET("/healthz", func(c *gin.Context) { 51 | c.JSON(http.StatusOK, gin.H{"msg": "ok"}) 52 | }) 53 | 54 | router.GET("/version", apiServer.list) 55 | router.POST("/version/:name", apiServer.create) 56 | router.GET("/version/:name", apiServer.get) 57 | router.DELETE("/version/:name", apiServer.delete) 58 | 59 | return apiServer 60 | } 61 | 62 | func (s *ApiServer) Start() { 63 | go func() { 64 | if err := s.srv.ListenAndServe(); err != nil { 65 | log.Infof("[ApiServer] closed with %s", err) 66 | } 67 | }() 68 | log.Info("[ApiServer] Started") 69 | } 70 | 71 | func (s *ApiServer) Stop() { 72 | log.Info("[ApiServer] Stopping") 73 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 74 | defer cancel() 75 | if err := s.srv.Shutdown(ctx); err != nil { 76 | log.Error("[ApiServer] error: ", err) 77 | } 78 | log.Info("[ApiServer] Stopped") 79 | } 80 | 81 | func (s *ApiServer) create(c *gin.Context) { 82 | name := c.Param("name") 83 | version := Version{Name: name} 84 | err := s.repository.insert(&version) 85 | if err != nil { 86 | log.Errorf("[ApiServer.create] insert %#v error. %s", version, err) 87 | c.JSON(http.StatusInternalServerError, gin.H{"error": err}) 88 | return 89 | } 90 | 91 | c.JSON(http.StatusCreated, gin.H{"msg": "created"}) 92 | } 93 | 94 | func (s *ApiServer) get(c *gin.Context) { 95 | name := c.Param("name") 96 | c.JSON(http.StatusOK, s.repository.get(name)) 97 | } 98 | 99 | func (s *ApiServer) list(c *gin.Context) { 100 | c.JSON(http.StatusOK, s.repository.list()) 101 | } 102 | 103 | func (s *ApiServer) delete(c *gin.Context) { 104 | name := c.Param("name") 105 | err := s.repository.delete(name) 106 | if err != nil { 107 | log.Errorf("[ApiServer.delete] delete %s error. %s", name, err) 108 | c.JSON(http.StatusInternalServerError, gin.H{"error": err}) 109 | } else { 110 | c.JSON(http.StatusOK, gin.H{"msg": "deleted version " + name}) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /pkg/gatekeeper/chaos.go: -------------------------------------------------------------------------------- 1 | package gatekeeper 2 | 3 | import ( 4 | "math/rand" 5 | "sync" 6 | "time" 7 | 8 | "github.com/juju/errors" 9 | "github.com/prometheus/client_golang/prometheus" 10 | log "github.com/sirupsen/logrus" 11 | "k8s.io/apimachinery/pkg/runtime/schema" 12 | "k8s.io/client-go/dynamic" 13 | 14 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 | "k8s.io/apimachinery/pkg/labels" 16 | ) 17 | 18 | var ( 19 | killed = prometheus.NewCounterVec(prometheus.CounterOpts{ 20 | Namespace: "gravity", 21 | Subsystem: "gatekeeper", 22 | Name: "chaos", 23 | Help: "killed component by chaos", 24 | }, []string{"kind", "name"}) 25 | ) 26 | 27 | type ChaosMonkey struct { 28 | namespace string 29 | 30 | kube dynamic.Interface 31 | 32 | tickerInterval time.Duration 33 | closeC <-chan struct{} 34 | wg sync.WaitGroup 35 | } 36 | 37 | func NewChaosMonkey(namespace string, kube dynamic.Interface, duration string, stopCh <-chan struct{}) *ChaosMonkey { 38 | prometheus.MustRegister(killed) 39 | monkey := &ChaosMonkey{ 40 | namespace: namespace, 41 | kube: kube, 42 | closeC: stopCh, 43 | } 44 | tickerInterval, err := time.ParseDuration(duration) 45 | if err != nil { 46 | log.Fatalf("wrong duration format %s", duration) 47 | } 48 | monkey.tickerInterval = tickerInterval 49 | return monkey 50 | } 51 | 52 | func (c *ChaosMonkey) Start() error { 53 | go c.run() 54 | return nil 55 | } 56 | 57 | func (c *ChaosMonkey) run() { 58 | ticker := time.NewTicker(c.tickerInterval) 59 | defer ticker.Stop() 60 | 61 | rnd := rand.New(rand.NewSource(time.Now().UnixNano())) 62 | 63 | m := map[string]string{ 64 | "app.kubernetes.io/name": "gravity", 65 | } 66 | selector := labels.SelectorFromSet(m) 67 | 68 | podGvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} 69 | statefulSetGvr := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"} 70 | 71 | for { 72 | select { 73 | case <-c.closeC: 74 | return 75 | 76 | case <-ticker.C: 77 | if rnd.Float32() < 0.5 { 78 | continue 79 | } 80 | 81 | gvr := podGvr 82 | if rnd.Float32() < 0.3 { 83 | gvr = statefulSetGvr 84 | } 85 | 86 | list, err := c.kube.Resource(gvr).Namespace(c.namespace).List(metav1.ListOptions{ 87 | LabelSelector: selector.String(), 88 | }) 89 | if err != nil { 90 | log.Error(errors.Annotatef(err, "[ChaosMonkey] fail to list %s", gvr.Resource)) 91 | continue 92 | } 93 | 94 | if len(list.Items) == 0 { 95 | log.Infof("[ChaosMonkey] no %s to kill", gvr.String()) 96 | continue 97 | } 98 | 99 | item := list.Items[rnd.Intn(len(list.Items))] 100 | err = c.kube.Resource(gvr).Namespace(item.GetNamespace()).Delete(item.GetName(), deleteOps(rnd)) 101 | if err != nil { 102 | log.Error(errors.Annotatef(err, "[ChaosMonkey] fail to delete %s %s", item.GetKind(), item.GetName())) 103 | } else { 104 | killed.WithLabelValues(item.GetKind(), item.GetLabels()["app.kubernetes.io/instance"]).Add(1) 105 | log.Infof("[ChaosMonkey] deleted %s %s", item.GetKind(), item.GetLabels()["app.kubernetes.io/instance"]) 106 | } 107 | } 108 | } 109 | } 110 | 111 | func deleteOps(rnd *rand.Rand) *metav1.DeleteOptions { 112 | ops := metav1.NewDeleteOptions(int64(rnd.Intn(8))) 113 | return ops 114 | } 115 | 116 | func (c *ChaosMonkey) Close() { 117 | c.wg.Wait() 118 | } 119 | -------------------------------------------------------------------------------- /pkg/gatekeeper/domain.go: -------------------------------------------------------------------------------- 1 | package gatekeeper 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "database/sql" 7 | "encoding/json" 8 | "fmt" 9 | "io/ioutil" 10 | "net/http" 11 | "reflect" 12 | "strconv" 13 | "strings" 14 | "sync" 15 | "time" 16 | 17 | "github.com/go-sql-driver/mysql" 18 | "github.com/prometheus/client_golang/prometheus" 19 | log "github.com/sirupsen/logrus" 20 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | 22 | "github.com/moiot/gravity-operator/pkg/apiserver" 23 | "github.com/moiot/gravity/pkg/config" 24 | "github.com/moiot/gravity/pkg/mysql_test" 25 | ) 26 | 27 | var inconsistent = prometheus.NewGaugeVec(prometheus.GaugeOpts{ 28 | Namespace: "gravity", 29 | Subsystem: "gatekeeper", 30 | Name: "inconsistent", 31 | Help: "count of inconsistent checks", 32 | }, []string{"case"}) 33 | 34 | func init() { 35 | prometheus.MustRegister(inconsistent) 36 | } 37 | 38 | type Version struct { 39 | Name string 40 | RunningCases []string 41 | 42 | cases []*TestCase 43 | } 44 | 45 | func (v *Version) Reconcile(configs []TestCaseConfig, operatorAddr string, sourceDB *sql.DB, targetDB *sql.DB, bootstrap bool) { 46 | set := make(map[string]bool) 47 | for _, c := range configs { 48 | set[c.Name] = true 49 | } 50 | 51 | for _, previous := range v.RunningCases { 52 | if !set[previous] { 53 | tc := NewTestCase(TestCaseConfig{Name: previous}, v.Name, operatorAddr, sourceDB, targetDB) 54 | tc.Delete() 55 | } 56 | } 57 | 58 | v.RunningCases = v.RunningCases[:0] 59 | for _, c := range configs { 60 | v.RunningCases = append(v.RunningCases, c.Name) 61 | tc := NewTestCase(c, v.Name, operatorAddr, sourceDB, targetDB) 62 | tc.Prepare() 63 | v.cases = append(v.cases, tc) 64 | tc.Start(bootstrap) 65 | } 66 | } 67 | 68 | func (v *Version) Delete() { 69 | for _, tc := range v.cases { 70 | tc.Delete() 71 | } 72 | v.cases = v.cases[:0] 73 | v.RunningCases = v.RunningCases[:0] 74 | } 75 | 76 | type TestCaseConfig struct { 77 | Name string `json:"name" yaml:"name"` 78 | Desc string `json:"desc" yaml:"desc"` 79 | mysql_test.GeneratorConfig `json:",inline" yaml:",inline"` 80 | } 81 | 82 | type TestCase struct { 83 | TestCaseConfig 84 | 85 | fullName string 86 | operatorAddr string 87 | sourceDB *sql.DB 88 | targetDB *sql.DB 89 | 90 | client *http.Client 91 | generator *mysql_test.Generator 92 | 93 | wg sync.WaitGroup 94 | stopC chan struct{} 95 | } 96 | 97 | func NewTestCase(c TestCaseConfig, version string, operatorAddr string, sourceDB *sql.DB, targetDB *sql.DB) *TestCase { 98 | tc := &TestCase{ 99 | TestCaseConfig: c, 100 | fullName: fmt.Sprintf("%s-%s", version, c.Name), 101 | operatorAddr: operatorAddr, 102 | sourceDB: sourceDB, 103 | targetDB: targetDB, 104 | stopC: make(chan struct{}), 105 | } 106 | 107 | tc.client = &http.Client{ 108 | Timeout: 5 * time.Second, 109 | } 110 | 111 | tc.generator = &mysql_test.Generator{ 112 | SourceDB: tc.sourceDB, 113 | SourceSchema: tc.fullName, 114 | TargetDB: tc.targetDB, 115 | TargetSchema: tc.fullName, 116 | GeneratorConfig: mysql_test.GeneratorConfig{ 117 | NrTables: tc.NrTables, 118 | NrSeedRows: tc.NrSeedRows, 119 | DeleteRatio: tc.DeleteRatio, 120 | InsertRatio: tc.InsertRatio, 121 | Concurrency: tc.Concurrency, 122 | TransactionLength: tc.TransactionLength, 123 | }, 124 | } 125 | 126 | return tc 127 | } 128 | 129 | func (tc *TestCase) Prepare() { 130 | tc.prepareDB() 131 | tc.createPipe() 132 | } 133 | 134 | func (tc *TestCase) Start(bootstrap bool) { 135 | tc.wg.Add(1) 136 | go tc.run(bootstrap) 137 | } 138 | 139 | func (tc *TestCase) run(bootstrap bool) { 140 | defer tc.wg.Done() 141 | 142 | tc.generator.SetupTestTables(false) 143 | 144 | if bootstrap { 145 | start := time.Now() 146 | log.Infof("[TestCase.prepareDB] %s seed %d rows ........", tc.fullName, tc.NrSeedRows) 147 | tc.generator.SeedRows() 148 | log.Infof("[TestCase.prepareDB] %s seed %d rows finished, elapsed %s", tc.fullName, tc.NrSeedRows, time.Since(start)) 149 | } 150 | 151 | timeout := 30 * time.Second 152 | maxTimeout := 10 * time.Minute 153 | 154 | for { 155 | select { 156 | case <-tc.stopC: 157 | return 158 | 159 | default: 160 | if timeout == maxTimeout || timeout.Seconds()*2 > maxTimeout.Seconds() { 161 | timeout = maxTimeout 162 | } else { 163 | timeout = timeout * 2 164 | } 165 | c, cancel := context.WithTimeout(context.Background(), timeout) 166 | done := tc.generator.ParallelUpdate(c) 167 | <-c.Done() 168 | cancel() 169 | done.Wait() 170 | if c.Err() != context.DeadlineExceeded { 171 | log.Infof("[TestCase.Start] exist due to %s", c.Err()) 172 | return 173 | } 174 | 175 | err := tc.generator.TestChecksum() 176 | for err != nil { 177 | inconsistent.WithLabelValues(tc.fullName).Add(1) 178 | log.Errorf("inconsistent data. case: %s, err: %s", tc.fullName, err) 179 | select { 180 | case <-tc.stopC: 181 | return 182 | 183 | case <-time.After(time.Second): 184 | } 185 | err = tc.generator.TestChecksum() 186 | } 187 | inconsistent.WithLabelValues(tc.fullName).Set(0) 188 | } 189 | } 190 | } 191 | 192 | func (tc *TestCase) Delete() { 193 | close(tc.stopC) 194 | tc.wg.Wait() 195 | inconsistent.WithLabelValues(tc.fullName).Set(0) 196 | 197 | tc.deletePipe() 198 | tc.dropDB() 199 | } 200 | 201 | func (tc *TestCase) createPipe() { 202 | url := fmt.Sprintf("%s/pipeline/%s", tc.operatorAddr, tc.fullName) 203 | resp, err := tc.client.Get(url) 204 | if err != nil { 205 | log.Panicf("[TestCase.createPipe] error get %s. err: %s", url, err) 206 | } 207 | defer resp.Body.Close() 208 | 209 | if resp.StatusCode == http.StatusOK { 210 | log.Infof("[TestCase.createPipe] %s already exists") 211 | return 212 | } 213 | 214 | if resp.StatusCode != http.StatusNotFound { 215 | body, _ := ioutil.ReadAll(resp.Body) 216 | log.Panicf("[TestCase.createPipe] error get %s. status: %d, body: %s", url, resp.StatusCode, body) 217 | } 218 | 219 | cfg := tc.pipelineConfig() 220 | b, err := json.Marshal(cfg) 221 | if err != nil { 222 | log.Panic(err) 223 | } 224 | rawCfg := json.RawMessage(b) 225 | 226 | p := apiserver.ApiPipeline{ 227 | ObjectMeta: v1.ObjectMeta{ 228 | Name: tc.fullName, 229 | }, 230 | Spec: apiserver.ApiPipelineSpec{ 231 | Config: &rawCfg, 232 | }, 233 | } 234 | 235 | req, err := json.Marshal(p) 236 | if err != nil { 237 | log.Panic(err) 238 | } 239 | resp, err = tc.client.Post(tc.operatorAddr+"/pipeline", "application/json", bytes.NewReader(req)) 240 | if err != nil { 241 | log.Panic(err) 242 | } 243 | if resp.StatusCode != http.StatusCreated { 244 | body, _ := ioutil.ReadAll(resp.Body) 245 | log.Panicf("[TestCase.createPipe] error create pipeline. status: %d, body: %s", resp.StatusCode, string(body)) 246 | } 247 | } 248 | 249 | func (tc *TestCase) pipelineConfig() config.PipelineConfigV3 { 250 | sourceDBConfig := getConfigFromDB(tc.sourceDB) 251 | targetDBConfig := getConfigFromDB(tc.targetDB) 252 | // create pipeline 253 | tableConfigs := []map[string]interface{}{ 254 | { 255 | "schema": tc.fullName, 256 | "table": "*", 257 | }, 258 | } 259 | return config.PipelineConfigV3{ 260 | PipelineName: tc.fullName, 261 | Version: config.PipelineConfigV3Version, 262 | InputPlugin: config.InputConfig{ 263 | Type: "mysql", 264 | Mode: config.Replication, 265 | Config: map[string]interface{}{ 266 | "source": map[string]interface{}{ 267 | "host": sourceDBConfig.Host, 268 | "username": sourceDBConfig.Username, 269 | "password": sourceDBConfig.Password, 270 | "port": sourceDBConfig.Port, 271 | "location": sourceDBConfig.Location, 272 | }, 273 | "table-configs": tableConfigs, 274 | }, 275 | }, 276 | OutputPlugin: config.GenericPluginConfig{ 277 | Type: "mysql", 278 | Config: map[string]interface{}{ 279 | "target": map[string]interface{}{ 280 | "host": targetDBConfig.Host, 281 | "username": targetDBConfig.Username, 282 | "password": targetDBConfig.Password, 283 | "port": targetDBConfig.Port, 284 | "location": targetDBConfig.Location, 285 | }, 286 | "enable-ddl": true, 287 | "routes": []map[string]interface{}{ 288 | { 289 | "match-schema": tc.fullName, 290 | }, 291 | }, 292 | }, 293 | }, 294 | } 295 | } 296 | 297 | func (tc *TestCase) deletePipe() { 298 | url := fmt.Sprintf("%s/pipeline/%s", tc.operatorAddr, tc.fullName) 299 | request, err := http.NewRequest("DELETE", url, nil) 300 | if err != nil { 301 | log.Panicf("[TestCase.deletePipe] error NewRequest: %s", err) 302 | } 303 | _, err = tc.client.Do(request) 304 | if err != nil { 305 | log.Panicf("[TestCase.deletePipe] error: %s", err) 306 | } 307 | } 308 | 309 | func (tc *TestCase) prepareDB() { 310 | ddl := fmt.Sprintf("create database if not exists `%s`", tc.fullName) 311 | _, err := tc.sourceDB.Exec(ddl) 312 | if err != nil { 313 | log.Panicf("[TestCase.prepareDB] err %s", err) 314 | } 315 | 316 | _, err = tc.targetDB.Exec(ddl) 317 | if err != nil { 318 | log.Panicf("[TestCase.prepareDB] err %s", err) 319 | } 320 | } 321 | 322 | func (tc *TestCase) dropDB() { 323 | ddl := fmt.Sprintf("drop database if exists `%s`", tc.fullName) 324 | _, err := tc.sourceDB.Exec(ddl) 325 | if err != nil { 326 | log.Panicf("[TestCase.dropDB] source err %s", err) 327 | } 328 | 329 | _, err = tc.targetDB.Exec(ddl) 330 | if err != nil { 331 | log.Panicf("[TestCase.dropDB] target err %s", err) 332 | } 333 | } 334 | 335 | func getConfigFromDB(db *sql.DB) *config.DBConfig { 336 | v := reflect.ValueOf(db).Elem() 337 | connector := v.FieldByName("connector").Elem() 338 | dsn := connector.FieldByName("dsn").String() 339 | driver := connector.FieldByName("driver").Elem().Type() 340 | if driver == reflect.ValueOf((*mysql.MySQLDriver)(nil)).Type() { 341 | cfg, err := mysql.ParseDSN(dsn) 342 | if err != nil { 343 | log.Panic(err) 344 | } 345 | addr := strings.Split(cfg.Addr, ":") 346 | port, err := strconv.Atoi(addr[1]) 347 | if err != nil { 348 | log.Panic(err) 349 | } 350 | config := &config.DBConfig{ 351 | Host: addr[0], 352 | Location: cfg.Loc.String(), 353 | Username: cfg.User, 354 | Password: cfg.Passwd, 355 | Port: port, 356 | Schema: cfg.DBName, 357 | MaxIdle: int(v.FieldByName("maxIdle").Int()), 358 | MaxOpen: int(v.FieldByName("maxOpen").Int()), 359 | MaxLifeTimeDurationStr: time.Duration(v.FieldByName("maxLifetime").Int()).String(), 360 | } 361 | err = config.ValidateAndSetDefault() 362 | if err != nil { 363 | log.Panic(err) 364 | } 365 | return config 366 | } 367 | 368 | log.Panicf("unknown driver type %s", driver) 369 | return nil 370 | } 371 | -------------------------------------------------------------------------------- /pkg/gatekeeper/repository.go: -------------------------------------------------------------------------------- 1 | package gatekeeper 2 | 3 | import ( 4 | "database/sql" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "sort" 10 | "strings" 11 | 12 | "github.com/juju/errors" 13 | "gopkg.in/yaml.v2" 14 | "k8s.io/apimachinery/pkg/apis/meta/v1" 15 | 16 | clusterapi "github.com/moiot/gravity-operator/pkg/apis/cluster/v1alpha1" 17 | clusterclient "github.com/moiot/gravity-operator/pkg/client/cluster/clientset/versioned/typed/cluster/v1alpha1" 18 | ) 19 | 20 | const dbName = "gatekeeper" 21 | const tableName = "version" 22 | const defaultRuleGroup = "default" 23 | 24 | var fullTableName = fmt.Sprintf("`%s`.`%s`", dbName, tableName) 25 | 26 | var createTable = fmt.Sprintf("create table if not exists %s(`name` varchar(50) NOT NULL, `cases` varchar(255) NOT NULL DEFAULT '', `created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`name`))ENGINE=InnoDB DEFAULT CHARSET=utf8;", 27 | fullTableName) 28 | 29 | type Repository struct { 30 | operatorAddr string 31 | clusterClient clusterclient.ClusterInterface 32 | 33 | sourceDB *sql.DB 34 | targetDB *sql.DB 35 | 36 | cases []TestCaseConfig 37 | versions map[string]*Version 38 | } 39 | 40 | func NewRepository(casePath string, operatorAddr string, sourceDB *sql.DB, targetDB *sql.DB, clusterClient clusterclient.ClusterInterface) *Repository { 41 | _, err := sourceDB.Exec(fmt.Sprintf("create database if not exists `%s`", dbName)) 42 | if err != nil { 43 | log.Panicf("error init db: %s", err) 44 | } 45 | 46 | _, err = sourceDB.Exec(createTable) 47 | if err != nil { 48 | log.Panicf("error init table: %s", err) 49 | } 50 | 51 | bytes, err := ioutil.ReadFile(casePath) 52 | if err != nil { 53 | log.Panic(err) 54 | } 55 | 56 | r := Repository{ 57 | operatorAddr: operatorAddr, 58 | clusterClient: clusterClient, 59 | sourceDB: sourceDB, 60 | targetDB: targetDB, 61 | versions: make(map[string]*Version), 62 | } 63 | 64 | err = yaml.UnmarshalStrict(bytes, &r.cases) 65 | if err != nil { 66 | log.Panic(err) 67 | } 68 | 69 | rows, err := sourceDB.Query(fmt.Sprintf("select name, cases from %s", fullTableName)) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | defer rows.Close() 74 | 75 | for rows.Next() { 76 | v := &Version{} 77 | var cases string 78 | if err = rows.Scan(&v.Name, &cases); err != nil { 79 | log.Panic(err) 80 | } 81 | err = json.Unmarshal([]byte(cases), &v.RunningCases) 82 | if err != nil { 83 | log.Panic(err) 84 | } 85 | v.Reconcile(r.cases, r.operatorAddr, r.sourceDB, r.targetDB, false) 86 | r.versions[v.Name] = v 87 | } 88 | if err = rows.Err(); err != nil { 89 | log.Panic(err) 90 | } 91 | 92 | return &r 93 | } 94 | 95 | func (r *Repository) insert(v *Version) error { 96 | c := r.getCluster() 97 | defaultRule := getDefaultRule(c.Spec.DeploymentRules) 98 | 99 | rule := clusterapi.DeploymentRule{ 100 | Group: v.Name, 101 | Pipelines: []string{v.Name + "*"}, 102 | Image: removeImageTag(defaultRule.Image) + v.Name, 103 | Command: defaultRule.Command, 104 | } 105 | c.Spec.DeploymentRules = append([]clusterapi.DeploymentRule{rule}, c.Spec.DeploymentRules...) 106 | c, err := r.clusterClient.Update(c) 107 | if err != nil { 108 | return errors.Annotatef(err, "error add deployment rule %#v.", rule) 109 | } 110 | 111 | v.Reconcile(r.cases, r.operatorAddr, r.sourceDB, r.targetDB, true) 112 | cases, _ := json.Marshal(v.RunningCases) 113 | _, err = r.sourceDB.Exec(fmt.Sprintf("insert into %s(name, cases) values (?, ?)", fullTableName), v.Name, string(cases)) 114 | if err != nil { 115 | v.Delete() 116 | return errors.Trace(err) 117 | } 118 | 119 | r.versions[v.Name] = v 120 | return nil 121 | } 122 | 123 | func removeImageTag(s string) string { 124 | p := strings.LastIndex(s, ":") 125 | return s[:p+1] 126 | } 127 | 128 | func getDefaultRule(rules []clusterapi.DeploymentRule) clusterapi.DeploymentRule { 129 | for _, r := range rules { 130 | if r.Group == defaultRuleGroup { 131 | return r 132 | } 133 | } 134 | log.Fatalf("can't find default deployment rule") 135 | panic("impossible") 136 | } 137 | 138 | func (r *Repository) getCluster() *clusterapi.Cluster { 139 | ret, err := r.clusterClient.List(v1.ListOptions{}) 140 | if err != nil { 141 | log.Fatalf("[Repository.insert] error list cluster: %s", err) 142 | } 143 | 144 | if len(ret.Items) != 1 { 145 | log.Fatalf("[Repository.insert] expect exactly one cluster object per namespace, actually %d", len(ret.Items)) 146 | } 147 | 148 | return &ret.Items[0] 149 | } 150 | 151 | func (r *Repository) delete(name string) error { 152 | _, err := r.sourceDB.Exec(fmt.Sprintf("delete from %s where name = ?", fullTableName), name) 153 | if err != nil { 154 | return errors.Trace(err) 155 | } 156 | 157 | r.versions[name].Delete() 158 | delete(r.versions, name) 159 | 160 | c := r.getCluster() 161 | var rules []clusterapi.DeploymentRule 162 | for _, r := range c.Spec.DeploymentRules { 163 | if r.Group != name { 164 | rules = append(rules, r) 165 | } 166 | } 167 | c.Spec.DeploymentRules = rules 168 | c, err = r.clusterClient.Update(c) 169 | if err != nil { 170 | return errors.Annotatef(err, "error remove deployment rule %s.", name) 171 | } 172 | return nil 173 | } 174 | 175 | func (r *Repository) get(name string) *Version { 176 | return r.versions[name] 177 | } 178 | 179 | func (r *Repository) list() []*Version { 180 | ret := make([]*Version, 0, len(r.versions)) 181 | for _, v := range r.versions { 182 | ret = append(ret, v) 183 | } 184 | sort.Slice(ret, func(i, j int) bool { 185 | return ret[i].Name < ret[j].Name 186 | }) 187 | return ret 188 | } 189 | -------------------------------------------------------------------------------- /pkg/signals/signal.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package signals 18 | 19 | import ( 20 | "os" 21 | "os/signal" 22 | ) 23 | 24 | var onlyOneSignalHandler = make(chan struct{}) 25 | 26 | // SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned 27 | // which is closed on one of these signals. If a second signal is caught, the program 28 | // is terminated with exit code 1. 29 | func SetupSignalHandler() (stopCh <-chan struct{}) { 30 | close(onlyOneSignalHandler) // panics when called twice 31 | 32 | stop := make(chan struct{}) 33 | c := make(chan os.Signal, 2) 34 | signal.Notify(c, shutdownSignals...) 35 | go func() { 36 | <-c 37 | close(stop) 38 | <-c 39 | os.Exit(1) // second signal. Exit directly. 40 | }() 41 | 42 | return stop 43 | } 44 | -------------------------------------------------------------------------------- /pkg/signals/signal_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | /* 4 | Copyright 2017 The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package signals 20 | 21 | import ( 22 | "os" 23 | "syscall" 24 | ) 25 | 26 | var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM} 27 | -------------------------------------------------------------------------------- /pkg/signals/signal_windows.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package signals 18 | 19 | import ( 20 | "os" 21 | ) 22 | 23 | var shutdownSignals = []os.Signal{os.Interrupt} 24 | -------------------------------------------------------------------------------- /pkg/utils/def.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 4 | 5 | var deleteFore = metav1.DeletePropagationForeground 6 | var ForegroundDeleteOptions = metav1.NewDeleteOptions(10) 7 | 8 | func init() { 9 | ForegroundDeleteOptions.PropagationPolicy = &deleteFore 10 | } 11 | -------------------------------------------------------------------------------- /pkg/utils/glob.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "strings" 4 | 5 | // The character which is treated like a glob 6 | const GLOB = "*" 7 | 8 | // Glob will test a string pattern, potentially containing globs, against a 9 | // subject string. The result is a simple true/false, determining whether or 10 | // not the glob pattern matched the subject text. 11 | func Glob(pattern, subj string) bool { 12 | // Empty pattern can only match empty subject 13 | if pattern == "" { 14 | return subj == pattern 15 | } 16 | 17 | // If the pattern _is_ a glob, it matches everything 18 | if pattern == GLOB { 19 | return true 20 | } 21 | 22 | parts := strings.Split(pattern, GLOB) 23 | 24 | if len(parts) == 1 { 25 | // No globs in pattern, so test for equality 26 | return subj == pattern 27 | } 28 | 29 | leadingGlob := strings.HasPrefix(pattern, GLOB) 30 | trailingGlob := strings.HasSuffix(pattern, GLOB) 31 | end := len(parts) - 1 32 | 33 | // Go over the leading parts and ensure they match. 34 | for i := 0; i < end; i++ { 35 | idx := strings.Index(subj, parts[i]) 36 | 37 | switch i { 38 | case 0: 39 | // Check the first section. Requires special handling. 40 | if !leadingGlob && idx != 0 { 41 | return false 42 | } 43 | default: 44 | // Check that the middle parts match. 45 | if idx < 0 { 46 | return false 47 | } 48 | } 49 | 50 | // Trim evaluated text from subj as we loop over the pattern. 51 | subj = subj[idx+len(parts[i]):] 52 | } 53 | 54 | // Reached the last section. Requires special handling. 55 | return trailingGlob || strings.HasSuffix(subj, parts[end]) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/utils/glob_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func testGlobMatch(t *testing.T, pattern, subj string) { 9 | if !Glob(pattern, subj) { 10 | t.Fatalf("%s should match %s", pattern, subj) 11 | } 12 | } 13 | 14 | func testGlobNoMatch(t *testing.T, pattern, subj string) { 15 | if Glob(pattern, subj) { 16 | t.Fatalf("%s should not match %s", pattern, subj) 17 | } 18 | } 19 | 20 | func TestEmptyPattern(t *testing.T) { 21 | testGlobMatch(t, "", "") 22 | testGlobNoMatch(t, "", "test") 23 | } 24 | 25 | func TestEmptySubject(t *testing.T) { 26 | for _, pattern := range []string{ 27 | "", 28 | "*", 29 | "**", 30 | "***", 31 | "****************", 32 | strings.Repeat("*", 1000000), 33 | } { 34 | testGlobMatch(t, pattern, "") 35 | } 36 | 37 | for _, pattern := range []string{ 38 | // No globs/non-glob characters 39 | "test", 40 | "*test*", 41 | 42 | // Trailing characters 43 | "*x", 44 | "*****************x", 45 | strings.Repeat("*", 1000000) + "x", 46 | 47 | // Leading characters 48 | "x*", 49 | "x*****************", 50 | "x" + strings.Repeat("*", 1000000), 51 | 52 | // Mixed leading/trailing characters 53 | "x*x", 54 | "x****************x", 55 | "x" + strings.Repeat("*", 1000000) + "x", 56 | } { 57 | testGlobNoMatch(t, pattern, "") 58 | } 59 | } 60 | 61 | func TestPatternWithoutGlobs(t *testing.T) { 62 | testGlobMatch(t, "test", "test") 63 | } 64 | 65 | func TestGlob(t *testing.T) { 66 | // Matches 67 | for _, pattern := range []string{ 68 | "*test", // Leading glob 69 | "this*", // Trailing glob 70 | "this*test", // Middle glob 71 | "*is *", // String in between two globs 72 | "*is*a*", // Lots of globs 73 | "**test**", // Double glob characters 74 | "**is**a***test*", // Varying number of globs 75 | "* *", // White space between globs 76 | "*", // Lone glob 77 | "**********", // Nothing but globs 78 | "*Ѿ*", // Unicode with globs 79 | "*is a ϗѾ *", // Mixed ASCII/unicode 80 | } { 81 | testGlobMatch(t, pattern, "this is a ϗѾ test") 82 | } 83 | 84 | // Non-matches 85 | for _, pattern := range []string{ 86 | "test*", // Implicit substring match 87 | "*is", // Partial match 88 | "*no*", // Globs without a match between them 89 | " ", // Plain white space 90 | "* ", // Trailing white space 91 | " *", // Leading white space 92 | "*ʤ*", // Non-matching unicode 93 | "this*this is a test", // Repeated prefix 94 | } { 95 | testGlobNoMatch(t, pattern, "this is a test") 96 | } 97 | } 98 | 99 | func BenchmarkGlob(b *testing.B) { 100 | for i := 0; i < b.N; i++ { 101 | if !Glob("*quick*fox*dog", "The quick brown fox jumped over the lazy dog") { 102 | b.Fatalf("should match") 103 | } 104 | } 105 | } 106 | --------------------------------------------------------------------------------