├── .dockerignore ├── .drone.yml ├── .gitignore ├── .golangci.json ├── Dockerfile.dapper ├── LICENSE ├── Makefile ├── README.md ├── chart ├── .helmignore ├── Chart.yaml ├── crds │ └── crd.yaml ├── templates │ ├── clusterrolebinding.yaml │ ├── deployment.yaml │ └── serviceaccount.yaml └── values.yaml ├── e2e ├── README.md ├── e2e.go ├── e2e_test.go ├── init.go └── init_test.go ├── example ├── 00-envvar.yaml ├── 00-secret.yaml ├── 10-module.yaml └── 20-state.yaml ├── go.mod ├── go.sum ├── hack └── boilerplate.go.txt ├── main.go ├── manifests ├── 00-clusterrolebinding.yaml ├── 00-crd.yaml ├── 00-namespace.yaml ├── 00-serviceaccount.yaml └── 10-deployment.yaml ├── package ├── Dockerfile.appliance ├── Dockerfile.controller └── Dockerfile.executor ├── pkg ├── apis │ └── terraformcontroller.cattle.io │ │ ├── v1 │ │ ├── doc.go │ │ ├── types.go │ │ ├── zz_generated_deepcopy.go │ │ ├── zz_generated_list_types.go │ │ └── zz_generated_register.go │ │ └── zz_generated_register.go ├── cli │ ├── cmds │ │ ├── common.go │ │ ├── executions.go │ │ ├── modules.go │ │ ├── states.go │ │ └── writer.go │ └── main.go ├── codegen │ ├── cleanup │ │ └── main.go │ └── main.go ├── digest │ └── digest.go ├── executor │ ├── main.go │ ├── runner │ │ ├── backend.go │ │ └── runner.go │ ├── terraform │ │ ├── cmd.go │ │ └── terraform.go │ └── writer │ │ └── writer.go ├── generated │ ├── clientset │ │ └── versioned │ │ │ ├── clientset.go │ │ │ ├── doc.go │ │ │ ├── fake │ │ │ ├── clientset_generated.go │ │ │ ├── doc.go │ │ │ └── register.go │ │ │ ├── scheme │ │ │ ├── doc.go │ │ │ └── register.go │ │ │ └── typed │ │ │ └── terraformcontroller.cattle.io │ │ │ └── v1 │ │ │ ├── doc.go │ │ │ ├── execution.go │ │ │ ├── fake │ │ │ ├── doc.go │ │ │ ├── fake_execution.go │ │ │ ├── fake_module.go │ │ │ ├── fake_state.go │ │ │ └── fake_terraformcontroller.cattle.io_client.go │ │ │ ├── generated_expansion.go │ │ │ ├── module.go │ │ │ ├── state.go │ │ │ └── terraformcontroller.cattle.io_client.go │ ├── controllers │ │ └── terraformcontroller.cattle.io │ │ │ ├── factory.go │ │ │ ├── interface.go │ │ │ └── v1 │ │ │ ├── execution.go │ │ │ ├── interface.go │ │ │ ├── module.go │ │ │ └── state.go │ ├── informers │ │ └── externalversions │ │ │ ├── factory.go │ │ │ ├── generic.go │ │ │ ├── internalinterfaces │ │ │ └── factory_interfaces.go │ │ │ └── terraformcontroller.cattle.io │ │ │ ├── interface.go │ │ │ └── v1 │ │ │ ├── execution.go │ │ │ ├── interface.go │ │ │ ├── module.go │ │ │ └── state.go │ └── listers │ │ └── terraformcontroller.cattle.io │ │ └── v1 │ │ ├── execution.go │ │ ├── expansion_generated.go │ │ ├── module.go │ │ └── state.go ├── git │ ├── auth.go │ ├── cmd.go │ ├── format.go │ └── git.go ├── gz │ └── main.go ├── interval │ └── interval.go └── terraform │ ├── controller.go │ ├── controller_test.go │ ├── execution │ └── handler.go │ ├── module │ └── handler.go │ └── state │ ├── deploy.go │ ├── gather.go │ └── handler.go └── scripts ├── build ├── build-cli ├── build-controller ├── build-executor ├── ci ├── e2e ├── e2e-package-executor ├── entry ├── package ├── package-appliance ├── package-cli ├── package-controller ├── package-executor ├── package-helm ├── release ├── test ├── validate └── version /.dockerignore: -------------------------------------------------------------------------------- 1 | ./.dapper 2 | ./.cache 3 | ./.trash-cache 4 | ./dist 5 | .idea 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.dapper 2 | /.cache 3 | /.trash-cache 4 | /bin 5 | /dist 6 | /build 7 | *.swp 8 | .idea 9 | tffy 10 | -------------------------------------------------------------------------------- /.golangci.json: -------------------------------------------------------------------------------- 1 | { 2 | "linters": { 3 | "disable-all": true, 4 | "enable": [ 5 | "govet", 6 | "golint", 7 | "goimports" 8 | ] 9 | }, 10 | "run": { 11 | "timeout": "10m" 12 | } 13 | } -------------------------------------------------------------------------------- /Dockerfile.dapper: -------------------------------------------------------------------------------- 1 | FROM golang:1.16.2-alpine3.12 2 | 3 | ARG DAPPER_HOST_ARCH 4 | ENV ARCH $DAPPER_HOST_ARCH 5 | ENV HELM_VERSION v3.4.2 6 | ENV HELM_URL_V3=https://get.helm.sh/helm-${HELM_VERSION}-linux-${ARCH}.tar.gz 7 | 8 | RUN apk -U add bash git gcc musl-dev docker vim less file curl wget ca-certificates 9 | RUN curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.38.0 10 | 11 | ENV K3S_VERSION v1.18.3+k3s1 12 | #integration tests only support amd64 13 | RUN if [ "${ARCH}" == "amd64" ]; then \ 14 | curl -sL https://github.com/rancher/k3s/releases/download/${K3S_VERSION}/k3s > /usr/bin/k3s \ 15 | && chmod +x /usr/bin/k3s; \ 16 | fi 17 | 18 | RUN mkdir /usr/tmp && \ 19 | curl ${HELM_URL_V3} | tar xvzf - --strip-components=1 -C /usr/tmp/ && \ 20 | mv /usr/tmp/helm /usr/bin/helm 21 | 22 | ENV DAPPER_RUN_ARGS --privileged 23 | VOLUME /var/lib/rancher/k3s 24 | VOLUME /var/lib/cni 25 | VOLUME /var/log 26 | 27 | ENV DAPPER_ENV REPO TAG DRONE_TAG 28 | ENV DAPPER_SOURCE /go/src/github.com/rancher/terraform-controller/ 29 | ENV DAPPER_OUTPUT ./bin ./dist 30 | ENV DAPPER_DOCKER_SOCKET true 31 | ENV TRASH_CACHE ${DAPPER_SOURCE}/.trash-cache 32 | ENV HOME ${DAPPER_SOURCE} 33 | WORKDIR ${DAPPER_SOURCE} 34 | 35 | ENTRYPOINT ["./scripts/entry"] 36 | CMD ["ci"] 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGETS := $(shell ls scripts) 2 | 3 | .dapper: 4 | @echo Downloading dapper 5 | @curl -sL https://releases.rancher.com/dapper/latest/dapper-`uname -s`-`uname -m` > .dapper.tmp 6 | @@chmod +x .dapper.tmp 7 | @./.dapper.tmp -v 8 | @mv .dapper.tmp .dapper 9 | 10 | $(TARGETS): .dapper 11 | ./.dapper $@ 12 | 13 | .DEFAULT_GOAL := ci 14 | 15 | .PHONY: $(TARGETS) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [EXPERIMENTAL] terraform-controller 2 | ======== 3 | 4 | ## ***Use K8s to Run Terraform*** 5 | 6 | **NOTE:** We are actively experimenting with this in the open. Consider this ALPHA software and subject to change. 7 | 8 | Terraform-controller - This is a low level tool to run Git controlled Terraform modules in Kubernetes. The controller manages the TF state file using Kubernetes as a remote statefile backend (requires Terraform 0.13.4)! You can have changes auto-applied or wait for an explicit "OK" before running. 9 | 10 | There are two parts to the stack, the controller and the executor. 11 | 12 | The controller creates three CRDs and runs controllers for modules and executions. A module is the building block and is the same as a terraform module. This is referenced from an execution which is used to combine all information needed to run Terraform. The execution combines Terraform variables and environment variables from secrets and/or config maps to provide to the executor. 13 | 14 | The executor is a job that runs Terraform. Taking input from the execution run CRD the executor runs `terraform init`, `terraform plan` and `terraform create/destroy` depending on the context. 15 | 16 | Executions have a 1-to-many relationship with execution runs, as updates or changes are made in the module or execution additional runs are created to update the terraform resources. 17 | 18 | # Deploying 19 | Use provided manifests `kubectl create -f ./manifests` to deploy to an existing k8s cluster. Manifests will create all CRDs necessary and a Deployment with the rancher/terraform-controller image. 20 | 21 | ## Verify 22 | ``` 23 | ~ kubectl get all -n terraform-controller 24 | NAME READY STATUS RESTARTS AGE 25 | pod/terraform-controller-8494cf85c5-x97sn 1/1 Running 0 17s 26 | 27 | NAME READY UP-TO-DATE AVAILABLE AGE 28 | deployment.apps/terraform-controller 1/1 1 1 18s 29 | 30 | NAME DESIRED CURRENT READY AGE 31 | replicaset.apps/terraform-controller-8494cf85c5 1 1 1 18s 32 | ``` 33 | 34 | ## Namespace 35 | Everything is put in the `terraform-controller` namespace with these provided manifests. Edit metadata.namespace in files to change name space or remove to run in default. You will need to update the args for the command in the deployment to update or remove `--namespace` argument for the executable. Passing in the flag limits the controller to only watching CRD objects in it's namespace, remove this param to let the terraform-controller see all CRD objects in any namespace. 36 | 37 | ## Quickstart Appliance + k3s 38 | Use (k3d)[https://github.com/rancher/k3d/releases] to spin up small (k3s)[https://github.com/rancher/k3s] clusters for a quick start for using the Terraform Controller. The appliance image comes pre-built with the deployment manifests and will auto-create verything the Terraform Controller needs when they boot. 39 | 40 | ```shell 41 | ~ k3d create --name terraform-controller --image rancher/terraform-controller-appliance 42 | ~ export KUBECONFIG="$(k3d get-kubeconfig --name='terraform-controller')" 43 | ~ kubectl get all -n terraform-controller 44 | NAME READY STATUS RESTARTS AGE 45 | pod/terraform-controller-d774bbd44-w4mzk 0/1 Pending 0 1s 46 | 47 | NAME READY UP-TO-DATE AVAILABLE AGE 48 | deployment.apps/terraform-controller 0/1 1 0 14s 49 | 50 | NAME DESIRED CURRENT READY AGE 51 | replicaset.apps/terraform-controller-d774bbd44 1 1 0 1s 52 | 53 | ~ kubectl get crd | grep terraformcontroller 54 | executionruns.terraformcontroller.cattle.io 2019-05-22T17:19:01Z 55 | executions.terraformcontroller.cattle.io 2019-05-22T17:19:01Z 56 | modules.terraformcontroller.cattle.io 2019-05-22T17:19:01Z 57 | 58 | ~ k3d delete --name terraform 59 | ``` 60 | 61 | # Example 62 | With the controller running you can run the provided example in the `./example` directory which shows you how to run a basic [Digital Ocean Terraform module](https://github.com/dramich/domodule) which takes a do_token and do_name and creates a droplet. 63 | 64 | Modify `./example/00-secret.yaml` with your Digital Ocean API token and desired droplet name. 65 | 66 | Run `kubectl create -f ./example -n terraform-controller` to create all envvars/secrets/module and the execution which will automatically run. The controller creates Jobs for the Terraform runs so to access logs check the pod logs for the executor create and destroy jobs. This example is setup to auto-confirm and auto-delete when the CRD object is destroyed. 67 | 68 | Delete the droplet by deleting the CRD `kubectl delete -f ./example/20-deployment.yaml -n terraform-controller`. 69 | 70 | ## Approving a Plan 71 | In `./example/20-state.yaml` its pre-configured to auto-approve and auto-delete when you make the execution CRD. You can turn off `spec.destroyOnDelete` and `spec.autoConfirm` and do these by hand doing the following. 72 | 73 | To get the plan check logs of the pods used to run the job. 74 | `kubectl logs [executer-pod-name] -n terraform-controller` 75 | 76 | Assuming the action Terraform is going to perform is correct annotate the Execution Run to approve the changes: 77 | 78 | `kubectl annotate executionruns.terraform-controller.cattle.io [execution-run-name] -n terraform-controller approved="yes" --overwrite` 79 | 80 | Once the job completes, you can see the outputs from Terraform by checking the Execution Run: 81 | 82 | `kubectl get executionruns.terraform-controller.cattle.io [execution-run-name] -n terraform-controller -o yaml` 83 | 84 | With destroyOnDelete turned off you will have to delete the Droplet by hand as a destroy job will not kick off. 85 | 86 | ## Building Custom Execution Environment 87 | 88 | Create a Dockerfile 89 | 90 | ``` 91 | FROM rancher/terraform-controller-executor:v0.0.3 #Or whatever the release is 92 | RUN curl https://myurl.com/get-some-binary 93 | ``` 94 | 95 | Build that image and push to a registry. 96 | 97 | When creating the execution define the image: 98 | ``` 99 | apiVersion: terraformcontroller.cattle.io/v1 100 | kind: Execution 101 | metadata: 102 | name: cluster-create 103 | spec: 104 | moduleName: cluster-modules 105 | destroyOnDelete: true 106 | autoConfirm: false 107 | image: cloudnautique/tf-executor-rancher2-provider:v0.0.3 # Custom IMAGE 108 | variables: 109 | SecretNames: 110 | - my-secret 111 | envConfigNames: 112 | - env-config 113 | ``` 114 | 115 | If you already have an execution, edit the CR via kubectl and add the image field. 116 | 117 | ## Building 118 | `make` 119 | 120 | ### Local Execution 121 | Use `./bin/terraform-controller` 122 | 123 | ### Running the Executor in Docker - Useful for testing the Executor 124 | docker run -d -v "/Path/To/Kubeconfig:/root/.kube/config" -e "KUBECONFIG=/root/.kube/config" -e "EXECUTOR_RUN_NAME=RUN_NAME" -e "EXECUTOR_ACTION=create" rancher/terraform-controller-executor:dev 125 | 126 | ## License 127 | Copyright (c) 2019 [Rancher Labs, Inc.](http://rancher.com) 128 | 129 | Licensed under the Apache License, Version 2.0 (the "License"); 130 | you may not use this file except in compliance with the License. 131 | You may obtain a copy of the License at 132 | 133 | [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) 134 | 135 | Unless required by applicable law or agreed to in writing, software 136 | distributed under the License is distributed on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138 | See the License for the specific language governing permissions and 139 | limitations under the License. 140 | -------------------------------------------------------------------------------- /chart/.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 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: terraform-controller 3 | description: Terraform controller Helm Chart 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | version: ${VERSION} 16 | appVersion: ${VERSION} 17 | -------------------------------------------------------------------------------- /chart/crds/crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: modules.terraformcontroller.cattle.io 5 | spec: 6 | group: terraformcontroller.cattle.io 7 | version: v1 8 | names: 9 | kind: Module 10 | plural: modules 11 | singular: module 12 | scope: Namespaced 13 | --- 14 | apiVersion: apiextensions.k8s.io/v1beta1 15 | kind: CustomResourceDefinition 16 | metadata: 17 | name: states.terraformcontroller.cattle.io 18 | spec: 19 | group: terraformcontroller.cattle.io 20 | version: v1 21 | names: 22 | kind: State 23 | plural: states 24 | singular: state 25 | scope: Namespaced 26 | --- 27 | apiVersion: apiextensions.k8s.io/v1beta1 28 | kind: CustomResourceDefinition 29 | metadata: 30 | name: executions.terraformcontroller.cattle.io 31 | spec: 32 | group: terraformcontroller.cattle.io 33 | version: v1 34 | names: 35 | kind: Execution 36 | plural: executions 37 | singular: execution 38 | scope: Namespaced 39 | -------------------------------------------------------------------------------- /chart/templates/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | apps.kubernetes.io/component: controller 6 | apps.kubernetes.io/name: terraform-controller 7 | name: terraform-controller 8 | roleRef: 9 | apiGroup: rbac.authorization.k8s.io 10 | kind: ClusterRole 11 | name: cluster-admin 12 | subjects: 13 | - kind: ServiceAccount 14 | name: terraform-controller 15 | namespace: {{ .Release.Namespace }} 16 | -------------------------------------------------------------------------------- /chart/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | run: terraform-controller 6 | name: terraform-controller 7 | namespace: {{ .Release.Namespace }} 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | run: terraform-controller 13 | template: 14 | metadata: 15 | labels: 16 | run: terraform-controller 17 | spec: 18 | serviceAccountName: terraform-controller 19 | containers: 20 | - image: {{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }} 21 | name: terraform-controller 22 | command: ["terraform-controller"] 23 | env: 24 | - name: NAMESPACE 25 | valueFrom: 26 | fieldRef: 27 | fieldPath: metadata.namespace 28 | -------------------------------------------------------------------------------- /chart/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | apps.kubernetes.io/component: controller 6 | apps.kubernetes.io/name: terraform-controller 7 | name: terraform-controller 8 | namespace: {{ .Release.Namespace }} 9 | -------------------------------------------------------------------------------- /chart/values.yaml: -------------------------------------------------------------------------------- 1 | #terraform-controller helm chart values 2 | 3 | image: 4 | repository: rancher/terraform-controller 5 | # Overrides the image tag whose default is the chart appVersion. 6 | tag: "${VERSION}" 7 | 8 | -------------------------------------------------------------------------------- /e2e/README.md: -------------------------------------------------------------------------------- 1 | # End to End Testing 2 | 3 | This folder contains all End to End (e2e) testing code 4 | 5 | ## Prerequisites 6 | 7 | - The e2e tests require you to run `make build-controller` at least once because the binary `./bin/terraform-controller` needs to be available to the e2e tests. 8 | - These tests are expecting a new clean k8s cluster and does not clean up after itself so it is expected that the cluster will be thrown away after e2e tests are complete. You will want to look at k3s/k3d to make this process smoother. Using the `make` scripts are the best way to run these and you are using them at your own risk on an existing cluster. 9 | 10 | ## Usage 11 | 12 | To build/run evertything, use: 13 | 14 | ``` 15 | make 16 | ``` 17 | 18 | To target only the e2e tests, use: 19 | 20 | ``` 21 | make build-controller #created ./bin/terraform-controller 22 | make e2e 23 | ``` 24 | 25 | ## Running Tests Locally with k3d 26 | 27 | If you'd like to run against a local k3s, it is recommended that you use [k3d](https://github.com/rancher/k3d). 28 | 29 | To boot a cluster, run: 30 | 31 | ``` 32 | k3d create --name e2e 33 | ``` 34 | 35 | Then use the provided config to boot the controller. You can use a command like this: 36 | 37 | ``` 38 | KUBECONFIG="$(k3d get-kubeconfig --name='e2e')" ./terraform-controller --threads 1 39 | ``` 40 | 41 | After the controller is running locally, you can run the tests in the same manner: 42 | 43 | ``` 44 | KUBECONFIG="$(k3d get-kubeconfig --name='e2e')" go test -json -count=1 ./e2e/... 45 | ``` 46 | 47 | The `count=1` option is needed because tests will be cached if the code doesn't change, even though you are running the tests against a new cluster with no data. In this case, you would want to re-run the tests for a new cluster. 48 | 49 | # Initializing 50 | 51 | There is an initilization process which mimics `kubectl create -f ./manifests`. This process assumes that you are running a new k3s server, and tests could fail if it tries to make something that already exists. Therefore, if you are doing local development of the e2e tests, it is recommended to delete and recreate your k3s cluster before performing another run. 52 | 53 | To automate the process of deleting your k3s cluster before you recreate it, you can use a Run/Debug configuration in Goland or use a one-line shell tool. 54 | 55 | # Terraform Module 56 | 57 | We use a [test module](https://github.com/luthermonson/terraform-controller-test-module) to test executions. It uses the k8s Terraform provider and creates a ConfigMap. The e2e tests validate that they were created. 58 | 59 | Please note that the e2e test module uses the default k3s setting to boot the API server on https://10.43.0.1 as seen [here](https://github.com/luthermonson/terraform-controller-test-module/blob/master/main.tf#L5). If you change the `--api-port` setting, you will need to change this line to match. 60 | -------------------------------------------------------------------------------- /e2e/e2e.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | tfv1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 8 | tf "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1" 9 | "github.com/rancher/wrangler/pkg/crd" 10 | "github.com/rancher/wrangler/pkg/signals" 11 | "github.com/sirupsen/logrus" 12 | v1 "k8s.io/api/core/v1" 13 | "k8s.io/apimachinery/pkg/api/errors" 14 | v12 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 | "k8s.io/apimachinery/pkg/util/wait" 16 | "k8s.io/client-go/kubernetes" 17 | "k8s.io/client-go/rest" 18 | "k8s.io/client-go/tools/clientcmd" 19 | ) 20 | 21 | type E2E struct { 22 | ctx context.Context 23 | cs *kubernetes.Clientset 24 | cfg *rest.Config 25 | kubeconfig string 26 | namespace string 27 | moduleURL string 28 | crds []crd.CRD 29 | } 30 | 31 | func NewE2E(namespace, kubeconfig, module string, crdsNames []string) *E2E { 32 | cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) 33 | if err != nil { 34 | logrus.Fatalf("Error building kubeconfig: %s", err.Error()) 35 | } 36 | 37 | cs, err := kubernetes.NewForConfig(cfg) 38 | if err != nil { 39 | logrus.Fatalf("Error building kubeconfig: %s", err.Error()) 40 | } 41 | 42 | var crds = make([]crd.CRD, len(crdsNames)) 43 | for k, v := range crdsNames { 44 | crds[k] = crd.FromGV(tfv1.SchemeGroupVersion, v) 45 | } 46 | 47 | return &E2E{ 48 | ctx: signals.SetupSignalHandler(context.Background()), 49 | cs: cs, 50 | cfg: cfg, 51 | kubeconfig: kubeconfig, 52 | namespace: namespace, 53 | moduleURL: module, 54 | crds: crds, 55 | } 56 | } 57 | 58 | func (e *E2E) createState() error { 59 | cs, err := tf.NewForConfig(e.cfg) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | _, err = cs.States(e.namespace).Create(e.ctx, e.getState(), v12.CreateOptions{}) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | return nil 70 | } 71 | 72 | func (e *E2E) createModule() error { 73 | cs, err := tf.NewForConfig(e.cfg) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | _, err = cs.Modules(e.namespace).Create(e.ctx, e.getModule(), v12.CreateOptions{}) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | err = wait.Poll(time.Second, 45*time.Second, func() (bool, error) { 84 | module, err := cs.Modules(e.namespace).Get(e.ctx, e.generateModuleName(), v12.GetOptions{}) 85 | if err == nil && module.Status.ContentHash != "" { 86 | return true, nil 87 | } 88 | 89 | if errors.IsNotFound(err) { 90 | return false, nil 91 | } 92 | 93 | logrus.Printf("Waiting for Module to be processed by terraform-controller: %+v\n", err) 94 | return false, err 95 | }) 96 | 97 | if err != nil { 98 | return err 99 | } 100 | 101 | return nil 102 | } 103 | 104 | func (e *E2E) createVariables() error { 105 | _, err := e.cs.CoreV1().Secrets(e.namespace).Create(e.ctx, e.getSecret(), v12.CreateOptions{}) 106 | if err != nil { 107 | return err 108 | } 109 | 110 | _, err = e.cs.CoreV1().Secrets(e.namespace).Create(e.ctx, e.getSecretEnv(), v12.CreateOptions{}) 111 | if err != nil { 112 | return err 113 | } 114 | 115 | _, err = e.cs.CoreV1().ConfigMaps(e.namespace).Create(e.ctx, e.getConfigMap(), v12.CreateOptions{}) 116 | if err != nil { 117 | return err 118 | } 119 | 120 | _, err = e.cs.CoreV1().ConfigMaps(e.namespace).Create(e.ctx, e.getConfigMapEnv(), v12.CreateOptions{}) 121 | if err != nil { 122 | return err 123 | } 124 | 125 | return nil 126 | } 127 | 128 | func (e *E2E) getState() *tfv1.State { 129 | return &tfv1.State{ 130 | ObjectMeta: v12.ObjectMeta{ 131 | Name: e.generateStateName(), 132 | Namespace: e.namespace, 133 | }, 134 | Spec: tfv1.StateSpec{ 135 | ModuleName: e.generateModuleName(), 136 | AutoConfirm: true, 137 | DestroyOnDelete: true, 138 | Image: "terraform-controller-executor:e2e", 139 | Variables: tfv1.Variables{ 140 | ConfigNames: []string{e.generateConfigMapName()}, 141 | EnvConfigName: []string{e.generateConfigMapEnvName()}, 142 | SecretNames: []string{e.generateSecretName()}, 143 | EnvSecretNames: []string{e.generateSecretEnvName()}, 144 | }, 145 | }, 146 | } 147 | } 148 | 149 | func (e *E2E) generateStateName() string { 150 | return e.namespace + "-state" 151 | } 152 | 153 | func (e *E2E) generateModuleName() string { 154 | return e.namespace + "-module" 155 | } 156 | 157 | func (e *E2E) generateSecretName() string { 158 | return e.namespace + "-secret" 159 | } 160 | 161 | func (e *E2E) generateSecretEnvName() string { 162 | return e.namespace + "-secret-env" 163 | } 164 | 165 | func (e *E2E) getSecret() *v1.Secret { 166 | return &v1.Secret{ 167 | ObjectMeta: v12.ObjectMeta{ 168 | Name: e.generateSecretName(), 169 | Namespace: e.namespace, 170 | }, 171 | Type: "opaque", 172 | StringData: map[string]string{ 173 | "test_secret": e.namespace, 174 | }, 175 | } 176 | } 177 | 178 | func (e *E2E) getSecretEnv() *v1.Secret { 179 | return &v1.Secret{ 180 | ObjectMeta: v12.ObjectMeta{ 181 | Name: e.generateSecretEnvName(), 182 | Namespace: e.namespace, 183 | }, 184 | Type: "opaque", 185 | StringData: map[string]string{ 186 | "test_secret_env": e.namespace, 187 | }, 188 | } 189 | } 190 | 191 | func (e *E2E) generateConfigMapName() string { 192 | return e.namespace + "-config-map" 193 | } 194 | 195 | func (e *E2E) generateConfigMapEnvName() string { 196 | return e.namespace + "-config-map-env" 197 | } 198 | 199 | func (e *E2E) getConfigMap() *v1.ConfigMap { 200 | return &v1.ConfigMap{ 201 | ObjectMeta: v12.ObjectMeta{ 202 | Name: e.generateConfigMapName(), 203 | Namespace: e.namespace, 204 | }, 205 | Data: map[string]string{ 206 | "test_config_map": e.namespace, 207 | }, 208 | } 209 | } 210 | 211 | func (e *E2E) getConfigMapEnv() *v1.ConfigMap { 212 | return &v1.ConfigMap{ 213 | ObjectMeta: v12.ObjectMeta{ 214 | Name: e.generateConfigMapEnvName(), 215 | Namespace: e.namespace, 216 | }, 217 | Data: map[string]string{ 218 | "test_config_map_env": e.namespace, 219 | }, 220 | } 221 | } 222 | 223 | func (e *E2E) getModule() *tfv1.Module { 224 | return &tfv1.Module{ 225 | ObjectMeta: v12.ObjectMeta{ 226 | Name: e.generateModuleName(), 227 | Namespace: e.namespace, 228 | }, 229 | Spec: tfv1.ModuleSpec{ 230 | ModuleContent: tfv1.ModuleContent{ 231 | Git: tfv1.GitLocation{ 232 | URL: e.moduleURL, 233 | }, 234 | }, 235 | }, 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /e2e/e2e_test.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "math/rand" 5 | "os" 6 | "testing" 7 | "time" 8 | 9 | tfv1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 10 | tf "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1" 11 | "github.com/sirupsen/logrus" 12 | "github.com/stretchr/testify/assert" 13 | v1 "k8s.io/api/core/v1" 14 | "k8s.io/apimachinery/pkg/api/errors" 15 | v13 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 | "k8s.io/apimachinery/pkg/util/wait" 17 | ) 18 | 19 | const ( 20 | Namespace = "terraform-controller" 21 | ModuleURL = "https://github.com/luthermonson/terraform-controller-test-module" 22 | TestConfigMap = "test-config-map" 23 | ) 24 | 25 | var e *E2E 26 | 27 | func TestMain(m *testing.M) { 28 | rand.Seed(time.Now().UnixNano()) 29 | kubeconfig := os.Getenv("KUBECONFIG") 30 | if _, err := os.Stat(kubeconfig); os.IsNotExist(err) { 31 | logrus.Fatal("kubeconfig file does not exist") 32 | } 33 | namespace := os.Getenv("Namespace") 34 | if namespace == "" { 35 | namespace = Namespace 36 | } 37 | 38 | e = NewE2E(namespace, kubeconfig, ModuleURL, []string{ 39 | "Module", 40 | "State", 41 | "Execution", 42 | }) 43 | 44 | err := e.initialize() 45 | if err != nil { 46 | logrus.Fatalf("Failed to initialize: %s", err.Error()) 47 | } 48 | os.Exit(m.Run()) 49 | } 50 | 51 | func TestCreateModule(t *testing.T) { 52 | assert := assert.New(t) 53 | err := e.createModule() 54 | if err != nil { 55 | logrus.Fatalf("Creating terraform module failed: %s", err.Error()) 56 | } 57 | 58 | cs, err := tf.NewForConfig(e.cfg) 59 | if err != nil { 60 | logrus.Fatalf("Creating clientset for modules: %s", err.Error()) 61 | } 62 | 63 | err = wait.Poll(time.Second, 15*time.Second, func() (bool, error) { 64 | var err error 65 | module, err := cs.Modules(e.namespace).Get(e.ctx, e.generateModuleName(), v13.GetOptions{}) 66 | 67 | if err == nil && module.Status.ContentHash != "" { 68 | return true, nil 69 | } 70 | logrus.Printf("Waiting for module to be ready and have a run hash: %+v\n", err) 71 | 72 | return false, err 73 | }) 74 | 75 | assert.Nil(err) 76 | } 77 | 78 | func TestCreateVariables(t *testing.T) { 79 | //assert := assert.New(t) 80 | err := e.createVariables() 81 | if err != nil { 82 | logrus.Fatalf("Creating terraform state failed: %s", err.Error()) 83 | } 84 | } 85 | 86 | func TestCreateState(t *testing.T) { 87 | 88 | assert := assert.New(t) 89 | err := e.createState() 90 | if err != nil { 91 | logrus.Fatalf("Creating terraform state failed: %s", err.Error()) 92 | } 93 | 94 | cs, err := tf.NewForConfig(e.cfg) 95 | if err != nil { 96 | logrus.Fatalf("Creating clientset for states: %s", err.Error()) 97 | } 98 | 99 | err = wait.Poll(time.Second, 15*time.Second, func() (bool, error) { 100 | var err error 101 | state, err := cs.States(e.namespace).Get(e.ctx, e.generateStateName(), v13.GetOptions{}) 102 | 103 | if err == nil && state.Status.LastRunHash != "" { 104 | return true, nil 105 | } 106 | logrus.Printf("Waiting for state to be ready and have a run hash: %+v\n", err) 107 | 108 | return false, err 109 | }) 110 | 111 | assert.Nil(err) 112 | } 113 | 114 | func TestCreateJobComplete(t *testing.T) { 115 | assert := assert.New(t) 116 | var cm *v1.ConfigMap 117 | err := wait.Poll(time.Second, 30*time.Second, func() (bool, error) { 118 | var err error 119 | cm, err = e.cs.CoreV1().ConfigMaps(e.namespace).Get(e.ctx, TestConfigMap, v13.GetOptions{}) 120 | if err == nil { 121 | return true, nil 122 | } 123 | if errors.IsNotFound(err) { 124 | return false, nil 125 | } 126 | 127 | logrus.Printf("Waiting for config map creation: %+v\n", err) 128 | return false, err 129 | }) 130 | 131 | assert.Nil(err) 132 | assert.Equal(e.namespace, cm.Data["test_config_map"]) 133 | assert.Equal(e.namespace, cm.Data["test_secret"]) 134 | } 135 | 136 | func TestExecution(t *testing.T) { 137 | assert := assert.New(t) 138 | 139 | cs, err := tf.NewForConfig(e.cfg) 140 | if err != nil { 141 | logrus.Fatalf("Creating clientset for modules: %s", err.Error()) 142 | } 143 | 144 | executions, err := cs.Executions(e.namespace).List(e.ctx, v13.ListOptions{ 145 | LabelSelector: "state=" + e.generateStateName(), 146 | }) 147 | 148 | assert.Nil(err) 149 | assert.Equal(1, len(executions.Items)) 150 | 151 | var jobDeleted = false 152 | err = wait.Poll(time.Second, 30*time.Second, func() (bool, error) { 153 | var err error 154 | _, err = e.cs.BatchV1().Jobs(e.namespace).Get(e.ctx, "job-"+executions.Items[0].Name, v13.GetOptions{}) 155 | if errors.IsNotFound(err) { 156 | jobDeleted = true 157 | return true, nil 158 | } 159 | 160 | return false, nil 161 | }) 162 | 163 | assert.Nil(err) 164 | exec, err := cs.Executions(e.namespace).Get(e.ctx, executions.Items[0].Name, v13.GetOptions{}) 165 | assert.Nil(err) 166 | assert.True(jobDeleted) 167 | assert.NotEmpty(exec.Status.JobLogs) 168 | assert.True(tfv1.ExecutionRunConditionPlanned.IsTrue(exec)) 169 | assert.True(tfv1.ExecutionRunConditionApplied.IsTrue(exec)) 170 | } 171 | 172 | func TestTerraState(t *testing.T) { 173 | assert := assert.New(t) 174 | 175 | ts, err := e.cs.CoreV1().Secrets(e.namespace).List(e.ctx, v13.ListOptions{ 176 | LabelSelector: "tfstateSecretSuffix=" + e.generateStateName(), 177 | }) 178 | 179 | assert.Nil(err) 180 | assert.Equal(len(ts.Items), 1) 181 | assert.NotEmpty(ts.Items[0].Data["tfstate"]) 182 | assert.Empty(ts.Items[0].Data["lockInfo"]) 183 | } 184 | 185 | func TestDeleteState(t *testing.T) { 186 | assert := assert.New(t) 187 | 188 | cs, err := tf.NewForConfig(e.cfg) 189 | assert.Nil(err) 190 | err = cs.States(e.namespace).Delete(e.ctx, e.generateStateName(), v13.DeleteOptions{}) 191 | assert.Nil(err) 192 | } 193 | 194 | func TestDeleteJobComplete(t *testing.T) { 195 | assert := assert.New(t) 196 | var configMapDeleted = false 197 | err := wait.Poll(time.Second, 30*time.Second, func() (bool, error) { 198 | var err error 199 | _, err = e.cs.CoreV1().ConfigMaps(e.namespace).Get(e.ctx, TestConfigMap, v13.GetOptions{}) 200 | if errors.IsNotFound(err) { 201 | configMapDeleted = true 202 | return true, nil 203 | } 204 | 205 | return false, nil 206 | }) 207 | 208 | assert.Nil(err) 209 | assert.True(configMapDeleted) 210 | } 211 | -------------------------------------------------------------------------------- /e2e/init.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/rancher/wrangler/pkg/crd" 7 | "github.com/sirupsen/logrus" 8 | v12 "k8s.io/api/core/v1" 9 | v1 "k8s.io/api/rbac/v1" 10 | "k8s.io/apimachinery/pkg/api/errors" 11 | v13 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 | "k8s.io/apimachinery/pkg/util/wait" 13 | ) 14 | 15 | func (e *E2E) initialize() error { 16 | var err error 17 | 18 | crdFactory, err := crd.NewFactoryFromClient(e.cfg) 19 | if err != nil { 20 | logrus.Fatalf("Error building crd: %s", err.Error()) 21 | } 22 | 23 | _, err = crdFactory.CreateCRDs(e.ctx, e.crds...) 24 | if err != nil { 25 | return err 26 | } 27 | 28 | _, err = e.cs.CoreV1().Namespaces().Create(e.ctx, e.getNs(), v13.CreateOptions{}) 29 | if err != nil { 30 | return err 31 | } 32 | _, err = e.cs.RbacV1().ClusterRoleBindings().Create(e.ctx, e.getCrb(), v13.CreateOptions{}) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | _, err = e.cs.CoreV1().ServiceAccounts(e.namespace).Create(e.ctx, e.getSa(), v13.CreateOptions{}) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | err = wait.Poll(time.Second, 15*time.Second, func() (bool, error) { 43 | _, err := e.cs.CoreV1().ServiceAccounts(e.namespace).Get(e.ctx, e.namespace, v13.GetOptions{}) 44 | if err == nil { 45 | return true, nil 46 | } 47 | 48 | if errors.IsNotFound(err) { 49 | return false, nil 50 | } 51 | 52 | logrus.Printf("Waiting for SA to be ready: %+v\n", err) 53 | return false, err 54 | }) 55 | 56 | if err != nil { 57 | return err 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func (e *E2E) getNs() *v12.Namespace { 64 | return &v12.Namespace{ 65 | ObjectMeta: v13.ObjectMeta{ 66 | Name: e.namespace, 67 | }, 68 | } 69 | } 70 | 71 | func (e *E2E) getSa() *v12.ServiceAccount { 72 | return &v12.ServiceAccount{ 73 | ObjectMeta: v13.ObjectMeta{ 74 | Name: e.namespace, 75 | Namespace: e.namespace, 76 | Labels: map[string]string{ 77 | "apps.kubernetes.io/component": "controller", 78 | "apps.kubernetes.io/name": e.namespace, 79 | }, 80 | }, 81 | } 82 | } 83 | 84 | func (e *E2E) getCrb() *v1.ClusterRoleBinding { 85 | return &v1.ClusterRoleBinding{ 86 | ObjectMeta: v13.ObjectMeta{ 87 | Name: e.namespace, 88 | Labels: map[string]string{ 89 | "apps.kubernetes.io/component": "controller", 90 | "apps.kubernetes.io/name": e.namespace, 91 | }, 92 | }, 93 | RoleRef: v1.RoleRef{ 94 | APIGroup: "rbac.authorization.k8s.io", 95 | Kind: "ClusterRole", 96 | Name: "cluster-admin", 97 | }, 98 | Subjects: []v1.Subject{ 99 | { 100 | Kind: "ServiceAccount", 101 | Name: e.namespace, 102 | Namespace: e.namespace, 103 | }, 104 | }, 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /e2e/init_test.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | corev1 "k8s.io/api/core/v1" 10 | rbacv1 "k8s.io/api/rbac/v1" 11 | "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" 12 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 | "k8s.io/gengo/namer" 14 | "k8s.io/gengo/types" 15 | ) 16 | 17 | func TestCrds(t *testing.T) { 18 | assert := assert.New(t) 19 | cs, err := clientset.NewForConfig(e.cfg) 20 | assert.Nil(err) 21 | for _, c := range e.crds { 22 | crdName := fmt.Sprintf("%s.%s", lowerPlural(c.GVK.Kind), c.GVK.Group) 23 | crd, err := cs.ApiextensionsV1beta1().CustomResourceDefinitions().Get(e.ctx, crdName, metav1.GetOptions{}) 24 | assert.Nil(err) 25 | assert.Equal(crdName, crd.Name) 26 | } 27 | } 28 | 29 | func lowerPlural(s string) string { 30 | lcp := namer.NewAllLowercasePluralNamer(map[string]string{}) 31 | return lcp.Name(&types.Type{ 32 | Name: types.Name{ 33 | Name: s, 34 | }, 35 | }) 36 | } 37 | 38 | func TestGetNs(t *testing.T) { 39 | assert := assert.New(t) 40 | ns := e.getNs() 41 | assert.Equal(reflect.TypeOf(ns), reflect.TypeOf(&corev1.Namespace{})) 42 | assert.Equal(ns.ObjectMeta.Name, e.namespace) 43 | } 44 | 45 | func TestGetSa(t *testing.T) { 46 | assert := assert.New(t) 47 | sa := e.getSa() 48 | assert.Equal(reflect.TypeOf(sa), reflect.TypeOf(&corev1.ServiceAccount{})) 49 | assert.Equal(sa.ObjectMeta.Name, e.namespace) 50 | assert.Equal(sa.ObjectMeta.Namespace, e.namespace) 51 | } 52 | 53 | func TestGetCrb(t *testing.T) { 54 | assert := assert.New(t) 55 | crb := e.getCrb() 56 | assert.Equal(reflect.TypeOf(crb), reflect.TypeOf(&rbacv1.ClusterRoleBinding{})) 57 | assert.Equal(crb.ObjectMeta.Name, e.namespace) 58 | assert.Equal(crb.Subjects[0].Kind, "ServiceAccount") 59 | assert.Equal(crb.Subjects[0].Name, e.namespace) 60 | assert.Equal(crb.Subjects[0].Namespace, e.namespace) 61 | } 62 | -------------------------------------------------------------------------------- /example/00-envvar.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | PROXY_URL: proxy_url 4 | DEBUG: "true" 5 | kind: ConfigMap 6 | metadata: 7 | name: env-config 8 | -------------------------------------------------------------------------------- /example/00-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: mysecret 5 | type: Opaque 6 | stringData: 7 | do_token: #add your dotoken 8 | do_name: terraform-controller-test 9 | -------------------------------------------------------------------------------- /example/10-module.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: terraformcontroller.cattle.io/v1 2 | kind: Module 3 | metadata: 4 | name: my-module 5 | spec: 6 | git: 7 | url: https://github.com/dramich/domodule 8 | 9 | -------------------------------------------------------------------------------- /example/20-state.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: terraformcontroller.cattle.io/v1 2 | kind: State 3 | metadata: 4 | name: my-state 5 | spec: 6 | moduleName: my-module 7 | destroyOnDelete: true 8 | autoConfirm: true 9 | image: rancher/terraform-controller-executor:v0.0.12-alpha1 10 | variables: 11 | secretNames: 12 | - mysecret 13 | envConfigNames: 14 | - env-config 15 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rancher/terraform-controller 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/docker/go-units v0.4.0 7 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect 8 | github.com/google/go-cmp v0.3.1 // indirect 9 | github.com/hashicorp/golang-lru v0.5.4 // indirect 10 | github.com/pkg/errors v0.9.1 11 | github.com/rancher/lasso v0.0.0-20200905045615-7fcb07d6a20b 12 | github.com/rancher/wrangler v0.7.2 13 | github.com/sirupsen/logrus v1.6.0 14 | github.com/stretchr/testify v1.4.0 15 | github.com/urfave/cli v1.20.0 16 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 // indirect 17 | google.golang.org/appengine v1.6.1 // indirect 18 | k8s.io/api v0.18.8 19 | k8s.io/apiextensions-apiserver v0.18.0 20 | k8s.io/apimachinery v0.18.8 21 | k8s.io/client-go v0.18.8 22 | k8s.io/gengo v0.0.0-20200114144118-36b2048a9120 23 | ) 24 | 25 | replace github.com/matryer/moq => github.com/rancher/moq v0.0.0-20190404221404-ee5226d43009 26 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Rancher Labs, Inc. 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 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | //go:generate go run pkg/codegen/cleanup/main.go 2 | //go:generate /bin/rm -rf pkg/generated 3 | //go:generate go run pkg/codegen/main.go 4 | 5 | package main 6 | 7 | import ( 8 | "context" 9 | "os" 10 | 11 | "github.com/rancher/terraform-controller/pkg/generated/controllers/terraformcontroller.cattle.io" 12 | "github.com/rancher/terraform-controller/pkg/terraform" 13 | "github.com/rancher/wrangler/pkg/generated/controllers/batch" 14 | "github.com/rancher/wrangler/pkg/generated/controllers/core" 15 | "github.com/rancher/wrangler/pkg/generated/controllers/rbac" 16 | "github.com/rancher/wrangler/pkg/resolvehome" 17 | "github.com/rancher/wrangler/pkg/signals" 18 | "github.com/rancher/wrangler/pkg/start" 19 | "github.com/sirupsen/logrus" 20 | "github.com/urfave/cli" 21 | "k8s.io/client-go/tools/clientcmd" 22 | ) 23 | 24 | var ( 25 | VERSION = "v0.0.0-dev" 26 | ) 27 | 28 | func main() { 29 | app := cli.NewApp() 30 | app.Name = "terraform-controller" 31 | app.Version = VERSION 32 | app.Flags = []cli.Flag{ 33 | 34 | cli.IntFlag{ 35 | Name: "threads", 36 | EnvVar: "THREADS", 37 | Value: 2, 38 | }, 39 | cli.BoolFlag{ 40 | Name: "debug", 41 | EnvVar: "DEBUG", 42 | }, 43 | cli.StringFlag{ 44 | Name: "kubeconfig", 45 | EnvVar: "KUBECONFIG", 46 | Value: "${HOME}/.kube/config", 47 | }, 48 | cli.StringFlag{ 49 | Name: "namespace", 50 | EnvVar: "NAMESPACE", 51 | Value: "default", 52 | }, 53 | cli.StringFlag{ 54 | Name: "masterurl", 55 | EnvVar: "MASTERURL", 56 | Value: "", 57 | }, 58 | } 59 | app.Action = run 60 | 61 | if err := app.Run(os.Args); err != nil { 62 | logrus.Fatal(err) 63 | } 64 | } 65 | 66 | func run(c *cli.Context) { 67 | 68 | if c.Bool("debug") { 69 | logrus.SetLevel(logrus.DebugLevel) 70 | logrus.SetReportCaller(true) 71 | } 72 | 73 | logrus.Info("Starting Terraform Controller") 74 | kubeconfig, err := resolvehome.Resolve(c.String("kubeconfig")) 75 | 76 | if err != nil { 77 | logrus.Info("Resolving home dir failed.") 78 | } 79 | 80 | if _, err := os.Stat(kubeconfig); os.IsNotExist(err) { 81 | kubeconfig = "" 82 | } 83 | 84 | threadiness := c.Int("threads") 85 | masterurl := c.String("masterurl") 86 | ns := c.String("namespace") 87 | 88 | logrus.Printf("Booting Terraform Controller, namespace: %s", ns) 89 | 90 | ctx := signals.SetupSignalHandler(context.Background()) 91 | 92 | cfg, err := clientcmd.BuildConfigFromFlags(masterurl, kubeconfig) 93 | if err != nil { 94 | logrus.Fatalf("Error building kubeconfig: %s", err.Error()) 95 | } 96 | 97 | tfFactory, err := terraformcontroller.NewFactoryFromConfigWithNamespace(cfg, ns) 98 | if err != nil { 99 | logrus.Fatalf("Error building terraform controllers: %s", err.Error()) 100 | } 101 | 102 | coreFactory, err := core.NewFactoryFromConfigWithNamespace(cfg, ns) 103 | if err != nil { 104 | logrus.Fatalf("Error building core controllers: %s", err.Error()) 105 | } 106 | 107 | rbacFactory, err := rbac.NewFactoryFromConfigWithNamespace(cfg, ns) 108 | if err != nil { 109 | logrus.Fatalf("Error building rbac controllers: %s", err.Error()) 110 | } 111 | 112 | batchFactory, err := batch.NewFactoryFromConfigWithNamespace(cfg, ns) 113 | if err != nil { 114 | logrus.Fatalf("Error building rbac controllers: %s", err.Error()) 115 | } 116 | 117 | terraform.Register(ctx, 118 | tfFactory.Terraformcontroller().V1().Module(), 119 | tfFactory.Terraformcontroller().V1().State(), 120 | tfFactory.Terraformcontroller().V1().Execution(), 121 | rbacFactory.Rbac().V1().ClusterRole(), 122 | rbacFactory.Rbac().V1().ClusterRoleBinding(), 123 | coreFactory.Core().V1().Secret(), 124 | coreFactory.Core().V1().ConfigMap(), 125 | coreFactory.Core().V1().ServiceAccount(), 126 | batchFactory.Batch().V1().Job(), 127 | ) 128 | 129 | if err := start.All(ctx, threadiness, tfFactory, coreFactory, rbacFactory, batchFactory); err != nil { 130 | logrus.Fatalf("Error starting: %s", err.Error()) 131 | } 132 | 133 | <-ctx.Done() 134 | } 135 | -------------------------------------------------------------------------------- /manifests/00-clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | apps.kubernetes.io/component: controller 6 | apps.kubernetes.io/name: terraform-controller 7 | name: terraform-controller 8 | roleRef: 9 | apiGroup: rbac.authorization.k8s.io 10 | kind: ClusterRole 11 | name: cluster-admin 12 | subjects: 13 | - kind: ServiceAccount 14 | name: terraform-controller 15 | namespace: terraform-controller 16 | -------------------------------------------------------------------------------- /manifests/00-crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: modules.terraformcontroller.cattle.io 5 | namespace: terraform-controller 6 | spec: 7 | group: terraformcontroller.cattle.io 8 | version: v1 9 | names: 10 | kind: Module 11 | plural: modules 12 | singular: module 13 | scope: Namespaced 14 | --- 15 | apiVersion: apiextensions.k8s.io/v1beta1 16 | kind: CustomResourceDefinition 17 | metadata: 18 | name: states.terraformcontroller.cattle.io 19 | namespace: terraform-controller 20 | spec: 21 | group: terraformcontroller.cattle.io 22 | version: v1 23 | names: 24 | kind: State 25 | plural: states 26 | singular: state 27 | scope: Namespaced 28 | --- 29 | apiVersion: apiextensions.k8s.io/v1beta1 30 | kind: CustomResourceDefinition 31 | metadata: 32 | name: executions.terraformcontroller.cattle.io 33 | namespace: terraform-controller 34 | spec: 35 | group: terraformcontroller.cattle.io 36 | version: v1 37 | names: 38 | kind: Execution 39 | plural: executions 40 | singular: execution 41 | scope: Namespaced 42 | -------------------------------------------------------------------------------- /manifests/00-namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: terraform-controller 5 | -------------------------------------------------------------------------------- /manifests/00-serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | apps.kubernetes.io/component: controller 6 | apps.kubernetes.io/name: terraform-controller 7 | name: terraform-controller 8 | namespace: terraform-controller 9 | -------------------------------------------------------------------------------- /manifests/10-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | run: terraform-controller 6 | name: terraform-controller 7 | namespace: terraform-controller 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | run: terraform-controller 13 | template: 14 | metadata: 15 | labels: 16 | run: terraform-controller 17 | version: v0.0.3 18 | spec: 19 | serviceAccountName: terraform-controller 20 | containers: 21 | - image: rancher/terraform-controller:v0.0.11-alpha1 22 | name: terraform-controller 23 | command: ["terraform-controller"] 24 | args: ["--namespace", "terraform-controller"] 25 | -------------------------------------------------------------------------------- /package/Dockerfile.appliance: -------------------------------------------------------------------------------- 1 | FROM rancher/k3s:v0.5.0 2 | COPY ./yaml/* /var/lib/rancher/k3s/server/manifests/ 3 | -------------------------------------------------------------------------------- /package/Dockerfile.controller: -------------------------------------------------------------------------------- 1 | FROM alpine:3.12 2 | RUN apk add --no-cache curl git openssh unzip 3 | COPY terraform-controller /usr/bin/ 4 | CMD ["terraform-controller"] 5 | -------------------------------------------------------------------------------- /package/Dockerfile.executor: -------------------------------------------------------------------------------- 1 | FROM alpine:3.12 2 | 3 | # Need to grab terraform binary 4 | 5 | RUN apk add --no-cache curl git openssh unzip 6 | RUN curl -sLf https://releases.hashicorp.com/terraform/0.14.2/terraform_0.14.2_linux_amd64.zip -o terraform_0.14.2_linux_amd64.zip && \ 7 | unzip terraform_0.14.2_linux_amd64.zip -d /usr/bin && \ 8 | chmod +x /usr/bin/terraform && \ 9 | rm terraform_0.14.2_linux_amd64.zip 10 | 11 | COPY terraform-executor /usr/bin/ 12 | 13 | RUN mkdir -p /root/module 14 | WORKDIR /root/module 15 | 16 | CMD ["terraform-executor"] 17 | -------------------------------------------------------------------------------- /pkg/apis/terraformcontroller.cattle.io/v1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | // +k8s:deepcopy-gen=package 20 | // +groupName=terraformcontroller.cattle.io 21 | package v1 22 | -------------------------------------------------------------------------------- /pkg/apis/terraformcontroller.cattle.io/v1/types.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/rancher/wrangler/pkg/condition" 5 | "github.com/rancher/wrangler/pkg/genericcondition" 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | ) 8 | 9 | var ( 10 | ModuleConditionGitUpdated = condition.Cond("GitUpdated") 11 | 12 | StateConditionJobDeployed = condition.Cond("JobDeployed") 13 | ExecutionConditionMissingInfo = condition.Cond("MissingInfo") 14 | ExecutionConditionWatchRunning = condition.Cond("WatchRunning") 15 | StateConditionDestroyed = condition.Cond("Destroyed") 16 | 17 | ExecutionRunConditionPlanned = condition.Cond("Planned") 18 | ExecutionRunConditionApplied = condition.Cond("Applied") 19 | ) 20 | 21 | // +genclient 22 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 23 | 24 | type Module struct { 25 | metav1.TypeMeta `json:",inline"` 26 | metav1.ObjectMeta `json:"metadata,omitempty"` 27 | 28 | Spec ModuleSpec `json:"spec"` 29 | Status ModuleStatus `json:"status"` 30 | } 31 | 32 | type ModuleSpec struct { 33 | ModuleContent 34 | } 35 | 36 | type ModuleContent struct { 37 | Content map[string]string `json:"content,omitempty"` 38 | Git GitLocation `json:"git,omitempty"` 39 | } 40 | 41 | type ModuleStatus struct { 42 | CheckTime metav1.Time `json:"time,omitempty"` 43 | GitChecked *GitLocation `json:"gitChecked,omitempty"` 44 | Content ModuleContent `json:"content,omitempty"` 45 | ContentHash string `json:"contentHash,omitempty"` 46 | Conditions []genericcondition.GenericCondition `json:"conditions,omitempty"` 47 | } 48 | 49 | type GitLocation struct { 50 | URL string `json:"url,omitempty"` 51 | Branch string `json:"branch,omitempty"` 52 | Tag string `json:"tag,omitempty"` 53 | Commit string `json:"commit,omitempty"` 54 | SecretName string `json:"secretName,omitempty"` 55 | IntervalSeconds int `json:"intervalSeconds,omitempty"` 56 | } 57 | 58 | // +genclient 59 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 60 | 61 | type State struct { 62 | metav1.TypeMeta `json:",inline"` 63 | metav1.ObjectMeta `json:"metadata,omitempty"` 64 | 65 | Spec StateSpec `json:"spec"` 66 | Status StateStatus `json:"status"` 67 | } 68 | 69 | type Variables struct { 70 | EnvConfigName []string `json:"envConfigNames,omitempty"` 71 | EnvSecretNames []string `json:"envSecretNames,omitempty"` 72 | ConfigNames []string `json:"configNames,omitempty"` 73 | SecretNames []string `json:"secretNames,omitempty"` 74 | } 75 | 76 | type StateSpec struct { 77 | Image string `json:"image,omitempty"` 78 | Variables Variables `json:"variables,omitempty"` 79 | ModuleName string `json:"moduleName,omitempty"` 80 | // Data is dataName mapped to another execution name 81 | // so terraform variable name that should be an output from the run 82 | Data map[string]string `json:"data,omitempty"` 83 | AutoConfirm bool `json:"autoConfirm,omitempty"` 84 | DestroyOnDelete bool `json:"destroyOnDelete,omitempty"` 85 | Version int32 `json:"version,omitempty"` 86 | NodeSelector map[string]string `json:"nodeSelector,omitempty"` 87 | } 88 | 89 | type StateStatus struct { 90 | Conditions []genericcondition.GenericCondition `json:"conditions,omitempty"` 91 | LastRunHash string `json:"lastRunHash,omitempty"` 92 | ExecutionName string `json:"executionName,omitempty"` 93 | StatePlanName string `json:"executionPlanName,omitempty"` 94 | } 95 | 96 | // +genclient 97 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 98 | 99 | type Execution struct { 100 | metav1.TypeMeta `json:",inline"` 101 | metav1.ObjectMeta `json:"metadata,omitempty"` 102 | 103 | Spec ExecutionSpec `json:"spec"` 104 | Status ExecutionStatus `json:"status"` 105 | } 106 | 107 | type ExecutionSpec struct { 108 | AutoConfirm bool `json:"autoConfirm,omitempty"` 109 | Content ModuleContent `json:"content,omitempty"` 110 | ContentHash string `json:"contentHash,omitempty"` 111 | RunHash string `json:"runHash,omitempty"` 112 | Data map[string]string `json:"data,omitempty"` 113 | ExecutionName string `json:"executionName,omitempty"` 114 | ExecutionVersion int32 `json:"executionVersion,omitempty"` 115 | // Secrets and config maps referenced in the Execution spec will be combined into this secret 116 | SecretName string `json:"secretName,omitempty"` 117 | } 118 | 119 | type ExecutionStatus struct { 120 | Conditions []genericcondition.GenericCondition `json:"conditions,omitempty"` 121 | JobName string `json:"jobName,omitempty"` 122 | JobLogs string `json:"jobLogs,omitempty"` 123 | PlanOutput string `json:"planOutput,omitempty"` 124 | PlanConfirmed bool `json:"planConfirmed,omitempty"` 125 | ApplyOutput string `json:"applyOutput,omitempty"` 126 | Outputs string `json:"outputs,omitempty"` 127 | } 128 | -------------------------------------------------------------------------------- /pkg/apis/terraformcontroller.cattle.io/v1/zz_generated_list_types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | // +k8s:deepcopy-gen=package 20 | // +groupName=terraformcontroller.cattle.io 21 | package v1 22 | 23 | import ( 24 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 | ) 26 | 27 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 28 | 29 | // ModuleList is a list of Module resources 30 | type ModuleList struct { 31 | metav1.TypeMeta `json:",inline"` 32 | metav1.ListMeta `json:"metadata"` 33 | 34 | Items []Module `json:"items"` 35 | } 36 | 37 | func NewModule(namespace, name string, obj Module) *Module { 38 | obj.APIVersion, obj.Kind = SchemeGroupVersion.WithKind("Module").ToAPIVersionAndKind() 39 | obj.Name = name 40 | obj.Namespace = namespace 41 | return &obj 42 | } 43 | 44 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 45 | 46 | // StateList is a list of State resources 47 | type StateList struct { 48 | metav1.TypeMeta `json:",inline"` 49 | metav1.ListMeta `json:"metadata"` 50 | 51 | Items []State `json:"items"` 52 | } 53 | 54 | func NewState(namespace, name string, obj State) *State { 55 | obj.APIVersion, obj.Kind = SchemeGroupVersion.WithKind("State").ToAPIVersionAndKind() 56 | obj.Name = name 57 | obj.Namespace = namespace 58 | return &obj 59 | } 60 | 61 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 62 | 63 | // ExecutionList is a list of Execution resources 64 | type ExecutionList struct { 65 | metav1.TypeMeta `json:",inline"` 66 | metav1.ListMeta `json:"metadata"` 67 | 68 | Items []Execution `json:"items"` 69 | } 70 | 71 | func NewExecution(namespace, name string, obj Execution) *Execution { 72 | obj.APIVersion, obj.Kind = SchemeGroupVersion.WithKind("Execution").ToAPIVersionAndKind() 73 | obj.Name = name 74 | obj.Namespace = namespace 75 | return &obj 76 | } 77 | -------------------------------------------------------------------------------- /pkg/apis/terraformcontroller.cattle.io/v1/zz_generated_register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | // +k8s:deepcopy-gen=package 20 | // +groupName=terraformcontroller.cattle.io 21 | package v1 22 | 23 | import ( 24 | terraformcontroller "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io" 25 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | "k8s.io/apimachinery/pkg/runtime" 27 | "k8s.io/apimachinery/pkg/runtime/schema" 28 | ) 29 | 30 | var ( 31 | ExecutionResourceName = "executions" 32 | ModuleResourceName = "modules" 33 | StateResourceName = "states" 34 | ) 35 | 36 | // SchemeGroupVersion is group version used to register these objects 37 | var SchemeGroupVersion = schema.GroupVersion{Group: terraformcontroller.GroupName, Version: "v1"} 38 | 39 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind 40 | func Kind(kind string) schema.GroupKind { 41 | return SchemeGroupVersion.WithKind(kind).GroupKind() 42 | } 43 | 44 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 45 | func Resource(resource string) schema.GroupResource { 46 | return SchemeGroupVersion.WithResource(resource).GroupResource() 47 | } 48 | 49 | var ( 50 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 51 | AddToScheme = SchemeBuilder.AddToScheme 52 | ) 53 | 54 | // Adds the list of known types to Scheme. 55 | func addKnownTypes(scheme *runtime.Scheme) error { 56 | scheme.AddKnownTypes(SchemeGroupVersion, 57 | &Execution{}, 58 | &ExecutionList{}, 59 | &Module{}, 60 | &ModuleList{}, 61 | &State{}, 62 | &StateList{}, 63 | ) 64 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /pkg/apis/terraformcontroller.cattle.io/zz_generated_register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package terraformcontroller 20 | 21 | const ( 22 | // Package-wide consts from generator "zz_generated_register". 23 | GroupName = "terraformcontroller.cattle.io" 24 | ) 25 | -------------------------------------------------------------------------------- /pkg/cli/cmds/common.go: -------------------------------------------------------------------------------- 1 | package cmds 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/rancher/terraform-controller/pkg/generated/controllers/terraformcontroller.cattle.io" 7 | v1 "github.com/rancher/terraform-controller/pkg/generated/controllers/terraformcontroller.cattle.io/v1" 8 | "github.com/rancher/wrangler/pkg/generated/controllers/batch" 9 | batchv1 "github.com/rancher/wrangler/pkg/generated/controllers/batch/v1" 10 | "github.com/rancher/wrangler/pkg/generated/controllers/core" 11 | corev1 "github.com/rancher/wrangler/pkg/generated/controllers/core/v1" 12 | "github.com/rancher/wrangler/pkg/resolvehome" 13 | "github.com/rancher/wrangler/pkg/signals" 14 | "github.com/rancher/wrangler/pkg/start" 15 | "github.com/sirupsen/logrus" 16 | "k8s.io/client-go/tools/clientcmd" 17 | ) 18 | 19 | type controllers struct { 20 | modules v1.ModuleController 21 | states v1.StateController 22 | executions v1.ExecutionController 23 | configMaps corev1.ConfigMapController 24 | secrets corev1.SecretController 25 | jobs batchv1.JobController 26 | } 27 | 28 | const ( 29 | terraState = "tfstate" 30 | terraKey = "tfstateSecretSuffix" 31 | ) 32 | 33 | var controllerCache *controllers 34 | 35 | func getControllers(kc, ns string) (*controllers, error) { 36 | if controllerCache != nil { 37 | return controllerCache, nil 38 | } 39 | 40 | kubeconfig, err := resolvehome.Resolve(kc) 41 | 42 | if err != nil { 43 | kubeconfig = kc 44 | } 45 | 46 | cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) 47 | if err != nil { 48 | logrus.Fatalf("Error building kubeconfig: %s", err.Error()) 49 | } 50 | 51 | tfFactory, err := terraformcontroller.NewFactoryFromConfigWithNamespace(cfg, ns) 52 | if err != nil { 53 | logrus.Fatalf("Error building terraform controllers: %s", err.Error()) 54 | } 55 | 56 | coreFactory, err := core.NewFactoryFromConfigWithNamespace(cfg, ns) 57 | if err != nil { 58 | logrus.Fatalf("Error building core controllers: %s", err.Error()) 59 | } 60 | 61 | batchFactory, err := batch.NewFactoryFromConfigWithNamespace(cfg, ns) 62 | if err != nil { 63 | logrus.Fatalf("Error building batch controllers: %s", err.Error()) 64 | } 65 | 66 | controllers := &controllers{ 67 | modules: tfFactory.Terraformcontroller().V1().Module(), 68 | states: tfFactory.Terraformcontroller().V1().State(), 69 | executions: tfFactory.Terraformcontroller().V1().Execution(), 70 | configMaps: coreFactory.Core().V1().ConfigMap(), 71 | secrets: coreFactory.Core().V1().Secret(), 72 | jobs: batchFactory.Batch().V1().Job(), 73 | } 74 | 75 | controllerCache = controllers 76 | 77 | ctx := signals.SetupSignalHandler(context.Background()) 78 | if err := start.All(ctx, 1, tfFactory, coreFactory, batchFactory); err != nil { 79 | logrus.Fatalf("Error starting: %s", err.Error()) 80 | } 81 | 82 | return controllers, nil 83 | } 84 | -------------------------------------------------------------------------------- /pkg/cli/cmds/modules.go: -------------------------------------------------------------------------------- 1 | package cmds 2 | 3 | import ( 4 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 5 | "github.com/urfave/cli" 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | ) 8 | 9 | var simpleModuleTableHeader = []string{"NAME", "GIT REPO"} 10 | 11 | type InvalidArgs struct{} 12 | 13 | func (e InvalidArgs) Error() string { 14 | return "Invalid args" 15 | } 16 | 17 | func ModuleCommand() cli.Command { 18 | return cli.Command{ 19 | Name: "modules", 20 | Aliases: []string{"module", "m"}, 21 | Usage: "Manage modules", 22 | Action: moduleList, 23 | Subcommands: []cli.Command{ 24 | { 25 | Name: "ls", 26 | Usage: "List Modules", 27 | ArgsUsage: "None", 28 | Action: moduleList, 29 | }, 30 | { 31 | Name: "create", 32 | Usage: "Create new module", 33 | ArgsUsage: "[NAME] [GIT URL]", 34 | Action: createModule, 35 | }, 36 | { 37 | Name: "delete", 38 | Usage: "Create new module", 39 | ArgsUsage: "[NAME]", 40 | Action: deleteModule, 41 | }, 42 | { 43 | Name: "update", 44 | Usage: "Force the handler to update the git content.", 45 | ArgsUsage: "[NAME]", 46 | Action: updateModule, 47 | }, 48 | }, 49 | } 50 | } 51 | 52 | func updateModule(c *cli.Context) error { 53 | kubeConfig := c.GlobalString("kubeconfig") 54 | namespace := c.GlobalString("namespace") 55 | 56 | controllers, err := getControllers(kubeConfig, namespace) 57 | if err != nil { 58 | return err 59 | } 60 | 61 | args := c.Args() 62 | if len(args) != 1 { 63 | return InvalidArgs{} 64 | } 65 | 66 | moduleName := c.Args()[0] 67 | 68 | module, err := controllers.modules.Get(namespace, moduleName, metav1.GetOptions{}) 69 | if err != nil { 70 | return err 71 | } 72 | 73 | v1.ModuleConditionGitUpdated.False(module) 74 | _, err = controllers.modules.Update(module) 75 | return err 76 | } 77 | func moduleList(c *cli.Context) error { 78 | kubeConfig := c.GlobalString("kubeconfig") 79 | namespace := c.GlobalString("namespace") 80 | 81 | modules, err := getModuleList(namespace, kubeConfig) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | NewTableWriter(getSimpleModuleTableHeader(), moduleListToTableStrings(modules)).Write() 87 | 88 | return nil 89 | } 90 | 91 | func createModule(c *cli.Context) error { 92 | kubeConfig := c.GlobalString("kubeconfig") 93 | namespace := c.GlobalString("namespace") 94 | 95 | if len(c.Args()) != 2 { 96 | return InvalidArgs{} 97 | } 98 | 99 | moduleName := c.Args()[0] 100 | gitURL := c.Args()[1] 101 | 102 | return doModuleCreate(namespace, kubeConfig, moduleName, gitURL) 103 | } 104 | 105 | func deleteModule(c *cli.Context) error { 106 | kubeConfig := c.GlobalString("kubeconfig") 107 | namespace := c.GlobalString("namespace") 108 | 109 | if len(c.Args()) != 1 { 110 | return InvalidArgs{} 111 | } 112 | 113 | moduleName := c.Args()[0] 114 | 115 | return doModuleDelete(namespace, kubeConfig, moduleName) 116 | } 117 | 118 | func getModuleList(namespace, kubeConfig string) (*v1.ModuleList, error) { 119 | controllers, err := getControllers(kubeConfig, namespace) 120 | if err != nil { 121 | return nil, err 122 | } 123 | return controllers.modules.List(namespace, metav1.ListOptions{}) 124 | 125 | } 126 | 127 | func doModuleCreate(namespace, kubeConfig, name, url string) error { 128 | controllers, err := getControllers(kubeConfig, namespace) 129 | if err != nil { 130 | return err 131 | } 132 | 133 | module := &v1.Module{ 134 | Spec: v1.ModuleSpec{ 135 | ModuleContent: v1.ModuleContent{ 136 | Git: v1.GitLocation{ 137 | URL: url, 138 | }, 139 | }, 140 | }, 141 | } 142 | 143 | module.Namespace = namespace 144 | module.Name = name 145 | 146 | _, err = controllers.modules.Create(module) 147 | return err 148 | } 149 | 150 | func doModuleDelete(namespace, kubeConfig, name string) error { 151 | controllers, err := getControllers(kubeConfig, namespace) 152 | if err != nil { 153 | return err 154 | } 155 | 156 | return controllers.modules.Delete(namespace, name, &metav1.DeleteOptions{}) 157 | } 158 | 159 | func getSimpleModuleTableHeader() []string { 160 | return simpleModuleTableHeader 161 | } 162 | 163 | func moduleListToTableStrings(modules *v1.ModuleList) [][]string { 164 | var values [][]string 165 | 166 | for _, module := range modules.Items { 167 | values = append(values, []string{ 168 | module.Name, 169 | module.Spec.Git.URL, 170 | }) 171 | } 172 | 173 | return values 174 | } 175 | -------------------------------------------------------------------------------- /pkg/cli/cmds/writer.go: -------------------------------------------------------------------------------- 1 | package cmds 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "text/tabwriter" 8 | ) 9 | 10 | type TableWriter struct { 11 | Writer *tabwriter.Writer 12 | Header []string 13 | Values [][]string 14 | } 15 | 16 | func NewTableWriter(header []string, values [][]string) *TableWriter { 17 | return &TableWriter{ 18 | Writer: tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0), 19 | Header: header, 20 | Values: values, 21 | } 22 | } 23 | 24 | func (tw *TableWriter) Write() { 25 | fmt.Fprint(tw.Writer, stringListToTabDelimString(tw.Header)) 26 | for _, value := range tw.Values { 27 | fmt.Fprint(tw.Writer, stringListToTabDelimString(value)) 28 | } 29 | 30 | tw.Writer.Flush() 31 | } 32 | 33 | func stringListToTabDelimString(values []string) string { 34 | buffer := bytes.Buffer{} 35 | 36 | for _, v := range values { 37 | appendTabDelim(&buffer, v) 38 | } 39 | 40 | buffer.WriteString("\n") 41 | 42 | return buffer.String() 43 | } 44 | 45 | func appendTabDelim(buf *bytes.Buffer, value string) { 46 | if buf.Len() == 0 { 47 | buf.WriteString(value) 48 | } else { 49 | buf.WriteString("\t") 50 | buf.WriteString(value) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pkg/cli/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/rancher/terraform-controller/pkg/cli/cmds" 8 | "github.com/sirupsen/logrus" 9 | "github.com/urfave/cli" 10 | ) 11 | 12 | var ( 13 | VERSION = "v0.0.0-dev" 14 | ) 15 | 16 | func main() { 17 | app := cli.NewApp() 18 | app.Name = "tffy" 19 | app.Version = VERSION 20 | app.Action = cli.ShowCommandHelp 21 | app.HideHelp = false 22 | app.CommandNotFound = func(c *cli.Context, command string) { 23 | fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command) 24 | } 25 | app.Flags = []cli.Flag{ 26 | cli.StringFlag{ 27 | Name: "kubeconfig, k", 28 | EnvVar: "KUBECONFIG", 29 | Value: "${HOME}/.kube/config", 30 | }, 31 | cli.StringFlag{ 32 | Name: "namespace, n", 33 | EnvVar: "NAMESPACE", 34 | Value: "default", 35 | }, 36 | } 37 | 38 | app.Commands = []cli.Command{ 39 | cmds.ModuleCommand(), 40 | cmds.StateCommand(), 41 | cmds.ExecutionCommand(), 42 | } 43 | app.Action = run 44 | 45 | if err := app.Run(os.Args); err != nil { 46 | logrus.Fatal(err) 47 | } 48 | } 49 | 50 | func run(c *cli.Context) error { 51 | err := cli.ShowAppHelp(c) 52 | if err != nil { 53 | return err 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/codegen/cleanup/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/rancher/wrangler/pkg/cleanup" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | func main() { 9 | if err := cleanup.Cleanup("./pkg/apis"); err != nil { 10 | logrus.Fatal(err) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pkg/codegen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 5 | controllergen "github.com/rancher/wrangler/pkg/controller-gen" 6 | "github.com/rancher/wrangler/pkg/controller-gen/args" 7 | ) 8 | 9 | func main() { 10 | controllergen.Run(args.Options{ 11 | OutputPackage: "github.com/rancher/terraform-controller/pkg/generated", 12 | Boilerplate: "hack/boilerplate.go.txt", 13 | Groups: map[string]args.Group{ 14 | "terraformcontroller.cattle.io": { 15 | Types: []interface{}{ 16 | v1.Module{}, 17 | v1.State{}, 18 | v1.Execution{}, 19 | }, 20 | GenerateTypes: true, 21 | }, 22 | }, 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/digest/digest.go: -------------------------------------------------------------------------------- 1 | package digest 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/hex" 6 | "sort" 7 | 8 | "github.com/sirupsen/logrus" 9 | ) 10 | 11 | func SHA256Map(data map[string]string) string { 12 | var ( 13 | keys []string 14 | digest = sha256.New() 15 | ) 16 | 17 | if len(data) == 0 { 18 | return "" 19 | } 20 | 21 | for k := range data { 22 | keys = append(keys, k) 23 | } 24 | 25 | sort.Strings(keys) 26 | 27 | for _, key := range keys { 28 | if _, err := digest.Write([]byte(key)); err != nil { 29 | logrus.Error("Failed to write to digest") 30 | } 31 | 32 | if _, err := digest.Write([]byte(data[key])); err != nil { 33 | logrus.Error("Failed to write to digest") 34 | } 35 | } 36 | 37 | return hex.EncodeToString(digest.Sum(nil)) 38 | } 39 | -------------------------------------------------------------------------------- /pkg/executor/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "log" 8 | "os" 9 | 10 | "github.com/rancher/terraform-controller/pkg/executor/runner" 11 | "github.com/rancher/terraform-controller/pkg/git" 12 | "github.com/sirupsen/logrus" 13 | "k8s.io/client-go/rest" 14 | "k8s.io/client-go/tools/clientcmd" 15 | ) 16 | 17 | func main() { 18 | if os.Getenv("EXECUTOR_DEBUG") == "true" { 19 | logrus.SetLevel(logrus.DebugLevel) 20 | } 21 | 22 | err := run() 23 | 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | } 28 | 29 | func run() error { 30 | var config *rest.Config 31 | var err error 32 | 33 | // Useful for running executor locally without having to deploy to k8s 34 | if path := os.Getenv("KUBECONFIG"); path != "" { 35 | logrus.Info(path) 36 | 37 | config, err = clientcmd.BuildConfigFromFlags("", path) 38 | if err != nil { 39 | return err 40 | } 41 | } else { 42 | config, err = rest.InClusterConfig() 43 | if err != nil { 44 | return err 45 | } 46 | } 47 | 48 | runner, err := runner.NewRunner(config) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | err = runner.Populate() 54 | if err != nil { 55 | return err 56 | } 57 | 58 | logrus.Info("before clone") 59 | err = git.CloneRepo(context.Background(), runner.Execution.Spec.Content.Git.URL, runner.Execution.Spec.Content.Git.Commit, runner.GitAuth) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | logrus.Info("before config") 65 | 66 | err = runner.WriteConfigFile() 67 | if err != nil { 68 | return err 69 | } 70 | 71 | err = runner.WriteVarFile() 72 | if err != nil { 73 | return err 74 | } 75 | 76 | out, err := runner.TerraformInit() 77 | if err != nil { 78 | return err 79 | } 80 | 81 | fmt.Print(out) 82 | 83 | switch runner.Action { 84 | case "create": 85 | out, err = runner.Create() 86 | if err != nil { 87 | return err 88 | } 89 | 90 | err = runner.SetExecutionLogs(out) 91 | if err != nil { 92 | return err 93 | } 94 | 95 | err = runner.SetExecutionRunStatus("applied") 96 | if err != nil { 97 | return err 98 | } 99 | 100 | err = runner.SaveOutputs() 101 | if err != nil { 102 | return err 103 | } 104 | case "destroy": 105 | out, err = runner.Destroy() 106 | if err != nil { 107 | return err 108 | } 109 | 110 | err = runner.SetExecutionLogs(out) 111 | if err != nil { 112 | return err 113 | } 114 | 115 | err = runner.SetExecutionRunStatus("applied") 116 | if err != nil { 117 | return err 118 | } 119 | 120 | default: 121 | return errors.New("action is not valid, ony 'create' or 'destroy' allowed") 122 | } 123 | 124 | return runner.DeleteJob() 125 | } 126 | -------------------------------------------------------------------------------- /pkg/executor/runner/backend.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | type Config struct { 4 | Terraform `json:"terraform,omitempty"` 5 | } 6 | 7 | type Terraform struct { 8 | Backend map[string]*Backend `json:"backend,omitempty"` 9 | } 10 | 11 | type Backend struct { 12 | Namespace string `json:"namespace,omitempty"` 13 | SecretSuffix string `json:"secret_suffix,omitempty"` 14 | InClusterConfig string `json:"in_cluster_config,omitempty"` 15 | } 16 | -------------------------------------------------------------------------------- /pkg/executor/terraform/cmd.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | "fmt" 8 | "os" 9 | "os/exec" 10 | 11 | "github.com/pkg/errors" 12 | ) 13 | 14 | func terraform(ctx context.Context, env []string, args ...string) ([]string, error) { 15 | cmd := exec.CommandContext(ctx, "terraform", args...) 16 | cmd.Env = append(os.Environ(), env...) 17 | 18 | var ( 19 | out bytes.Buffer 20 | errOut bytes.Buffer 21 | ) 22 | cmd.Stdout = &out 23 | cmd.Stderr = &errOut 24 | err := cmd.Run() 25 | if err != nil { 26 | return nil, errors.Wrap(err, errOut.String()) 27 | } 28 | 29 | var output []string 30 | s := bufio.NewScanner(&out) 31 | for s.Scan() { 32 | line := s.Text() 33 | fmt.Println(line) 34 | output = append(output, line) 35 | } 36 | 37 | return output, s.Err() 38 | } 39 | -------------------------------------------------------------------------------- /pkg/executor/terraform/terraform.go: -------------------------------------------------------------------------------- 1 | // Package terraform to run terraform commands 2 | package terraform 3 | 4 | import ( 5 | "context" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | const newLine = "\n" 11 | 12 | func Apply() (string, error) { 13 | output, err := terraform(context.Background(), os.Environ(), "apply", "-input=false", "-auto-approve", "tfplan") 14 | if err != nil { 15 | return "", err 16 | } 17 | 18 | return combineOutput(output), nil 19 | } 20 | 21 | func Destroy() (string, error) { 22 | output, err := terraform(context.Background(), os.Environ(), "destroy", "-input=false", "-auto-approve") 23 | if err != nil { 24 | return "", err 25 | } 26 | 27 | return combineOutput(output), nil 28 | } 29 | 30 | func Init() (string, error) { 31 | output, err := terraform(context.Background(), os.Environ(), "init", "-input=false") 32 | if err != nil { 33 | return "", err 34 | } 35 | 36 | return combineOutput(output), nil 37 | } 38 | 39 | // Output runs 'terraform output -json' and returns the blob as a string 40 | func Output() (string, error) { 41 | output, err := terraform(context.Background(), os.Environ(), "output", "-json") 42 | if err != nil { 43 | return "", err 44 | } 45 | 46 | return combineOutput(output), nil 47 | } 48 | 49 | // Plan runs 'terraform plan' with the destroy flag controlling the play type 50 | func Plan(destroy bool) (string, error) { 51 | args := []string{"plan", "-input=false", "-out=tfplan"} 52 | if destroy { 53 | args = append(args, "-destroy") 54 | } 55 | 56 | output, err := terraform(context.Background(), os.Environ(), args...) 57 | if err != nil { 58 | return "", err 59 | } 60 | 61 | return combineOutput(output), nil 62 | } 63 | 64 | func combineOutput(in []string) string { 65 | var b strings.Builder 66 | for _, v := range in { 67 | b.WriteString(v) 68 | b.WriteString(newLine) 69 | } 70 | return b.String() 71 | } 72 | -------------------------------------------------------------------------------- /pkg/executor/writer/writer.go: -------------------------------------------------------------------------------- 1 | package writer 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | // Write files to disk at the specified path 8 | func Write(contents []byte, path string) error { 9 | file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) 10 | if err != nil { 11 | return err 12 | } 13 | 14 | defer file.Close() 15 | 16 | _, err = file.Write(contents) 17 | 18 | return err 19 | } 20 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/clientset.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package versioned 20 | 21 | import ( 22 | "fmt" 23 | 24 | terraformcontrollerv1 "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1" 25 | discovery "k8s.io/client-go/discovery" 26 | rest "k8s.io/client-go/rest" 27 | flowcontrol "k8s.io/client-go/util/flowcontrol" 28 | ) 29 | 30 | type Interface interface { 31 | Discovery() discovery.DiscoveryInterface 32 | TerraformcontrollerV1() terraformcontrollerv1.TerraformcontrollerV1Interface 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 | terraformcontrollerV1 *terraformcontrollerv1.TerraformcontrollerV1Client 40 | } 41 | 42 | // TerraformcontrollerV1 retrieves the TerraformcontrollerV1Client 43 | func (c *Clientset) TerraformcontrollerV1() terraformcontrollerv1.TerraformcontrollerV1Interface { 44 | return c.terraformcontrollerV1 45 | } 46 | 47 | // Discovery retrieves the DiscoveryClient 48 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 49 | if c == nil { 50 | return nil 51 | } 52 | return c.DiscoveryClient 53 | } 54 | 55 | // NewForConfig creates a new Clientset for the given config. 56 | // If config's RateLimiter is not set and QPS and Burst are acceptable, 57 | // NewForConfig will generate a rate-limiter in configShallowCopy. 58 | func NewForConfig(c *rest.Config) (*Clientset, error) { 59 | configShallowCopy := *c 60 | if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { 61 | if configShallowCopy.Burst <= 0 { 62 | return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") 63 | } 64 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) 65 | } 66 | var cs Clientset 67 | var err error 68 | cs.terraformcontrollerV1, err = terraformcontrollerv1.NewForConfig(&configShallowCopy) 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) 74 | if err != nil { 75 | return nil, err 76 | } 77 | return &cs, nil 78 | } 79 | 80 | // NewForConfigOrDie creates a new Clientset for the given config and 81 | // panics if there is an error in the config. 82 | func NewForConfigOrDie(c *rest.Config) *Clientset { 83 | var cs Clientset 84 | cs.terraformcontrollerV1 = terraformcontrollerv1.NewForConfigOrDie(c) 85 | 86 | cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) 87 | return &cs 88 | } 89 | 90 | // New creates a new Clientset for the given RESTClient. 91 | func New(c rest.Interface) *Clientset { 92 | var cs Clientset 93 | cs.terraformcontrollerV1 = terraformcontrollerv1.New(c) 94 | 95 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c) 96 | return &cs 97 | } 98 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | // This package has the automatically generated clientset. 20 | package versioned 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/fake/clientset_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | clientset "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned" 23 | terraformcontrollerv1 "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1" 24 | faketerraformcontrollerv1 "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/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{tracker: o} 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 | tracker testing.ObjectTracker 67 | } 68 | 69 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 70 | return c.discovery 71 | } 72 | 73 | func (c *Clientset) Tracker() testing.ObjectTracker { 74 | return c.tracker 75 | } 76 | 77 | var _ clientset.Interface = &Clientset{} 78 | 79 | // TerraformcontrollerV1 retrieves the TerraformcontrollerV1Client 80 | func (c *Clientset) TerraformcontrollerV1() terraformcontrollerv1.TerraformcontrollerV1Interface { 81 | return &faketerraformcontrollerv1.FakeTerraformcontrollerV1{Fake: &c.Fake} 82 | } 83 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | // This package has the automatically generated fake clientset. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/fake/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | terraformcontrollerv1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 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 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 28 | ) 29 | 30 | var scheme = runtime.NewScheme() 31 | var codecs = serializer.NewCodecFactory(scheme) 32 | var parameterCodec = runtime.NewParameterCodec(scheme) 33 | var localSchemeBuilder = runtime.SchemeBuilder{ 34 | terraformcontrollerv1.AddToScheme, 35 | } 36 | 37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 38 | // of clientsets, like in: 39 | // 40 | // import ( 41 | // "k8s.io/client-go/kubernetes" 42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 44 | // ) 45 | // 46 | // kclientset, _ := kubernetes.NewForConfig(c) 47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 48 | // 49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 50 | // correctly. 51 | var AddToScheme = localSchemeBuilder.AddToScheme 52 | 53 | func init() { 54 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) 55 | utilruntime.Must(AddToScheme(scheme)) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | // This package contains the scheme of the automatically generated clientset. 20 | package scheme 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/scheme/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package scheme 20 | 21 | import ( 22 | terraformcontrollerv1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 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 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 28 | ) 29 | 30 | var Scheme = runtime.NewScheme() 31 | var Codecs = serializer.NewCodecFactory(Scheme) 32 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 33 | var localSchemeBuilder = runtime.SchemeBuilder{ 34 | terraformcontrollerv1.AddToScheme, 35 | } 36 | 37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 38 | // of clientsets, like in: 39 | // 40 | // import ( 41 | // "k8s.io/client-go/kubernetes" 42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 44 | // ) 45 | // 46 | // kclientset, _ := kubernetes.NewForConfig(c) 47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 48 | // 49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 50 | // correctly. 51 | var AddToScheme = localSchemeBuilder.AddToScheme 52 | 53 | func init() { 54 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 55 | utilruntime.Must(AddToScheme(Scheme)) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v1 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/execution.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | "context" 23 | "time" 24 | 25 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 26 | scheme "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/scheme" 27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 | types "k8s.io/apimachinery/pkg/types" 29 | watch "k8s.io/apimachinery/pkg/watch" 30 | rest "k8s.io/client-go/rest" 31 | ) 32 | 33 | // ExecutionsGetter has a method to return a ExecutionInterface. 34 | // A group's client should implement this interface. 35 | type ExecutionsGetter interface { 36 | Executions(namespace string) ExecutionInterface 37 | } 38 | 39 | // ExecutionInterface has methods to work with Execution resources. 40 | type ExecutionInterface interface { 41 | Create(ctx context.Context, execution *v1.Execution, opts metav1.CreateOptions) (*v1.Execution, error) 42 | Update(ctx context.Context, execution *v1.Execution, opts metav1.UpdateOptions) (*v1.Execution, error) 43 | UpdateStatus(ctx context.Context, execution *v1.Execution, opts metav1.UpdateOptions) (*v1.Execution, error) 44 | Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error 45 | DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error 46 | Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Execution, error) 47 | List(ctx context.Context, opts metav1.ListOptions) (*v1.ExecutionList, error) 48 | Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) 49 | Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Execution, err error) 50 | ExecutionExpansion 51 | } 52 | 53 | // executions implements ExecutionInterface 54 | type executions struct { 55 | client rest.Interface 56 | ns string 57 | } 58 | 59 | // newExecutions returns a Executions 60 | func newExecutions(c *TerraformcontrollerV1Client, namespace string) *executions { 61 | return &executions{ 62 | client: c.RESTClient(), 63 | ns: namespace, 64 | } 65 | } 66 | 67 | // Get takes name of the execution, and returns the corresponding execution object, and an error if there is any. 68 | func (c *executions) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Execution, err error) { 69 | result = &v1.Execution{} 70 | err = c.client.Get(). 71 | Namespace(c.ns). 72 | Resource("executions"). 73 | Name(name). 74 | VersionedParams(&options, scheme.ParameterCodec). 75 | Do(ctx). 76 | Into(result) 77 | return 78 | } 79 | 80 | // List takes label and field selectors, and returns the list of Executions that match those selectors. 81 | func (c *executions) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ExecutionList, err error) { 82 | var timeout time.Duration 83 | if opts.TimeoutSeconds != nil { 84 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 85 | } 86 | result = &v1.ExecutionList{} 87 | err = c.client.Get(). 88 | Namespace(c.ns). 89 | Resource("executions"). 90 | VersionedParams(&opts, scheme.ParameterCodec). 91 | Timeout(timeout). 92 | Do(ctx). 93 | Into(result) 94 | return 95 | } 96 | 97 | // Watch returns a watch.Interface that watches the requested executions. 98 | func (c *executions) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { 99 | var timeout time.Duration 100 | if opts.TimeoutSeconds != nil { 101 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 102 | } 103 | opts.Watch = true 104 | return c.client.Get(). 105 | Namespace(c.ns). 106 | Resource("executions"). 107 | VersionedParams(&opts, scheme.ParameterCodec). 108 | Timeout(timeout). 109 | Watch(ctx) 110 | } 111 | 112 | // Create takes the representation of a execution and creates it. Returns the server's representation of the execution, and an error, if there is any. 113 | func (c *executions) Create(ctx context.Context, execution *v1.Execution, opts metav1.CreateOptions) (result *v1.Execution, err error) { 114 | result = &v1.Execution{} 115 | err = c.client.Post(). 116 | Namespace(c.ns). 117 | Resource("executions"). 118 | VersionedParams(&opts, scheme.ParameterCodec). 119 | Body(execution). 120 | Do(ctx). 121 | Into(result) 122 | return 123 | } 124 | 125 | // Update takes the representation of a execution and updates it. Returns the server's representation of the execution, and an error, if there is any. 126 | func (c *executions) Update(ctx context.Context, execution *v1.Execution, opts metav1.UpdateOptions) (result *v1.Execution, err error) { 127 | result = &v1.Execution{} 128 | err = c.client.Put(). 129 | Namespace(c.ns). 130 | Resource("executions"). 131 | Name(execution.Name). 132 | VersionedParams(&opts, scheme.ParameterCodec). 133 | Body(execution). 134 | Do(ctx). 135 | Into(result) 136 | return 137 | } 138 | 139 | // UpdateStatus was generated because the type contains a Status member. 140 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 141 | func (c *executions) UpdateStatus(ctx context.Context, execution *v1.Execution, opts metav1.UpdateOptions) (result *v1.Execution, err error) { 142 | result = &v1.Execution{} 143 | err = c.client.Put(). 144 | Namespace(c.ns). 145 | Resource("executions"). 146 | Name(execution.Name). 147 | SubResource("status"). 148 | VersionedParams(&opts, scheme.ParameterCodec). 149 | Body(execution). 150 | Do(ctx). 151 | Into(result) 152 | return 153 | } 154 | 155 | // Delete takes name of the execution and deletes it. Returns an error if one occurs. 156 | func (c *executions) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { 157 | return c.client.Delete(). 158 | Namespace(c.ns). 159 | Resource("executions"). 160 | Name(name). 161 | Body(&opts). 162 | Do(ctx). 163 | Error() 164 | } 165 | 166 | // DeleteCollection deletes a collection of objects. 167 | func (c *executions) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { 168 | var timeout time.Duration 169 | if listOpts.TimeoutSeconds != nil { 170 | timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second 171 | } 172 | return c.client.Delete(). 173 | Namespace(c.ns). 174 | Resource("executions"). 175 | VersionedParams(&listOpts, scheme.ParameterCodec). 176 | Timeout(timeout). 177 | Body(&opts). 178 | Do(ctx). 179 | Error() 180 | } 181 | 182 | // Patch applies the patch and returns the patched execution. 183 | func (c *executions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Execution, err error) { 184 | result = &v1.Execution{} 185 | err = c.client.Patch(pt). 186 | Namespace(c.ns). 187 | Resource("executions"). 188 | Name(name). 189 | SubResource(subresources...). 190 | VersionedParams(&opts, scheme.ParameterCodec). 191 | Body(data). 192 | Do(ctx). 193 | Into(result) 194 | return 195 | } 196 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/fake/fake_execution.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | "context" 23 | 24 | terraformcontrollercattleiov1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | labels "k8s.io/apimachinery/pkg/labels" 27 | schema "k8s.io/apimachinery/pkg/runtime/schema" 28 | types "k8s.io/apimachinery/pkg/types" 29 | watch "k8s.io/apimachinery/pkg/watch" 30 | testing "k8s.io/client-go/testing" 31 | ) 32 | 33 | // FakeExecutions implements ExecutionInterface 34 | type FakeExecutions struct { 35 | Fake *FakeTerraformcontrollerV1 36 | ns string 37 | } 38 | 39 | var executionsResource = schema.GroupVersionResource{Group: "terraformcontroller.cattle.io", Version: "v1", Resource: "executions"} 40 | 41 | var executionsKind = schema.GroupVersionKind{Group: "terraformcontroller.cattle.io", Version: "v1", Kind: "Execution"} 42 | 43 | // Get takes name of the execution, and returns the corresponding execution object, and an error if there is any. 44 | func (c *FakeExecutions) Get(ctx context.Context, name string, options v1.GetOptions) (result *terraformcontrollercattleiov1.Execution, err error) { 45 | obj, err := c.Fake. 46 | Invokes(testing.NewGetAction(executionsResource, c.ns, name), &terraformcontrollercattleiov1.Execution{}) 47 | 48 | if obj == nil { 49 | return nil, err 50 | } 51 | return obj.(*terraformcontrollercattleiov1.Execution), err 52 | } 53 | 54 | // List takes label and field selectors, and returns the list of Executions that match those selectors. 55 | func (c *FakeExecutions) List(ctx context.Context, opts v1.ListOptions) (result *terraformcontrollercattleiov1.ExecutionList, err error) { 56 | obj, err := c.Fake. 57 | Invokes(testing.NewListAction(executionsResource, executionsKind, c.ns, opts), &terraformcontrollercattleiov1.ExecutionList{}) 58 | 59 | if obj == nil { 60 | return nil, err 61 | } 62 | 63 | label, _, _ := testing.ExtractFromListOptions(opts) 64 | if label == nil { 65 | label = labels.Everything() 66 | } 67 | list := &terraformcontrollercattleiov1.ExecutionList{ListMeta: obj.(*terraformcontrollercattleiov1.ExecutionList).ListMeta} 68 | for _, item := range obj.(*terraformcontrollercattleiov1.ExecutionList).Items { 69 | if label.Matches(labels.Set(item.Labels)) { 70 | list.Items = append(list.Items, item) 71 | } 72 | } 73 | return list, err 74 | } 75 | 76 | // Watch returns a watch.Interface that watches the requested executions. 77 | func (c *FakeExecutions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { 78 | return c.Fake. 79 | InvokesWatch(testing.NewWatchAction(executionsResource, c.ns, opts)) 80 | 81 | } 82 | 83 | // Create takes the representation of a execution and creates it. Returns the server's representation of the execution, and an error, if there is any. 84 | func (c *FakeExecutions) Create(ctx context.Context, execution *terraformcontrollercattleiov1.Execution, opts v1.CreateOptions) (result *terraformcontrollercattleiov1.Execution, err error) { 85 | obj, err := c.Fake. 86 | Invokes(testing.NewCreateAction(executionsResource, c.ns, execution), &terraformcontrollercattleiov1.Execution{}) 87 | 88 | if obj == nil { 89 | return nil, err 90 | } 91 | return obj.(*terraformcontrollercattleiov1.Execution), err 92 | } 93 | 94 | // Update takes the representation of a execution and updates it. Returns the server's representation of the execution, and an error, if there is any. 95 | func (c *FakeExecutions) Update(ctx context.Context, execution *terraformcontrollercattleiov1.Execution, opts v1.UpdateOptions) (result *terraformcontrollercattleiov1.Execution, err error) { 96 | obj, err := c.Fake. 97 | Invokes(testing.NewUpdateAction(executionsResource, c.ns, execution), &terraformcontrollercattleiov1.Execution{}) 98 | 99 | if obj == nil { 100 | return nil, err 101 | } 102 | return obj.(*terraformcontrollercattleiov1.Execution), err 103 | } 104 | 105 | // UpdateStatus was generated because the type contains a Status member. 106 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 107 | func (c *FakeExecutions) UpdateStatus(ctx context.Context, execution *terraformcontrollercattleiov1.Execution, opts v1.UpdateOptions) (*terraformcontrollercattleiov1.Execution, error) { 108 | obj, err := c.Fake. 109 | Invokes(testing.NewUpdateSubresourceAction(executionsResource, "status", c.ns, execution), &terraformcontrollercattleiov1.Execution{}) 110 | 111 | if obj == nil { 112 | return nil, err 113 | } 114 | return obj.(*terraformcontrollercattleiov1.Execution), err 115 | } 116 | 117 | // Delete takes name of the execution and deletes it. Returns an error if one occurs. 118 | func (c *FakeExecutions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { 119 | _, err := c.Fake. 120 | Invokes(testing.NewDeleteAction(executionsResource, c.ns, name), &terraformcontrollercattleiov1.Execution{}) 121 | 122 | return err 123 | } 124 | 125 | // DeleteCollection deletes a collection of objects. 126 | func (c *FakeExecutions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { 127 | action := testing.NewDeleteCollectionAction(executionsResource, c.ns, listOpts) 128 | 129 | _, err := c.Fake.Invokes(action, &terraformcontrollercattleiov1.ExecutionList{}) 130 | return err 131 | } 132 | 133 | // Patch applies the patch and returns the patched execution. 134 | func (c *FakeExecutions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *terraformcontrollercattleiov1.Execution, err error) { 135 | obj, err := c.Fake. 136 | Invokes(testing.NewPatchSubresourceAction(executionsResource, c.ns, name, pt, data, subresources...), &terraformcontrollercattleiov1.Execution{}) 137 | 138 | if obj == nil { 139 | return nil, err 140 | } 141 | return obj.(*terraformcontrollercattleiov1.Execution), err 142 | } 143 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/fake/fake_module.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | "context" 23 | 24 | terraformcontrollercattleiov1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | labels "k8s.io/apimachinery/pkg/labels" 27 | schema "k8s.io/apimachinery/pkg/runtime/schema" 28 | types "k8s.io/apimachinery/pkg/types" 29 | watch "k8s.io/apimachinery/pkg/watch" 30 | testing "k8s.io/client-go/testing" 31 | ) 32 | 33 | // FakeModules implements ModuleInterface 34 | type FakeModules struct { 35 | Fake *FakeTerraformcontrollerV1 36 | ns string 37 | } 38 | 39 | var modulesResource = schema.GroupVersionResource{Group: "terraformcontroller.cattle.io", Version: "v1", Resource: "modules"} 40 | 41 | var modulesKind = schema.GroupVersionKind{Group: "terraformcontroller.cattle.io", Version: "v1", Kind: "Module"} 42 | 43 | // Get takes name of the module, and returns the corresponding module object, and an error if there is any. 44 | func (c *FakeModules) Get(ctx context.Context, name string, options v1.GetOptions) (result *terraformcontrollercattleiov1.Module, err error) { 45 | obj, err := c.Fake. 46 | Invokes(testing.NewGetAction(modulesResource, c.ns, name), &terraformcontrollercattleiov1.Module{}) 47 | 48 | if obj == nil { 49 | return nil, err 50 | } 51 | return obj.(*terraformcontrollercattleiov1.Module), err 52 | } 53 | 54 | // List takes label and field selectors, and returns the list of Modules that match those selectors. 55 | func (c *FakeModules) List(ctx context.Context, opts v1.ListOptions) (result *terraformcontrollercattleiov1.ModuleList, err error) { 56 | obj, err := c.Fake. 57 | Invokes(testing.NewListAction(modulesResource, modulesKind, c.ns, opts), &terraformcontrollercattleiov1.ModuleList{}) 58 | 59 | if obj == nil { 60 | return nil, err 61 | } 62 | 63 | label, _, _ := testing.ExtractFromListOptions(opts) 64 | if label == nil { 65 | label = labels.Everything() 66 | } 67 | list := &terraformcontrollercattleiov1.ModuleList{ListMeta: obj.(*terraformcontrollercattleiov1.ModuleList).ListMeta} 68 | for _, item := range obj.(*terraformcontrollercattleiov1.ModuleList).Items { 69 | if label.Matches(labels.Set(item.Labels)) { 70 | list.Items = append(list.Items, item) 71 | } 72 | } 73 | return list, err 74 | } 75 | 76 | // Watch returns a watch.Interface that watches the requested modules. 77 | func (c *FakeModules) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { 78 | return c.Fake. 79 | InvokesWatch(testing.NewWatchAction(modulesResource, c.ns, opts)) 80 | 81 | } 82 | 83 | // Create takes the representation of a module and creates it. Returns the server's representation of the module, and an error, if there is any. 84 | func (c *FakeModules) Create(ctx context.Context, module *terraformcontrollercattleiov1.Module, opts v1.CreateOptions) (result *terraformcontrollercattleiov1.Module, err error) { 85 | obj, err := c.Fake. 86 | Invokes(testing.NewCreateAction(modulesResource, c.ns, module), &terraformcontrollercattleiov1.Module{}) 87 | 88 | if obj == nil { 89 | return nil, err 90 | } 91 | return obj.(*terraformcontrollercattleiov1.Module), err 92 | } 93 | 94 | // Update takes the representation of a module and updates it. Returns the server's representation of the module, and an error, if there is any. 95 | func (c *FakeModules) Update(ctx context.Context, module *terraformcontrollercattleiov1.Module, opts v1.UpdateOptions) (result *terraformcontrollercattleiov1.Module, err error) { 96 | obj, err := c.Fake. 97 | Invokes(testing.NewUpdateAction(modulesResource, c.ns, module), &terraformcontrollercattleiov1.Module{}) 98 | 99 | if obj == nil { 100 | return nil, err 101 | } 102 | return obj.(*terraformcontrollercattleiov1.Module), err 103 | } 104 | 105 | // UpdateStatus was generated because the type contains a Status member. 106 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 107 | func (c *FakeModules) UpdateStatus(ctx context.Context, module *terraformcontrollercattleiov1.Module, opts v1.UpdateOptions) (*terraformcontrollercattleiov1.Module, error) { 108 | obj, err := c.Fake. 109 | Invokes(testing.NewUpdateSubresourceAction(modulesResource, "status", c.ns, module), &terraformcontrollercattleiov1.Module{}) 110 | 111 | if obj == nil { 112 | return nil, err 113 | } 114 | return obj.(*terraformcontrollercattleiov1.Module), err 115 | } 116 | 117 | // Delete takes name of the module and deletes it. Returns an error if one occurs. 118 | func (c *FakeModules) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { 119 | _, err := c.Fake. 120 | Invokes(testing.NewDeleteAction(modulesResource, c.ns, name), &terraformcontrollercattleiov1.Module{}) 121 | 122 | return err 123 | } 124 | 125 | // DeleteCollection deletes a collection of objects. 126 | func (c *FakeModules) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { 127 | action := testing.NewDeleteCollectionAction(modulesResource, c.ns, listOpts) 128 | 129 | _, err := c.Fake.Invokes(action, &terraformcontrollercattleiov1.ModuleList{}) 130 | return err 131 | } 132 | 133 | // Patch applies the patch and returns the patched module. 134 | func (c *FakeModules) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *terraformcontrollercattleiov1.Module, err error) { 135 | obj, err := c.Fake. 136 | Invokes(testing.NewPatchSubresourceAction(modulesResource, c.ns, name, pt, data, subresources...), &terraformcontrollercattleiov1.Module{}) 137 | 138 | if obj == nil { 139 | return nil, err 140 | } 141 | return obj.(*terraformcontrollercattleiov1.Module), err 142 | } 143 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/fake/fake_state.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | "context" 23 | 24 | terraformcontrollercattleiov1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | labels "k8s.io/apimachinery/pkg/labels" 27 | schema "k8s.io/apimachinery/pkg/runtime/schema" 28 | types "k8s.io/apimachinery/pkg/types" 29 | watch "k8s.io/apimachinery/pkg/watch" 30 | testing "k8s.io/client-go/testing" 31 | ) 32 | 33 | // FakeStates implements StateInterface 34 | type FakeStates struct { 35 | Fake *FakeTerraformcontrollerV1 36 | ns string 37 | } 38 | 39 | var statesResource = schema.GroupVersionResource{Group: "terraformcontroller.cattle.io", Version: "v1", Resource: "states"} 40 | 41 | var statesKind = schema.GroupVersionKind{Group: "terraformcontroller.cattle.io", Version: "v1", Kind: "State"} 42 | 43 | // Get takes name of the state, and returns the corresponding state object, and an error if there is any. 44 | func (c *FakeStates) Get(ctx context.Context, name string, options v1.GetOptions) (result *terraformcontrollercattleiov1.State, err error) { 45 | obj, err := c.Fake. 46 | Invokes(testing.NewGetAction(statesResource, c.ns, name), &terraformcontrollercattleiov1.State{}) 47 | 48 | if obj == nil { 49 | return nil, err 50 | } 51 | return obj.(*terraformcontrollercattleiov1.State), err 52 | } 53 | 54 | // List takes label and field selectors, and returns the list of States that match those selectors. 55 | func (c *FakeStates) List(ctx context.Context, opts v1.ListOptions) (result *terraformcontrollercattleiov1.StateList, err error) { 56 | obj, err := c.Fake. 57 | Invokes(testing.NewListAction(statesResource, statesKind, c.ns, opts), &terraformcontrollercattleiov1.StateList{}) 58 | 59 | if obj == nil { 60 | return nil, err 61 | } 62 | 63 | label, _, _ := testing.ExtractFromListOptions(opts) 64 | if label == nil { 65 | label = labels.Everything() 66 | } 67 | list := &terraformcontrollercattleiov1.StateList{ListMeta: obj.(*terraformcontrollercattleiov1.StateList).ListMeta} 68 | for _, item := range obj.(*terraformcontrollercattleiov1.StateList).Items { 69 | if label.Matches(labels.Set(item.Labels)) { 70 | list.Items = append(list.Items, item) 71 | } 72 | } 73 | return list, err 74 | } 75 | 76 | // Watch returns a watch.Interface that watches the requested states. 77 | func (c *FakeStates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { 78 | return c.Fake. 79 | InvokesWatch(testing.NewWatchAction(statesResource, c.ns, opts)) 80 | 81 | } 82 | 83 | // Create takes the representation of a state and creates it. Returns the server's representation of the state, and an error, if there is any. 84 | func (c *FakeStates) Create(ctx context.Context, state *terraformcontrollercattleiov1.State, opts v1.CreateOptions) (result *terraformcontrollercattleiov1.State, err error) { 85 | obj, err := c.Fake. 86 | Invokes(testing.NewCreateAction(statesResource, c.ns, state), &terraformcontrollercattleiov1.State{}) 87 | 88 | if obj == nil { 89 | return nil, err 90 | } 91 | return obj.(*terraformcontrollercattleiov1.State), err 92 | } 93 | 94 | // Update takes the representation of a state and updates it. Returns the server's representation of the state, and an error, if there is any. 95 | func (c *FakeStates) Update(ctx context.Context, state *terraformcontrollercattleiov1.State, opts v1.UpdateOptions) (result *terraformcontrollercattleiov1.State, err error) { 96 | obj, err := c.Fake. 97 | Invokes(testing.NewUpdateAction(statesResource, c.ns, state), &terraformcontrollercattleiov1.State{}) 98 | 99 | if obj == nil { 100 | return nil, err 101 | } 102 | return obj.(*terraformcontrollercattleiov1.State), err 103 | } 104 | 105 | // UpdateStatus was generated because the type contains a Status member. 106 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 107 | func (c *FakeStates) UpdateStatus(ctx context.Context, state *terraformcontrollercattleiov1.State, opts v1.UpdateOptions) (*terraformcontrollercattleiov1.State, error) { 108 | obj, err := c.Fake. 109 | Invokes(testing.NewUpdateSubresourceAction(statesResource, "status", c.ns, state), &terraformcontrollercattleiov1.State{}) 110 | 111 | if obj == nil { 112 | return nil, err 113 | } 114 | return obj.(*terraformcontrollercattleiov1.State), err 115 | } 116 | 117 | // Delete takes name of the state and deletes it. Returns an error if one occurs. 118 | func (c *FakeStates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { 119 | _, err := c.Fake. 120 | Invokes(testing.NewDeleteAction(statesResource, c.ns, name), &terraformcontrollercattleiov1.State{}) 121 | 122 | return err 123 | } 124 | 125 | // DeleteCollection deletes a collection of objects. 126 | func (c *FakeStates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { 127 | action := testing.NewDeleteCollectionAction(statesResource, c.ns, listOpts) 128 | 129 | _, err := c.Fake.Invokes(action, &terraformcontrollercattleiov1.StateList{}) 130 | return err 131 | } 132 | 133 | // Patch applies the patch and returns the patched state. 134 | func (c *FakeStates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *terraformcontrollercattleiov1.State, err error) { 135 | obj, err := c.Fake. 136 | Invokes(testing.NewPatchSubresourceAction(statesResource, c.ns, name, pt, data, subresources...), &terraformcontrollercattleiov1.State{}) 137 | 138 | if obj == nil { 139 | return nil, err 140 | } 141 | return obj.(*terraformcontrollercattleiov1.State), err 142 | } 143 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/fake/fake_terraformcontroller.cattle.io_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1 "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1" 23 | rest "k8s.io/client-go/rest" 24 | testing "k8s.io/client-go/testing" 25 | ) 26 | 27 | type FakeTerraformcontrollerV1 struct { 28 | *testing.Fake 29 | } 30 | 31 | func (c *FakeTerraformcontrollerV1) Executions(namespace string) v1.ExecutionInterface { 32 | return &FakeExecutions{c, namespace} 33 | } 34 | 35 | func (c *FakeTerraformcontrollerV1) Modules(namespace string) v1.ModuleInterface { 36 | return &FakeModules{c, namespace} 37 | } 38 | 39 | func (c *FakeTerraformcontrollerV1) States(namespace string) v1.StateInterface { 40 | return &FakeStates{c, namespace} 41 | } 42 | 43 | // RESTClient returns a RESTClient that is used to communicate 44 | // with API server by this client implementation. 45 | func (c *FakeTerraformcontrollerV1) RESTClient() rest.Interface { 46 | var ret *rest.RESTClient 47 | return ret 48 | } 49 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | type ExecutionExpansion interface{} 22 | 23 | type ModuleExpansion interface{} 24 | 25 | type StateExpansion interface{} 26 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/module.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | "context" 23 | "time" 24 | 25 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 26 | scheme "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/scheme" 27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 | types "k8s.io/apimachinery/pkg/types" 29 | watch "k8s.io/apimachinery/pkg/watch" 30 | rest "k8s.io/client-go/rest" 31 | ) 32 | 33 | // ModulesGetter has a method to return a ModuleInterface. 34 | // A group's client should implement this interface. 35 | type ModulesGetter interface { 36 | Modules(namespace string) ModuleInterface 37 | } 38 | 39 | // ModuleInterface has methods to work with Module resources. 40 | type ModuleInterface interface { 41 | Create(ctx context.Context, module *v1.Module, opts metav1.CreateOptions) (*v1.Module, error) 42 | Update(ctx context.Context, module *v1.Module, opts metav1.UpdateOptions) (*v1.Module, error) 43 | UpdateStatus(ctx context.Context, module *v1.Module, opts metav1.UpdateOptions) (*v1.Module, error) 44 | Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error 45 | DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error 46 | Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Module, error) 47 | List(ctx context.Context, opts metav1.ListOptions) (*v1.ModuleList, error) 48 | Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) 49 | Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Module, err error) 50 | ModuleExpansion 51 | } 52 | 53 | // modules implements ModuleInterface 54 | type modules struct { 55 | client rest.Interface 56 | ns string 57 | } 58 | 59 | // newModules returns a Modules 60 | func newModules(c *TerraformcontrollerV1Client, namespace string) *modules { 61 | return &modules{ 62 | client: c.RESTClient(), 63 | ns: namespace, 64 | } 65 | } 66 | 67 | // Get takes name of the module, and returns the corresponding module object, and an error if there is any. 68 | func (c *modules) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.Module, err error) { 69 | result = &v1.Module{} 70 | err = c.client.Get(). 71 | Namespace(c.ns). 72 | Resource("modules"). 73 | Name(name). 74 | VersionedParams(&options, scheme.ParameterCodec). 75 | Do(ctx). 76 | Into(result) 77 | return 78 | } 79 | 80 | // List takes label and field selectors, and returns the list of Modules that match those selectors. 81 | func (c *modules) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ModuleList, err error) { 82 | var timeout time.Duration 83 | if opts.TimeoutSeconds != nil { 84 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 85 | } 86 | result = &v1.ModuleList{} 87 | err = c.client.Get(). 88 | Namespace(c.ns). 89 | Resource("modules"). 90 | VersionedParams(&opts, scheme.ParameterCodec). 91 | Timeout(timeout). 92 | Do(ctx). 93 | Into(result) 94 | return 95 | } 96 | 97 | // Watch returns a watch.Interface that watches the requested modules. 98 | func (c *modules) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { 99 | var timeout time.Duration 100 | if opts.TimeoutSeconds != nil { 101 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 102 | } 103 | opts.Watch = true 104 | return c.client.Get(). 105 | Namespace(c.ns). 106 | Resource("modules"). 107 | VersionedParams(&opts, scheme.ParameterCodec). 108 | Timeout(timeout). 109 | Watch(ctx) 110 | } 111 | 112 | // Create takes the representation of a module and creates it. Returns the server's representation of the module, and an error, if there is any. 113 | func (c *modules) Create(ctx context.Context, module *v1.Module, opts metav1.CreateOptions) (result *v1.Module, err error) { 114 | result = &v1.Module{} 115 | err = c.client.Post(). 116 | Namespace(c.ns). 117 | Resource("modules"). 118 | VersionedParams(&opts, scheme.ParameterCodec). 119 | Body(module). 120 | Do(ctx). 121 | Into(result) 122 | return 123 | } 124 | 125 | // Update takes the representation of a module and updates it. Returns the server's representation of the module, and an error, if there is any. 126 | func (c *modules) Update(ctx context.Context, module *v1.Module, opts metav1.UpdateOptions) (result *v1.Module, err error) { 127 | result = &v1.Module{} 128 | err = c.client.Put(). 129 | Namespace(c.ns). 130 | Resource("modules"). 131 | Name(module.Name). 132 | VersionedParams(&opts, scheme.ParameterCodec). 133 | Body(module). 134 | Do(ctx). 135 | Into(result) 136 | return 137 | } 138 | 139 | // UpdateStatus was generated because the type contains a Status member. 140 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 141 | func (c *modules) UpdateStatus(ctx context.Context, module *v1.Module, opts metav1.UpdateOptions) (result *v1.Module, err error) { 142 | result = &v1.Module{} 143 | err = c.client.Put(). 144 | Namespace(c.ns). 145 | Resource("modules"). 146 | Name(module.Name). 147 | SubResource("status"). 148 | VersionedParams(&opts, scheme.ParameterCodec). 149 | Body(module). 150 | Do(ctx). 151 | Into(result) 152 | return 153 | } 154 | 155 | // Delete takes name of the module and deletes it. Returns an error if one occurs. 156 | func (c *modules) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { 157 | return c.client.Delete(). 158 | Namespace(c.ns). 159 | Resource("modules"). 160 | Name(name). 161 | Body(&opts). 162 | Do(ctx). 163 | Error() 164 | } 165 | 166 | // DeleteCollection deletes a collection of objects. 167 | func (c *modules) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { 168 | var timeout time.Duration 169 | if listOpts.TimeoutSeconds != nil { 170 | timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second 171 | } 172 | return c.client.Delete(). 173 | Namespace(c.ns). 174 | Resource("modules"). 175 | VersionedParams(&listOpts, scheme.ParameterCodec). 176 | Timeout(timeout). 177 | Body(&opts). 178 | Do(ctx). 179 | Error() 180 | } 181 | 182 | // Patch applies the patch and returns the patched module. 183 | func (c *modules) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Module, err error) { 184 | result = &v1.Module{} 185 | err = c.client.Patch(pt). 186 | Namespace(c.ns). 187 | Resource("modules"). 188 | Name(name). 189 | SubResource(subresources...). 190 | VersionedParams(&opts, scheme.ParameterCodec). 191 | Body(data). 192 | Do(ctx). 193 | Into(result) 194 | return 195 | } 196 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/state.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | "context" 23 | "time" 24 | 25 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 26 | scheme "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/scheme" 27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 | types "k8s.io/apimachinery/pkg/types" 29 | watch "k8s.io/apimachinery/pkg/watch" 30 | rest "k8s.io/client-go/rest" 31 | ) 32 | 33 | // StatesGetter has a method to return a StateInterface. 34 | // A group's client should implement this interface. 35 | type StatesGetter interface { 36 | States(namespace string) StateInterface 37 | } 38 | 39 | // StateInterface has methods to work with State resources. 40 | type StateInterface interface { 41 | Create(ctx context.Context, state *v1.State, opts metav1.CreateOptions) (*v1.State, error) 42 | Update(ctx context.Context, state *v1.State, opts metav1.UpdateOptions) (*v1.State, error) 43 | UpdateStatus(ctx context.Context, state *v1.State, opts metav1.UpdateOptions) (*v1.State, error) 44 | Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error 45 | DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error 46 | Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.State, error) 47 | List(ctx context.Context, opts metav1.ListOptions) (*v1.StateList, error) 48 | Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) 49 | Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.State, err error) 50 | StateExpansion 51 | } 52 | 53 | // states implements StateInterface 54 | type states struct { 55 | client rest.Interface 56 | ns string 57 | } 58 | 59 | // newStates returns a States 60 | func newStates(c *TerraformcontrollerV1Client, namespace string) *states { 61 | return &states{ 62 | client: c.RESTClient(), 63 | ns: namespace, 64 | } 65 | } 66 | 67 | // Get takes name of the state, and returns the corresponding state object, and an error if there is any. 68 | func (c *states) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.State, err error) { 69 | result = &v1.State{} 70 | err = c.client.Get(). 71 | Namespace(c.ns). 72 | Resource("states"). 73 | Name(name). 74 | VersionedParams(&options, scheme.ParameterCodec). 75 | Do(ctx). 76 | Into(result) 77 | return 78 | } 79 | 80 | // List takes label and field selectors, and returns the list of States that match those selectors. 81 | func (c *states) List(ctx context.Context, opts metav1.ListOptions) (result *v1.StateList, err error) { 82 | var timeout time.Duration 83 | if opts.TimeoutSeconds != nil { 84 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 85 | } 86 | result = &v1.StateList{} 87 | err = c.client.Get(). 88 | Namespace(c.ns). 89 | Resource("states"). 90 | VersionedParams(&opts, scheme.ParameterCodec). 91 | Timeout(timeout). 92 | Do(ctx). 93 | Into(result) 94 | return 95 | } 96 | 97 | // Watch returns a watch.Interface that watches the requested states. 98 | func (c *states) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { 99 | var timeout time.Duration 100 | if opts.TimeoutSeconds != nil { 101 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second 102 | } 103 | opts.Watch = true 104 | return c.client.Get(). 105 | Namespace(c.ns). 106 | Resource("states"). 107 | VersionedParams(&opts, scheme.ParameterCodec). 108 | Timeout(timeout). 109 | Watch(ctx) 110 | } 111 | 112 | // Create takes the representation of a state and creates it. Returns the server's representation of the state, and an error, if there is any. 113 | func (c *states) Create(ctx context.Context, state *v1.State, opts metav1.CreateOptions) (result *v1.State, err error) { 114 | result = &v1.State{} 115 | err = c.client.Post(). 116 | Namespace(c.ns). 117 | Resource("states"). 118 | VersionedParams(&opts, scheme.ParameterCodec). 119 | Body(state). 120 | Do(ctx). 121 | Into(result) 122 | return 123 | } 124 | 125 | // Update takes the representation of a state and updates it. Returns the server's representation of the state, and an error, if there is any. 126 | func (c *states) Update(ctx context.Context, state *v1.State, opts metav1.UpdateOptions) (result *v1.State, err error) { 127 | result = &v1.State{} 128 | err = c.client.Put(). 129 | Namespace(c.ns). 130 | Resource("states"). 131 | Name(state.Name). 132 | VersionedParams(&opts, scheme.ParameterCodec). 133 | Body(state). 134 | Do(ctx). 135 | Into(result) 136 | return 137 | } 138 | 139 | // UpdateStatus was generated because the type contains a Status member. 140 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 141 | func (c *states) UpdateStatus(ctx context.Context, state *v1.State, opts metav1.UpdateOptions) (result *v1.State, err error) { 142 | result = &v1.State{} 143 | err = c.client.Put(). 144 | Namespace(c.ns). 145 | Resource("states"). 146 | Name(state.Name). 147 | SubResource("status"). 148 | VersionedParams(&opts, scheme.ParameterCodec). 149 | Body(state). 150 | Do(ctx). 151 | Into(result) 152 | return 153 | } 154 | 155 | // Delete takes name of the state and deletes it. Returns an error if one occurs. 156 | func (c *states) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { 157 | return c.client.Delete(). 158 | Namespace(c.ns). 159 | Resource("states"). 160 | Name(name). 161 | Body(&opts). 162 | Do(ctx). 163 | Error() 164 | } 165 | 166 | // DeleteCollection deletes a collection of objects. 167 | func (c *states) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { 168 | var timeout time.Duration 169 | if listOpts.TimeoutSeconds != nil { 170 | timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second 171 | } 172 | return c.client.Delete(). 173 | Namespace(c.ns). 174 | Resource("states"). 175 | VersionedParams(&listOpts, scheme.ParameterCodec). 176 | Timeout(timeout). 177 | Body(&opts). 178 | Do(ctx). 179 | Error() 180 | } 181 | 182 | // Patch applies the patch and returns the patched state. 183 | func (c *states) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.State, err error) { 184 | result = &v1.State{} 185 | err = c.client.Patch(pt). 186 | Namespace(c.ns). 187 | Resource("states"). 188 | Name(name). 189 | SubResource(subresources...). 190 | VersionedParams(&opts, scheme.ParameterCodec). 191 | Body(data). 192 | Do(ctx). 193 | Into(result) 194 | return 195 | } 196 | -------------------------------------------------------------------------------- /pkg/generated/clientset/versioned/typed/terraformcontroller.cattle.io/v1/terraformcontroller.cattle.io_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 23 | "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned/scheme" 24 | rest "k8s.io/client-go/rest" 25 | ) 26 | 27 | type TerraformcontrollerV1Interface interface { 28 | RESTClient() rest.Interface 29 | ExecutionsGetter 30 | ModulesGetter 31 | StatesGetter 32 | } 33 | 34 | // TerraformcontrollerV1Client is used to interact with features provided by the terraformcontroller.cattle.io group. 35 | type TerraformcontrollerV1Client struct { 36 | restClient rest.Interface 37 | } 38 | 39 | func (c *TerraformcontrollerV1Client) Executions(namespace string) ExecutionInterface { 40 | return newExecutions(c, namespace) 41 | } 42 | 43 | func (c *TerraformcontrollerV1Client) Modules(namespace string) ModuleInterface { 44 | return newModules(c, namespace) 45 | } 46 | 47 | func (c *TerraformcontrollerV1Client) States(namespace string) StateInterface { 48 | return newStates(c, namespace) 49 | } 50 | 51 | // NewForConfig creates a new TerraformcontrollerV1Client for the given config. 52 | func NewForConfig(c *rest.Config) (*TerraformcontrollerV1Client, error) { 53 | config := *c 54 | if err := setConfigDefaults(&config); err != nil { 55 | return nil, err 56 | } 57 | client, err := rest.RESTClientFor(&config) 58 | if err != nil { 59 | return nil, err 60 | } 61 | return &TerraformcontrollerV1Client{client}, nil 62 | } 63 | 64 | // NewForConfigOrDie creates a new TerraformcontrollerV1Client for the given config and 65 | // panics if there is an error in the config. 66 | func NewForConfigOrDie(c *rest.Config) *TerraformcontrollerV1Client { 67 | client, err := NewForConfig(c) 68 | if err != nil { 69 | panic(err) 70 | } 71 | return client 72 | } 73 | 74 | // New creates a new TerraformcontrollerV1Client for the given RESTClient. 75 | func New(c rest.Interface) *TerraformcontrollerV1Client { 76 | return &TerraformcontrollerV1Client{c} 77 | } 78 | 79 | func setConfigDefaults(config *rest.Config) error { 80 | gv := v1.SchemeGroupVersion 81 | config.GroupVersion = &gv 82 | config.APIPath = "/apis" 83 | config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() 84 | 85 | if config.UserAgent == "" { 86 | config.UserAgent = rest.DefaultKubernetesUserAgent() 87 | } 88 | 89 | return nil 90 | } 91 | 92 | // RESTClient returns a RESTClient that is used to communicate 93 | // with API server by this client implementation. 94 | func (c *TerraformcontrollerV1Client) RESTClient() rest.Interface { 95 | if c == nil { 96 | return nil 97 | } 98 | return c.restClient 99 | } 100 | -------------------------------------------------------------------------------- /pkg/generated/controllers/terraformcontroller.cattle.io/factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package terraformcontroller 20 | 21 | import ( 22 | "github.com/rancher/wrangler/pkg/generic" 23 | "k8s.io/client-go/rest" 24 | ) 25 | 26 | type Factory struct { 27 | *generic.Factory 28 | } 29 | 30 | func NewFactoryFromConfigOrDie(config *rest.Config) *Factory { 31 | f, err := NewFactoryFromConfig(config) 32 | if err != nil { 33 | panic(err) 34 | } 35 | return f 36 | } 37 | 38 | func NewFactoryFromConfig(config *rest.Config) (*Factory, error) { 39 | return NewFactoryFromConfigWithOptions(config, nil) 40 | } 41 | 42 | func NewFactoryFromConfigWithNamespace(config *rest.Config, namespace string) (*Factory, error) { 43 | return NewFactoryFromConfigWithOptions(config, &FactoryOptions{ 44 | Namespace: namespace, 45 | }) 46 | } 47 | 48 | type FactoryOptions = generic.FactoryOptions 49 | 50 | func NewFactoryFromConfigWithOptions(config *rest.Config, opts *FactoryOptions) (*Factory, error) { 51 | f, err := generic.NewFactoryFromConfigWithOptions(config, opts) 52 | return &Factory{ 53 | Factory: f, 54 | }, err 55 | } 56 | 57 | func (c *Factory) Terraformcontroller() Interface { 58 | return New(c.ControllerFactory()) 59 | } 60 | -------------------------------------------------------------------------------- /pkg/generated/controllers/terraformcontroller.cattle.io/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package terraformcontroller 20 | 21 | import ( 22 | "github.com/rancher/lasso/pkg/controller" 23 | v1 "github.com/rancher/terraform-controller/pkg/generated/controllers/terraformcontroller.cattle.io/v1" 24 | ) 25 | 26 | type Interface interface { 27 | V1() v1.Interface 28 | } 29 | 30 | type group struct { 31 | controllerFactory controller.SharedControllerFactory 32 | } 33 | 34 | // New returns a new Interface. 35 | func New(controllerFactory controller.SharedControllerFactory) Interface { 36 | return &group{ 37 | controllerFactory: controllerFactory, 38 | } 39 | } 40 | 41 | func (g *group) V1() v1.Interface { 42 | return v1.New(g.controllerFactory) 43 | } 44 | -------------------------------------------------------------------------------- /pkg/generated/controllers/terraformcontroller.cattle.io/v1/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | "github.com/rancher/lasso/pkg/controller" 23 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 24 | "github.com/rancher/wrangler/pkg/schemes" 25 | "k8s.io/apimachinery/pkg/runtime/schema" 26 | ) 27 | 28 | func init() { 29 | schemes.Register(v1.AddToScheme) 30 | } 31 | 32 | type Interface interface { 33 | Execution() ExecutionController 34 | Module() ModuleController 35 | State() StateController 36 | } 37 | 38 | func New(controllerFactory controller.SharedControllerFactory) Interface { 39 | return &version{ 40 | controllerFactory: controllerFactory, 41 | } 42 | } 43 | 44 | type version struct { 45 | controllerFactory controller.SharedControllerFactory 46 | } 47 | 48 | func (c *version) Execution() ExecutionController { 49 | return NewExecutionController(schema.GroupVersionKind{Group: "terraformcontroller.cattle.io", Version: "v1", Kind: "Execution"}, "executions", true, c.controllerFactory) 50 | } 51 | func (c *version) Module() ModuleController { 52 | return NewModuleController(schema.GroupVersionKind{Group: "terraformcontroller.cattle.io", Version: "v1", Kind: "Module"}, "modules", true, c.controllerFactory) 53 | } 54 | func (c *version) State() StateController { 55 | return NewStateController(schema.GroupVersionKind{Group: "terraformcontroller.cattle.io", Version: "v1", Kind: "State"}, "states", true, c.controllerFactory) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | reflect "reflect" 23 | sync "sync" 24 | time "time" 25 | 26 | versioned "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned" 27 | internalinterfaces "github.com/rancher/terraform-controller/pkg/generated/informers/externalversions/internalinterfaces" 28 | terraformcontrollercattleio "github.com/rancher/terraform-controller/pkg/generated/informers/externalversions/terraformcontroller.cattle.io" 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 | Terraformcontroller() terraformcontrollercattleio.Interface 176 | } 177 | 178 | func (f *sharedInformerFactory) Terraformcontroller() terraformcontrollercattleio.Interface { 179 | return terraformcontrollercattleio.New(f, f.namespace, f.tweakListOptions) 180 | } 181 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/generic.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package externalversions 20 | 21 | import ( 22 | "fmt" 23 | 24 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 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=terraformcontroller.cattle.io, Version=v1 56 | case v1.SchemeGroupVersion.WithResource("executions"): 57 | return &genericInformer{resource: resource.GroupResource(), informer: f.Terraformcontroller().V1().Executions().Informer()}, nil 58 | case v1.SchemeGroupVersion.WithResource("modules"): 59 | return &genericInformer{resource: resource.GroupResource(), informer: f.Terraformcontroller().V1().Modules().Informer()}, nil 60 | case v1.SchemeGroupVersion.WithResource("states"): 61 | return &genericInformer{resource: resource.GroupResource(), informer: f.Terraformcontroller().V1().States().Informer()}, nil 62 | 63 | } 64 | 65 | return nil, fmt.Errorf("no informer found for %v", resource) 66 | } 67 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package internalinterfaces 20 | 21 | import ( 22 | time "time" 23 | 24 | versioned "github.com/rancher/terraform-controller/pkg/generated/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 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. 31 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer 32 | 33 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle 34 | type SharedInformerFactory interface { 35 | Start(stopCh <-chan struct{}) 36 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer 37 | } 38 | 39 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions. 40 | type TweakListOptionsFunc func(*v1.ListOptions) 41 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/terraformcontroller.cattle.io/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package terraformcontroller 20 | 21 | import ( 22 | internalinterfaces "github.com/rancher/terraform-controller/pkg/generated/informers/externalversions/internalinterfaces" 23 | v1 "github.com/rancher/terraform-controller/pkg/generated/informers/externalversions/terraformcontroller.cattle.io/v1" 24 | ) 25 | 26 | // Interface provides access to each of this group's versions. 27 | type Interface interface { 28 | // V1 provides access to shared informers for resources in V1. 29 | V1() v1.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 | // V1 returns a new v1.Interface. 44 | func (g *group) V1() v1.Interface { 45 | return v1.New(g.factory, g.namespace, g.tweakListOptions) 46 | } 47 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/terraformcontroller.cattle.io/v1/execution.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | "context" 23 | time "time" 24 | 25 | terraformcontrollercattleiov1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 26 | versioned "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned" 27 | internalinterfaces "github.com/rancher/terraform-controller/pkg/generated/informers/externalversions/internalinterfaces" 28 | v1 "github.com/rancher/terraform-controller/pkg/generated/listers/terraformcontroller.cattle.io/v1" 29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | runtime "k8s.io/apimachinery/pkg/runtime" 31 | watch "k8s.io/apimachinery/pkg/watch" 32 | cache "k8s.io/client-go/tools/cache" 33 | ) 34 | 35 | // ExecutionInformer provides access to a shared informer and lister for 36 | // Executions. 37 | type ExecutionInformer interface { 38 | Informer() cache.SharedIndexInformer 39 | Lister() v1.ExecutionLister 40 | } 41 | 42 | type executionInformer struct { 43 | factory internalinterfaces.SharedInformerFactory 44 | tweakListOptions internalinterfaces.TweakListOptionsFunc 45 | namespace string 46 | } 47 | 48 | // NewExecutionInformer constructs a new informer for Execution type. 49 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 50 | // one. This reduces memory footprint and number of connections to the server. 51 | func NewExecutionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 52 | return NewFilteredExecutionInformer(client, namespace, resyncPeriod, indexers, nil) 53 | } 54 | 55 | // NewFilteredExecutionInformer constructs a new informer for Execution type. 56 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 57 | // one. This reduces memory footprint and number of connections to the server. 58 | func NewFilteredExecutionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { 59 | return cache.NewSharedIndexInformer( 60 | &cache.ListWatch{ 61 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 62 | if tweakListOptions != nil { 63 | tweakListOptions(&options) 64 | } 65 | return client.TerraformcontrollerV1().Executions(namespace).List(context.TODO(), options) 66 | }, 67 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 68 | if tweakListOptions != nil { 69 | tweakListOptions(&options) 70 | } 71 | return client.TerraformcontrollerV1().Executions(namespace).Watch(context.TODO(), options) 72 | }, 73 | }, 74 | &terraformcontrollercattleiov1.Execution{}, 75 | resyncPeriod, 76 | indexers, 77 | ) 78 | } 79 | 80 | func (f *executionInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 81 | return NewFilteredExecutionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) 82 | } 83 | 84 | func (f *executionInformer) Informer() cache.SharedIndexInformer { 85 | return f.factory.InformerFor(&terraformcontrollercattleiov1.Execution{}, f.defaultInformer) 86 | } 87 | 88 | func (f *executionInformer) Lister() v1.ExecutionLister { 89 | return v1.NewExecutionLister(f.Informer().GetIndexer()) 90 | } 91 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/terraformcontroller.cattle.io/v1/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | internalinterfaces "github.com/rancher/terraform-controller/pkg/generated/informers/externalversions/internalinterfaces" 23 | ) 24 | 25 | // Interface provides access to all the informers in this group version. 26 | type Interface interface { 27 | // Executions returns a ExecutionInformer. 28 | Executions() ExecutionInformer 29 | // Modules returns a ModuleInformer. 30 | Modules() ModuleInformer 31 | // States returns a StateInformer. 32 | States() StateInformer 33 | } 34 | 35 | type version struct { 36 | factory internalinterfaces.SharedInformerFactory 37 | namespace string 38 | tweakListOptions internalinterfaces.TweakListOptionsFunc 39 | } 40 | 41 | // New returns a new Interface. 42 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 43 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 44 | } 45 | 46 | // Executions returns a ExecutionInformer. 47 | func (v *version) Executions() ExecutionInformer { 48 | return &executionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 49 | } 50 | 51 | // Modules returns a ModuleInformer. 52 | func (v *version) Modules() ModuleInformer { 53 | return &moduleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 54 | } 55 | 56 | // States returns a StateInformer. 57 | func (v *version) States() StateInformer { 58 | return &stateInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} 59 | } 60 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/terraformcontroller.cattle.io/v1/module.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | "context" 23 | time "time" 24 | 25 | terraformcontrollercattleiov1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 26 | versioned "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned" 27 | internalinterfaces "github.com/rancher/terraform-controller/pkg/generated/informers/externalversions/internalinterfaces" 28 | v1 "github.com/rancher/terraform-controller/pkg/generated/listers/terraformcontroller.cattle.io/v1" 29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | runtime "k8s.io/apimachinery/pkg/runtime" 31 | watch "k8s.io/apimachinery/pkg/watch" 32 | cache "k8s.io/client-go/tools/cache" 33 | ) 34 | 35 | // ModuleInformer provides access to a shared informer and lister for 36 | // Modules. 37 | type ModuleInformer interface { 38 | Informer() cache.SharedIndexInformer 39 | Lister() v1.ModuleLister 40 | } 41 | 42 | type moduleInformer struct { 43 | factory internalinterfaces.SharedInformerFactory 44 | tweakListOptions internalinterfaces.TweakListOptionsFunc 45 | namespace string 46 | } 47 | 48 | // NewModuleInformer constructs a new informer for Module type. 49 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 50 | // one. This reduces memory footprint and number of connections to the server. 51 | func NewModuleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 52 | return NewFilteredModuleInformer(client, namespace, resyncPeriod, indexers, nil) 53 | } 54 | 55 | // NewFilteredModuleInformer constructs a new informer for Module type. 56 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 57 | // one. This reduces memory footprint and number of connections to the server. 58 | func NewFilteredModuleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { 59 | return cache.NewSharedIndexInformer( 60 | &cache.ListWatch{ 61 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 62 | if tweakListOptions != nil { 63 | tweakListOptions(&options) 64 | } 65 | return client.TerraformcontrollerV1().Modules(namespace).List(context.TODO(), options) 66 | }, 67 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 68 | if tweakListOptions != nil { 69 | tweakListOptions(&options) 70 | } 71 | return client.TerraformcontrollerV1().Modules(namespace).Watch(context.TODO(), options) 72 | }, 73 | }, 74 | &terraformcontrollercattleiov1.Module{}, 75 | resyncPeriod, 76 | indexers, 77 | ) 78 | } 79 | 80 | func (f *moduleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 81 | return NewFilteredModuleInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) 82 | } 83 | 84 | func (f *moduleInformer) Informer() cache.SharedIndexInformer { 85 | return f.factory.InformerFor(&terraformcontrollercattleiov1.Module{}, f.defaultInformer) 86 | } 87 | 88 | func (f *moduleInformer) Lister() v1.ModuleLister { 89 | return v1.NewModuleLister(f.Informer().GetIndexer()) 90 | } 91 | -------------------------------------------------------------------------------- /pkg/generated/informers/externalversions/terraformcontroller.cattle.io/v1/state.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | "context" 23 | time "time" 24 | 25 | terraformcontrollercattleiov1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 26 | versioned "github.com/rancher/terraform-controller/pkg/generated/clientset/versioned" 27 | internalinterfaces "github.com/rancher/terraform-controller/pkg/generated/informers/externalversions/internalinterfaces" 28 | v1 "github.com/rancher/terraform-controller/pkg/generated/listers/terraformcontroller.cattle.io/v1" 29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | runtime "k8s.io/apimachinery/pkg/runtime" 31 | watch "k8s.io/apimachinery/pkg/watch" 32 | cache "k8s.io/client-go/tools/cache" 33 | ) 34 | 35 | // StateInformer provides access to a shared informer and lister for 36 | // States. 37 | type StateInformer interface { 38 | Informer() cache.SharedIndexInformer 39 | Lister() v1.StateLister 40 | } 41 | 42 | type stateInformer struct { 43 | factory internalinterfaces.SharedInformerFactory 44 | tweakListOptions internalinterfaces.TweakListOptionsFunc 45 | namespace string 46 | } 47 | 48 | // NewStateInformer constructs a new informer for State type. 49 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 50 | // one. This reduces memory footprint and number of connections to the server. 51 | func NewStateInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { 52 | return NewFilteredStateInformer(client, namespace, resyncPeriod, indexers, nil) 53 | } 54 | 55 | // NewFilteredStateInformer constructs a new informer for State type. 56 | // Always prefer using an informer factory to get a shared informer instead of getting an independent 57 | // one. This reduces memory footprint and number of connections to the server. 58 | func NewFilteredStateInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { 59 | return cache.NewSharedIndexInformer( 60 | &cache.ListWatch{ 61 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { 62 | if tweakListOptions != nil { 63 | tweakListOptions(&options) 64 | } 65 | return client.TerraformcontrollerV1().States(namespace).List(context.TODO(), options) 66 | }, 67 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { 68 | if tweakListOptions != nil { 69 | tweakListOptions(&options) 70 | } 71 | return client.TerraformcontrollerV1().States(namespace).Watch(context.TODO(), options) 72 | }, 73 | }, 74 | &terraformcontrollercattleiov1.State{}, 75 | resyncPeriod, 76 | indexers, 77 | ) 78 | } 79 | 80 | func (f *stateInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 81 | return NewFilteredStateInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) 82 | } 83 | 84 | func (f *stateInformer) Informer() cache.SharedIndexInformer { 85 | return f.factory.InformerFor(&terraformcontrollercattleiov1.State{}, f.defaultInformer) 86 | } 87 | 88 | func (f *stateInformer) Lister() v1.StateLister { 89 | return v1.NewStateLister(f.Informer().GetIndexer()) 90 | } 91 | -------------------------------------------------------------------------------- /pkg/generated/listers/terraformcontroller.cattle.io/v1/execution.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 23 | "k8s.io/apimachinery/pkg/api/errors" 24 | "k8s.io/apimachinery/pkg/labels" 25 | "k8s.io/client-go/tools/cache" 26 | ) 27 | 28 | // ExecutionLister helps list Executions. 29 | type ExecutionLister interface { 30 | // List lists all Executions in the indexer. 31 | List(selector labels.Selector) (ret []*v1.Execution, err error) 32 | // Executions returns an object that can list and get Executions. 33 | Executions(namespace string) ExecutionNamespaceLister 34 | ExecutionListerExpansion 35 | } 36 | 37 | // executionLister implements the ExecutionLister interface. 38 | type executionLister struct { 39 | indexer cache.Indexer 40 | } 41 | 42 | // NewExecutionLister returns a new ExecutionLister. 43 | func NewExecutionLister(indexer cache.Indexer) ExecutionLister { 44 | return &executionLister{indexer: indexer} 45 | } 46 | 47 | // List lists all Executions in the indexer. 48 | func (s *executionLister) List(selector labels.Selector) (ret []*v1.Execution, err error) { 49 | err = cache.ListAll(s.indexer, selector, func(m interface{}) { 50 | ret = append(ret, m.(*v1.Execution)) 51 | }) 52 | return ret, err 53 | } 54 | 55 | // Executions returns an object that can list and get Executions. 56 | func (s *executionLister) Executions(namespace string) ExecutionNamespaceLister { 57 | return executionNamespaceLister{indexer: s.indexer, namespace: namespace} 58 | } 59 | 60 | // ExecutionNamespaceLister helps list and get Executions. 61 | type ExecutionNamespaceLister interface { 62 | // List lists all Executions in the indexer for a given namespace. 63 | List(selector labels.Selector) (ret []*v1.Execution, err error) 64 | // Get retrieves the Execution from the indexer for a given namespace and name. 65 | Get(name string) (*v1.Execution, error) 66 | ExecutionNamespaceListerExpansion 67 | } 68 | 69 | // executionNamespaceLister implements the ExecutionNamespaceLister 70 | // interface. 71 | type executionNamespaceLister struct { 72 | indexer cache.Indexer 73 | namespace string 74 | } 75 | 76 | // List lists all Executions in the indexer for a given namespace. 77 | func (s executionNamespaceLister) List(selector labels.Selector) (ret []*v1.Execution, err error) { 78 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { 79 | ret = append(ret, m.(*v1.Execution)) 80 | }) 81 | return ret, err 82 | } 83 | 84 | // Get retrieves the Execution from the indexer for a given namespace and name. 85 | func (s executionNamespaceLister) Get(name string) (*v1.Execution, 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(v1.Resource("execution"), name) 92 | } 93 | return obj.(*v1.Execution), nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/generated/listers/terraformcontroller.cattle.io/v1/expansion_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | // ExecutionListerExpansion allows custom methods to be added to 22 | // ExecutionLister. 23 | type ExecutionListerExpansion interface{} 24 | 25 | // ExecutionNamespaceListerExpansion allows custom methods to be added to 26 | // ExecutionNamespaceLister. 27 | type ExecutionNamespaceListerExpansion interface{} 28 | 29 | // ModuleListerExpansion allows custom methods to be added to 30 | // ModuleLister. 31 | type ModuleListerExpansion interface{} 32 | 33 | // ModuleNamespaceListerExpansion allows custom methods to be added to 34 | // ModuleNamespaceLister. 35 | type ModuleNamespaceListerExpansion interface{} 36 | 37 | // StateListerExpansion allows custom methods to be added to 38 | // StateLister. 39 | type StateListerExpansion interface{} 40 | 41 | // StateNamespaceListerExpansion allows custom methods to be added to 42 | // StateNamespaceLister. 43 | type StateNamespaceListerExpansion interface{} 44 | -------------------------------------------------------------------------------- /pkg/generated/listers/terraformcontroller.cattle.io/v1/module.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 23 | "k8s.io/apimachinery/pkg/api/errors" 24 | "k8s.io/apimachinery/pkg/labels" 25 | "k8s.io/client-go/tools/cache" 26 | ) 27 | 28 | // ModuleLister helps list Modules. 29 | type ModuleLister interface { 30 | // List lists all Modules in the indexer. 31 | List(selector labels.Selector) (ret []*v1.Module, err error) 32 | // Modules returns an object that can list and get Modules. 33 | Modules(namespace string) ModuleNamespaceLister 34 | ModuleListerExpansion 35 | } 36 | 37 | // moduleLister implements the ModuleLister interface. 38 | type moduleLister struct { 39 | indexer cache.Indexer 40 | } 41 | 42 | // NewModuleLister returns a new ModuleLister. 43 | func NewModuleLister(indexer cache.Indexer) ModuleLister { 44 | return &moduleLister{indexer: indexer} 45 | } 46 | 47 | // List lists all Modules in the indexer. 48 | func (s *moduleLister) List(selector labels.Selector) (ret []*v1.Module, err error) { 49 | err = cache.ListAll(s.indexer, selector, func(m interface{}) { 50 | ret = append(ret, m.(*v1.Module)) 51 | }) 52 | return ret, err 53 | } 54 | 55 | // Modules returns an object that can list and get Modules. 56 | func (s *moduleLister) Modules(namespace string) ModuleNamespaceLister { 57 | return moduleNamespaceLister{indexer: s.indexer, namespace: namespace} 58 | } 59 | 60 | // ModuleNamespaceLister helps list and get Modules. 61 | type ModuleNamespaceLister interface { 62 | // List lists all Modules in the indexer for a given namespace. 63 | List(selector labels.Selector) (ret []*v1.Module, err error) 64 | // Get retrieves the Module from the indexer for a given namespace and name. 65 | Get(name string) (*v1.Module, error) 66 | ModuleNamespaceListerExpansion 67 | } 68 | 69 | // moduleNamespaceLister implements the ModuleNamespaceLister 70 | // interface. 71 | type moduleNamespaceLister struct { 72 | indexer cache.Indexer 73 | namespace string 74 | } 75 | 76 | // List lists all Modules in the indexer for a given namespace. 77 | func (s moduleNamespaceLister) List(selector labels.Selector) (ret []*v1.Module, err error) { 78 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { 79 | ret = append(ret, m.(*v1.Module)) 80 | }) 81 | return ret, err 82 | } 83 | 84 | // Get retrieves the Module from the indexer for a given namespace and name. 85 | func (s moduleNamespaceLister) Get(name string) (*v1.Module, 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(v1.Resource("module"), name) 92 | } 93 | return obj.(*v1.Module), nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/generated/listers/terraformcontroller.cattle.io/v1/state.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 Rancher Labs, Inc. 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 main. DO NOT EDIT. 18 | 19 | package v1 20 | 21 | import ( 22 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 23 | "k8s.io/apimachinery/pkg/api/errors" 24 | "k8s.io/apimachinery/pkg/labels" 25 | "k8s.io/client-go/tools/cache" 26 | ) 27 | 28 | // StateLister helps list States. 29 | type StateLister interface { 30 | // List lists all States in the indexer. 31 | List(selector labels.Selector) (ret []*v1.State, err error) 32 | // States returns an object that can list and get States. 33 | States(namespace string) StateNamespaceLister 34 | StateListerExpansion 35 | } 36 | 37 | // stateLister implements the StateLister interface. 38 | type stateLister struct { 39 | indexer cache.Indexer 40 | } 41 | 42 | // NewStateLister returns a new StateLister. 43 | func NewStateLister(indexer cache.Indexer) StateLister { 44 | return &stateLister{indexer: indexer} 45 | } 46 | 47 | // List lists all States in the indexer. 48 | func (s *stateLister) List(selector labels.Selector) (ret []*v1.State, err error) { 49 | err = cache.ListAll(s.indexer, selector, func(m interface{}) { 50 | ret = append(ret, m.(*v1.State)) 51 | }) 52 | return ret, err 53 | } 54 | 55 | // States returns an object that can list and get States. 56 | func (s *stateLister) States(namespace string) StateNamespaceLister { 57 | return stateNamespaceLister{indexer: s.indexer, namespace: namespace} 58 | } 59 | 60 | // StateNamespaceLister helps list and get States. 61 | type StateNamespaceLister interface { 62 | // List lists all States in the indexer for a given namespace. 63 | List(selector labels.Selector) (ret []*v1.State, err error) 64 | // Get retrieves the State from the indexer for a given namespace and name. 65 | Get(name string) (*v1.State, error) 66 | StateNamespaceListerExpansion 67 | } 68 | 69 | // stateNamespaceLister implements the StateNamespaceLister 70 | // interface. 71 | type stateNamespaceLister struct { 72 | indexer cache.Indexer 73 | namespace string 74 | } 75 | 76 | // List lists all States in the indexer for a given namespace. 77 | func (s stateNamespaceLister) List(selector labels.Selector) (ret []*v1.State, err error) { 78 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { 79 | ret = append(ret, m.(*v1.State)) 80 | }) 81 | return ret, err 82 | } 83 | 84 | // Get retrieves the State from the indexer for a given namespace and name. 85 | func (s stateNamespaceLister) Get(name string) (*v1.State, 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(v1.Resource("state"), name) 92 | } 93 | return obj.(*v1.State), nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/git/auth.go: -------------------------------------------------------------------------------- 1 | package git 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/url" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | const ( 12 | BasicAuthUsernameKey = "username" 13 | BasicAuthPasswordKey = "password" 14 | SSHAuthPrivateKey = "ssh-privatekey" 15 | ) 16 | 17 | var ErrNoSecret = fmt.Errorf("failed to find one of the following keys in secret: %v", []string{ 18 | BasicAuthUsernameKey, 19 | BasicAuthPasswordKey, 20 | SSHAuthPrivateKey, 21 | }) 22 | 23 | func noop() {} 24 | 25 | type Auth struct { 26 | Basic Basic 27 | SSH SSH 28 | } 29 | 30 | type Basic struct { 31 | Username string 32 | Password string 33 | } 34 | 35 | type SSH struct { 36 | Key []byte 37 | } 38 | 39 | func FromSecret(secret map[string][]byte) (Auth, error) { 40 | auth := Auth{} 41 | ok := auth.Basic.fromSecret(secret) 42 | ok = ok || auth.SSH.fromSecret(secret) 43 | if !ok { 44 | return auth, ErrNoSecret 45 | } 46 | return auth, nil 47 | } 48 | 49 | func (a Auth) Populate(url string) (string, []string, func()) { 50 | url = a.Basic.populate(url) 51 | env, close := a.SSH.populate() 52 | if len(env) == 0 { 53 | env = []string{"GIT_SSH_COMMAND=ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"} 54 | } 55 | return url, env, close 56 | } 57 | 58 | func (b *Basic) fromSecret(secret map[string][]byte) bool { 59 | username, unameOK := secret[BasicAuthUsernameKey] 60 | if unameOK { 61 | b.Username = string(username) 62 | } 63 | password, pwdOK := secret[BasicAuthPasswordKey] 64 | if pwdOK { 65 | b.Password = string(password) 66 | } 67 | 68 | return unameOK && pwdOK 69 | } 70 | 71 | func (b *Basic) populate(gitURL string) string { 72 | if b.Username == "" && b.Password == "" { 73 | return gitURL 74 | } 75 | 76 | u, err := url.Parse(gitURL) 77 | if err != nil || !strings.HasPrefix(u.Scheme, "http") { 78 | return gitURL 79 | } 80 | 81 | u.User = url.UserPassword(b.Username, b.Password) 82 | return u.String() 83 | } 84 | 85 | func (s *SSH) fromSecret(secret map[string][]byte) bool { 86 | key, ok := secret[SSHAuthPrivateKey] 87 | if ok { 88 | s.Key = key 89 | } 90 | return ok 91 | } 92 | 93 | func (s *SSH) populate() ([]string, func()) { 94 | if len(s.Key) == 0 { 95 | return nil, noop 96 | } 97 | 98 | f, err := ioutil.TempFile("", "ssh-key") 99 | if err != nil { 100 | return nil, noop 101 | } 102 | close := func() { 103 | f.Close() 104 | os.Remove(f.Name()) 105 | } 106 | 107 | if _, err := f.Write(s.Key); err != nil { 108 | return nil, close 109 | } 110 | 111 | if err := f.Close(); err != nil { 112 | return nil, close 113 | } 114 | 115 | return []string{ 116 | fmt.Sprintf("GIT_SSH_COMMAND=ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i %s", f.Name()), 117 | }, close 118 | } 119 | -------------------------------------------------------------------------------- /pkg/git/cmd.go: -------------------------------------------------------------------------------- 1 | package git 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | "os" 8 | "os/exec" 9 | 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | func git(ctx context.Context, env []string, args ...string) ([]string, error) { 14 | cmd := exec.CommandContext(ctx, "git", args...) 15 | cmd.Env = append(os.Environ(), env...) 16 | 17 | var ( 18 | out bytes.Buffer 19 | errOut bytes.Buffer 20 | ) 21 | cmd.Stdout = &out 22 | cmd.Stderr = &errOut 23 | err := cmd.Run() 24 | if err != nil { 25 | return nil, errors.Wrap(err, errOut.String()) 26 | } 27 | 28 | var output []string 29 | s := bufio.NewScanner(&out) 30 | for s.Scan() { 31 | output = append(output, s.Text()) 32 | } 33 | 34 | return output, s.Err() 35 | } 36 | -------------------------------------------------------------------------------- /pkg/git/format.go: -------------------------------------------------------------------------------- 1 | package git 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func firstField(lines []string, errText string) (string, error) { 10 | if len(lines) == 0 { 11 | return "", errors.New(errText) 12 | } 13 | 14 | fields := strings.Fields(lines[0]) 15 | if len(fields) == 0 { 16 | return "", errors.New(errText) 17 | } 18 | 19 | if len(fields[0]) == 0 { 20 | return "", errors.New(errText) 21 | } 22 | 23 | return fields[0], nil 24 | } 25 | 26 | func formatRef(branch, tag string) string { 27 | if branch != "" { 28 | return formatRefForBranch(branch) 29 | } 30 | if tag != "" { 31 | return formatRefForTag(tag) 32 | } 33 | return "" 34 | } 35 | 36 | func formatRefForBranch(branch string) string { 37 | return fmt.Sprintf("refs/heads/%s", branch) 38 | } 39 | 40 | func formatRefForTag(tag string) string { 41 | return fmt.Sprintf("refs/tags/%s", tag) 42 | } 43 | -------------------------------------------------------------------------------- /pkg/git/git.go: -------------------------------------------------------------------------------- 1 | package git 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/sirupsen/logrus" 8 | ) 9 | 10 | func GetCommit(ctx context.Context, url, branch, tag string, auth *Auth) (string, error) { 11 | url, env, close := auth.Populate(url) 12 | defer close() 13 | 14 | lines, err := git(ctx, env, "ls-remote", url, formatRef(branch, tag)) 15 | if err != nil { 16 | return "", err 17 | } 18 | 19 | return firstField(lines, fmt.Sprintf("no commit for branch: %s or tag: %s", branch, tag)) 20 | } 21 | 22 | func CloneRepo(ctx context.Context, url string, commit string, auth *Auth) error { 23 | url, env, close := auth.Populate(url) 24 | defer close() 25 | 26 | lines, err := git(ctx, env, "clone", "-n", url, ".") 27 | if err != nil { 28 | return err 29 | } 30 | 31 | logrus.Infof("Output from git clone %v", lines) 32 | 33 | lines, err = git(ctx, env, "checkout", commit) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | logrus.Infof("Output from git checkout %v", lines) 39 | 40 | return nil 41 | } 42 | -------------------------------------------------------------------------------- /pkg/gz/main.go: -------------------------------------------------------------------------------- 1 | package gz 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | ) 7 | 8 | func Compress(data []byte) ([]byte, error) { 9 | b := new(bytes.Buffer) 10 | gz := gzip.NewWriter(b) 11 | if _, err := gz.Write(data); err != nil { 12 | return nil, err 13 | } 14 | if err := gz.Close(); err != nil { 15 | return nil, err 16 | } 17 | return b.Bytes(), nil 18 | } 19 | 20 | func Uncompress(data []byte) ([]byte, error) { 21 | b := new(bytes.Buffer) 22 | gz, err := gzip.NewReader(bytes.NewReader(data)) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | _, err = b.ReadFrom(gz) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | if err := gz.Close(); err != nil { 33 | return nil, err 34 | } 35 | 36 | return b.Bytes(), nil 37 | } 38 | -------------------------------------------------------------------------------- /pkg/interval/interval.go: -------------------------------------------------------------------------------- 1 | package interval 2 | 3 | import "time" 4 | 5 | const ( 6 | DefaultInterval = 30 * time.Minute 7 | ) 8 | 9 | func NeedsUpdate(lastCheck time.Time, interval time.Duration) bool { 10 | if lastCheck.IsZero() { 11 | return true 12 | } 13 | 14 | if interval == 0 { 15 | interval = DefaultInterval 16 | } 17 | 18 | return time.Now().After(lastCheck.Add(interval)) 19 | } 20 | -------------------------------------------------------------------------------- /pkg/terraform/controller.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "context" 5 | 6 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 7 | tfv1 "github.com/rancher/terraform-controller/pkg/generated/controllers/terraformcontroller.cattle.io/v1" 8 | "github.com/rancher/terraform-controller/pkg/terraform/execution" 9 | "github.com/rancher/terraform-controller/pkg/terraform/module" 10 | "github.com/rancher/terraform-controller/pkg/terraform/state" 11 | batchv1 "github.com/rancher/wrangler/pkg/generated/controllers/batch/v1" 12 | corev1 "github.com/rancher/wrangler/pkg/generated/controllers/core/v1" 13 | rbacv1 "github.com/rancher/wrangler/pkg/generated/controllers/rbac/v1" 14 | "github.com/rancher/wrangler/pkg/relatedresource" 15 | core "k8s.io/api/core/v1" 16 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" 17 | "k8s.io/apimachinery/pkg/runtime" 18 | ) 19 | 20 | func Register( 21 | ctx context.Context, 22 | modules tfv1.ModuleController, 23 | states tfv1.StateController, 24 | executions tfv1.ExecutionController, 25 | clusterRoles rbacv1.ClusterRoleController, 26 | clusterRoleBindings rbacv1.ClusterRoleBindingController, 27 | secrets corev1.SecretController, 28 | configMaps corev1.ConfigMapController, 29 | serviceAccounts corev1.ServiceAccountController, 30 | jobs batchv1.JobController, 31 | ) { 32 | // watch for modules 33 | relatedresource.Watch(ctx, "state-module-watch", 34 | func(namespace, name string, obj runtime.Object) ([]relatedresource.Key, error) { 35 | var statesFound []string 36 | var result []relatedresource.Key 37 | stateList, err := states.List(namespace, metaV1.ListOptions{}) 38 | if err != nil { 39 | return nil, err 40 | } 41 | for _, state := range stateList.Items { 42 | if _, ok := obj.(*v1.Module); ok { 43 | module := obj.(*v1.Module) 44 | if state.Spec.ModuleName == module.Name { 45 | statesFound = append(statesFound, state.Name) 46 | } 47 | } 48 | } 49 | if len(statesFound) > 0 { 50 | for _, foundState := range statesFound { 51 | result = append(result, relatedresource.NewKey(namespace, foundState)) 52 | } 53 | return result, nil 54 | } 55 | return nil, nil 56 | }, 57 | states, 58 | modules) 59 | // watch configs and secrets 60 | relatedresource.Watch(ctx, "state-config-secret-watch", 61 | func(namespace, name string, obj runtime.Object) ([]relatedresource.Key, error) { 62 | var statesFound []string 63 | var result []relatedresource.Key 64 | 65 | stateList, err := states.List(namespace, metaV1.ListOptions{}) 66 | if err != nil { 67 | return nil, err 68 | } 69 | for _, state := range stateList.Items { 70 | if _, ok := obj.(*core.ConfigMap); ok { 71 | for _, envCm := range state.Spec.Variables.EnvConfigName { 72 | config := obj.(*core.ConfigMap) 73 | if envCm == config.Name { 74 | statesFound = append(statesFound, state.Name) 75 | } 76 | } 77 | for _, configmap := range state.Spec.Variables.ConfigNames { 78 | config := obj.(*core.ConfigMap) 79 | if configmap == config.Name { 80 | statesFound = append(statesFound, state.Name) 81 | } 82 | } 83 | } 84 | if _, ok := obj.(*core.Secret); ok { 85 | for _, envSecret := range state.Spec.Variables.EnvSecretNames { 86 | secret := obj.(*core.Secret) 87 | if envSecret == secret.Name { 88 | statesFound = append(statesFound, state.Name) 89 | } 90 | } 91 | for _, rSecret := range state.Spec.Variables.SecretNames { 92 | secret := obj.(*core.Secret) 93 | if rSecret == secret.Name { 94 | statesFound = append(statesFound, state.Name) 95 | } 96 | } 97 | } 98 | 99 | } 100 | if len(statesFound) > 0 { 101 | for _, foundState := range statesFound { 102 | result = append(result, relatedresource.NewKey(namespace, foundState)) 103 | } 104 | return result, nil 105 | } 106 | return nil, nil 107 | }, 108 | states, 109 | configMaps, 110 | secrets) 111 | 112 | stateHandler := state.NewHandler( 113 | ctx, 114 | modules, 115 | states, 116 | executions, 117 | clusterRoles, 118 | clusterRoleBindings, 119 | secrets, 120 | configMaps, 121 | serviceAccounts, 122 | jobs) 123 | states.OnChange(ctx, "states-handler", stateHandler.OnChange) 124 | states.OnRemove(ctx, "states-handler", stateHandler.OnRemove) 125 | 126 | moduleHandler := module.NewHandler(ctx, modules, secrets) 127 | modules.OnChange(ctx, "modules-handler", moduleHandler.OnChange) 128 | modules.OnRemove(ctx, "modules-handler", moduleHandler.OnRemove) 129 | 130 | executionHandler := execution.NewHandler(ctx, executions, states, modules) 131 | executions.OnChange(ctx, "execution-handler", executionHandler.OnChange) 132 | executions.OnRemove(ctx, "execution-handler", executionHandler.OnRemove) 133 | } 134 | -------------------------------------------------------------------------------- /pkg/terraform/controller_test.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestFooControllerOnChange(t *testing.T) { 10 | assert := assert.New(t) 11 | assert.True(true) 12 | } 13 | 14 | func TestFooControllerOnRemove(t *testing.T) { 15 | assert := assert.New(t) 16 | assert.True(true) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/terraform/execution/handler.go: -------------------------------------------------------------------------------- 1 | package execution 2 | 3 | import ( 4 | "context" 5 | 6 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 7 | tfv1 "github.com/rancher/terraform-controller/pkg/generated/controllers/terraformcontroller.cattle.io/v1" 8 | ) 9 | 10 | func NewHandler(ctx context.Context, executions tfv1.ExecutionController, states tfv1.StateController, modules tfv1.ModuleController) *Handler { 11 | return &Handler{ 12 | ctx: ctx, 13 | states: states, 14 | executions: executions, 15 | modules: modules, 16 | } 17 | } 18 | 19 | type Handler struct { 20 | ctx context.Context 21 | executions tfv1.ExecutionController 22 | states tfv1.StateController 23 | modules tfv1.ModuleController 24 | } 25 | 26 | func (h *Handler) OnChange(key string, execution *v1.Execution) (*v1.Execution, error) { 27 | if execution == nil { 28 | return nil, nil 29 | } 30 | 31 | h.states.Enqueue(execution.Namespace, execution.Labels["state"]) 32 | 33 | return execution, nil 34 | } 35 | 36 | func (h *Handler) OnRemove(key string, execution *v1.Execution) (*v1.Execution, error) { 37 | return execution, nil 38 | } 39 | -------------------------------------------------------------------------------- /pkg/terraform/module/handler.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/pkg/errors" 8 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 9 | "github.com/rancher/terraform-controller/pkg/digest" 10 | tfv1 "github.com/rancher/terraform-controller/pkg/generated/controllers/terraformcontroller.cattle.io/v1" 11 | "github.com/rancher/terraform-controller/pkg/git" 12 | "github.com/rancher/terraform-controller/pkg/interval" 13 | corev1 "github.com/rancher/wrangler/pkg/generated/controllers/core/v1" 14 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 | ) 16 | 17 | func NewHandler(ctx context.Context, modules tfv1.ModuleController, secrets corev1.SecretController) *Handler { 18 | return &Handler{ 19 | ctx: ctx, 20 | modules: modules, 21 | secrets: secrets, 22 | } 23 | } 24 | 25 | type Handler struct { 26 | ctx context.Context 27 | modules tfv1.ModuleController 28 | secrets corev1.SecretController 29 | } 30 | 31 | func (h *Handler) OnChange(key string, module *v1.Module) (*v1.Module, error) { 32 | if module == nil { 33 | return nil, nil 34 | } 35 | if module.Spec.Git.IntervalSeconds == 0 { 36 | module.Spec.Git.IntervalSeconds = int(interval.DefaultInterval / time.Second) 37 | } 38 | 39 | if isPolling(module.Spec) && needsUpdate(module) { 40 | return h.updateCommit(key, module) 41 | } 42 | hash := computeHash(module) 43 | if module.Status.ContentHash != hash { 44 | return h.updateHash(module, hash) 45 | } 46 | 47 | h.modules.EnqueueAfter(module.Namespace, module.Name, time.Duration(module.Spec.Git.IntervalSeconds)*time.Second) 48 | 49 | return h.modules.Update(module) 50 | } 51 | 52 | func (h *Handler) OnRemove(key string, module *v1.Module) (*v1.Module, error) { 53 | //nothing to do here 54 | return module, nil 55 | } 56 | 57 | func (h *Handler) updateHash(module *v1.Module, hash string) (*v1.Module, error) { 58 | module = module.DeepCopy() 59 | module.Status.Content = module.Spec.ModuleContent 60 | module.Status.ContentHash = hash 61 | if isPolling(module.Spec) && module.Status.GitChecked != nil { 62 | module.Status.Content.Git.Commit = module.Status.GitChecked.Commit 63 | } 64 | return h.modules.Update(module) 65 | } 66 | 67 | func (h *Handler) updateCommit(key string, module *v1.Module) (*v1.Module, error) { 68 | branch := module.Spec.Git.Branch 69 | tag := module.Spec.Git.Tag 70 | 71 | if branch == "" { 72 | branch = "master" 73 | } 74 | // unset branch if tag is set 75 | if tag != "" { 76 | branch = "" 77 | } 78 | 79 | auth, err := h.getAuth(module.Namespace, module.Spec) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | commit, err := git.GetCommit(h.ctx, module.Spec.Git.URL, branch, tag, &auth) 85 | if err != nil { 86 | return nil, err 87 | } 88 | 89 | gitChecked := module.Spec.Git 90 | gitChecked.Commit = commit 91 | module.Status.GitChecked = &gitChecked 92 | module.Status.CheckTime = metav1.Now() 93 | 94 | v1.ModuleConditionGitUpdated.True(module) 95 | 96 | return h.modules.Update(module) 97 | } 98 | 99 | func (h *Handler) getAuth(ns string, spec v1.ModuleSpec) (git.Auth, error) { 100 | auth := git.Auth{} 101 | name := spec.Git.SecretName 102 | 103 | if name == "" { 104 | return auth, nil 105 | } 106 | 107 | secret, err := h.secrets.Get(ns, name, metav1.GetOptions{}) 108 | if err != nil { 109 | return auth, errors.Wrapf(err, "fetch git secret %s:", name) 110 | } 111 | 112 | return git.FromSecret(secret.Data) 113 | } 114 | 115 | func needsUpdate(m *v1.Module) bool { 116 | return interval.NeedsUpdate(m.Status.CheckTime.Time, time.Duration(m.Spec.Git.IntervalSeconds)*time.Second) || 117 | v1.ModuleConditionGitUpdated.IsFalse(m) || 118 | m.Status.GitChecked == nil || 119 | m.Status.GitChecked.URL != m.Spec.Git.URL || 120 | m.Status.GitChecked.Branch != m.Spec.Git.Branch 121 | } 122 | 123 | func isPolling(spec v1.ModuleSpec) bool { 124 | return len(spec.Content) == 0 && 125 | spec.Git.URL != "" && 126 | spec.Git.Commit == "" 127 | } 128 | 129 | func computeHash(obj *v1.Module) string { 130 | if len(obj.Spec.Content) > 0 { 131 | return digest.SHA256Map(obj.Spec.Content) 132 | } 133 | 134 | git := obj.Spec.Git 135 | if git.URL == "" { 136 | return "" 137 | } 138 | 139 | if isPolling(obj.Spec) && obj.Status.GitChecked != nil { 140 | git.Commit = obj.Status.GitChecked.Commit 141 | } 142 | 143 | if git.Commit != "" { 144 | return digest.SHA256Map(map[string]string{ 145 | "url": git.URL, 146 | "commit": git.Commit, 147 | }) 148 | } 149 | 150 | if git.Tag != "" { 151 | return digest.SHA256Map(map[string]string{ 152 | "url": git.URL, 153 | "tag": git.Tag, 154 | }) 155 | } 156 | 157 | return "" 158 | } 159 | -------------------------------------------------------------------------------- /pkg/terraform/state/gather.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/errors" 7 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 8 | "github.com/sirupsen/logrus" 9 | coreV1 "k8s.io/api/core/v1" 10 | k8sError "k8s.io/apimachinery/pkg/api/errors" 11 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 | ) 13 | 14 | func (h *Handler) gatherInput(obj *v1.State) (*Input, bool, error) { 15 | var ( 16 | ns = obj.Namespace 17 | spec = obj.Spec 18 | ) 19 | 20 | mod, err := h.modules.Get(ns, spec.ModuleName, metaV1.GetOptions{}) 21 | 22 | if err != nil { 23 | if k8sError.IsNotFound(err) { 24 | return nil, false, fmt.Errorf("no module with name %s", spec.ModuleName) 25 | } 26 | return nil, false, errors.New("pulling module failed") 27 | } 28 | 29 | if mod.Status.ContentHash == "" { 30 | return nil, false, errors.New("module content hash is empty") 31 | } 32 | 33 | secrets, ok, err := h.getSecrets(ns, spec) 34 | if !ok || err != nil { 35 | return nil, false, errors.New("pulling secrets failed") 36 | } 37 | 38 | configs, ok, err := h.getConfigs(ns, spec) 39 | if !ok || err != nil { 40 | return nil, false, errors.New("pulling config maps failed") 41 | } 42 | 43 | executions, ok, err := h.getExecutions(ns, spec) 44 | if !ok || err != nil { 45 | logrus.Debug() 46 | return nil, false, errors.New("pulling executions failed") 47 | } 48 | 49 | envVars, ok, err := h.getEnvVars(ns, spec) 50 | if !ok || err != nil { 51 | return nil, false, errors.New("pulling environment variables failed") 52 | } 53 | 54 | return &Input{ 55 | Configs: configs, 56 | EnvVars: envVars, 57 | Executions: executions, 58 | Image: spec.Image, 59 | Module: mod, 60 | Secrets: secrets, 61 | }, true, nil 62 | } 63 | 64 | func (h *Handler) getSecrets(ns string, spec v1.StateSpec) ([]*coreV1.Secret, bool, error) { 65 | var secrets []*coreV1.Secret 66 | 67 | for _, name := range spec.Variables.SecretNames { 68 | secret, err := h.secrets.Get(ns, name, metaV1.GetOptions{}) 69 | if k8sError.IsNotFound(err) { 70 | return secrets, false, nil 71 | } else if err != nil { 72 | return secrets, false, err 73 | } 74 | 75 | secrets = append(secrets, secret) 76 | } 77 | 78 | return secrets, true, nil 79 | } 80 | 81 | func (h *Handler) getConfigs(ns string, spec v1.StateSpec) ([]*coreV1.ConfigMap, bool, error) { 82 | var configMaps []*coreV1.ConfigMap 83 | 84 | for _, name := range spec.Variables.ConfigNames { 85 | configMap, err := h.configMaps.Get(ns, name, metaV1.GetOptions{}) 86 | if k8sError.IsNotFound(err) { 87 | return configMaps, false, nil 88 | } else if err != nil { 89 | return configMaps, false, err 90 | } 91 | 92 | configMaps = append(configMaps, configMap) 93 | } 94 | 95 | return configMaps, true, nil 96 | } 97 | 98 | func (h *Handler) getExecutions(ns string, spec v1.StateSpec) (map[string]string, bool, error) { 99 | result := map[string]string{} 100 | for dataName, execName := range spec.Data { 101 | state, err := h.states.Get(ns, execName, metaV1.GetOptions{}) 102 | if k8sError.IsNotFound(err) { 103 | return result, false, nil 104 | } else if err != nil { 105 | return result, false, err 106 | } 107 | 108 | if state.Status.ExecutionName == "" { 109 | return result, false, fmt.Errorf("referenced execution %v does not have any runs", execName) 110 | } 111 | 112 | result[dataName] = state.Status.ExecutionName 113 | } 114 | 115 | return result, true, nil 116 | } 117 | 118 | func (h *Handler) getEnvVars(ns string, spec v1.StateSpec) ([]coreV1.EnvVar, bool, error) { 119 | result := []coreV1.EnvVar{} 120 | 121 | for _, name := range spec.Variables.EnvSecretNames { 122 | secret, err := h.secrets.Get(ns, name, metaV1.GetOptions{}) 123 | if k8sError.IsNotFound(err) { 124 | return result, false, nil 125 | } else if err != nil { 126 | return result, false, err 127 | } 128 | 129 | for k, v := range secret.Data { 130 | e := coreV1.EnvVar{ 131 | Name: k, 132 | Value: string(v), 133 | } 134 | result = append(result, e) 135 | } 136 | } 137 | 138 | for _, name := range spec.Variables.EnvConfigName { 139 | config, err := h.configMaps.Get(ns, name, metaV1.GetOptions{}) 140 | if k8sError.IsNotFound(err) { 141 | return result, false, nil 142 | } else if err != nil { 143 | return result, false, err 144 | } 145 | 146 | for k, v := range config.Data { 147 | e := coreV1.EnvVar{ 148 | Name: k, 149 | Value: v, 150 | } 151 | result = append(result, e) 152 | } 153 | } 154 | return result, true, nil 155 | } 156 | -------------------------------------------------------------------------------- /pkg/terraform/state/handler.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | v1 "github.com/rancher/terraform-controller/pkg/apis/terraformcontroller.cattle.io/v1" 8 | tfv1 "github.com/rancher/terraform-controller/pkg/generated/controllers/terraformcontroller.cattle.io/v1" 9 | batchv1 "github.com/rancher/wrangler/pkg/generated/controllers/batch/v1" 10 | corev1 "github.com/rancher/wrangler/pkg/generated/controllers/core/v1" 11 | rbacv1 "github.com/rancher/wrangler/pkg/generated/controllers/rbac/v1" 12 | "github.com/sirupsen/logrus" 13 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 | ) 15 | 16 | const ( 17 | //ActionCreate for terraform 18 | ActionCreate = "create" 19 | //ActionDestroy for terraform 20 | ActionDestroy = "destroy" 21 | //Default Image 22 | DefaultExecutorImage = "rancher/terraform-controller-executor" 23 | ) 24 | 25 | func NewHandler( 26 | ctx context.Context, 27 | modules tfv1.ModuleController, 28 | states tfv1.StateController, 29 | executions tfv1.ExecutionController, 30 | clusterRoles rbacv1.ClusterRoleController, 31 | clusterRoleBindings rbacv1.ClusterRoleBindingController, 32 | secrets corev1.SecretController, 33 | configMaps corev1.ConfigMapController, 34 | serviceAccounts corev1.ServiceAccountController, 35 | jobs batchv1.JobController, 36 | ) *Handler { 37 | return &Handler{ 38 | ctx: ctx, 39 | modules: modules, 40 | states: states, 41 | executions: executions, 42 | clusterRoles: clusterRoles, 43 | clusterRoleBindings: clusterRoleBindings, 44 | secrets: secrets, 45 | configMaps: configMaps, 46 | serviceAccounts: serviceAccounts, 47 | jobs: jobs, 48 | } 49 | } 50 | 51 | type Handler struct { 52 | ctx context.Context 53 | modules tfv1.ModuleController 54 | states tfv1.StateController 55 | executions tfv1.ExecutionController 56 | clusterRoles rbacv1.ClusterRoleController 57 | clusterRoleBindings rbacv1.ClusterRoleBindingController 58 | secrets corev1.SecretController 59 | configMaps corev1.ConfigMapController 60 | serviceAccounts corev1.ServiceAccountController 61 | jobs batchv1.JobController 62 | } 63 | 64 | func (h *Handler) OnChange(key string, obj *v1.State) (*v1.State, error) { 65 | logrus.Debugf("State On Change Handler %s", key) 66 | if obj == nil { 67 | return nil, nil 68 | } 69 | 70 | if obj.DeletionTimestamp != nil { 71 | logrus.Debugf("object %s is marked for deletion", key) 72 | return nil, nil 73 | } 74 | 75 | input, ok, err := h.gatherInput(obj) 76 | if err != nil { 77 | return obj, err 78 | } 79 | 80 | if !ok { 81 | v1.ExecutionConditionMissingInfo.SetStatusBool(obj, ok) 82 | logrus.Debug("missing info") 83 | return h.states.Update(obj) 84 | } 85 | 86 | if v1.StateConditionJobDeployed.IsTrue(obj) && obj.Status.LastRunHash != "" { 87 | logrus.Debugf("job already running %s, checking execution", obj.Status.LastRunHash) 88 | execution, err := h.executions.Get(obj.Namespace, obj.Status.ExecutionName, metaV1.GetOptions{}) 89 | if err != nil { 90 | logrus.Errorf("error while retrieving execution %v", err) 91 | return obj, err 92 | } 93 | if v1.ExecutionRunConditionApplied.IsTrue(execution) { 94 | logrus.Debugf("execution is complete. setting required conditions on state") 95 | v1.StateConditionJobDeployed.False(obj) 96 | obj.Status.ExecutionName = "" 97 | obj, err = h.states.Update(obj) 98 | if err != nil { 99 | logrus.Error(err) 100 | return obj, err 101 | } 102 | return obj, nil // return nil which will remove this state because the execution is done 103 | } 104 | } 105 | 106 | if obj.Spec.Version < 1 { 107 | obj.Spec.Version = 1 108 | } 109 | 110 | if obj.Spec.Version < 1 { 111 | obj.Spec.Version = 1 112 | } 113 | 114 | runHash := createRunHash(obj, input, ActionCreate) 115 | if runHash == obj.Status.LastRunHash { 116 | logrus.Debugf("last run hash is %s", runHash) 117 | return obj, nil 118 | } 119 | 120 | //running an execution 121 | obj, err = h.states.Update(obj) 122 | if err != nil { 123 | logrus.Error(err) 124 | return obj, nil 125 | } 126 | 127 | logrus.Debug("lock acquired with new hash") 128 | 129 | if obj.Spec.Image == "" { 130 | obj.Spec.Image = fmt.Sprintf("%s:latest", DefaultExecutorImage) 131 | } 132 | 133 | //new execution if none running 134 | exec, err := h.deployCreate(obj, input) 135 | if err != nil { 136 | logrus.Debugf("failed to create execution for %s: %s", obj.Name, err) 137 | return obj, err 138 | } 139 | 140 | v1.StateConditionJobDeployed.True(obj) 141 | obj.Status.ExecutionName = exec.Name 142 | obj.Status.LastRunHash = runHash 143 | 144 | return h.states.Update(obj) 145 | } 146 | 147 | func (h *Handler) OnRemove(key string, obj *v1.State) (*v1.State, error) { 148 | logrus.Debugf("State On Remove Handler %s", key) 149 | input, ok, err := h.gatherInput(obj) 150 | if err != nil { 151 | logrus.Debug("error gathering input") 152 | return obj, err 153 | } 154 | if !ok { 155 | v1.ExecutionConditionMissingInfo.SetStatusBool(obj, ok) 156 | state, err := h.states.Update(obj) 157 | if err != nil { 158 | return state, err 159 | } 160 | 161 | return state, fmt.Errorf("missing info and can not run destroy") 162 | } 163 | 164 | if !obj.Spec.DestroyOnDelete || v1.StateConditionDestroyed.IsTrue(obj) { 165 | return obj, nil 166 | } 167 | 168 | v1.ExecutionConditionMissingInfo.False(obj) 169 | 170 | if v1.StateConditionJobDeployed.IsTrue(obj) && obj.Status.LastRunHash != "" { 171 | logrus.Debugf("remove job already running %s, checking execution", obj.Status.LastRunHash) 172 | execution, err := h.executions.Get(obj.Namespace, obj.Status.ExecutionName, metaV1.GetOptions{}) 173 | if err != nil { 174 | logrus.Errorf("error while retrieving execution %v", err) 175 | } 176 | if v1.ExecutionRunConditionApplied.IsTrue(execution) { 177 | logrus.Debugf("execution is complete. cleaning up") 178 | return obj, nil // return nil which will remove this state because the execution is done 179 | } 180 | return obj, fmt.Errorf("execution job for remove has been deployed and is not done yet") 181 | } 182 | 183 | runHash := createRunHash(obj, input, ActionDestroy) 184 | if runHash == obj.Status.LastRunHash && v1.StateConditionJobDeployed.IsTrue(obj) { 185 | logrus.Debug("hashes the same and job already deployed, nothing to do") 186 | return obj, fmt.Errorf("benign error, hashes are same") 187 | } 188 | 189 | //running an execution 190 | logrus.Debug("acquire lock") 191 | obj.Status.LastRunHash = runHash 192 | obj, err = h.states.Update(obj) 193 | if err != nil { 194 | logrus.Debug("lock failed") 195 | logrus.Debug(err) 196 | return obj, err 197 | } 198 | 199 | logrus.Debug("deploying destroy job") 200 | 201 | //no job running, try and run a destroy 202 | exec, err := h.deployDestroy(obj, input) 203 | if err != nil { 204 | logrus.Error(err) 205 | return obj, err 206 | } 207 | 208 | obj.Status.ExecutionName = exec.Name 209 | v1.StateConditionJobDeployed.True(obj) 210 | 211 | _, err = h.states.Update(obj) 212 | if err != nil { 213 | return obj, err 214 | } 215 | 216 | //return error because no error will clear finalizer even if job did not complete. 217 | return obj, fmt.Errorf("execution for destroy has been run") 218 | } 219 | -------------------------------------------------------------------------------- /scripts/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | $(dirname $0)/build-cli 5 | $(dirname $0)/build-executor 6 | $(dirname $0)/build-controller 7 | -------------------------------------------------------------------------------- /scripts/build-cli: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | cd $(dirname $0)/.. 7 | 8 | mkdir -p bin 9 | [ "$(uname)" != "Darwin" ] && LINKFLAGS="-extldflags -static -s" 10 | CGO_ENABLED=0 go build -ldflags "-X main.VERSION=$VERSION $LINKFLAGS" -o bin/tffy ./pkg/cli 11 | -------------------------------------------------------------------------------- /scripts/build-controller: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | cd $(dirname $0)/.. 7 | 8 | mkdir -p bin 9 | [ "$(uname)" != "Darwin" ] && LINKFLAGS="-extldflags -static -s" 10 | CGO_ENABLED=0 go build -ldflags "-X main.VERSION=$VERSION $LINKFLAGS" -o bin/terraform-controller 11 | -------------------------------------------------------------------------------- /scripts/build-executor: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | cd $(dirname $0)/.. 7 | 8 | mkdir -p bin 9 | [ "$(uname)" != "Darwin" ] && LINKFLAGS="-extldflags -static -s" 10 | CGO_ENABLED=0 go build -ldflags "-X main.VERSION=$VERSION $LINKFLAGS" -o bin/terraform-executor ./pkg/executor 11 | -------------------------------------------------------------------------------- /scripts/ci: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cd $(dirname $0) 5 | 6 | ./build 7 | ./test 8 | ./e2e 9 | ./validate 10 | ./package 11 | -------------------------------------------------------------------------------- /scripts/e2e: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ "${ARCH}" != "amd64" ]; then 5 | exit 0 6 | fi 7 | 8 | if [ ! -f ./bin/terraform-controller ]; then 9 | $(dirname $0)/build-controller 10 | fi 11 | 12 | if [ ! -f ./bin/terraform-executor ]; then 13 | $(dirname $0)/build-executor 14 | fi 15 | 16 | $(dirname $0)/e2e-package-executor 17 | 18 | cd $(dirname $0)/.. 19 | 20 | k3s server --disable servicelb --disable traefik --disable local-storage --disable metrics-server& 21 | k3s_pid=$! 22 | 23 | kubeconfig=/etc/rancher/k3s/k3s.yaml 24 | declare -i i; i=0 25 | until [ -f $kubeconfig ]; do 26 | echo "sleeping while waiting for k3s to start..." 27 | if (( i > 15 )); then 28 | break 29 | fi 30 | 31 | sleep 2 32 | i+=1 33 | done 34 | 35 | k3s ctr images import --base-name terraform-controller-executor artifacts/images/terraform-controller-executor-e2e 36 | 37 | k3s kubectl rollout status deployment coredns -n kube-system # make sure coredns is actually running 38 | 39 | export KUBECONFIG=$kubeconfig 40 | export NAMESPACE=terraform-controller 41 | 42 | ./bin/terraform-controller --threads 1& 43 | tfc_pid=$! 44 | 45 | sleep 2 #slight pause to make sure everything is running 46 | 47 | echo "Starting e2e Testing" 48 | go test -json -count=1 ./e2e/... 49 | -------------------------------------------------------------------------------- /scripts/e2e-package-executor: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | ARCH=${ARCH:-"amd64"} 7 | SUFFIX="" 8 | [ "${ARCH}" != "amd64" ] && SUFFIX="_${ARCH}" 9 | 10 | cd $(dirname $0)/../package 11 | 12 | cp ../bin/terraform-executor . 13 | 14 | IMAGE=terraform-controller-executor:e2e 15 | docker build -t ${IMAGE} -f Dockerfile.executor . 16 | mkdir -p ../artifacts/images 17 | docker image save terraform-controller-executor:e2e -o ../artifacts/images/terraform-controller-executor-e2e 18 | echo Built ${IMAGE} 19 | -------------------------------------------------------------------------------- /scripts/entry: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | echo $1 5 | 6 | mkdir -p bin dist 7 | if [ -e ./scripts/$1 ]; then 8 | ./scripts/"$@" 9 | else 10 | exec "$@" 11 | fi 12 | 13 | chown -R $DAPPER_UID:$DAPPER_GID . 14 | -------------------------------------------------------------------------------- /scripts/package: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | mkdir -p $(dirname $0)/../dist/artifacts 5 | 6 | $(dirname $0)/package-executor 7 | $(dirname $0)/package-controller 8 | $(dirname $0)/package-appliance 9 | $(dirname $0)/package-cli 10 | $(dirname $0)/package-helm 11 | -------------------------------------------------------------------------------- /scripts/package-appliance: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | cd $(dirname $0)/../package 7 | 8 | mkdir ./yaml 9 | cp ../manifests/*.yaml ./yaml 10 | 11 | IMAGE=${REPO}/terraform-controller-appliance:${TAG} 12 | docker build -t ${IMAGE} -f Dockerfile.appliance . 13 | echo ${IMAGE} > ../dist/images 14 | echo Built ${IMAGE} 15 | 16 | rm -rf ./yaml 17 | -------------------------------------------------------------------------------- /scripts/package-cli: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | cd $(dirname $0)/.. 7 | 8 | cp bin/tffy dist/artifacts/tffy${SUFFIX} 9 | -------------------------------------------------------------------------------- /scripts/package-controller: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | cd $(dirname $0)/.. 7 | 8 | cp bin/terraform-controller package/ 9 | cp bin/terraform-controller dist/artifacts/terraform-controller${SUFFIX} 10 | 11 | cd package 12 | 13 | IMAGE=${REPO}/terraform-controller:${TAG} 14 | docker build -t ${IMAGE} -f Dockerfile.controller . 15 | echo ${IMAGE} > ../dist/images 16 | echo Built ${IMAGE} 17 | -------------------------------------------------------------------------------- /scripts/package-executor: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | source $(dirname $0)/version 5 | 6 | cd $(dirname $0)/.. 7 | 8 | cp bin/terraform-executor package/ 9 | cp bin/terraform-executor dist/artifacts/terraform-executor${SUFFIX} 10 | 11 | cd package 12 | 13 | IMAGE=${REPO}/terraform-controller-executor:${TAG} 14 | docker build -t ${IMAGE} -f Dockerfile.executor . 15 | echo ${IMAGE} > ../dist/images 16 | echo Built ${IMAGE} 17 | -------------------------------------------------------------------------------- /scripts/package-helm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if ! hash helm 2>/dev/null; then 5 | exit 0 6 | fi 7 | 8 | source $(dirname $0)/version 9 | 10 | cd $(dirname $0)/.. 11 | 12 | rm -rf build/chart 13 | mkdir -p build 14 | cp -rf chart build/ 15 | 16 | sed -i \ 17 | -e 's/version:.*/version: '${HELM_VERSION}'/' \ 18 | -e 's/appVersion:.*/appVersion: '${HELM_VERSION}'/' \ 19 | build/chart/Chart.yaml 20 | 21 | sed -i \ 22 | -e 's/tag: ${VERSION}/tag: '${HELM_TAG}'/' \ 23 | build/chart/values.yaml 24 | 25 | helm package -d ./dist/artifacts ./build/chart 26 | -------------------------------------------------------------------------------- /scripts/release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec $(dirname $0)/ci 4 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cd $(dirname $0)/.. 5 | 6 | 7 | echo Running tests 8 | go test -cover -tags=test ./pkg/... 9 | -------------------------------------------------------------------------------- /scripts/validate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cd $(dirname $0)/.. 5 | 6 | echo Running validation 7 | 8 | PACKAGES="$(go list ./...)" 9 | 10 | if ! command -v golangci-lint; then 11 | echo Skipping validation: no golangci-lint available 12 | exit 13 | fi 14 | 15 | echo Running validation 16 | 17 | echo Running: golangci-lint 18 | golangci-lint run 19 | 20 | echo Tidying up modules 21 | go mod tidy 22 | 23 | echo Verifying modules 24 | go mod verify 25 | 26 | if [ -n "$(git status --porcelain --untracked-files=no)" ]; then 27 | echo "Encountered dirty repo! Did you run go mod tidy?" 28 | exit 1 29 | fi -------------------------------------------------------------------------------- /scripts/version: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -n "$(git status --porcelain --untracked-files=no)" ]; then 4 | DIRTY="-dirty" 5 | fi 6 | 7 | COMMIT=$(git rev-parse --short HEAD) 8 | GIT_TAG=${DRONE_TAG:-$(git tag -l --contains HEAD | head -n 1)} 9 | 10 | if [[ -z "$DIRTY" && -n "$GIT_TAG" ]]; then 11 | VERSION=$GIT_TAG 12 | else 13 | VERSION="${COMMIT}${DIRTY}" 14 | fi 15 | 16 | if [ -z "$ARCH" ]; then 17 | ARCH=$(go env GOHOSTARCH) 18 | fi 19 | 20 | SUFFIX="-${ARCH}" 21 | 22 | HELM_TAG=${GIT_TAG:-v0.0.0+${VERSION}} 23 | HELM_VERSION=${HELM_TAG/v/} 24 | TAG=${GIT_TAG:-${VERSION}${SUFFIX}} 25 | REPO=${REPO:-rancher} 26 | 27 | if echo $GIT_TAG | grep -q dirty; then 28 | TAG=dev 29 | HELM_TAG=v0.0.0+${COMMIT} 30 | HELM_VERSION=v0.0.0 31 | fi 32 | --------------------------------------------------------------------------------